Merge branch 'master' of github.com:azerothcore/azerothcore-wotlk into Playerbot
This commit is contained in:
@@ -575,7 +575,7 @@ if(OPENSSL_FOUND)
|
||||
include(EnsureVersion)
|
||||
ENSURE_VERSION("${OPENSSL_EXPECTED_VERSION}" "${OPENSSL_VERSION}" OPENSSL_VERSION_OK)
|
||||
if(NOT OPENSSL_VERSION_OK)
|
||||
message(FATAL_ERROR "TrinityCore needs OpenSSL version ${OPENSSL_EXPECTED_VERSION} but found too new version ${OPENSSL_VERSION}. TrinityCore needs OpenSSL 1.0.x or 1.1.x to work properly. If you still have problems please install OpenSSL 1.0.x if you still have problems search on forum for TCE00022")
|
||||
message(FATAL_ERROR "AzerothCore needs OpenSSL version ${OPENSSL_EXPECTED_VERSION} but found too new version ${OPENSSL_VERSION}. AzerothCore needs OpenSSL 1.0.x or 1.1.x to work properly. If you still have problems please install OpenSSL 1.0.x if you still have problems search on forum for TCE00022")
|
||||
endif()
|
||||
|
||||
if(NOT TARGET OpenSSL::Crypto AND
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008+ TrinityCore <http://www.trinitycore.org/>
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 _MAPDEFINES_H
|
||||
|
||||
@@ -41,13 +41,6 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if AC_COMPILER == AC_COMPILER_MICROSOFT
|
||||
#define atoll _atoi64
|
||||
#define llabs _abs64
|
||||
#else
|
||||
#define stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
#define STRINGIZE(a) #a
|
||||
|
||||
#define MAX_NETCLIENT_PACKET_SIZE (32767 - 1) // Client hardcap: int16 with trailing zero space otherwise crash on memory free
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace
|
||||
std::vector<std::string> _additonalFiles;
|
||||
std::vector<std::string> _args;
|
||||
std::unordered_map<std::string /*name*/, std::string /*value*/> _configOptions;
|
||||
std::unordered_map<std::string /*name*/, std::string /*value*/> _envVarCache;
|
||||
std::mutex _configLock;
|
||||
|
||||
// Check system configs like *server.conf*
|
||||
@@ -39,8 +40,9 @@ namespace
|
||||
{
|
||||
size_t foundAuth = fileName.find("authserver.conf");
|
||||
size_t foundWorld = fileName.find("worldserver.conf");
|
||||
size_t foundImport = fileName.find("dbimport.conf");
|
||||
|
||||
return foundAuth != std::string_view::npos || foundWorld != std::string_view::npos;
|
||||
return foundAuth != std::string_view::npos || foundWorld != std::string_view::npos || foundImport != std::string_view::npos;
|
||||
}
|
||||
|
||||
// Check logging system configs like Appender.* and Logger.*
|
||||
@@ -119,7 +121,7 @@ namespace
|
||||
auto const& itr = fileConfigs.find(confOption);
|
||||
if (itr != fileConfigs.end())
|
||||
{
|
||||
PrintError(file, "> Config::LoadFile: Dublicate key name '{}' in config file '{}'", confOption, file);
|
||||
PrintError(file, "> Config::LoadFile: Duplicate key name '{}' in config file '{}'", confOption, file);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -282,9 +284,14 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetEnvVarName(std::string const& configName)
|
||||
{
|
||||
return "AC_" + IniKeyToEnvVarKey(configName);
|
||||
}
|
||||
|
||||
Optional<std::string> EnvVarForIniKey(std::string const& key)
|
||||
{
|
||||
std::string envKey = "AC_" + IniKeyToEnvVarKey(key);
|
||||
std::string envKey = GetEnvVarName(key);
|
||||
char* val = std::getenv(envKey.c_str());
|
||||
if (!val)
|
||||
return std::nullopt;
|
||||
@@ -329,6 +336,29 @@ bool ConfigMgr::Reload()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the _envVarCache if the env var is there
|
||||
// if not, check the env for the value
|
||||
Optional<std::string> GetEnvFromCache(std::string const& configName, std::string const& envVarName)
|
||||
{
|
||||
auto foundInCache = _envVarCache.find(envVarName);
|
||||
Optional<std::string> foundInEnv;
|
||||
// If it's not in the cache
|
||||
if (foundInCache == _envVarCache.end())
|
||||
{
|
||||
// Check the env itself
|
||||
foundInEnv = EnvVarForIniKey(configName);
|
||||
if (foundInEnv)
|
||||
{
|
||||
// If it's found in the env, put it in the cache
|
||||
_envVarCache.emplace(envVarName, *foundInEnv);
|
||||
}
|
||||
// Return the result of checking env
|
||||
return foundInEnv;
|
||||
}
|
||||
|
||||
return foundInCache->second;
|
||||
}
|
||||
|
||||
std::vector<std::string> ConfigMgr::OverrideWithEnvVariablesIfAny()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_configLock);
|
||||
@@ -356,29 +386,31 @@ template<class T>
|
||||
T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLogs /*= true*/) const
|
||||
{
|
||||
std::string strValue;
|
||||
|
||||
auto const& itr = _configOptions.find(name);
|
||||
if (itr == _configOptions.end())
|
||||
bool notFound = itr == _configOptions.end();
|
||||
auto envVarName = GetEnvVarName(name);
|
||||
Optional<std::string> envVar = GetEnvFromCache(name, envVarName);
|
||||
if (envVar)
|
||||
{
|
||||
Optional<std::string> envVar = EnvVarForIniKey(name);
|
||||
if (!envVar)
|
||||
// If showLogs and this key/value pair wasn't found in the currently saved config
|
||||
if (showLogs && (notFound || itr->second != envVar->c_str()))
|
||||
{
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
|
||||
name, _filename, name, Acore::ToString(def));
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
|
||||
name, _filename, envVar->c_str());
|
||||
LOG_INFO("server.loading", "> Config: Found config value '{}' from environment variable '{}'.", name, envVarName );
|
||||
AddKey(name, envVar->c_str(), "ENVIRONMENT", false, false);
|
||||
}
|
||||
|
||||
strValue = *envVar;
|
||||
}
|
||||
else if (notFound)
|
||||
{
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.",
|
||||
name, _filename, name, Acore::ToString(def), envVarName);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
else
|
||||
{
|
||||
strValue = itr->second;
|
||||
@@ -403,24 +435,26 @@ template<>
|
||||
std::string ConfigMgr::GetValueDefault<std::string>(std::string const& name, std::string const& def, bool showLogs /*= true*/) const
|
||||
{
|
||||
auto const& itr = _configOptions.find(name);
|
||||
if (itr == _configOptions.end())
|
||||
bool notFound = itr == _configOptions.end();
|
||||
auto envVarName = GetEnvVarName(name);
|
||||
Optional<std::string> envVar = GetEnvFromCache(name, envVarName);
|
||||
if (envVar)
|
||||
{
|
||||
Optional<std::string> envVar = EnvVarForIniKey(name);
|
||||
if (envVar)
|
||||
// If showLogs and this key/value pair wasn't found in the currently saved config
|
||||
if (showLogs && (notFound || itr->second != envVar->c_str()))
|
||||
{
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
|
||||
name, _filename, envVar->c_str());
|
||||
}
|
||||
|
||||
return *envVar;
|
||||
LOG_INFO("server.loading", "> Config: Found config value '{}' from environment variable '{}'.", name, envVarName);
|
||||
AddKey(name, *envVar, "ENVIRONMENT", false, false);
|
||||
}
|
||||
|
||||
return *envVar;
|
||||
}
|
||||
else if (notFound)
|
||||
{
|
||||
if (showLogs)
|
||||
{
|
||||
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
|
||||
name, _filename, name, def);
|
||||
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.",
|
||||
name, _filename, name, def, envVarName);
|
||||
}
|
||||
|
||||
return def;
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 "GitRevision.h"
|
||||
#include "revision.h"
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2018 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 __GITREVISION_H__
|
||||
#define __GITREVISION_H__
|
||||
|
||||
@@ -398,6 +398,4 @@ void Log::LoadFromConfig()
|
||||
|
||||
ReadAppendersFromConfig();
|
||||
ReadLoggersFromConfig();
|
||||
|
||||
_debugLogMask = DebugLogFilters(sConfigMgr->GetOption<uint32>("DebugLogMask", LOG_FILTER_NONE, false));
|
||||
}
|
||||
|
||||
@@ -121,8 +121,6 @@ private:
|
||||
|
||||
Acore::Asio::IoContext* _ioContext;
|
||||
Acore::Asio::Strand* _strand;
|
||||
// Deprecated debug filter logs
|
||||
DebugLogFilters _debugLogMask;
|
||||
};
|
||||
|
||||
#define sLog Log::instance()
|
||||
|
||||
@@ -46,6 +46,7 @@ enum AppenderType : uint8
|
||||
APPENDER_INVALID = 0xFF // SKIP
|
||||
};
|
||||
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
enum AppenderFlags : uint8
|
||||
{
|
||||
APPENDER_FLAGS_NONE = 0x00,
|
||||
@@ -56,37 +57,4 @@ enum AppenderFlags : uint8
|
||||
APPENDER_FLAGS_MAKE_FILE_BACKUP = 0x10
|
||||
};
|
||||
|
||||
// Dprecated debug log filters need delte later
|
||||
enum DebugLogFilters
|
||||
{
|
||||
LOG_FILTER_NONE = 0x00000000,
|
||||
LOG_FILTER_UNITS = 0x00000001, // Anything related to units that doesn't fit in other categories. ie. creature formations
|
||||
LOG_FILTER_PETS = 0x00000002,
|
||||
LOG_FILTER_VEHICLES = 0x00000004,
|
||||
LOG_FILTER_TSCR = 0x00000008, // C++ AI, instance scripts, etc.
|
||||
LOG_FILTER_DATABASE_AI = 0x00000010, // SmartAI, EventAI, CreatureAI
|
||||
LOG_FILTER_MAPSCRIPTS = 0x00000020,
|
||||
LOG_FILTER_NETWORKIO = 0x00000040, // Anything packet/netcode related
|
||||
LOG_FILTER_SPELLS_AURAS = 0x00000080,
|
||||
LOG_FILTER_ACHIEVEMENTSYS = 0x00000100,
|
||||
LOG_FILTER_CONDITIONSYS = 0x00000200,
|
||||
LOG_FILTER_POOLSYS = 0x00000400,
|
||||
LOG_FILTER_AUCTIONHOUSE = 0x00000800,
|
||||
LOG_FILTER_BATTLEGROUND = 0x00001000, // Anything related to arena's and battlegrounds
|
||||
LOG_FILTER_OUTDOORPVP = 0x00002000,
|
||||
LOG_FILTER_CHATSYS = 0x00004000,
|
||||
LOG_FILTER_LFG = 0x00008000,
|
||||
LOG_FILTER_MAPS = 0x00010000, // Maps, instances, grids, cells, visibility
|
||||
LOG_FILTER_PLAYER_LOADING = 0x00020000, // Debug output from Player::_Load functions
|
||||
LOG_FILTER_PLAYER_ITEMS = 0x00040000, // Anything item related
|
||||
LOG_FILTER_PLAYER_SKILLS = 0x00080000, // Skills related
|
||||
LOG_FILTER_LOOT = 0x00100000, // Loot related
|
||||
LOG_FILTER_GUILD = 0x00200000, // Guild related
|
||||
LOG_FILTER_TRANSPORTS = 0x00400000, // Transport related
|
||||
LOG_FILTER_WARDEN = 0x00800000, // Warden related
|
||||
LOG_FILTER_BATTLEFIELD = 0x01000000, // Battlefield related
|
||||
LOG_FILTER_MODULES = 0x02000000, // Modules debug
|
||||
LOG_FILTER_CLOSE_SOCKET = 0x04000000, // Whenever KickPlayer() or CloseSocket() are called
|
||||
};
|
||||
|
||||
#endif // LogCommon_h__
|
||||
|
||||
@@ -121,4 +121,55 @@ AC_API_EXPORT size_t EnumUtils<AppenderType>::ToIndex(AppenderType value)
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************\
|
||||
|* data for enum 'AppenderFlags' in 'LogCommon.h' auto-generated *|
|
||||
\*****************************************************************/
|
||||
template <>
|
||||
AC_API_EXPORT EnumText EnumUtils<AppenderFlags>::ToString(AppenderFlags value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case APPENDER_FLAGS_NONE: return { "APPENDER_FLAGS_NONE", "APPENDER_FLAGS_NONE", "" };
|
||||
case APPENDER_FLAGS_PREFIX_TIMESTAMP: return { "APPENDER_FLAGS_PREFIX_TIMESTAMP", "APPENDER_FLAGS_PREFIX_TIMESTAMP", "" };
|
||||
case APPENDER_FLAGS_PREFIX_LOGLEVEL: return { "APPENDER_FLAGS_PREFIX_LOGLEVEL", "APPENDER_FLAGS_PREFIX_LOGLEVEL", "" };
|
||||
case APPENDER_FLAGS_PREFIX_LOGFILTERTYPE: return { "APPENDER_FLAGS_PREFIX_LOGFILTERTYPE", "APPENDER_FLAGS_PREFIX_LOGFILTERTYPE", "" };
|
||||
case APPENDER_FLAGS_USE_TIMESTAMP: return { "APPENDER_FLAGS_USE_TIMESTAMP", "APPENDER_FLAGS_USE_TIMESTAMP", "" };
|
||||
case APPENDER_FLAGS_MAKE_FILE_BACKUP: return { "APPENDER_FLAGS_MAKE_FILE_BACKUP", "APPENDER_FLAGS_MAKE_FILE_BACKUP", "" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<AppenderFlags>::Count() { return 6; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT AppenderFlags EnumUtils<AppenderFlags>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return APPENDER_FLAGS_NONE;
|
||||
case 1: return APPENDER_FLAGS_PREFIX_TIMESTAMP;
|
||||
case 2: return APPENDER_FLAGS_PREFIX_LOGLEVEL;
|
||||
case 3: return APPENDER_FLAGS_PREFIX_LOGFILTERTYPE;
|
||||
case 4: return APPENDER_FLAGS_USE_TIMESTAMP;
|
||||
case 5: return APPENDER_FLAGS_MAKE_FILE_BACKUP;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<AppenderFlags>::ToIndex(AppenderFlags value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case APPENDER_FLAGS_NONE: return 0;
|
||||
case APPENDER_FLAGS_PREFIX_TIMESTAMP: return 1;
|
||||
case APPENDER_FLAGS_PREFIX_LOGLEVEL: return 2;
|
||||
case APPENDER_FLAGS_PREFIX_LOGFILTERTYPE: return 3;
|
||||
case APPENDER_FLAGS_USE_TIMESTAMP: return 4;
|
||||
case APPENDER_FLAGS_MAKE_FILE_BACKUP: return 5;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 EnumFlag_h__
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_SMARTENUM_H
|
||||
#define TRINITY_SMARTENUM_H
|
||||
#ifndef AC_SMARTENUM_H
|
||||
#define AC_SMARTENUM_H
|
||||
|
||||
#include "IteratorPair.h"
|
||||
#include <iterator>
|
||||
@@ -130,4 +130,4 @@ public:
|
||||
static char const* ToDescription(Enum value) { return ToString(value).Description; }
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // AC_SMART_ENUM_H
|
||||
|
||||
@@ -72,8 +72,22 @@ namespace Acore
|
||||
std::string const& logger, std::string const& input,
|
||||
bool secure)
|
||||
{
|
||||
#if AC_COMPILER == AC_COMPILER_MICROSOFT
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4297)
|
||||
/*
|
||||
Silence warning with boost 1.83
|
||||
boost/process/pipe.hpp(132,5): warning C4297: 'boost::process::basic_pipebuf<char,std::char_traits<char>>::~basic_pipebuf': function assumed not to throw an exception but does
|
||||
boost/process/pipe.hpp(132,5): message : destructor or deallocator has a (possibly implicit) non-throwing exception specification
|
||||
boost/process/pipe.hpp(124,6): message : while compiling class template member function 'boost::process::basic_pipebuf<char,std::char_traits<char>>::~basic_pipebuf(void)'
|
||||
boost/process/pipe.hpp(304,42): message : see reference to class template instantiation 'boost::process::basic_pipebuf<char,std::char_traits<char>>' being compiled
|
||||
*/
|
||||
#endif
|
||||
ipstream outStream;
|
||||
ipstream errStream;
|
||||
#if AC_COMPILER == AC_COMPILER_MICROSOFT
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if (!secure)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008+ TrinityCore <http://www.trinitycore.org/>
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 "TaskScheduler.h"
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008+ TrinityCore <http://www.trinitycore.org/>
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 _TASK_SCHEDULER_H_
|
||||
@@ -432,11 +444,11 @@ public:
|
||||
: _task(right._task), _owner(right._owner), _consumed(right._consumed) { }
|
||||
|
||||
// Move construct
|
||||
TaskContext(TaskContext&& right)
|
||||
TaskContext(TaskContext&& right) noexcept
|
||||
: _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { }
|
||||
|
||||
// Copy assign
|
||||
TaskContext& operator= (TaskContext const& right)
|
||||
TaskContext& operator= (TaskContext const& right) noexcept
|
||||
{
|
||||
_task = right._task;
|
||||
_owner = right._owner;
|
||||
@@ -445,7 +457,7 @@ public:
|
||||
}
|
||||
|
||||
// Move assign
|
||||
TaskContext& operator= (TaskContext&& right)
|
||||
TaskContext& operator= (TaskContext&& right) noexcept
|
||||
{
|
||||
_task = std::move(right._task);
|
||||
_owner = std::move(right._owner);
|
||||
|
||||
@@ -85,8 +85,6 @@ int main(int argc, char** argv)
|
||||
if (!sConfigMgr->LoadAppConfigs())
|
||||
return 1;
|
||||
|
||||
std::vector<std::string> overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny();
|
||||
|
||||
// Init logging
|
||||
sLog->RegisterAppender<AppenderDB>();
|
||||
sLog->Initialize(nullptr);
|
||||
@@ -103,9 +101,6 @@ int main(int argc, char** argv)
|
||||
LOG_INFO("server.authserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
|
||||
});
|
||||
|
||||
for (std::string const& key : overriddenKeys)
|
||||
LOG_INFO("server.authserver", "Configuration field {} was overridden with environment variable.", key);
|
||||
|
||||
OpenSSLCrypto::threadsSetup();
|
||||
|
||||
std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
|
||||
|
||||
@@ -45,6 +45,7 @@ enum AuthStatus
|
||||
STATUS_CLOSED
|
||||
};
|
||||
|
||||
// cppcheck-suppress ctuOneDefinitionRuleViolation
|
||||
struct AccountInfo
|
||||
{
|
||||
void LoadResult(Field* fields);
|
||||
|
||||
@@ -184,8 +184,6 @@ int main(int argc, char** argv)
|
||||
if (!sConfigMgr->LoadAppConfigs())
|
||||
return 1;
|
||||
|
||||
std::vector<std::string> overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny();
|
||||
|
||||
std::shared_ptr<Acore::Asio::IoContext> ioContext = std::make_shared<Acore::Asio::IoContext>();
|
||||
|
||||
// Init all logs
|
||||
@@ -205,9 +203,6 @@ int main(int argc, char** argv)
|
||||
LOG_INFO("server.worldserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
|
||||
});
|
||||
|
||||
for (std::string const& key : overriddenKeys)
|
||||
LOG_INFO("server.worldserver", "Configuration field {} was overridden with environment variable.", key);
|
||||
|
||||
OpenSSLCrypto::threadsSetup();
|
||||
|
||||
std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -71,7 +71,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
"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, "
|
||||
"health, power1, power2, power3, power4, power5, power6, power7, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, "
|
||||
"knownTitles, actionBars, grantableLevels, innTriggerId, extraBonusTalentCount FROM characters WHERE guid = ?", CONNECTION_ASYNC);
|
||||
"knownTitles, actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date) FROM characters WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, "
|
||||
"base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
@@ -82,7 +82,7 @@ protected:
|
||||
Creature* DoSummon(uint32 entry, WorldObject* obj, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
Creature* DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
public:
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
// EnumUtils: DESCRIBE THIS (in CreatureAI::)
|
||||
enum EvadeReason
|
||||
{
|
||||
EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty
|
||||
|
||||
@@ -601,7 +601,7 @@ void SmartAI::MovepointReached(uint32 id)
|
||||
if (mLastWP)
|
||||
{
|
||||
me->SetPosition(mLastWP->x, mLastWP->y, mLastWP->z, me->GetOrientation());
|
||||
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
me->SetHomePosition(me->GetPosition());
|
||||
}
|
||||
|
||||
if (HasEscortState(SMART_ESCORT_PAUSED))
|
||||
|
||||
@@ -593,9 +593,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
// may be nullptr
|
||||
if (go)
|
||||
{
|
||||
go->CastSpell(target->ToUnit(), e.action.cast.spell);
|
||||
}
|
||||
|
||||
if (!IsUnit(target))
|
||||
continue;
|
||||
@@ -604,29 +602,24 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED));
|
||||
}
|
||||
else if (me && (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)))
|
||||
else if (me)
|
||||
{
|
||||
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
}
|
||||
// If target has the aura, skip
|
||||
if ((e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) && target->ToUnit()->HasAura(e.action.cast.spell))
|
||||
continue;
|
||||
|
||||
// If the threatlist is a singleton, cancel
|
||||
if (e.action.cast.castFlags & SMARTCAST_THREATLIST_NOT_SINGLE)
|
||||
if (me->GetThreatMgr().GetThreatListSize() <= 1)
|
||||
break;
|
||||
|
||||
TriggerCastFlags triggerFlags = TRIGGERED_NONE;
|
||||
if (e.action.cast.castFlags & SMARTCAST_TRIGGERED)
|
||||
{
|
||||
if (e.action.cast.triggerFlags)
|
||||
{
|
||||
triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
triggerFlags = TRIGGERED_FULL_MASK;
|
||||
}
|
||||
}
|
||||
// If target does not use mana, skip
|
||||
if ((e.action.cast.castFlags & SMARTCAST_TARGET_POWER_MANA) && !target->ToUnit()->GetPower(POWER_MANA))
|
||||
continue;
|
||||
|
||||
// Interrupts current spellcast
|
||||
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
// Flag usable only if caster has max dist set.
|
||||
if ((e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0)
|
||||
@@ -647,15 +640,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
}
|
||||
|
||||
TriggerCastFlags triggerFlags = TRIGGERED_NONE;
|
||||
if (e.action.cast.castFlags & SMARTCAST_TRIGGERED)
|
||||
{
|
||||
if (e.action.cast.triggerFlags)
|
||||
triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
|
||||
else
|
||||
triggerFlags = TRIGGERED_FULL_MASK;
|
||||
}
|
||||
|
||||
me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
|
||||
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST: Unit {} casts spell {} on target {} with castflags {}",
|
||||
me->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
|
||||
e.action.cast.spell, target->GetGUID().ToString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2991,6 +2988,47 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_SET_ORIENTATION_TARGET:
|
||||
{
|
||||
switch (e.action.orientationTarget.type)
|
||||
{
|
||||
case 0: // Reset
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingTo((target->ToCreature()->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && target->ToCreature()->GetTransGUID() ? target->ToCreature()->GetTransportHomePosition() : target->ToCreature()->GetHomePosition()).GetOrientation());
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // Target target.o
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingTo(e.target.o);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Target source
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingToObject(me);
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Target parameters
|
||||
{
|
||||
ObjectVector facingTargets;
|
||||
GetTargets(facingTargets, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.orientationTarget.targetType, e.action.orientationTarget.targetParam1, e.action.orientationTarget.targetParam2, e.action.orientationTarget.targetParam3, e.action.orientationTarget.targetParam4, 0), unit);
|
||||
|
||||
for (WorldObject* facingTarget : facingTargets)
|
||||
for (WorldObject* target : targets)
|
||||
target->ToCreature()->SetFacingToObject(facingTarget);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
@@ -3162,7 +3200,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3174,7 +3212,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3186,7 +3224,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3198,7 +3236,7 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
|
||||
if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
|
||||
targets.push_back(u);
|
||||
}
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
|
||||
else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly, true, -e.target.hostileRandom.aura))
|
||||
targets.push_back(u);
|
||||
}
|
||||
break;
|
||||
@@ -3785,16 +3823,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (!me || !me->IsEngaged() || !me->GetVictim())
|
||||
return;
|
||||
|
||||
if (me->IsInRange(me->GetVictim(), (float)e.event.rangeRepeat.minRange, (float)e.event.rangeRepeat.maxRange))
|
||||
{
|
||||
if (e.event.rangeRepeat.onlyFireOnRepeat == 2)
|
||||
{
|
||||
e.event.rangeRepeat.onlyFireOnRepeat = 1;
|
||||
RecalcTimer(e, e.event.rangeRepeat.repeatMin, e.event.rangeRepeat.repeatMax);
|
||||
}
|
||||
else
|
||||
ProcessTimedAction(e, e.event.rangeRepeat.repeatMin, e.event.rangeRepeat.repeatMax, me->GetVictim());
|
||||
}
|
||||
if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax))
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->GetVictim());
|
||||
else
|
||||
RecalcTimer(e, 1200, 1200); // make it predictable
|
||||
|
||||
@@ -3947,9 +3977,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
|
||||
if (Unit* victim = me->GetVictim())
|
||||
{
|
||||
if (!victim->HasInArc(static_cast<float>(M_PI), me))
|
||||
ProcessTimedAction(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax, victim);
|
||||
if (e.event.minMaxRepeat.rangeMax && (me->IsInRange(victim, (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax)))
|
||||
if (!victim->HasInArc(static_cast<float>(M_PI), me))
|
||||
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, victim);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_RECEIVE_EMOTE:
|
||||
@@ -4229,7 +4261,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat())
|
||||
{
|
||||
uint32 healthPct = uint32(target->ToUnit()->GetHealthPct());
|
||||
if (healthPct > e.event.friendlyHealthPct.maxHpPct || healthPct < e.event.friendlyHealthPct.minHpPct)
|
||||
if (healthPct > e.event.friendlyHealthPct.hpPct)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -4243,7 +4275,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
}
|
||||
case SMART_TARGET_SELF:
|
||||
case SMART_TARGET_ACTION_INVOKER:
|
||||
unitTarget = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct);
|
||||
unitTarget = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, 0, e.event.friendlyHealthPct.hpPct);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -4435,14 +4467,14 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
|
||||
{
|
||||
if (!target || target->IsPet() || target->IsTotem() || !target->IsNonMeleeSpellCast(false, false, true))
|
||||
if (!target || !IsPlayer(target) || !target->IsNonMeleeSpellCast(false, false, true))
|
||||
continue;
|
||||
|
||||
if (e.event.areaCasting.rangeMin && !(me->IsInRange(target, (float)e.event.areaCasting.rangeMin, (float)e.event.areaCasting.rangeMax)))
|
||||
if (!(me->IsInRange(target, (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax)))
|
||||
continue;
|
||||
|
||||
ProcessAction(e, target);
|
||||
RecalcTimer(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax);
|
||||
RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4463,11 +4495,11 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
|
||||
{
|
||||
if (!(me->IsInRange(target, (float)e.event.areaRange.rangeMin, (float)e.event.areaRange.rangeMax)))
|
||||
if (!(me->IsInRange(target, (float)e.event.minMaxRepeat.rangeMin, (float)e.event.minMaxRepeat.rangeMax)))
|
||||
continue;
|
||||
|
||||
ProcessAction(e, target);
|
||||
RecalcTimer(e, e.event.areaRange.repeatMin, e.event.areaRange.repeatMax);
|
||||
RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4487,16 +4519,6 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
|
||||
switch (e.GetEventType())
|
||||
{
|
||||
//set only events which have initial timers
|
||||
case SMART_EVENT_RANGE:
|
||||
// If onlyFireOnRepeat is true set to 2 before entering combat. Will be set back to 1 after entering combat to ignore initial firing.
|
||||
if (e.event.rangeRepeat.onlyFireOnRepeat == 1)
|
||||
e.event.rangeRepeat.onlyFireOnRepeat = 2;
|
||||
// make it predictable
|
||||
RecalcTimer(e, 1200, 1200);
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
RecalcTimer(e, e.event.areaRange.min, e.event.areaRange.max);
|
||||
break;
|
||||
case SMART_EVENT_NEAR_PLAYERS:
|
||||
case SMART_EVENT_NEAR_PLAYERS_NEGATION:
|
||||
RecalcTimer(e, e.event.nearPlayer.firstTimer, e.event.nearPlayer.firstTimer);
|
||||
@@ -4504,13 +4526,13 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
|
||||
case SMART_EVENT_UPDATE:
|
||||
case SMART_EVENT_UPDATE_IC:
|
||||
case SMART_EVENT_UPDATE_OOC:
|
||||
case SMART_EVENT_RANGE:
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
case SMART_EVENT_FRIENDLY_HEALTH_PCT:
|
||||
RecalcTimer(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max);
|
||||
break;
|
||||
case SMART_EVENT_OOC_LOS:
|
||||
case SMART_EVENT_IC_LOS:
|
||||
// Xinef: cooldown should be processed AFTER action is done, not before...
|
||||
//RecalcTimer(e, e.event.los.cooldownMin, e.event.los.cooldownMax);
|
||||
//break;
|
||||
case SMART_EVENT_DISTANCE_CREATURE:
|
||||
case SMART_EVENT_DISTANCE_GAMEOBJECT:
|
||||
RecalcTimer(e, e.event.distance.repeat, e.event.distance.repeat);
|
||||
@@ -4519,9 +4541,6 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
|
||||
case SMART_EVENT_NEAR_UNIT_NEGATION:
|
||||
RecalcTimer(e, e.event.nearUnit.timer, e.event.nearUnit.timer);
|
||||
break;
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
RecalcTimer(e, e.event.areaCasting.min, e.event.areaCasting.max);
|
||||
break;
|
||||
default:
|
||||
e.active = true;
|
||||
break;
|
||||
@@ -4550,14 +4569,14 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
|
||||
|
||||
if (e.timer < diff)
|
||||
{
|
||||
// delay spell cast event if another spell is being casted
|
||||
// delay spell cast for another AI tick if another spell is being cast
|
||||
if (e.GetActionType() == SMART_ACTION_CAST)
|
||||
{
|
||||
if (!(e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS))
|
||||
{
|
||||
if (me && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
e.timer = 1;
|
||||
e.timer = 1200;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4566,9 +4585,9 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
|
||||
// Delay flee for assist event if casting
|
||||
if (e.GetActionType() == SMART_ACTION_FLEE_FOR_ASSIST && me && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
e.timer = 1;
|
||||
e.timer = 1200;
|
||||
return;
|
||||
}
|
||||
} // @TODO: Can't these be handled by the action themselves instead? Less expensive
|
||||
|
||||
e.active = true;//activate events with cooldown
|
||||
switch (e.GetEventType())//process ONLY timed events
|
||||
@@ -4809,10 +4828,10 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTrigger const* at)
|
||||
InitTimer((*i));//calculate timers for first time use
|
||||
if (i->GetEventType() == SMART_EVENT_RANGE && i->GetActionType() == SMART_ACTION_ALLOW_COMBAT_MOVEMENT)
|
||||
{
|
||||
if (i->action.combatMove.move == 1 && i->event.rangeRepeat.minRange > minEnableDist)
|
||||
minEnableDist = i->event.rangeRepeat.minRange;
|
||||
else if (i->action.combatMove.move == 0 && (i->event.rangeRepeat.maxRange < maxDisableDist || maxDisableDist == 0))
|
||||
maxDisableDist = i->event.rangeRepeat.maxRange;
|
||||
if (i->action.combatMove.move == 1 && i->event.minMaxRepeat.rangeMin > minEnableDist)
|
||||
minEnableDist = i->event.minMaxRepeat.rangeMin;
|
||||
else if (i->action.combatMove.move == 0 && (i->event.minMaxRepeat.rangeMax < maxDisableDist || maxDisableDist == 0))
|
||||
maxDisableDist = i->event.minMaxRepeat.rangeMax;
|
||||
}
|
||||
|
||||
// Xinef: if smartcast combat move flag is present
|
||||
|
||||
@@ -264,29 +264,14 @@ void SmartAIMgr::LoadSmartAIFromDB()
|
||||
case SMART_EVENT_FRIENDLY_MISSING_BUFF:
|
||||
case SMART_EVENT_HAS_AURA:
|
||||
case SMART_EVENT_TARGET_BUFFED:
|
||||
case SMART_EVENT_RANGE:
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (temp.event.minMaxRepeat.repeatMin == 0 && temp.event.minMaxRepeat.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_RANGE:
|
||||
if (temp.event.rangeRepeat.repeatMin == 0 && temp.event.rangeRepeat.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
// Will only work properly if value is 0 or 1
|
||||
if (temp.event.rangeRepeat.onlyFireOnRepeat > 1)
|
||||
temp.event.rangeRepeat.onlyFireOnRepeat = 1;
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
if (temp.event.areaRange.repeatMin == 0 && temp.event.areaRange.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_VICTIM_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (temp.event.minMaxRepeat.min == 0 && temp.event.minMaxRepeat.max == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
if (temp.event.areaCasting.repeatMin == 0 && temp.event.areaCasting.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
break;
|
||||
case SMART_EVENT_FRIENDLY_IS_CC:
|
||||
if (temp.event.friendlyCC.repeatMin == 0 && temp.event.friendlyCC.repeatMax == 0)
|
||||
temp.event.event_flags |= SMART_EVENT_FLAG_NOT_REPEATABLE;
|
||||
@@ -506,7 +491,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_DEATH: return NO_PARAMS;
|
||||
case SMART_EVENT_EVADE: return NO_PARAMS;
|
||||
case SMART_EVENT_SPELLHIT: return sizeof(SmartEvent::spellHit);
|
||||
case SMART_EVENT_RANGE: return sizeof(SmartEvent::rangeRepeat);
|
||||
case SMART_EVENT_RANGE: return sizeof(SmartEvent::minMaxRepeat);
|
||||
case SMART_EVENT_OOC_LOS: return sizeof(SmartEvent::los);
|
||||
case SMART_EVENT_RESPAWN: return sizeof(SmartEvent::respawn);
|
||||
case SMART_EVENT_TARGET_HEALTH_PCT: return sizeof(SmartEvent::minMaxRepeat);
|
||||
@@ -564,7 +549,7 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_GOSSIP_HELLO: return sizeof(SmartEvent::gossipHello);
|
||||
case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS;
|
||||
case SMART_EVENT_EVENT_PHASE_CHANGE: return sizeof(SmartEvent::eventPhaseChange);
|
||||
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::behindTarget);
|
||||
case SMART_EVENT_IS_BEHIND_TARGET: return sizeof(SmartEvent::minMaxRepeat);
|
||||
case SMART_EVENT_GAME_EVENT_START: return sizeof(SmartEvent::gameEvent);
|
||||
case SMART_EVENT_GAME_EVENT_END: return sizeof(SmartEvent::gameEvent);
|
||||
case SMART_EVENT_GO_STATE_CHANGED: return sizeof(SmartEvent::goStateChanged);
|
||||
@@ -584,8 +569,8 @@ bool SmartAIMgr::CheckUnusedEventParams(SmartScriptHolder const& e)
|
||||
case SMART_EVENT_NEAR_PLAYERS_NEGATION: return sizeof(SmartEvent::nearPlayerNegation);
|
||||
case SMART_EVENT_NEAR_UNIT: return sizeof(SmartEvent::nearUnit);
|
||||
case SMART_EVENT_NEAR_UNIT_NEGATION: return sizeof(SmartEvent::nearUnitNegation);
|
||||
case SMART_EVENT_AREA_CASTING: return sizeof(SmartEvent::areaCasting);
|
||||
case SMART_EVENT_AREA_RANGE: return sizeof(SmartEvent::areaRange);
|
||||
case SMART_EVENT_AREA_CASTING: return sizeof(SmartEvent::minMaxRepeat);
|
||||
case SMART_EVENT_AREA_RANGE: return sizeof(SmartEvent::minMaxRepeat);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an event {} with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetEventType());
|
||||
@@ -781,6 +766,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_SUMMON_RADIAL: return sizeof(SmartAction::radialSummon);
|
||||
case SMART_ACTION_PLAY_SPELL_VISUAL: return sizeof(SmartAction::spellVisual);
|
||||
case SMART_ACTION_FOLLOW_GROUP: return sizeof(SmartAction::followGroup);
|
||||
case SMART_ACTION_SET_ORIENTATION_TARGET: return sizeof(SmartAction::orientationTarget);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
@@ -963,21 +949,17 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_RANGE:
|
||||
if (!IsMinMaxValid(e, e.event.rangeRepeat.minRange, e.event.rangeRepeat.maxRange))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.rangeRepeat.repeatMin, e.event.rangeRepeat.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_AREA_RANGE:
|
||||
if (!IsMinMaxValid(e, e.event.areaRange.min, e.event.areaRange.max))
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
case SMART_EVENT_RANGE:
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaRange.repeatMin, e.event.areaRange.repeatMax))
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaRange.rangeMin, e.event.areaRange.rangeMax))
|
||||
if (!IsMinMaxValid(e, e.event.minMaxRepeat.rangeMin, e.event.minMaxRepeat.rangeMax))
|
||||
return false;
|
||||
|
||||
break;
|
||||
@@ -1070,16 +1052,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsMinMaxValid(e, e.event.targetCasting.repeatMin, e.event.targetCasting.repeatMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_AREA_CASTING:
|
||||
if (!IsMinMaxValid(e, e.event.areaCasting.min, e.event.areaCasting.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaCasting.repeatMin, e.event.areaCasting.repeatMax))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.areaCasting.rangeMin, e.event.areaCasting.rangeMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_PASSENGER_BOARDED:
|
||||
case SMART_EVENT_PASSENGER_REMOVED:
|
||||
if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax))
|
||||
@@ -1185,10 +1157,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_IS_BEHIND_TARGET:
|
||||
if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax))
|
||||
return false;
|
||||
break;
|
||||
case SMART_EVENT_GAME_EVENT_START:
|
||||
case SMART_EVENT_GAME_EVENT_END:
|
||||
{
|
||||
@@ -1207,10 +1175,13 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
}
|
||||
case SMART_EVENT_FRIENDLY_HEALTH_PCT:
|
||||
if (!IsMinMaxValid(e, e.event.friendlyHealthPct.min, e.event.friendlyHealthPct.max))
|
||||
return false;
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax))
|
||||
return false;
|
||||
|
||||
if (e.event.friendlyHealthPct.maxHpPct > 100 || e.event.friendlyHealthPct.minHpPct > 100)
|
||||
if (e.event.friendlyHealthPct.hpPct > 100)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
return false;
|
||||
@@ -1971,6 +1942,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_SUMMON_RADIAL:
|
||||
case SMART_ACTION_PLAY_SPELL_VISUAL:
|
||||
case SMART_ACTION_FOLLOW_GROUP:
|
||||
case SMART_ACTION_SET_ORIENTATION_TARGET:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -124,7 +124,7 @@ enum SMART_EVENT
|
||||
SMART_EVENT_DEATH = 6, // NONE
|
||||
SMART_EVENT_EVADE = 7, // NONE
|
||||
SMART_EVENT_SPELLHIT = 8, // SpellID, School, CooldownMin, CooldownMax
|
||||
SMART_EVENT_RANGE = 9, // minRange, maxRange, repeatMin, repeatMax, onlyFireOnRepeat
|
||||
SMART_EVENT_RANGE = 9, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
SMART_EVENT_OOC_LOS = 10, // HostilityMode, MaxRnage, CooldownMin, CooldownMax, PlayerOnly
|
||||
SMART_EVENT_RESPAWN = 11, // type, MapId, ZoneId
|
||||
SMART_EVENT_TARGET_HEALTH_PCT = 12, // HPMin%, HPMax%, RepeatMin, RepeatMax
|
||||
@@ -182,14 +182,14 @@ enum SMART_EVENT
|
||||
SMART_EVENT_GOSSIP_HELLO = 64, // event_para_1 (only) 0 = no filter set, always execute action, 1 = GossipHello only filter set, skip action if reportUse, 2 = reportUse only filter set, skip action if GossipHello
|
||||
SMART_EVENT_FOLLOW_COMPLETED = 65, // none
|
||||
SMART_EVENT_EVENT_PHASE_CHANGE = 66, // event phase mask (<= SMART_EVENT_PHASE_ALL)
|
||||
SMART_EVENT_IS_BEHIND_TARGET = 67, // cooldownMin, CooldownMax
|
||||
SMART_EVENT_IS_BEHIND_TARGET = 67, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
SMART_EVENT_GAME_EVENT_START = 68, // game_event.Entry
|
||||
SMART_EVENT_GAME_EVENT_END = 69, // game_event.Entry
|
||||
SMART_EVENT_GO_STATE_CHANGED = 70, // go state
|
||||
SMART_EVENT_GO_EVENT_INFORM = 71, // eventId
|
||||
SMART_EVENT_ACTION_DONE = 72, // eventId (SharedDefines.EventId)
|
||||
SMART_EVENT_ON_SPELLCLICK = 73, // clicker (unit)
|
||||
SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // minHpPct, maxHpPct, repeatMin, repeatMax
|
||||
SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // min, max, repeatMin, repeatMax, hpPct, range
|
||||
SMART_EVENT_DISTANCE_CREATURE = 75, // guid, entry, distance, repeat
|
||||
SMART_EVENT_DISTANCE_GAMEOBJECT = 76, // guid, entry, distance, repeat
|
||||
SMART_EVENT_COUNTER_SET = 77, // id, value, cooldownMin, cooldownMax
|
||||
@@ -210,8 +210,8 @@ enum SMART_EVENT
|
||||
SMART_EVENT_NEAR_PLAYERS_NEGATION = 102, // max, radius, first timer, repeatMin, repeatMax
|
||||
SMART_EVENT_NEAR_UNIT = 103, // type (0: creature 1: gob), entry, count, range, timer
|
||||
SMART_EVENT_NEAR_UNIT_NEGATION = 104, // type (0: creature 1: gob), entry, count, range, timer
|
||||
SMART_EVENT_AREA_CASTING = 105, // min, max, repeatMin, repeatMax, range
|
||||
SMART_EVENT_AREA_RANGE = 106, // min, max, repeatMin, repeatMax, range
|
||||
SMART_EVENT_AREA_CASTING = 105, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
SMART_EVENT_AREA_RANGE = 106, // min, max, repeatMin, repeatMax, rangeMin, rangeMax
|
||||
|
||||
SMART_EVENT_AC_END = 107
|
||||
};
|
||||
@@ -230,17 +230,10 @@ struct SmartEvent
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 rangeMin;
|
||||
uint32 rangeMax;
|
||||
} minMaxRepeat;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 minRange;
|
||||
uint32 maxRange;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 onlyFireOnRepeat;
|
||||
} rangeRepeat;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 cooldownMin;
|
||||
@@ -430,12 +423,6 @@ struct SmartEvent
|
||||
uint32 phasemask;
|
||||
} eventPhaseChange;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 cooldownMin;
|
||||
uint32 cooldownMax;
|
||||
} behindTarget;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 gameEventId;
|
||||
@@ -458,10 +445,11 @@ struct SmartEvent
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 minHpPct;
|
||||
uint32 maxHpPct;
|
||||
uint32 min;
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 hpPct;
|
||||
uint32 radius;
|
||||
} friendlyHealthPct;
|
||||
|
||||
@@ -517,26 +505,6 @@ struct SmartEvent
|
||||
uint32 timer;
|
||||
} nearUnitNegation;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 min;
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 rangeMin;
|
||||
uint32 rangeMax;
|
||||
} areaCasting;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 min;
|
||||
uint32 max;
|
||||
uint32 repeatMin;
|
||||
uint32 repeatMax;
|
||||
uint32 rangeMin;
|
||||
uint32 rangeMax;
|
||||
} areaRange;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 param1;
|
||||
@@ -743,8 +711,9 @@ enum SMART_ACTION
|
||||
SMART_ACTION_SUMMON_RADIAL = 228, // summonEntry, summonDuration, repetitions, startAngle, stepAngle, dist
|
||||
SMART_ACTION_PLAY_SPELL_VISUAL = 229, // visualId, visualIdImpact
|
||||
SMART_ACTION_FOLLOW_GROUP = 230, // followState, followType, dist
|
||||
SMART_ACTION_SET_ORIENTATION_TARGET = 231, // type, target_type, target_param1, target_param2, target_param3, target_param4
|
||||
|
||||
SMART_ACTION_AC_END = 231, // placeholder
|
||||
SMART_ACTION_AC_END = 232, // placeholder
|
||||
};
|
||||
|
||||
enum class SmartActionSummonCreatureFlags
|
||||
@@ -1453,6 +1422,16 @@ struct SmartAction
|
||||
uint32 followType;
|
||||
uint32 dist;
|
||||
} followGroup;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 type;
|
||||
uint32 targetType;
|
||||
uint32 targetParam1;
|
||||
uint32 targetParam2;
|
||||
uint32 targetParam3;
|
||||
uint32 targetParam4;
|
||||
} orientationTarget;
|
||||
//! Note for any new future actions
|
||||
//! All parameters must have type uint32
|
||||
|
||||
@@ -1484,10 +1463,10 @@ enum SMARTAI_TARGETS
|
||||
SMART_TARGET_NONE = 0, // NONE
|
||||
SMART_TARGET_SELF = 1, // Self cast
|
||||
SMART_TARGET_VICTIM = 2, // Our current target (ie: highest aggro)
|
||||
SMART_TARGET_HOSTILE_SECOND_AGGRO = 3, // Second highest aggro, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_LAST_AGGRO = 4, // Dead last on aggro, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_RANDOM = 5, // Just any random target on our threat list, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_RANDOM_NOT_TOP = 6, // Any random target except top threat, maxdist, playerOnly, powerType + 1
|
||||
SMART_TARGET_HOSTILE_SECOND_AGGRO = 3, // Second highest aggro, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_HOSTILE_LAST_AGGRO = 4, // Dead last on aggro, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_HOSTILE_RANDOM = 5, // Just any random target on our threat list, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_HOSTILE_RANDOM_NOT_TOP = 6, // Any random target except top threat, maxdist, playerOnly, powerType + 1, missing aura
|
||||
SMART_TARGET_ACTION_INVOKER = 7, // Unit who caused this Event to occur
|
||||
SMART_TARGET_POSITION = 8, // use xyz from event params
|
||||
SMART_TARGET_CREATURE_RANGE = 9, // CreatureEntry(0any), minDist, maxDist, alive(0 - both, 1 - alive, 2 - dead)
|
||||
@@ -1551,6 +1530,7 @@ struct SmartTarget
|
||||
uint32 maxDist;
|
||||
SAIBool playerOnly;
|
||||
uint32 powerType;
|
||||
uint32 aura;
|
||||
} hostileRandom;
|
||||
|
||||
struct
|
||||
@@ -1864,16 +1844,16 @@ const uint32 SmartAIEventMask[SMART_EVENT_AC_END][2] =
|
||||
|
||||
enum SmartEventFlags
|
||||
{
|
||||
SMART_EVENT_FLAG_NOT_REPEATABLE = 0x001, //Event can not repeat
|
||||
SMART_EVENT_FLAG_DIFFICULTY_0 = 0x002, //Event only occurs in instance difficulty 0
|
||||
SMART_EVENT_FLAG_DIFFICULTY_1 = 0x004, //Event only occurs in instance difficulty 1
|
||||
SMART_EVENT_FLAG_DIFFICULTY_2 = 0x008, //Event only occurs in instance difficulty 2
|
||||
SMART_EVENT_FLAG_DIFFICULTY_3 = 0x010, //Event only occurs in instance difficulty 3
|
||||
SMART_EVENT_FLAG_NOT_REPEATABLE = 0x001, // Event can not repeat
|
||||
SMART_EVENT_FLAG_DIFFICULTY_0 = 0x002, // Event only occurs in instance difficulty 0
|
||||
SMART_EVENT_FLAG_DIFFICULTY_1 = 0x004, // Event only occurs in instance difficulty 1
|
||||
SMART_EVENT_FLAG_DIFFICULTY_2 = 0x008, // Event only occurs in instance difficulty 2
|
||||
SMART_EVENT_FLAG_DIFFICULTY_3 = 0x010, // Event only occurs in instance difficulty 3
|
||||
SMART_EVENT_FLAG_RESERVED_5 = 0x020,
|
||||
SMART_EVENT_FLAG_RESERVED_6 = 0x040,
|
||||
SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, //Event only occurs in debug build
|
||||
SMART_EVENT_FLAG_DONT_RESET = 0x100, //Event will not reset in SmartScript::OnReset()
|
||||
SMART_EVENT_FLAG_WHILE_CHARMED = 0x200, //Event occurs even if AI owner is charmed
|
||||
SMART_EVENT_FLAG_DEBUG_ONLY = 0x080, // Event only occurs in debug build
|
||||
SMART_EVENT_FLAG_DONT_RESET = 0x100, // Event will not reset in SmartScript::OnReset()
|
||||
SMART_EVENT_FLAG_WHILE_CHARMED = 0x200, // Event occurs even if AI owner is charmed
|
||||
|
||||
SMART_EVENT_FLAG_DIFFICULTY_ALL = (SMART_EVENT_FLAG_DIFFICULTY_0 | SMART_EVENT_FLAG_DIFFICULTY_1 | SMART_EVENT_FLAG_DIFFICULTY_2 | SMART_EVENT_FLAG_DIFFICULTY_3),
|
||||
SMART_EVENT_FLAGS_ALL = (SMART_EVENT_FLAG_NOT_REPEATABLE | SMART_EVENT_FLAG_DIFFICULTY_ALL | SMART_EVENT_FLAG_RESERVED_5 | SMART_EVENT_FLAG_RESERVED_6 | SMART_EVENT_FLAG_DEBUG_ONLY | SMART_EVENT_FLAG_DONT_RESET | SMART_EVENT_FLAG_WHILE_CHARMED)
|
||||
@@ -1881,14 +1861,15 @@ enum SmartEventFlags
|
||||
|
||||
enum SmartCastFlags
|
||||
{
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range
|
||||
//CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x40, //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_THREATLIST_NOT_SINGLE = 0x80 //Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
|
||||
//CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
|
||||
SMARTCAST_TARGET_POWER_MANA = 0x100 // Only cast if the target has power type mana (e.g. Mana Drain)
|
||||
};
|
||||
|
||||
enum SmartFollowType
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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 "CreatureAI.h"
|
||||
#include "Define.h"
|
||||
#include "SmartEnum.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Acore::Impl::EnumUtilsImpl
|
||||
{
|
||||
|
||||
/****************************************************************************\
|
||||
|* data for enum 'CreatureAI::EvadeReason' in 'CreatureAI.h' auto-generated *|
|
||||
\****************************************************************************/
|
||||
template <>
|
||||
AC_API_EXPORT EnumText EnumUtils<CreatureAI::EvadeReason>::ToString(CreatureAI::EvadeReason value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case CreatureAI::EVADE_REASON_NO_HOSTILES: return { "EVADE_REASON_NO_HOSTILES", "EVADE_REASON_NO_HOSTILES", "the creature's threat list is empty" };
|
||||
case CreatureAI::EVADE_REASON_BOUNDARY: return { "EVADE_REASON_BOUNDARY", "EVADE_REASON_BOUNDARY", "the creature has moved outside its evade boundary" };
|
||||
case CreatureAI::EVADE_REASON_SEQUENCE_BREAK: return { "EVADE_REASON_SEQUENCE_BREAK", "EVADE_REASON_SEQUENCE_BREAK", "this is a boss and the pre-requisite encounters for engaging it are not defeated yet" };
|
||||
case CreatureAI::EVADE_REASON_NO_PATH: return { "EVADE_REASON_NO_PATH", "EVADE_REASON_NO_PATH", "the creature was unable to reach its target for over 5 seconds" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<CreatureAI::EvadeReason>::Count() { return 4; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT CreatureAI::EvadeReason EnumUtils<CreatureAI::EvadeReason>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return CreatureAI::EVADE_REASON_NO_HOSTILES;
|
||||
case 1: return CreatureAI::EVADE_REASON_BOUNDARY;
|
||||
case 2: return CreatureAI::EVADE_REASON_SEQUENCE_BREAK;
|
||||
case 3: return CreatureAI::EVADE_REASON_NO_PATH;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<CreatureAI::EvadeReason>::ToIndex(CreatureAI::EvadeReason value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case CreatureAI::EVADE_REASON_NO_HOSTILES: return 0;
|
||||
case CreatureAI::EVADE_REASON_BOUNDARY: return 1;
|
||||
case CreatureAI::EVADE_REASON_SEQUENCE_BREAK: return 2;
|
||||
case CreatureAI::EVADE_REASON_NO_PATH: return 3;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
break;
|
||||
default:
|
||||
if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT)
|
||||
@@ -757,7 +758,12 @@ void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, C
|
||||
data << uint32(timedCompleted ? 0 : 1); // 1 is for keeping the counter at 0 in client
|
||||
data.AppendPackedTime(progress->date);
|
||||
data << uint32(timeElapsed); // time elapsed in seconds
|
||||
data << uint32(0); // unk
|
||||
|
||||
if (sAchievementMgr->IsAverageCriteria(entry))
|
||||
data << uint32(GameTime::GetGameTime().count() - GetPlayer()->GetCreationTime().count()); // for average achievements
|
||||
else
|
||||
data << uint32(timeElapsed); // time elapsed in seconds
|
||||
|
||||
GetPlayer()->SendDirectMessage(&data);
|
||||
}
|
||||
|
||||
@@ -881,6 +887,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
|
||||
@@ -1147,6 +1154,21 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
{
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if (!miscValue1)
|
||||
continue;
|
||||
|
||||
Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
|
||||
if (!map || !map->IsDungeon())
|
||||
continue;
|
||||
|
||||
if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->complete_raid.groupSize)
|
||||
continue;
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
|
||||
if (!miscValue1)
|
||||
@@ -1732,6 +1754,16 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
{
|
||||
// those requirements couldn't be found in the dbc
|
||||
AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
|
||||
if (!data || !data->Meets(GetPlayer(), nullptr))
|
||||
continue;
|
||||
|
||||
SetCriteriaProgress(achievementCriteria, 1);
|
||||
break;
|
||||
}
|
||||
// std case: not exist in DBC, not triggered in code as result
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
|
||||
@@ -1741,8 +1773,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
|
||||
break;
|
||||
// FIXME: not triggered in code as result, need to implement
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
|
||||
break; // Not implemented yet :(
|
||||
}
|
||||
@@ -1907,11 +1937,14 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
|
||||
return true;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
|
||||
return achievementCriteria->win_arena.count && progress->counter >= achievementCriteria->win_arena.count;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
return true;
|
||||
// handle all statistic-only criteria here
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
|
||||
@@ -1936,6 +1969,7 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
|
||||
@@ -2344,7 +2378,11 @@ void AchievementMgr::BuildAllDataPacket(WorldPacket* data) const
|
||||
*data << uint32(0); /// @todo: This should be 1 if it is a failed timed criteria
|
||||
data->AppendPackedTime(iter->second.date);
|
||||
*data << uint32(now - iter->second.date);
|
||||
*data << uint32(now - iter->second.date);
|
||||
|
||||
if (sAchievementMgr->IsAverageCriteria(sAchievementCriteriaStore.LookupEntry(iter->first)))
|
||||
*data << uint32(now - GetPlayer()->GetCreationTime().count()); // for average achievements
|
||||
else
|
||||
*data << uint32(now - iter->second.date);
|
||||
}
|
||||
|
||||
*data << int32(-1);
|
||||
@@ -2433,6 +2471,19 @@ bool AchievementGlobalMgr::IsStatisticAchievement(AchievementEntry const* achiev
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsAverageCriteria(AchievementCriteriaEntry const* criteria) const
|
||||
{
|
||||
if ((sAchievementStore.LookupEntry(criteria->referredAchievement))->flags & ACHIEVEMENT_FLAG_AVERAGE)
|
||||
return true;
|
||||
|
||||
if (AchievementEntryList const* achRefList = GetAchievementByReferencedId(criteria->referredAchievement))
|
||||
for (AchievementEntryList::const_iterator itr = achRefList->begin(); itr != achRefList->end(); ++itr)
|
||||
if ((*itr)->flags & ACHIEVEMENT_FLAG_AVERAGE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AchievementGlobalMgr::IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
auto itr = _allCompletedAchievements.find(achievement->ID);
|
||||
@@ -2724,6 +2775,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
|
||||
|
||||
@@ -330,6 +330,7 @@ public:
|
||||
|
||||
bool IsStatisticCriteria(AchievementCriteriaEntry const* achievementCriteria) const;
|
||||
bool IsStatisticAchievement(AchievementEntry const* achievement) const;
|
||||
bool IsAverageCriteria(AchievementCriteriaEntry const* criteria) const;
|
||||
|
||||
[[nodiscard]] AchievementCriteriaEntryList const* GetAchievementCriteriaByType(AchievementCriteriaTypes type) const
|
||||
{
|
||||
|
||||
@@ -761,6 +761,9 @@ bool AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
|
||||
}
|
||||
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (!Aentry)
|
||||
return false;
|
||||
|
||||
// Skip expired auctions
|
||||
if (Aentry->expire_time < curTime.count())
|
||||
{
|
||||
|
||||
@@ -122,4 +122,4 @@ protected:
|
||||
uint32 HealingDone = 0;
|
||||
};
|
||||
|
||||
#endif // TRINITY_BATTLEGROUND_SCORE_H
|
||||
#endif // _BATTLEGROUND_SCORE_H
|
||||
|
||||
@@ -42,7 +42,7 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
|
||||
case CREATURE_FLAG_EXTRA_NO_TAUNT: return { "CREATURE_FLAG_EXTRA_NO_TAUNT", "CREATURE_FLAG_EXTRA_NO_TAUNT", "creature is immune to taunt auras and 'attack me' effects" };
|
||||
case CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE: return { "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE", "creature won't update movement flags" };
|
||||
case CREATURE_FLAG_EXTRA_GHOST_VISIBILITY: return { "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "CREATURE_FLAG_EXTRA_GHOST_VISIBILITY", "creature will only be visible to dead players" };
|
||||
case CREATURE_FLAG_EXTRA_UNUSED_12: return { "CREATURE_FLAG_EXTRA_UNUSED_12", "CREATURE_FLAG_EXTRA_UNUSED_12", "TODO: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
|
||||
case CREATURE_FLAG_EXTRA_UNUSED_12: return { "CREATURE_FLAG_EXTRA_UNUSED_12", "CREATURE_FLAG_EXTRA_UNUSED_12", "/ @todo: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)" };
|
||||
case CREATURE_FLAG_EXTRA_NO_SELL_VENDOR: return { "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "CREATURE_FLAG_EXTRA_NO_SELL_VENDOR", "players can't sell items to this vendor" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_COMBAT: return { "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "CREATURE_FLAG_EXTRA_IGNORE_COMBAT", "" };
|
||||
case CREATURE_FLAG_EXTRA_WORLDEVENT: return { "CREATURE_FLAG_EXTRA_WORLDEVENT", "CREATURE_FLAG_EXTRA_WORLDEVENT", "custom flag for world event creatures (left room for merging)" };
|
||||
@@ -55,10 +55,10 @@ AC_API_EXPORT EnumText EnumUtils<CreatureFlagsExtra>::ToString(CreatureFlagsExtr
|
||||
case CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ: return { "CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ", "CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ", "creature does not need to take player damage for kill credit" };
|
||||
case CREATURE_FLAG_EXTRA_AVOID_AOE: return { "CREATURE_FLAG_EXTRA_AVOID_AOE", "CREATURE_FLAG_EXTRA_AVOID_AOE", "pussywizard: ignored by aoe attacks (for icc blood prince council npc - Dark Nucleus)" };
|
||||
case CREATURE_FLAG_EXTRA_NO_DODGE: return { "CREATURE_FLAG_EXTRA_NO_DODGE", "CREATURE_FLAG_EXTRA_NO_DODGE", "xinef: target cannot dodge" };
|
||||
case CREATURE_FLAG_EXTRA_MODULE: return { "CREATURE_FLAG_EXTRA_MODULE", "CREATURE_FLAG_EXTRA_MODULE", "Used by module creatures to avoid blizzlike checks." };
|
||||
case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return { "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "Creature does not call for assistance on initial aggro", "" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS: return { "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "Prevents creature from responding to assistance calls", "" };
|
||||
case CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI: return { "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "Creature entry SAI won't be overriden by GUID SAI", "" };
|
||||
case CREATURE_FLAG_EXTRA_MODULE: return { "CREATURE_FLAG_EXTRA_MODULE", "CREATURE_FLAG_EXTRA_MODULE", "" };
|
||||
case CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE: return { "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE", "Prevent creatures from calling for assistance on initial aggro" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS: return { "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "CREATURE_FLAG_EXTRA_IGNORE_ALL_ASSISTANCE_CALLS", "Prevents creature from responding to assistance calls" };
|
||||
case CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI: return { "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI", "Load both ENTRY and GUID specific SAI" };
|
||||
case CREATURE_FLAG_EXTRA_DUNGEON_BOSS: return { "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "CREATURE_FLAG_EXTRA_DUNGEON_BOSS", "creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)" };
|
||||
case CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING: return { "CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING", "CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING", "creature ignore pathfinding" };
|
||||
case CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK: return { "CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK", "CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK", "creature is immune to knockback effects" };
|
||||
|
||||
@@ -1725,7 +1725,10 @@ void GameObject::Use(Unit* user)
|
||||
player->SendCinematicStart(info->camera.cinematicId);
|
||||
|
||||
if (info->camera.eventID)
|
||||
{
|
||||
GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this);
|
||||
EventInform(info->camera.eventID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -196,10 +196,10 @@ struct Position
|
||||
|
||||
float GetRelativeAngle(const Position* pos) const
|
||||
{
|
||||
return GetAngle(pos) - m_orientation;
|
||||
return NormalizeOrientation(GetAngle(pos) - m_orientation);
|
||||
}
|
||||
|
||||
[[nodiscard]] float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; }
|
||||
[[nodiscard]] float GetRelativeAngle(float x, float y) const { return NormalizeOrientation(GetAngle(x, y) - m_orientation); }
|
||||
[[nodiscard]] float ToAbsoluteAngle(float relAngle) const { return NormalizeOrientation(relAngle + m_orientation); }
|
||||
|
||||
void GetSinCos(float x, float y, float& vsin, float& vcos) const;
|
||||
|
||||
@@ -384,6 +384,8 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
|
||||
|
||||
_activeCheats = CHEAT_NONE;
|
||||
|
||||
m_creationTime = 0s;
|
||||
|
||||
_cinematicMgr = new CinematicMgr(this);
|
||||
|
||||
m_achievementMgr = new AchievementMgr(this);
|
||||
@@ -8043,6 +8045,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
// need know merged fishing/corpse loot type for achievements
|
||||
loot->loot_type = loot_type;
|
||||
|
||||
if (!sScriptMgr->OnAllowedToLootContainerCheck(this, guid))
|
||||
{
|
||||
SendLootError(guid, LOOT_ERROR_DIDNT_KILL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (permission != NONE_PERMISSION)
|
||||
{
|
||||
SetLootGUID(guid);
|
||||
@@ -13268,6 +13276,8 @@ void Player::SetTitle(CharTitlesEntry const* title, bool lost)
|
||||
data << uint32(title->bit_index);
|
||||
data << uint32(lost ? 0 : 1); // 1 - earned, 0 - lost
|
||||
GetSession()->SendPacket(&data);
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK);
|
||||
}
|
||||
|
||||
uint32 Player::GetRuneBaseCooldown(uint8 index, bool skipGrace)
|
||||
@@ -13544,8 +13554,13 @@ uint32 Player::CalculateTalentsPoints() const
|
||||
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));
|
||||
}
|
||||
|
||||
bool Player::canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) const
|
||||
bool Player::canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell)
|
||||
{
|
||||
if (!sScriptMgr->OnCanPlayerFlyInZone(this, mapid,zone,bySpell))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// continent checked in SpellInfo::CheckLocation at cast and area update
|
||||
uint32 v_map = GetVirtualMapForMapAndZone(mapid, zone);
|
||||
if (v_map == 571 && !bySpell->HasAttribute(SPELL_ATTR7_IGNORES_COLD_WEATHER_FLYING_REQUIREMENT))
|
||||
|
||||
@@ -2299,7 +2299,7 @@ public:
|
||||
}
|
||||
void HandleFall(MovementInfo const& movementInfo);
|
||||
|
||||
[[nodiscard]] bool canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell) const;
|
||||
[[nodiscard]] bool canFlyInZone(uint32 mapid, uint32 zone, SpellInfo const* bySpell);
|
||||
|
||||
void SetClientControl(Unit* target, bool allowMove, bool packetOnly = false);
|
||||
|
||||
@@ -2495,6 +2495,9 @@ public:
|
||||
void CompletedAchievement(AchievementEntry const* entry);
|
||||
[[nodiscard]] AchievementMgr* GetAchievementMgr() const { return m_achievementMgr; }
|
||||
|
||||
void SetCreationTime(Seconds creationTime) { m_creationTime = creationTime; }
|
||||
[[nodiscard]] Seconds GetCreationTime() const { return m_creationTime; }
|
||||
|
||||
[[nodiscard]] bool HasTitle(uint32 bitIndex) const;
|
||||
bool HasTitle(CharTitlesEntry const* title) const { return HasTitle(title->bit_index); }
|
||||
void SetTitle(CharTitlesEntry const* title, bool lost = false);
|
||||
@@ -2951,6 +2954,8 @@ private:
|
||||
bool _wasOutdoor;
|
||||
|
||||
PlayerSettingMap m_charSettingsMap;
|
||||
|
||||
Seconds m_creationTime;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player* player, Item* item);
|
||||
|
||||
@@ -4948,8 +4948,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
//"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, "
|
||||
// 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
||||
//"health, power1, power2, power3, power4, power5, power6, power7, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, ammoId, knownTitles,
|
||||
// 70 71 72 73
|
||||
//"actionBars, grantableLevels, innTriggerId, extraBonusTalentCount FROM characters WHERE guid = '{}'", guid);
|
||||
// 70 71 72 73 74
|
||||
//"actionBars, grantableLevels, innTriggerId, extraBonusTalentCount, UNIX_TIMESTAMP(creation_date) FROM characters WHERE guid = '{}'", guid);
|
||||
PreparedQueryResult result = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM);
|
||||
|
||||
if (!result)
|
||||
@@ -5026,6 +5026,9 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
||||
SetObjectScale(1.0f);
|
||||
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f);
|
||||
|
||||
// load character creation date, relevant for achievements of type average
|
||||
SetCreationTime(fields[74].Get<Seconds>());
|
||||
|
||||
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
|
||||
m_achievementMgr->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS));
|
||||
|
||||
|
||||
@@ -13973,6 +13973,9 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo
|
||||
// additional checks - only PvP case
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
{
|
||||
if (!IsPvP() && bySpell && bySpell->IsAffectingArea() && !bySpell->HasAttribute(SPELL_ATTR5_IGNORE_AREA_EFFECT_PVP_CHECK))
|
||||
return false;
|
||||
|
||||
if (target->IsPvP())
|
||||
return true;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ AC_API_EXPORT EnumText EnumUtils<UnitFlags>::ToString(UnitFlags value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case UNIT_FLAG_NONE: return { "UNIT_FLAG_NONE", "UNIT_FLAG_NONE", "" };
|
||||
case UNIT_FLAG_SERVER_CONTROLLED: return { "UNIT_FLAG_SERVER_CONTROLLED", "UNIT_FLAG_SERVER_CONTROLLED", "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" };
|
||||
case UNIT_FLAG_NON_ATTACKABLE: return { "UNIT_FLAG_NON_ATTACKABLE", "UNIT_FLAG_NON_ATTACKABLE", "not attackable" };
|
||||
case UNIT_FLAG_DISABLE_MOVE: return { "UNIT_FLAG_DISABLE_MOVE", "UNIT_FLAG_DISABLE_MOVE", "" };
|
||||
@@ -68,45 +69,46 @@ AC_API_EXPORT EnumText EnumUtils<UnitFlags>::ToString(UnitFlags value)
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<UnitFlags>::Count() { return 32; }
|
||||
AC_API_EXPORT size_t EnumUtils<UnitFlags>::Count() { return 33; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT UnitFlags EnumUtils<UnitFlags>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return UNIT_FLAG_SERVER_CONTROLLED;
|
||||
case 1: return UNIT_FLAG_NON_ATTACKABLE;
|
||||
case 2: return UNIT_FLAG_DISABLE_MOVE;
|
||||
case 3: return UNIT_FLAG_PLAYER_CONTROLLED;
|
||||
case 4: return UNIT_FLAG_RENAME;
|
||||
case 5: return UNIT_FLAG_PREPARATION;
|
||||
case 6: return UNIT_FLAG_UNK_6;
|
||||
case 7: return UNIT_FLAG_NOT_ATTACKABLE_1;
|
||||
case 8: return UNIT_FLAG_IMMUNE_TO_PC;
|
||||
case 9: return UNIT_FLAG_IMMUNE_TO_NPC;
|
||||
case 10: return UNIT_FLAG_LOOTING;
|
||||
case 11: return UNIT_FLAG_PET_IN_COMBAT;
|
||||
case 12: return UNIT_FLAG_PVP;
|
||||
case 13: return UNIT_FLAG_SILENCED;
|
||||
case 14: return UNIT_FLAG_CANNOT_SWIM;
|
||||
case 15: return UNIT_FLAG_SWIMMING;
|
||||
case 16: return UNIT_FLAG_NON_ATTACKABLE_2;
|
||||
case 17: return UNIT_FLAG_PACIFIED;
|
||||
case 18: return UNIT_FLAG_STUNNED;
|
||||
case 19: return UNIT_FLAG_IN_COMBAT;
|
||||
case 20: return UNIT_FLAG_TAXI_FLIGHT;
|
||||
case 21: return UNIT_FLAG_DISARMED;
|
||||
case 22: return UNIT_FLAG_CONFUSED;
|
||||
case 23: return UNIT_FLAG_FLEEING;
|
||||
case 24: return UNIT_FLAG_POSSESSED;
|
||||
case 25: return UNIT_FLAG_NOT_SELECTABLE;
|
||||
case 26: return UNIT_FLAG_SKINNABLE;
|
||||
case 27: return UNIT_FLAG_MOUNT;
|
||||
case 28: return UNIT_FLAG_UNK_28;
|
||||
case 29: return UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT;
|
||||
case 30: return UNIT_FLAG_SHEATHE;
|
||||
case 31: return UNIT_FLAG_IMMUNE;
|
||||
case 0: return UNIT_FLAG_NONE;
|
||||
case 1: return UNIT_FLAG_SERVER_CONTROLLED;
|
||||
case 2: return UNIT_FLAG_NON_ATTACKABLE;
|
||||
case 3: return UNIT_FLAG_DISABLE_MOVE;
|
||||
case 4: return UNIT_FLAG_PLAYER_CONTROLLED;
|
||||
case 5: return UNIT_FLAG_RENAME;
|
||||
case 6: return UNIT_FLAG_PREPARATION;
|
||||
case 7: return UNIT_FLAG_UNK_6;
|
||||
case 8: return UNIT_FLAG_NOT_ATTACKABLE_1;
|
||||
case 9: return UNIT_FLAG_IMMUNE_TO_PC;
|
||||
case 10: return UNIT_FLAG_IMMUNE_TO_NPC;
|
||||
case 11: return UNIT_FLAG_LOOTING;
|
||||
case 12: return UNIT_FLAG_PET_IN_COMBAT;
|
||||
case 13: return UNIT_FLAG_PVP;
|
||||
case 14: return UNIT_FLAG_SILENCED;
|
||||
case 15: return UNIT_FLAG_CANNOT_SWIM;
|
||||
case 16: return UNIT_FLAG_SWIMMING;
|
||||
case 17: return UNIT_FLAG_NON_ATTACKABLE_2;
|
||||
case 18: return UNIT_FLAG_PACIFIED;
|
||||
case 19: return UNIT_FLAG_STUNNED;
|
||||
case 20: return UNIT_FLAG_IN_COMBAT;
|
||||
case 21: return UNIT_FLAG_TAXI_FLIGHT;
|
||||
case 22: return UNIT_FLAG_DISARMED;
|
||||
case 23: return UNIT_FLAG_CONFUSED;
|
||||
case 24: return UNIT_FLAG_FLEEING;
|
||||
case 25: return UNIT_FLAG_POSSESSED;
|
||||
case 26: return UNIT_FLAG_NOT_SELECTABLE;
|
||||
case 27: return UNIT_FLAG_SKINNABLE;
|
||||
case 28: return UNIT_FLAG_MOUNT;
|
||||
case 29: return UNIT_FLAG_UNK_28;
|
||||
case 30: return UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT;
|
||||
case 31: return UNIT_FLAG_SHEATHE;
|
||||
case 32: return UNIT_FLAG_IMMUNE;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
@@ -116,38 +118,39 @@ AC_API_EXPORT size_t EnumUtils<UnitFlags>::ToIndex(UnitFlags value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case UNIT_FLAG_SERVER_CONTROLLED: return 0;
|
||||
case UNIT_FLAG_NON_ATTACKABLE: return 1;
|
||||
case UNIT_FLAG_DISABLE_MOVE: return 2;
|
||||
case UNIT_FLAG_PLAYER_CONTROLLED: return 3;
|
||||
case UNIT_FLAG_RENAME: return 4;
|
||||
case UNIT_FLAG_PREPARATION: return 5;
|
||||
case UNIT_FLAG_UNK_6: return 6;
|
||||
case UNIT_FLAG_NOT_ATTACKABLE_1: return 7;
|
||||
case UNIT_FLAG_IMMUNE_TO_PC: return 8;
|
||||
case UNIT_FLAG_IMMUNE_TO_NPC: return 9;
|
||||
case UNIT_FLAG_LOOTING: return 10;
|
||||
case UNIT_FLAG_PET_IN_COMBAT: return 11;
|
||||
case UNIT_FLAG_PVP: return 12;
|
||||
case UNIT_FLAG_SILENCED: return 13;
|
||||
case UNIT_FLAG_CANNOT_SWIM: return 14;
|
||||
case UNIT_FLAG_SWIMMING: return 15;
|
||||
case UNIT_FLAG_NON_ATTACKABLE_2: return 16;
|
||||
case UNIT_FLAG_PACIFIED: return 17;
|
||||
case UNIT_FLAG_STUNNED: return 18;
|
||||
case UNIT_FLAG_IN_COMBAT: return 19;
|
||||
case UNIT_FLAG_TAXI_FLIGHT: return 20;
|
||||
case UNIT_FLAG_DISARMED: return 21;
|
||||
case UNIT_FLAG_CONFUSED: return 22;
|
||||
case UNIT_FLAG_FLEEING: return 23;
|
||||
case UNIT_FLAG_POSSESSED: return 24;
|
||||
case UNIT_FLAG_NOT_SELECTABLE: return 25;
|
||||
case UNIT_FLAG_SKINNABLE: return 26;
|
||||
case UNIT_FLAG_MOUNT: return 27;
|
||||
case UNIT_FLAG_UNK_28: return 28;
|
||||
case UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT: return 29;
|
||||
case UNIT_FLAG_SHEATHE: return 30;
|
||||
case UNIT_FLAG_IMMUNE: return 31;
|
||||
case UNIT_FLAG_NONE: return 0;
|
||||
case UNIT_FLAG_SERVER_CONTROLLED: return 1;
|
||||
case UNIT_FLAG_NON_ATTACKABLE: return 2;
|
||||
case UNIT_FLAG_DISABLE_MOVE: return 3;
|
||||
case UNIT_FLAG_PLAYER_CONTROLLED: return 4;
|
||||
case UNIT_FLAG_RENAME: return 5;
|
||||
case UNIT_FLAG_PREPARATION: return 6;
|
||||
case UNIT_FLAG_UNK_6: return 7;
|
||||
case UNIT_FLAG_NOT_ATTACKABLE_1: return 8;
|
||||
case UNIT_FLAG_IMMUNE_TO_PC: return 9;
|
||||
case UNIT_FLAG_IMMUNE_TO_NPC: return 10;
|
||||
case UNIT_FLAG_LOOTING: return 11;
|
||||
case UNIT_FLAG_PET_IN_COMBAT: return 12;
|
||||
case UNIT_FLAG_PVP: return 13;
|
||||
case UNIT_FLAG_SILENCED: return 14;
|
||||
case UNIT_FLAG_CANNOT_SWIM: return 15;
|
||||
case UNIT_FLAG_SWIMMING: return 16;
|
||||
case UNIT_FLAG_NON_ATTACKABLE_2: return 17;
|
||||
case UNIT_FLAG_PACIFIED: return 18;
|
||||
case UNIT_FLAG_STUNNED: return 19;
|
||||
case UNIT_FLAG_IN_COMBAT: return 20;
|
||||
case UNIT_FLAG_TAXI_FLIGHT: return 21;
|
||||
case UNIT_FLAG_DISARMED: return 22;
|
||||
case UNIT_FLAG_CONFUSED: return 23;
|
||||
case UNIT_FLAG_FLEEING: return 24;
|
||||
case UNIT_FLAG_POSSESSED: return 25;
|
||||
case UNIT_FLAG_NOT_SELECTABLE: return 26;
|
||||
case UNIT_FLAG_SKINNABLE: return 27;
|
||||
case UNIT_FLAG_MOUNT: return 28;
|
||||
case UNIT_FLAG_UNK_28: return 29;
|
||||
case UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT: return 30;
|
||||
case UNIT_FLAG_SHEATHE: return 31;
|
||||
case UNIT_FLAG_IMMUNE: return 32;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
@@ -187,12 +190,13 @@ AC_API_EXPORT EnumText EnumUtils<NPCFlags>::ToString(NPCFlags value)
|
||||
case UNIT_NPC_FLAG_SPELLCLICK: return { "UNIT_NPC_FLAG_SPELLCLICK", "has spell click enabled", "cause client to send 1015 opcode (spell click)" };
|
||||
case UNIT_NPC_FLAG_PLAYER_VEHICLE: return { "UNIT_NPC_FLAG_PLAYER_VEHICLE", "is player vehicle", "players with mounts that have vehicle data should have it set" };
|
||||
case UNIT_NPC_FLAG_MAILBOX: return { "UNIT_NPC_FLAG_MAILBOX", "is mailbox", "" };
|
||||
case UNIT_NPC_FLAG_VENDOR_MASK: return { "UNIT_NPC_FLAG_VENDOR_MASK", "UNIT_NPC_FLAG_VENDOR_MASK", "" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT size_t EnumUtils<NPCFlags>::Count() { return 27; }
|
||||
AC_API_EXPORT size_t EnumUtils<NPCFlags>::Count() { return 28; }
|
||||
|
||||
template <>
|
||||
AC_API_EXPORT NPCFlags EnumUtils<NPCFlags>::FromIndex(size_t index)
|
||||
@@ -226,6 +230,7 @@ AC_API_EXPORT NPCFlags EnumUtils<NPCFlags>::FromIndex(size_t index)
|
||||
case 24: return UNIT_NPC_FLAG_SPELLCLICK;
|
||||
case 25: return UNIT_NPC_FLAG_PLAYER_VEHICLE;
|
||||
case 26: return UNIT_NPC_FLAG_MAILBOX;
|
||||
case 27: return UNIT_NPC_FLAG_VENDOR_MASK;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
}
|
||||
@@ -262,6 +267,7 @@ AC_API_EXPORT size_t EnumUtils<NPCFlags>::ToIndex(NPCFlags value)
|
||||
case UNIT_NPC_FLAG_SPELLCLICK: return 24;
|
||||
case UNIT_NPC_FLAG_PLAYER_VEHICLE: return 25;
|
||||
case UNIT_NPC_FLAG_MAILBOX: return 26;
|
||||
case UNIT_NPC_FLAG_VENDOR_MASK: return 27;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2863,47 +2863,43 @@ void ObjectMgr::LoadItemTemplates()
|
||||
|
||||
if (dbcitem)
|
||||
{
|
||||
if (itemTemplate.Class != dbcitem->ClassID)
|
||||
if (enforceDBCAttributes)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({}), must be ({}).", entry, itemTemplate.Class, dbcitem->ClassID);
|
||||
if (enforceDBCAttributes)
|
||||
if (itemTemplate.Class != dbcitem->ClassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Class value ({}), must be ({}).", entry, itemTemplate.Class, dbcitem->ClassID);
|
||||
itemTemplate.Class = dbcitem->ClassID;
|
||||
}
|
||||
if (itemTemplate.SubClass != dbcitem->SubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}, must be ({}).", entry, itemTemplate.SubClass, itemTemplate.Class, dbcitem->SubclassID);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.SubClass != dbcitem->SubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Subclass value ({}) for class {}, must be ({}).", entry, itemTemplate.SubClass, itemTemplate.Class, dbcitem->SubclassID);
|
||||
itemTemplate.SubClass = dbcitem->SubclassID;
|
||||
}
|
||||
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct SoundOverrideSubclass ({}), must be {}.", entry, itemTemplate.SoundOverrideSubclass);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.SoundOverrideSubclass != dbcitem->SoundOverrideSubclassID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct SoundOverrideSubclass ({}), must be {}.", entry, itemTemplate.SoundOverrideSubclass, dbcitem->SoundOverrideSubclassID);
|
||||
itemTemplate.SoundOverrideSubclass = dbcitem->SoundOverrideSubclassID;
|
||||
}
|
||||
if (itemTemplate.Material != dbcitem->Material)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.Material != dbcitem->Material)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
|
||||
itemTemplate.Material = dbcitem->Material;
|
||||
}
|
||||
if (itemTemplate.InventoryType != dbcitem->InventoryType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({}), must be {}.", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.InventoryType != dbcitem->InventoryType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong InventoryType value ({}), must be {}.", entry, itemTemplate.InventoryType, dbcitem->InventoryType);
|
||||
itemTemplate.InventoryType = dbcitem->InventoryType;
|
||||
}
|
||||
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
|
||||
itemTemplate.DisplayInfoID = dbcitem->DisplayInfoID;
|
||||
}
|
||||
if (itemTemplate.Sheath != dbcitem->SheatheType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({}), must be {}.", entry, itemTemplate.Sheath, dbcitem->SheatheType);
|
||||
if (enforceDBCAttributes)
|
||||
}
|
||||
if (itemTemplate.Sheath != dbcitem->SheatheType)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) has wrong Sheath ({}), must be {}.", entry, itemTemplate.Sheath, dbcitem->SheatheType);
|
||||
itemTemplate.Sheath = dbcitem->SheatheType;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -4062,88 +4058,6 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
}
|
||||
}
|
||||
|
||||
// Loading levels data (class only dependent)
|
||||
LOG_INFO("server.loading", "Loading Player Create Level HP/Mana Data...");
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// 0 1 2 3
|
||||
QueryResult result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
LOG_FATAL("server.loading", ">> Loaded 0 level health/mana definitions. DB table `player_classlevelstats` is empty.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 current_class = fields[0].Get<uint8>();
|
||||
if (current_class >= MAX_CLASSES)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Wrong class {} in `player_classlevelstats` table, ignoring.", current_class);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8 current_level = fields[1].Get<uint8>(); // Can't be > than STRONG_MAX_LEVEL (hardcoded level maximum) due to var type
|
||||
if (current_level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
LOG_INFO("sql.sql", "Unused (> MaxPlayerLevel in worldserver.conf) level {} in `player_classlevelstats` table, ignoring.", current_level);
|
||||
++count; // make result loading percent "expected" correct in case disabled detail mode for example.
|
||||
continue;
|
||||
}
|
||||
|
||||
PlayerClassInfo* info = _playerClassInfo[current_class];
|
||||
if (!info)
|
||||
{
|
||||
info = new PlayerClassInfo();
|
||||
info->levelInfo = new PlayerClassLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)];
|
||||
_playerClassInfo[current_class] = info;
|
||||
}
|
||||
|
||||
PlayerClassLevelInfo& levelInfo = info->levelInfo[current_level - 1];
|
||||
|
||||
levelInfo.basehealth = fields[2].Get<uint32>();
|
||||
levelInfo.basemana = fields[3].Get<uint32>();
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
// Fill gaps and check integrity
|
||||
for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
|
||||
{
|
||||
// skip non existed classes
|
||||
if (!sChrClassesStore.LookupEntry(class_))
|
||||
continue;
|
||||
|
||||
PlayerClassInfo* pClassInfo = _playerClassInfo[class_];
|
||||
|
||||
// fatal error if no initial level data
|
||||
if (!pClassInfo->levelInfo || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) - 1].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) - 1].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} initial level does not have health/mana data!", class_);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// fill level gaps
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if ((pClassInfo->levelInfo[level].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (level >= sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) && pClassInfo->levelInfo[level].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} level {} does not have health/mana data. Using stats data of level {}.", class_, level + 1, level);
|
||||
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Level Health/Mana Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
// Loading levels data (class/race dependent)
|
||||
LOG_INFO("server.loading", "Loading Player Create Level Stats Data...");
|
||||
{
|
||||
@@ -4182,8 +4096,8 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
|
||||
} while (raceStatsResult->NextRow());
|
||||
|
||||
// 0 1 2 3 4 5 6
|
||||
QueryResult result = WorldDatabase.Query("SELECT Class, Level, Strength, Agility, Stamina, Intellect, Spirit FROM player_class_stats");
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult result = WorldDatabase.Query("SELECT Class, Level, Strength, Agility, Stamina, Intellect, Spirit, BaseHP, BaseMana FROM player_class_stats");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@@ -4207,7 +4121,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
uint32 current_level = fields[1].Get<uint8>();
|
||||
if (current_level > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
|
||||
{
|
||||
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
|
||||
if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
|
||||
LOG_ERROR("sql.sql", "Wrong (> {}) level {} in `player_class_stats` table, ignoring.", STRONG_MAX_LEVEL, current_level);
|
||||
else
|
||||
LOG_DEBUG("sql.sql", "Unused (> MaxPlayerLevel in worldserver.conf) level {} in `player_class_stats` table, ignoring.", current_level);
|
||||
@@ -4228,6 +4142,19 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
}
|
||||
}
|
||||
|
||||
PlayerClassInfo* info = _playerClassInfo[current_class];
|
||||
if (!info)
|
||||
{
|
||||
info = new PlayerClassInfo();
|
||||
info->levelInfo = new PlayerClassLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)];
|
||||
_playerClassInfo[current_class] = info;
|
||||
}
|
||||
|
||||
PlayerClassLevelInfo& levelInfo = info->levelInfo[current_level - 1];
|
||||
|
||||
levelInfo.basehealth = fields[7].Get<uint32>();
|
||||
levelInfo.basemana = fields[8].Get<uint32>();
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
@@ -4244,6 +4171,7 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
if (!sChrClassesStore.LookupEntry(class_))
|
||||
continue;
|
||||
|
||||
PlayerClassInfo* pClassInfo = _playerClassInfo[class_];
|
||||
PlayerInfo* info = _playerInfo[race][class_];
|
||||
if (!info)
|
||||
continue;
|
||||
@@ -4256,14 +4184,21 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
if (sWorld->getIntConfig(CONFIG_EXPANSION) < EXPANSION_WRATH_OF_THE_LICH_KING && class_ == CLASS_DEATH_KNIGHT)
|
||||
continue;
|
||||
|
||||
// fatal error if no initial level data
|
||||
// fatal error if no initial stats data
|
||||
if (!info->levelInfo || (info->levelInfo[sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) - 1].stats[0] == 0 && class_ != CLASS_DEATH_KNIGHT) || (info->levelInfo[sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) - 1].stats[0] == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Race {} class {} initial level does not have stats data!", race, class_);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// fill level gaps
|
||||
// fatal error if no initial health/mana data
|
||||
if (!pClassInfo->levelInfo || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) - 1].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (pClassInfo->levelInfo[sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) - 1].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} initial level does not have health/mana data!", class_);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// fill level gaps for stats
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if ((info->levelInfo[level].stats[0] == 0 && class_ != CLASS_DEATH_KNIGHT) || (level >= sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) && info->levelInfo[level].stats[0] == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
@@ -4272,6 +4207,16 @@ void ObjectMgr::LoadPlayerInfo()
|
||||
info->levelInfo[level] = info->levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// fill level gaps for health/mana
|
||||
for (uint8 level = 1; level < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
|
||||
{
|
||||
if ((pClassInfo->levelInfo[level].basehealth == 0 && class_ != CLASS_DEATH_KNIGHT) || (level >= sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL) && pClassInfo->levelInfo[level].basehealth == 0 && class_ == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Class {} level {} does not have health/mana data. Using stats data of level {}.", class_, level + 1, level);
|
||||
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -536,6 +536,9 @@ void WorldSession::HandleLootRoll(WorldPacket& recvData)
|
||||
case ROLL_GREED:
|
||||
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1);
|
||||
break;
|
||||
case ROLL_DISENCHANT:
|
||||
GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +675,8 @@ InstancePlayerBind* InstanceSaveMgr::PlayerBindToInstance(ObjectGuid guid, Insta
|
||||
stmt->SetData(1, save->GetInstanceId());
|
||||
stmt->SetData(2, permanent);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID, 1);
|
||||
}
|
||||
|
||||
if (bind.save != save)
|
||||
|
||||
@@ -218,6 +218,11 @@ void InstanceScript::UpdateMinionState(Creature* minion, EncounterState state)
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceScript::Update(uint32 diff)
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
void InstanceScript::UpdateDoorState(GameObject* door)
|
||||
{
|
||||
DoorInfoMapBounds range = doors.equal_range(door->GetEntry());
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "World.h"
|
||||
#include "ZoneScript.h"
|
||||
#include <set>
|
||||
@@ -159,7 +160,7 @@ public:
|
||||
|
||||
void SaveToDB();
|
||||
|
||||
virtual void Update(uint32 /*diff*/) {}
|
||||
virtual void Update(uint32 /*diff*/);
|
||||
|
||||
//Used by the map's CanEnter function.
|
||||
//This is to prevent players from entering during boss encounters.
|
||||
@@ -263,6 +264,8 @@ public:
|
||||
|
||||
// Allows executing code using all creatures registered in the instance script as minions
|
||||
void DoForAllMinions(uint32 id, std::function<void(Creature*)> exec);
|
||||
|
||||
TaskScheduler scheduler;
|
||||
protected:
|
||||
void SetHeaders(std::string const& dataHeaders);
|
||||
void SetBossNumber(uint32 number) { bosses.resize(number); }
|
||||
|
||||
@@ -1058,7 +1058,7 @@ enum AcoreStrings
|
||||
LANG_COMMAND_TICKETLISTRESPONSE = 2029,
|
||||
LANG_COMMAND_TICKETCOMPLETED = 2030,
|
||||
|
||||
// Trinity strings 5000-9999
|
||||
// acore strings 5000-9999
|
||||
LANG_COMMAND_FREEZE = 5000,
|
||||
LANG_COMMAND_FREEZE_ERROR = 5001,
|
||||
LANG_COMMAND_FREEZE_WRONG = 5002,
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVEPLINE_H
|
||||
#define TRINITYSERVER_MOVEPLINE_H
|
||||
#ifndef AC_MOVEPLINE_H
|
||||
#define AC_MOVEPLINE_H
|
||||
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include "Spline.h"
|
||||
@@ -132,4 +132,4 @@ namespace Movement
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // TRINITYSERVER_MOVEPLINE_H
|
||||
#endif // AC_MOVEPLINE_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#define TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#ifndef AC_MOVESPLINEFLAG_H
|
||||
#define AC_MOVESPLINEFLAG_H
|
||||
|
||||
#include "MovementTypedefs.h"
|
||||
#include <string>
|
||||
@@ -145,4 +145,4 @@ namespace Movement
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEFLAG_H
|
||||
#endif // AC_MOVESPLINEFLAG_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#define TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#ifndef AC_MOVESPLINEINIT_H
|
||||
#define AC_MOVESPLINEINIT_H
|
||||
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include "PathGenerator.h"
|
||||
@@ -209,4 +209,4 @@ namespace Movement
|
||||
|
||||
inline void MoveSplineInit::DisableTransportPathTransformations() { args.TransformForTransport = false; }
|
||||
}
|
||||
#endif // TRINITYSERVER_MOVESPLINEINIT_H
|
||||
#endif // AC_MOVESPLINEINIT_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#define TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#ifndef AC_MOVESPLINEINIT_ARGS_H
|
||||
#define AC_MOVESPLINEINIT_ARGS_H
|
||||
|
||||
#include "MoveSplineFlag.h"
|
||||
#include <G3D/Vector3.h>
|
||||
@@ -68,4 +68,4 @@ namespace Movement
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_MOVESPLINEINIT_ARGS_H
|
||||
#endif // AC_MOVESPLINEINIT_ARGS_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_PACKET_BUILDER_H
|
||||
#define TRINITYSERVER_PACKET_BUILDER_H
|
||||
#ifndef AC_PACKET_BUILDER_H
|
||||
#define AC_PACKET_BUILDER_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
@@ -40,4 +40,4 @@ namespace Movement
|
||||
static void WriteCreate(const MoveSpline& mov, ByteBuffer& data);
|
||||
};
|
||||
}
|
||||
#endif // TRINITYSERVER_PACKET_BUILDER_H
|
||||
#endif // AC_PACKET_BUILDER_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_TYPEDEFS_H
|
||||
#define TRINITYSERVER_TYPEDEFS_H
|
||||
#ifndef AC_TYPEDEFS_H
|
||||
#define AC_TYPEDEFS_H
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
@@ -74,4 +74,4 @@ namespace Movement
|
||||
extern UInt32Counter splineIdGen;
|
||||
}
|
||||
|
||||
#endif // TRINITYSERVER_TYPEDEFS_H
|
||||
#endif // AC_TYPEDEFS_H
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYSERVER_SPLINE_H
|
||||
#define TRINITYSERVER_SPLINE_H
|
||||
#ifndef AC_SPLINE_H
|
||||
#define AC_SPLINE_H
|
||||
|
||||
#include "Errors.h"
|
||||
#include "MovementTypedefs.h"
|
||||
@@ -210,4 +210,4 @@ namespace Movement
|
||||
|
||||
#include "SplineImpl.h"
|
||||
|
||||
#endif // TRINITYSERVER_SPLINE_H
|
||||
#endif // AC_SPLINE_H
|
||||
|
||||
@@ -178,6 +178,21 @@ bool ScriptMgr::OnAllowedForPlayerLootCheck(Player const* player, ObjectGuid sou
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnAllowedToLootContainerCheck(Player const* player, ObjectGuid source)
|
||||
{
|
||||
auto ret = IsValidBoolScript<GlobalScript>([&](GlobalScript* script)
|
||||
{
|
||||
return script->OnAllowedToLootContainerCheck(player, source);
|
||||
});
|
||||
|
||||
if (ret && *ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Called when an instance Id is deleted, usually because it expired or no players are bound to it anymore.
|
||||
*
|
||||
|
||||
@@ -74,6 +74,21 @@ void ScriptMgr::OnPlayerReleasedGhost(Player* player)
|
||||
});
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell)
|
||||
{
|
||||
auto ret = IsValidBoolScript<PlayerScript>([player, mapId, zoneId, bySpell](PlayerScript* script)
|
||||
{
|
||||
return !script->OnCanPlayerFlyInZone(player, mapId, zoneId, bySpell);
|
||||
});
|
||||
|
||||
if (ret && *ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPVPKill(Player* killer, Player* killed)
|
||||
{
|
||||
ExecuteScript<PlayerScript>([&](PlayerScript* script)
|
||||
|
||||
@@ -1474,6 +1474,16 @@ public:
|
||||
*/
|
||||
virtual void OnQuestAbandon(Player* /*player*/, uint32 /*questId*/) { }
|
||||
|
||||
/**
|
||||
* @brief This hook called before other CanFlyChecks are applied
|
||||
*
|
||||
* @param player Contains information about the Player
|
||||
* @param mapId Contains information about the current map id
|
||||
* @param zoneId Contains information about the current zone
|
||||
* @param bySpell Contains information about the spell that invoked the check
|
||||
*/
|
||||
[[nodiscard]] virtual bool OnCanPlayerFlyInZone(Player* /*player*/, uint32 /*mapId*/, uint32 /*zoneId*/, SpellInfo const* /*bySpell*/) { return true; }
|
||||
|
||||
// Passive Anticheat System
|
||||
virtual void AnticheatSetSkipOnePacketForASH(Player* /*player*/, bool /*apply*/) { }
|
||||
virtual void AnticheatSetCanFlybyServer(Player* /*player*/, bool /*apply*/) { }
|
||||
@@ -1648,9 +1658,12 @@ public:
|
||||
// Called after loading spell dbc corrections
|
||||
virtual void OnLoadSpellCustomAttr(SpellInfo* /*spell*/) { }
|
||||
|
||||
// Called when checking if a player can see the creature loot
|
||||
// Called when checking if a player can see the creature loot item
|
||||
virtual bool OnAllowedForPlayerLootCheck(Player const* /*player*/, ObjectGuid /*source*/) { return false; };
|
||||
|
||||
// Called when checking if a player can see the creature loot (if it can click the corpse f.e)
|
||||
virtual bool OnAllowedToLootContainerCheck(Player const* /*player*/, ObjectGuid /*source*/) { return false; };
|
||||
|
||||
// Called when instance id is removed from database (e.g. instance reset)
|
||||
virtual void OnInstanceIdRemoved(uint32 /*instanceId*/) { }
|
||||
|
||||
@@ -2474,6 +2487,7 @@ public: /* PlayerScript */
|
||||
bool CanSendErrorAlreadyLooted(Player* player);
|
||||
void OnAfterCreatureLoot(Player* player);
|
||||
void OnAfterCreatureLootMoney(Player* player);
|
||||
bool OnCanPlayerFlyInZone(Player* player, uint32 mapId, uint32 zoneId, SpellInfo const* bySpell);
|
||||
|
||||
// Anti cheat
|
||||
void AnticheatSetSkipOnePacketForASH(Player* player, bool apply);
|
||||
@@ -2535,6 +2549,7 @@ public: /* GlobalScript */
|
||||
bool OnSpellHealingBonusTakenNegativeModifiers(Unit const* target, Unit const* caster, SpellInfo const* spellInfo, float& val);
|
||||
void OnLoadSpellCustomAttr(SpellInfo* spell);
|
||||
bool OnAllowedForPlayerLootCheck(Player const* player, ObjectGuid source);
|
||||
bool OnAllowedToLootContainerCheck(Player const* player, ObjectGuid source);
|
||||
void OnInstanceIdRemoved(uint32 instanceId);
|
||||
void OnBeforeSetBossState(uint32 id, EncounterState newState, EncounterState oldState, Map* instance);
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace WorldPackets
|
||||
class AC_GAME_API PlayMusic final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress missingReturn
|
||||
PlayMusic() : ServerPacket(SMSG_PLAY_MUSIC, 4) { }
|
||||
PlayMusic(uint32 soundKitID) : ServerPacket(SMSG_PLAY_MUSIC, 4), SoundKitID(soundKitID) { }
|
||||
|
||||
@@ -68,6 +69,7 @@ namespace WorldPackets
|
||||
class AC_GAME_API PlayObjectSound final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress missingReturn
|
||||
PlayObjectSound() : ServerPacket(SMSG_PLAY_OBJECT_SOUND, 4 + 8) { }
|
||||
PlayObjectSound(ObjectGuid const& sourceObjectGUID, uint32 soundKitID)
|
||||
: ServerPacket(SMSG_PLAY_OBJECT_SOUND, 4 + 8), SourceObjectGUID(sourceObjectGUID), SoundKitID(soundKitID) { }
|
||||
@@ -82,6 +84,7 @@ namespace WorldPackets
|
||||
class AC_GAME_API Playsound final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress missingReturn
|
||||
Playsound() : ServerPacket(SMSG_PLAY_SOUND, 4) { }
|
||||
Playsound(uint32 soundKitID) : ServerPacket(SMSG_PLAY_SOUND, 4), SoundKitID(soundKitID) { }
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
|
||||
//! Negative mutetime indicates amount of minutes to be muted effective on next login - which is now.
|
||||
if (account.MuteTime < 0)
|
||||
{
|
||||
account.MuteTime = GameTime::GetGameTime().count() + llabs(account.MuteTime);
|
||||
account.MuteTime = GameTime::GetGameTime().count() + std::llabs(account.MuteTime);
|
||||
|
||||
auto* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN);
|
||||
stmt->SetData(0, account.MuteTime);
|
||||
|
||||
@@ -6088,23 +6088,6 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
// for effects of spells that have only one target
|
||||
switch (m_spellInfo->Effects[i].Effect)
|
||||
{
|
||||
case SPELL_EFFECT_DUMMY:
|
||||
{
|
||||
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT)
|
||||
{
|
||||
// Raise Ally
|
||||
if( m_spellInfo->Id == 61999 )
|
||||
{
|
||||
Unit* target = m_targets.GetUnitTarget();
|
||||
if (!target)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (target->IsAlive()) // not discovered attributeEx5?
|
||||
return SPELL_FAILED_TARGET_NOT_DEAD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_LEARN_SPELL:
|
||||
{
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
|
||||
@@ -1470,7 +1470,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player /*= nullptr*/, bool strict /*= true*/) const
|
||||
SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player /*= nullptr*/, bool strict /*= true*/) const
|
||||
{
|
||||
// normal case
|
||||
if (AreaGroupId > 0)
|
||||
|
||||
@@ -474,7 +474,7 @@ public:
|
||||
bool IsAuraExclusiveBySpecificPerCasterWith(SpellInfo const* spellInfo) const;
|
||||
|
||||
SpellCastResult CheckShapeshift(uint32 form) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = nullptr, bool strict = true) const;
|
||||
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player* player = nullptr, bool strict = true) const;
|
||||
SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const;
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
@@ -1530,8 +1530,8 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->ChannelInterruptFlags |= AURA_INTERRUPT_FLAG_MOVE;
|
||||
});
|
||||
|
||||
// Debris
|
||||
ApplySpellFix({ 36449 }, [](SpellInfo* spellInfo)
|
||||
// Debris - Debris Visual
|
||||
ApplySpellFix({ 36449, 30632 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Attributes |= SPELL_ATTR0_AURA_IS_DEBUFF;
|
||||
});
|
||||
@@ -1542,12 +1542,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
|
||||
});
|
||||
|
||||
// Debris Visual
|
||||
ApplySpellFix({ 30632 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_DEST_DYNOBJ_ALLY);
|
||||
});
|
||||
|
||||
// Activate Sunblade Protecto
|
||||
ApplySpellFix({ 46475, 46476 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
+1
-1
@@ -290,7 +290,7 @@ public:
|
||||
bool OnGossipHello(Player* player, GameObject* go) override
|
||||
{
|
||||
if (InstanceScript* instance = go->GetInstanceScript())
|
||||
if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION))
|
||||
if (instance->GetData(DATA_EGG_EVENT) != DONE && !player->HasAura(SPELL_MIND_EXHAUSTION) && !player->GetPet())
|
||||
if (Creature* razor = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_RAZORGORE_THE_UNTAMED)))
|
||||
{
|
||||
razor->AI()->SetGUID(player->GetGUID());
|
||||
|
||||
@@ -54,9 +54,11 @@ struct boss_curator : public BossAI
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_POWER_BURN, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_BURN, true);
|
||||
ScheduleHealthCheckEvent(15, [&] {
|
||||
DoCastSelf(SPELL_ARCANE_INFUSION, true);
|
||||
Talk(SAY_ENRAGE);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
DoCastSelf(SPELL_ARCANE_INFUSION, true);
|
||||
Talk(SAY_ENRAGE);
|
||||
});
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA));
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
@@ -85,7 +87,7 @@ struct boss_curator : public BossAI
|
||||
DoCastSelf(SPELL_ASTRAL_DECONSTRUCTION, true);
|
||||
}).Schedule(10s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, 45.0f, true, false))
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 45.0f, true, false))
|
||||
{
|
||||
DoCast(target, SPELL_HATEFUL_BOLT);
|
||||
}
|
||||
|
||||
@@ -218,13 +218,17 @@ struct boss_netherspite : public BossAI
|
||||
}
|
||||
}).Schedule(10s, PORTAL_PHASE, [this](TaskContext context)
|
||||
{
|
||||
UpdatePortals();
|
||||
context.Repeat(1s);
|
||||
UpdatePortals();
|
||||
context.Repeat(1s);
|
||||
}).Schedule(10s, PORTAL_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_EMPOWERMENT);
|
||||
me->AddAura(SPELL_NETHERBURN_AURA, me);
|
||||
context.Repeat(90s);
|
||||
DoCastSelf(SPELL_EMPOWERMENT);
|
||||
me->AddAura(SPELL_NETHERBURN_AURA, me);
|
||||
context.Repeat(90s);
|
||||
}).Schedule(15s, PORTAL_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_VOIDZONE, 1, 45.0f, true, true);
|
||||
context.Repeat(15s);
|
||||
});
|
||||
Talk(EMOTE_PHASE_PORTAL);
|
||||
}
|
||||
@@ -237,13 +241,10 @@ struct boss_netherspite : public BossAI
|
||||
DoCastSelf(SPELL_BANISH_VISUAL, true);
|
||||
DoCastSelf(SPELL_BANISH_ROOT, true);
|
||||
DestroyPortals();
|
||||
scheduler.Schedule(30s, [this](TaskContext /*context*/)
|
||||
scheduler.Schedule(30s, [this](TaskContext)
|
||||
{
|
||||
if (!me->IsNonMeleeSpellCast(false))
|
||||
{
|
||||
SwitchToPortalPhase();
|
||||
return;
|
||||
}
|
||||
SwitchToPortalPhase();
|
||||
return;
|
||||
}).Schedule(10s, VANISH_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_NETHERBREATH, 0, 40.0f, true);
|
||||
@@ -270,11 +271,7 @@ struct boss_netherspite : public BossAI
|
||||
HandleDoors(false);
|
||||
SwitchToPortalPhase();
|
||||
DoZoneInCombat();
|
||||
scheduler.Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_VOIDZONE, 1, 45.0f, true, true);
|
||||
context.Repeat(15s);
|
||||
}).Schedule(9min, [this](TaskContext /*context*/)
|
||||
scheduler.Schedule(9min, [this](TaskContext /*context*/)
|
||||
{
|
||||
if (!berserk)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "karazhan.h"
|
||||
|
||||
enum PrinceSay
|
||||
@@ -47,11 +48,13 @@ enum Spells
|
||||
|
||||
enum creatures
|
||||
{
|
||||
NPC_NETHERSPITE_INFERNAL = 17646,
|
||||
NPC_MALCHEZARS_AXE = 17650,
|
||||
INFERNAL_MODEL_INVISIBLE = 11686,
|
||||
SPELL_INFERNAL_RELAY = 33814, // 30835,
|
||||
EQUIP_ID_AXE = 33542
|
||||
NPC_NETHERSPITE_INFERNAL = 17646,
|
||||
NPC_MALCHEZAARS_AXE = 17650,
|
||||
INFERNAL_MODEL_INVISIBLE = 11686,
|
||||
SPELL_INFERNAL_RELAY = 33814, // 30835,
|
||||
SPELL_INFERNAL_RELAY_ONE = 30834,
|
||||
SPELL_INFERNAL_RELAY_TWO = 30835,
|
||||
EQUIP_ID_AXE = 33542
|
||||
};
|
||||
|
||||
enum EventGroups
|
||||
@@ -68,44 +71,19 @@ enum Phases
|
||||
PHASE_THREE = 3
|
||||
};
|
||||
|
||||
struct InfernalPoint
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
#define INFERNAL_Z 275.5f
|
||||
|
||||
/*static InfernalPoint InfernalPoints[] =
|
||||
{
|
||||
{ -10922.8f, -1985.2f },
|
||||
{ -10916.2f, -1996.2f },
|
||||
{ -10932.2f, -2008.1f },
|
||||
{ -10948.8f, -2022.1f },
|
||||
{ -10958.7f, -1997.7f },
|
||||
{ -10971.5f, -1997.5f },
|
||||
{ -10990.8f, -1995.1f },
|
||||
{ -10989.8f, -1976.5f },
|
||||
{ -10971.6f, -1973.0f },
|
||||
{ -10955.5f, -1974.0f },
|
||||
{ -10939.6f, -1969.8f },
|
||||
{ -10958.0f, -1952.2f },
|
||||
{ -10941.7f, -1954.8f },
|
||||
{ -10943.1f, -1988.5f },
|
||||
{ -10948.8f, -2005.1f },
|
||||
{ -10984.0f, -2019.3f },
|
||||
{ -10932.8f, -1979.6f },
|
||||
{ -10935.7f, -1996.0f }
|
||||
};*/
|
||||
|
||||
struct boss_malchezaar : public BossAI
|
||||
{
|
||||
boss_malchezaar(Creature* creature) : BossAI(creature, DATA_MALCHEZZAR) { }
|
||||
boss_malchezaar(Creature* creature) : BossAI(creature, DATA_MALCHEZAAR) { }
|
||||
|
||||
std::list<Creature*> relays;
|
||||
std::list<Creature*> infernalTargets;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_phase = 1;
|
||||
clearweapons();
|
||||
positions.clear();
|
||||
relays.clear();
|
||||
infernalTargets.clear();
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), true);
|
||||
}
|
||||
|
||||
@@ -145,7 +123,7 @@ struct boss_malchezaar : public BossAI
|
||||
_phase = PHASE_THREE;
|
||||
clearweapons();
|
||||
|
||||
me->SummonCreature(NPC_MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
|
||||
me->SummonCreature(NPC_MALCHEZAARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
|
||||
|
||||
scheduler.Schedule(20s, 30s, [this](TaskContext context)
|
||||
{
|
||||
@@ -174,15 +152,52 @@ struct boss_malchezaar : public BossAI
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), true);
|
||||
}
|
||||
|
||||
void SpawnInfernal(Creature* relay, Creature* target)
|
||||
{
|
||||
if (Creature* infernal = relay->SummonCreature(NPC_NETHERSPITE_INFERNAL, target->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 180000))
|
||||
{
|
||||
infernal->SetDisplayId(INFERNAL_MODEL_INVISIBLE);
|
||||
relay->CastSpell(infernal, SPELL_INFERNAL_RELAY);
|
||||
infernal->SetFaction(me->GetFaction());
|
||||
infernal->SetControlled(true, UNIT_STATE_ROOT);
|
||||
relay->CastSpell(infernal, SPELL_INFERNAL_RELAY);
|
||||
summons.Summon(infernal);
|
||||
}
|
||||
}
|
||||
|
||||
bool MaxSpawns(std::list<Creature*> spawns)
|
||||
{
|
||||
return spawns.size() == 0;
|
||||
}
|
||||
|
||||
Creature* PickTarget(std::list<Creature*> pickList)
|
||||
{
|
||||
uint8 index = urand(0, pickList.size()-1);
|
||||
uint8 counter = 0;
|
||||
for (Creature* creature : pickList)
|
||||
{
|
||||
if (counter == index)
|
||||
{
|
||||
return creature;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
|
||||
me->GetCreaturesWithEntryInRange(relays, 250.0f, NPC_INFERNAL_RELAY);
|
||||
me->GetCreaturesWithEntryInRange(infernalTargets, 100.0f, NPC_INFERNAL_TARGET);
|
||||
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), false);
|
||||
|
||||
scheduler.Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
EnfeebleHealthEffect();
|
||||
DoCastAOE(SPELL_ENFEEBLE);
|
||||
|
||||
scheduler.Schedule(9s, [this](TaskContext)
|
||||
{
|
||||
@@ -199,23 +214,30 @@ struct boss_malchezaar : public BossAI
|
||||
context.Repeat();
|
||||
}).Schedule(40s, [this](TaskContext context)
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(40.0);;
|
||||
|
||||
if (Creature* RELAY = me->FindNearestCreature(NPC_RELAY, 100.0f))
|
||||
if (!MaxSpawns(infernalTargets)) // only spawn infernal when the area is not full
|
||||
{
|
||||
if (Creature* infernal = RELAY->SummonCreature(NPC_NETHERSPITE_INFERNAL, pos, TEMPSUMMON_TIMED_DESPAWN, 180000))
|
||||
Talk(SAY_SUMMON);
|
||||
if (Creature* infernalRelayOne = relays.back())
|
||||
{
|
||||
infernal->SetDisplayId(INFERNAL_MODEL_INVISIBLE);
|
||||
infernal->SetFaction(me->GetFaction());
|
||||
infernal->SetControlled(true, UNIT_STATE_ROOT);
|
||||
RELAY->AI()->DoCast(infernal, SPELL_INFERNAL_RELAY);
|
||||
summons.Summon(infernal);
|
||||
if (Creature* infernalRelayTwo = relays.front())
|
||||
{
|
||||
infernalRelayOne->CastSpell(infernalRelayTwo, SPELL_INFERNAL_RELAY_ONE, true);
|
||||
|
||||
if (Creature* infernalTarget = PickTarget(infernalTargets))
|
||||
{
|
||||
infernalTargets.remove(infernalTarget);
|
||||
SpawnInfernal(infernalRelayTwo, infernalTarget);
|
||||
|
||||
scheduler.Schedule(3min, [this, infernalTarget](TaskContext)
|
||||
{
|
||||
infernalTargets.push_back(infernalTarget); //adds to list again
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.Repeat(_phase == PHASE_THREE ? 15s : 45s);
|
||||
|
||||
Talk(SAY_SUMMON);
|
||||
}).Schedule(20s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOW_WORD_PAIN);
|
||||
@@ -224,23 +246,12 @@ struct boss_malchezaar : public BossAI
|
||||
});
|
||||
}
|
||||
|
||||
void EnfeebleHealthEffect()
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
|
||||
{
|
||||
std::list<Unit*> targetList;
|
||||
SelectTargetList(targetList, 5, SelectTargetMethod::Random, 1, [&](Unit* u) { return u->IsAlive() && u->IsPlayer(); });
|
||||
|
||||
if (targetList.empty())
|
||||
return;
|
||||
|
||||
for (auto const& target : targetList)
|
||||
if (spell->Id == SPELL_ENFEEBLE)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
_enfeebleTargets[target->GetGUID()] = target->GetHealth();
|
||||
|
||||
me->CastSpell(target, SPELL_ENFEEBLE, true);
|
||||
target->SetHealth(1);
|
||||
}
|
||||
_enfeebleTargets[target->GetGUID()] = target->GetHealth();
|
||||
target->SetHealth(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +272,6 @@ struct boss_malchezaar : public BossAI
|
||||
private:
|
||||
uint32 _phase;
|
||||
std::map<ObjectGuid, uint32> _enfeebleTargets;
|
||||
std::vector<InfernalPoint*> positions;
|
||||
};
|
||||
|
||||
struct npc_netherspite_infernal : public ScriptedAI
|
||||
@@ -357,9 +367,43 @@ struct npc_malchezaar_axe : public ScriptedAI
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
// 30843 - Enfeeble
|
||||
class spell_malchezaar_enfeeble : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_malchezaar_enfeeble);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->ToCreature();
|
||||
}
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
uint8 maxSize = 5;
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
targets.remove_if([caster](WorldObject const* target) -> bool
|
||||
{
|
||||
// Should not target current victim.
|
||||
return caster->GetVictim() == target;
|
||||
});
|
||||
|
||||
if (targets.size() > maxSize)
|
||||
{
|
||||
Acore::Containers::RandomResize(targets, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malchezaar_enfeeble::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_malchezaar()
|
||||
{
|
||||
RegisterKarazhanCreatureAI(boss_malchezaar);
|
||||
RegisterKarazhanCreatureAI(npc_malchezaar_axe);
|
||||
RegisterKarazhanCreatureAI(npc_netherspite_infernal);
|
||||
RegisterSpellScript(spell_malchezaar_enfeeble);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ enum ShadeOfAran
|
||||
|
||||
//Creature Spells
|
||||
SPELL_CIRCULAR_BLIZZARD = 29951,
|
||||
SPELL_WATERBOLT = 31012,
|
||||
SPELL_SHADOW_PYRO = 29978,
|
||||
|
||||
//Creatures
|
||||
@@ -77,6 +76,8 @@ enum Groups
|
||||
GROUP_DRINKING = 1
|
||||
};
|
||||
|
||||
Position const roomCenter = {-11158.f, -1920.f};
|
||||
|
||||
Position const elementalPos[4] =
|
||||
{
|
||||
{-11168.1f, -1939.29f, 232.092f, 1.46f},
|
||||
@@ -103,12 +104,10 @@ struct boss_shade_of_aran : public BossAI
|
||||
|
||||
uint32 CurrentNormalSpell;
|
||||
|
||||
bool Drinking;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
drinkScheduler.CancelAll();
|
||||
_drinkScheduler.CancelAll();
|
||||
LastSuperSpell = rand() % 3;
|
||||
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
@@ -120,7 +119,7 @@ struct boss_shade_of_aran : public BossAI
|
||||
_fireCooledDown = true;
|
||||
_frostCooledDown = true;
|
||||
|
||||
Drinking = false;
|
||||
_drinking = false;
|
||||
|
||||
// Not in progress
|
||||
instance->SetData(DATA_ARAN, NOT_STARTED);
|
||||
@@ -149,6 +148,23 @@ struct boss_shade_of_aran : public BossAI
|
||||
});
|
||||
}
|
||||
|
||||
bool CheckAranInRoom()
|
||||
{
|
||||
return me->GetDistance2d(roomCenter.GetPositionX(), roomCenter.GetPositionY()) < 45.0f;
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (who && who->isTargetableForAttack() && me->GetReactState() != REACT_PASSIVE)
|
||||
{
|
||||
if (me->Attack(who, false))
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(who, 45.0f, 0);
|
||||
me->AddThreat(who, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
@@ -207,9 +223,9 @@ struct boss_shade_of_aran : public BossAI
|
||||
libraryDoor->SetGoState(GO_STATE_READY);
|
||||
libraryDoor->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||
}
|
||||
}).Schedule(1ms, [this](TaskContext context)
|
||||
}).Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
if (!me->IsNonMeleeSpellCast(false))
|
||||
if (!me->IsNonMeleeSpellCast(false) && !_drinking)
|
||||
{
|
||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
|
||||
if (!target)
|
||||
@@ -242,93 +258,144 @@ struct boss_shade_of_aran : public BossAI
|
||||
DoCast(target, CurrentNormalSpell);
|
||||
}
|
||||
}
|
||||
context.Repeat(10s);
|
||||
context.Repeat(2s);
|
||||
}).Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
switch (urand(0, 1))
|
||||
if (!_drinking)
|
||||
{
|
||||
case 0:
|
||||
DoCastSelf(SPELL_AOE_CS);
|
||||
break;
|
||||
case 1:
|
||||
DoCastRandomTarget(SPELL_CHAINSOFICE);
|
||||
break;
|
||||
switch (urand(0, 1))
|
||||
{
|
||||
case 0:
|
||||
DoCastSelf(SPELL_AOE_CS);
|
||||
break;
|
||||
case 1:
|
||||
DoCastRandomTarget(SPELL_CHAINSOFICE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
context.Repeat(5s, 20s);
|
||||
}).Schedule(35s, [this](TaskContext context)
|
||||
{
|
||||
uint8 Available[2];
|
||||
|
||||
switch (LastSuperSpell)
|
||||
if (!_drinking)
|
||||
{
|
||||
case SUPER_AE:
|
||||
Available[0] = SUPER_FLAME;
|
||||
Available[1] = SUPER_BLIZZARD;
|
||||
break;
|
||||
case SUPER_FLAME:
|
||||
Available[0] = SUPER_AE;
|
||||
Available[1] = SUPER_BLIZZARD;
|
||||
break;
|
||||
case SUPER_BLIZZARD:
|
||||
Available[0] = SUPER_FLAME;
|
||||
Available[1] = SUPER_AE;
|
||||
break;
|
||||
}
|
||||
uint8 Available[2];
|
||||
|
||||
LastSuperSpell = Available[urand(0, 1)];
|
||||
switch (LastSuperSpell)
|
||||
{
|
||||
case SUPER_AE:
|
||||
Available[0] = SUPER_FLAME;
|
||||
Available[1] = SUPER_BLIZZARD;
|
||||
break;
|
||||
case SUPER_FLAME:
|
||||
Available[0] = SUPER_AE;
|
||||
Available[1] = SUPER_BLIZZARD;
|
||||
break;
|
||||
case SUPER_BLIZZARD:
|
||||
Available[0] = SUPER_FLAME;
|
||||
Available[1] = SUPER_AE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (LastSuperSpell)
|
||||
{
|
||||
case SUPER_AE:
|
||||
Talk(SAY_EXPLOSION);
|
||||
LastSuperSpell = Available[urand(0, 1)];
|
||||
|
||||
DoCastSelf(SPELL_BLINK_CENTER, true);
|
||||
DoCastSelf(SPELL_PLAYERPULL, true);
|
||||
DoCastSelf(SPELL_MASSSLOW, true);
|
||||
DoCastSelf(SPELL_AEXPLOSION, false);
|
||||
break;
|
||||
switch (LastSuperSpell)
|
||||
{
|
||||
case SUPER_AE:
|
||||
Talk(SAY_EXPLOSION);
|
||||
|
||||
case SUPER_FLAME:
|
||||
Talk(SAY_FLAMEWREATH);
|
||||
DoCastSelf(SPELL_BLINK_CENTER, true);
|
||||
DoCastSelf(SPELL_PLAYERPULL, true);
|
||||
DoCastSelf(SPELL_MASSSLOW, true);
|
||||
DoCastSelf(SPELL_AEXPLOSION, false);
|
||||
break;
|
||||
|
||||
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
|
||||
{
|
||||
scheduler.CancelGroup(GROUP_FLAMEWREATH);
|
||||
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
|
||||
{
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
case SUPER_FLAME:
|
||||
Talk(SAY_FLAMEWREATH);
|
||||
|
||||
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
|
||||
{
|
||||
if (!FlameWreathTarget[i])
|
||||
continue;
|
||||
|
||||
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
|
||||
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
|
||||
scheduler.CancelGroup(GROUP_FLAMEWREATH);
|
||||
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
|
||||
{
|
||||
for (uint8 i = 0; i < 3; ++i)
|
||||
{
|
||||
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
|
||||
FlameWreathTarget[i].Clear();
|
||||
if (!FlameWreathTarget[i])
|
||||
continue;
|
||||
|
||||
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
|
||||
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
|
||||
{
|
||||
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
|
||||
FlameWreathTarget[i].Clear();
|
||||
}
|
||||
}
|
||||
context.Repeat(500ms);
|
||||
});
|
||||
|
||||
FlameWreathTarget[0].Clear();
|
||||
FlameWreathTarget[1].Clear();
|
||||
FlameWreathTarget[2].Clear();
|
||||
|
||||
FlameWreathEffect();
|
||||
break;
|
||||
|
||||
case SUPER_BLIZZARD:
|
||||
Talk(SAY_BLIZZARD);
|
||||
|
||||
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
|
||||
{
|
||||
pSpawn->SetFaction(me->GetFaction());
|
||||
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
|
||||
}
|
||||
context.Repeat(500ms);
|
||||
});
|
||||
|
||||
FlameWreathTarget[0].Clear();
|
||||
FlameWreathTarget[1].Clear();
|
||||
FlameWreathTarget[2].Clear();
|
||||
|
||||
FlameWreathEffect();
|
||||
break;
|
||||
|
||||
case SUPER_BLIZZARD:
|
||||
Talk(SAY_BLIZZARD);
|
||||
|
||||
if (Creature* pSpawn = me->SummonCreature(NPC_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 25000))
|
||||
{
|
||||
pSpawn->SetFaction(me->GetFaction());
|
||||
pSpawn->CastSpell(me, SPELL_CIRCULAR_BLIZZARD, false);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
context.Repeat(35s, 40s);
|
||||
}).Schedule(1s, [this](TaskContext context){
|
||||
if (me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
|
||||
{
|
||||
_drinking = true;
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
Talk(SAY_DRINK);
|
||||
DoCastSelf(SPELL_MASS_POLY, true);
|
||||
DoCastSelf(SPELL_CONJURE, false);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
DoCastSelf(SPELL_DRINK, true);
|
||||
_currentHealth = me->GetHealth();
|
||||
_drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
|
||||
{
|
||||
//check for damage to interrupt
|
||||
if (me->GetHealth() < _currentHealth)
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_DRINK);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_POTION, false);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
_drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
_drinking = false;
|
||||
} else
|
||||
{
|
||||
context.Repeat(500ms);
|
||||
}
|
||||
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
|
||||
{
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_POTION, true);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
_drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
_drinking = false;
|
||||
});
|
||||
context.Repeat(12s); //semi-arbitrary duration to envelop drinking duration
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Repeat(1s);
|
||||
}
|
||||
}).Schedule(12min, [this](TaskContext context)
|
||||
{
|
||||
for (uint32 i = 0; i < 5; ++i)
|
||||
@@ -384,70 +451,21 @@ struct boss_shade_of_aran : public BossAI
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
drinkScheduler.Update(diff);
|
||||
_drinkScheduler.Update(diff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
|
||||
if (!CheckAranInRoom())
|
||||
{
|
||||
Drinking = true;
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
Talk(SAY_DRINK);
|
||||
|
||||
scheduler.DelayAll(10s);
|
||||
DoCastSelf(SPELL_MASS_POLY, true);
|
||||
DoCastSelf(SPELL_CONJURE, false);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
DoCastSelf(SPELL_DRINK, true);
|
||||
_currentHealth = me->GetHealth();
|
||||
drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
|
||||
{
|
||||
//check for damage to interrupt
|
||||
if(CheckDamageDuringDrinking(_currentHealth))
|
||||
{
|
||||
Drinking = false;
|
||||
me->RemoveAurasDueToSpell(SPELL_DRINK);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_POTION, false);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
} else {
|
||||
context.Repeat(500ms);
|
||||
}
|
||||
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
|
||||
{
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
|
||||
DoCastSelf(SPELL_POTION, true);
|
||||
DoCastSelf(SPELL_AOE_PYROBLAST, false);
|
||||
|
||||
Drinking = false;
|
||||
drinkScheduler.CancelGroup(GROUP_DRINKING);
|
||||
});
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !Drinking)
|
||||
if (_arcaneCooledDown && _fireCooledDown && _frostCooledDown && !_drinking)
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
bool CheckDamageDuringDrinking(uint32 oldHealth)
|
||||
{
|
||||
if (Drinking)
|
||||
{
|
||||
if (me->GetHealth() < oldHealth)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*pAttacker*/, SpellInfo const* Spell) override
|
||||
{
|
||||
//We only care about interrupt effects and only if they are durring a spell currently being cast
|
||||
@@ -476,52 +494,16 @@ struct boss_shade_of_aran : public BossAI
|
||||
}
|
||||
}
|
||||
private:
|
||||
TaskScheduler drinkScheduler;
|
||||
TaskScheduler _drinkScheduler;
|
||||
|
||||
bool _arcaneCooledDown;
|
||||
bool _fireCooledDown;
|
||||
bool _frostCooledDown;
|
||||
bool _drinking;
|
||||
uint32 _currentHealth;
|
||||
};
|
||||
|
||||
struct npc_aran_elemental : public ScriptedAI
|
||||
{
|
||||
npc_aran_elemental(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
SetCombatMovement(false);
|
||||
_scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(2s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_WATERBOLT);
|
||||
context.Repeat(2s);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
void AddSC_boss_shade_of_aran()
|
||||
{
|
||||
RegisterKarazhanCreatureAI(boss_shade_of_aran);
|
||||
RegisterKarazhanCreatureAI(npc_aran_elemental);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ enum Spells
|
||||
enum Creatures
|
||||
{
|
||||
NPC_DEMONCHAINS = 17248,
|
||||
NPC_FIENDISHIMP = 17267,
|
||||
NPC_PORTAL = 17265
|
||||
};
|
||||
|
||||
@@ -146,64 +145,6 @@ private:
|
||||
ObjectGuid sacrificeGUID;
|
||||
};
|
||||
|
||||
struct npc_fiendish_portal : public PassiveAI
|
||||
{
|
||||
npc_fiendish_portal(Creature* creature) : PassiveAI(creature), summons(me) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
DespawnAllImp();
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
|
||||
void DespawnAllImp()
|
||||
{
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
private:
|
||||
SummonList summons;
|
||||
};
|
||||
|
||||
struct npc_fiendish_imp : public ScriptedAI
|
||||
{
|
||||
npc_fiendish_imp(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(2s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_FIREBOLT);
|
||||
context.Repeat(2200ms);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
struct boss_terestian_illhoof : public BossAI
|
||||
{
|
||||
boss_terestian_illhoof(Creature* creature) : BossAI(creature, DATA_TERESTIAN)
|
||||
@@ -218,20 +159,6 @@ struct boss_terestian_illhoof : public BossAI
|
||||
{
|
||||
_Reset();
|
||||
SummonKilrek();
|
||||
portalsCount = 0;
|
||||
berserk = false;
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
if (portalGUID[i])
|
||||
{
|
||||
if (Creature* pPortal = ObjectAccessor::GetCreature(*me, portalGUID[i]))
|
||||
{
|
||||
pPortal->AI()->Reset();
|
||||
pPortal->DespawnOrUnsummon();
|
||||
}
|
||||
portalGUID[i].Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SummonKilrek()
|
||||
@@ -256,10 +183,13 @@ struct boss_terestian_illhoof : public BossAI
|
||||
DoZoneInCombat();
|
||||
scheduler.Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit * target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, false))
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, false))
|
||||
{
|
||||
DoCast(target, SPELL_SACRIFICE, true);
|
||||
target->CastSpell(target, SPELL_SUMMON_DEMONCHAINS, true);
|
||||
target->m_Events.AddEventAtOffset([target] {
|
||||
target->CastSpell(target, SPELL_SUMMON_DEMONCHAINS, true);
|
||||
}, 1s);
|
||||
|
||||
Talk(SAY_SACRIFICE);
|
||||
context.Repeat(30s);
|
||||
}
|
||||
@@ -267,31 +197,15 @@ struct boss_terestian_illhoof : public BossAI
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
context.Repeat(10s);
|
||||
}).Schedule(10s, [this](TaskContext context)
|
||||
}).Schedule(10s, [this](TaskContext)
|
||||
{
|
||||
if (!portalGUID[0])
|
||||
{
|
||||
DoCastVictim(SPELL_FIENDISH_PORTAL);
|
||||
}
|
||||
if (!portalGUID[1])
|
||||
{
|
||||
DoCastVictim(SPELL_FIENDISH_PORTAL_1);
|
||||
}
|
||||
if (portalGUID[0] && portalGUID[1])
|
||||
{
|
||||
if (Creature* pPortal = ObjectAccessor::GetCreature(*me, portalGUID[urand(0, 1)]))
|
||||
{
|
||||
pPortal->CastSpell(me->GetVictim(), SPELL_SUMMON_FIENDISIMP);
|
||||
}
|
||||
context.Repeat(5s);
|
||||
}
|
||||
DoCastAOE(SPELL_FIENDISH_PORTAL);
|
||||
}).Schedule(11s, [this](TaskContext)
|
||||
{
|
||||
DoCastAOE(SPELL_FIENDISH_PORTAL_1);
|
||||
}).Schedule(10min, [this](TaskContext /*context*/)
|
||||
{
|
||||
if (!berserk)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK);
|
||||
berserk = true;
|
||||
}
|
||||
DoCastSelf(SPELL_BERSERK);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -299,13 +213,14 @@ struct boss_terestian_illhoof : public BossAI
|
||||
{
|
||||
if (summoned->GetEntry() == NPC_PORTAL)
|
||||
{
|
||||
portalGUID[portalsCount] = summoned->GetGUID();
|
||||
++portalsCount;
|
||||
summoned->SetReactState(REACT_PASSIVE);
|
||||
if (summoned->GetUInt32Value(UNIT_CREATED_BY_SPELL) == SPELL_FIENDISH_PORTAL_1)
|
||||
{
|
||||
Talk(SAY_SUMMON);
|
||||
}
|
||||
}
|
||||
|
||||
summons.Summon(summoned);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
@@ -318,44 +233,14 @@ struct boss_terestian_illhoof : public BossAI
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
{
|
||||
if (portalGUID[i])
|
||||
{
|
||||
if (Creature* pPortal = ObjectAccessor::GetCreature((*me), portalGUID[i]))
|
||||
{
|
||||
pPortal->AI()->Reset();
|
||||
pPortal->DespawnOrUnsummon();
|
||||
}
|
||||
portalGUID[i].Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool berserk;
|
||||
ObjectGuid portalGUID[2];
|
||||
uint8 portalsCount;
|
||||
};
|
||||
|
||||
void AddSC_boss_terestian_illhoof()
|
||||
{
|
||||
RegisterKarazhanCreatureAI(boss_terestian_illhoof);
|
||||
RegisterKarazhanCreatureAI(npc_fiendish_imp);
|
||||
RegisterKarazhanCreatureAI(npc_fiendish_portal);
|
||||
RegisterKarazhanCreatureAI(npc_kilrek);
|
||||
RegisterKarazhanCreatureAI(npc_demon_chain);
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ struct boss_strawman : public ScriptedAI
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* Spell) override
|
||||
{
|
||||
if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && (!(rand() % 10)))
|
||||
if ((Spell->SchoolMask == SPELL_SCHOOL_MASK_FIRE) && roll_chance_i(10))
|
||||
{
|
||||
/*
|
||||
if (not direct damage(aoe, dot))
|
||||
|
||||
@@ -44,6 +44,7 @@ ObjectData const creatureData[] =
|
||||
{ NPC_ROMULO, DATA_ROMULO },
|
||||
{ NPC_JULIANNE, DATA_JULIANNE },
|
||||
{ NPC_NIGHTBANE, DATA_NIGHTBANE },
|
||||
{ NPC_TERESTIAN_ILLHOOF, DATA_TERESTIAN },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
@@ -122,6 +123,16 @@ public:
|
||||
case NPC_ECHO_OF_MEDIVH:
|
||||
_echoOfMedivhGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_FIENDISH_IMP:
|
||||
if (Creature* terestrian = GetCreature(DATA_TERESTIAN))
|
||||
{
|
||||
if (terestrian->AI())
|
||||
{
|
||||
terestrian->AI()->JustSummoned(creature);
|
||||
creature->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -252,7 +263,6 @@ public:
|
||||
piece->NearTeleportTo(x, y, z, o);
|
||||
piece->AI()->DoAction(ACTION_CHESS_PIECE_RESET_ORIENTATION);
|
||||
piece->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
piece->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
piece->AI()->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ enum KZDataTypes
|
||||
DATA_TERESTIAN = 7,
|
||||
DATA_NETHERSPITE = 8,
|
||||
DATA_CHESS_EVENT = 9,
|
||||
DATA_MALCHEZZAR = 10,
|
||||
DATA_MALCHEZAAR = 10,
|
||||
DATA_NIGHTBANE = 11,
|
||||
DATA_SERVANT_QUARTERS = 12,
|
||||
DATA_OPERA_OZ_DEATHCOUNT = 13,
|
||||
@@ -117,6 +117,7 @@ enum KZCreatures
|
||||
NPC_ROAR = 17546,
|
||||
NPC_STRAWMAN = 17543,
|
||||
NPC_TINHEAD = 17547,
|
||||
NPC_FIENDISH_IMP = 17267,
|
||||
|
||||
// Chess Event
|
||||
NPC_ECHO_OF_MEDIVH = 16816,
|
||||
@@ -132,7 +133,12 @@ enum KZCreatures
|
||||
NPC_ROOK_A = 21160,
|
||||
NPC_KING_H = 21752,
|
||||
NPC_KING_A = 21684,
|
||||
NPC_CHESS_EVENT_MEDIVH_CHEAT_FIRES = 22521
|
||||
NPC_CHESS_EVENT_MEDIVH_CHEAT_FIRES = 22521,
|
||||
|
||||
// Malchezaar Helpers
|
||||
NPC_INFERNAL_TARGET = 17644,
|
||||
NPC_INFERNAL_RELAY = 17645
|
||||
|
||||
};
|
||||
|
||||
enum KZGameObjectIds
|
||||
|
||||
@@ -16,9 +16,18 @@
|
||||
*/
|
||||
|
||||
#include "InstanceScript.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "magisters_terrace.h"
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_KALECGOS, DATA_KALECGOS },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f };
|
||||
|
||||
class instance_magisters_terrace : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -29,6 +38,7 @@ public:
|
||||
instance_magisters_terrace_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
}
|
||||
|
||||
uint32 Encounter[MAX_ENCOUNTER];
|
||||
@@ -69,6 +79,24 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
|
||||
{
|
||||
if (eventId == EVENT_SPAWN_KALECGOS)
|
||||
{
|
||||
if (!GetCreature(DATA_KALECGOS) && !scheduler.IsGroupScheduled(DATA_KALECGOS))
|
||||
{
|
||||
scheduler.Schedule(1min, 1min, DATA_KALECGOS,[this](TaskContext)
|
||||
{
|
||||
if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos))
|
||||
{
|
||||
kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false);
|
||||
kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 identifier, uint32 data) override
|
||||
{
|
||||
switch (identifier)
|
||||
@@ -116,6 +144,8 @@ public:
|
||||
kael->AI()->JustSummoned(creature);
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
@@ -184,7 +214,53 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_KALECGOS_TRANSFORM = 44670,
|
||||
SPELL_TRANSFORM_VISUAL = 24085,
|
||||
SPELL_CAMERA_SHAKE = 44762,
|
||||
SPELL_ORB_KILL_CREDIT = 46307
|
||||
};
|
||||
|
||||
enum MovementPoints
|
||||
{
|
||||
POINT_ID_PREPARE_LANDING = 6
|
||||
};
|
||||
|
||||
struct npc_kalecgos : public ScriptedAI
|
||||
{
|
||||
npc_kalecgos(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void MovementInform(uint32 type, uint32 pointId) override
|
||||
{
|
||||
if (type != WAYPOINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (pointId == POINT_ID_PREPARE_LANDING)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetHover(false);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
DoCastAOE(SPELL_CAMERA_SHAKE);
|
||||
me->SetObjectScale(0.6f);
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
DoCastSelf(SPELL_ORB_KILL_CREDIT, true);
|
||||
DoCastSelf(SPELL_TRANSFORM_VISUAL);
|
||||
DoCastSelf(SPELL_KALECGOS_TRANSFORM);
|
||||
me->UpdateEntry(NPC_HUMAN_KALECGOS);
|
||||
}, 1s);
|
||||
}, 2s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_magisters_terrace()
|
||||
{
|
||||
new instance_magisters_terrace();
|
||||
RegisterMagistersTerraceCreatureAI(npc_kalecgos);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ enum MTData
|
||||
DATA_VEXALLUS_EVENT = 1,
|
||||
DATA_DELRISSA_EVENT = 2,
|
||||
DATA_KAELTHAS_EVENT = 3,
|
||||
MAX_ENCOUNTER = 4
|
||||
MAX_ENCOUNTER = 4,
|
||||
|
||||
DATA_KALECGOS = 5
|
||||
};
|
||||
|
||||
enum MTCreatures
|
||||
@@ -41,7 +43,9 @@ enum MTCreatures
|
||||
NPC_FEL_CRYSTAL = 24722,
|
||||
NPC_KAEL_THAS = 24664,
|
||||
NPC_PHOENIX = 21362,
|
||||
NPC_PHOENIX_EGG = 21364
|
||||
NPC_PHOENIX_EGG = 21364,
|
||||
NPC_KALECGOS = 24844,
|
||||
NPC_HUMAN_KALECGOS = 24848
|
||||
};
|
||||
|
||||
enum MTGameObjects
|
||||
@@ -54,10 +58,27 @@ enum MTGameObjects
|
||||
GO_ESCAPE_ORB = 188173
|
||||
};
|
||||
|
||||
enum InstanceEventIds
|
||||
{
|
||||
EVENT_SPAWN_KALECGOS = 16547
|
||||
};
|
||||
|
||||
enum InstanceText
|
||||
{
|
||||
SAY_KALECGOS_SPAWN = 0
|
||||
};
|
||||
|
||||
enum MovementData
|
||||
{
|
||||
PATH_KALECGOS_FLIGHT = 248440
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
inline AI* GetMagistersTerraceAI(T* obj)
|
||||
{
|
||||
return GetInstanceAI<AI>(obj, MTScriptName);
|
||||
}
|
||||
|
||||
#define RegisterMagistersTerraceCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetMagistersTerraceAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -695,106 +695,6 @@ class npc_fairbanks : public CreatureScript
|
||||
public:
|
||||
npc_fairbanks() : CreatureScript("npc_fairbanks") { }
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
AddGossipItemFor(player, 0, "Curse? What's going on here, Fairbanks?", GOSSIP_SENDER_MAIN, 1);
|
||||
SendGossipMenuFor(player, 100100, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*Sender*/, uint32 uiAction) override
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
|
||||
switch (uiAction)
|
||||
{
|
||||
case 1:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "Mograine?", GOSSIP_SENDER_MAIN, 2);
|
||||
SendGossipMenuFor(player, 100101, creature->GetGUID());
|
||||
return true;
|
||||
case 2:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "What do you mean?", GOSSIP_SENDER_MAIN, 3);
|
||||
SendGossipMenuFor(player, 100102, creature->GetGUID());
|
||||
return true;
|
||||
case 3:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "I still do not fully understand.", GOSSIP_SENDER_MAIN, 4);
|
||||
SendGossipMenuFor(player, 100103, creature->GetGUID());
|
||||
return true;
|
||||
case 4:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "Incredible story. So how did he die?", GOSSIP_SENDER_MAIN, 5);
|
||||
SendGossipMenuFor(player, 100104, creature->GetGUID());
|
||||
return true;
|
||||
case 5:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "You mean...", GOSSIP_SENDER_MAIN, 6);
|
||||
SendGossipMenuFor(player, 100105, creature->GetGUID());
|
||||
return true;
|
||||
case 6:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "How do you know all of this?", GOSSIP_SENDER_MAIN, 7);
|
||||
SendGossipMenuFor(player, 100106, creature->GetGUID());
|
||||
return true;
|
||||
case 7:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "A thousand? For one man?", GOSSIP_SENDER_MAIN, 8);
|
||||
SendGossipMenuFor(player, 100107, creature->GetGUID());
|
||||
return true;
|
||||
case 8:
|
||||
creature->HandleEmoteCommand(5);
|
||||
AddGossipItemFor(player, 0, "Yet? Yet what?", GOSSIP_SENDER_MAIN, 9);
|
||||
SendGossipMenuFor(player, 100108, creature->GetGUID());
|
||||
return true;
|
||||
case 9:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "And did he?", GOSSIP_SENDER_MAIN, 10);
|
||||
SendGossipMenuFor(player, 100109, creature->GetGUID());
|
||||
return true;
|
||||
case 10:
|
||||
creature->HandleEmoteCommand(274);
|
||||
AddGossipItemFor(player, 0, "Continue please, Fairbanks.", GOSSIP_SENDER_MAIN, 11);
|
||||
SendGossipMenuFor(player, 100110, creature->GetGUID());
|
||||
return true;
|
||||
case 11:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "You mean...", GOSSIP_SENDER_MAIN, 12);
|
||||
SendGossipMenuFor(player, 100111, creature->GetGUID());
|
||||
return true;
|
||||
case 12:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "You were right, Fairbanks. That is tragic.", GOSSIP_SENDER_MAIN, 13);
|
||||
SendGossipMenuFor(player, 100112, creature->GetGUID());
|
||||
return true;
|
||||
case 13:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "And you did...", GOSSIP_SENDER_MAIN, 14);
|
||||
SendGossipMenuFor(player, 100113, creature->GetGUID());
|
||||
return true;
|
||||
case 14:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "You tell an incredible tale, Fairbanks. What of the blade? Is it beyond redemption?", GOSSIP_SENDER_MAIN, 15);
|
||||
SendGossipMenuFor(player, 100114, creature->GetGUID());
|
||||
return true;
|
||||
case 15:
|
||||
creature->HandleEmoteCommand(1);
|
||||
AddGossipItemFor(player, 0, "But his son is dead.", GOSSIP_SENDER_MAIN, 16);
|
||||
SendGossipMenuFor(player, 100115, creature->GetGUID());
|
||||
return true;
|
||||
case 16:
|
||||
SendGossipMenuFor(player, 100116, creature->GetGUID());
|
||||
/// @todo: we need to play these 3 emote in sequence, we play only the last one right now.
|
||||
creature->HandleEmoteCommand(274);
|
||||
creature->HandleEmoteCommand(1);
|
||||
creature->HandleEmoteCommand(397);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct npc_fairbanksAI : public SmartAI
|
||||
{
|
||||
npc_fairbanksAI(Creature* creature) : SmartAI(creature) { }
|
||||
@@ -812,7 +712,6 @@ public:
|
||||
{
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
me->SetSheath(SHEATH_STATE_UNARMED);
|
||||
me->CastSpell(me, 57767, true);
|
||||
me->SetDisplayId(16179);
|
||||
me->SetFacingToObject(player);
|
||||
|
||||
@@ -154,8 +154,8 @@ public:
|
||||
switch (type)
|
||||
{
|
||||
case DATA_RAJAXX_WAVE_ENGAGED:
|
||||
_scheduler.CancelGroup(GROUP_RAJAXX_WAVE_TIMER);
|
||||
_scheduler.Schedule(2min, [this](TaskContext context)
|
||||
scheduler.CancelGroup(GROUP_RAJAXX_WAVE_TIMER);
|
||||
scheduler.Schedule(2min, [this](TaskContext context)
|
||||
{
|
||||
CallNextRajaxxLeader();
|
||||
context.SetGroup(GROUP_RAJAXX_WAVE_TIMER);
|
||||
@@ -195,8 +195,8 @@ public:
|
||||
case NPC_YEGGETH:
|
||||
case NPC_PAKKON:
|
||||
case NPC_ZERRAN:
|
||||
_scheduler.CancelAll();
|
||||
_scheduler.Schedule(1s, [this, formation](TaskContext /*context*/)
|
||||
scheduler.CancelAll();
|
||||
scheduler.Schedule(1s, [this, formation](TaskContext /*context*/)
|
||||
{
|
||||
if (!formation->IsAnyMemberAlive())
|
||||
{
|
||||
@@ -212,11 +212,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void Update(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
void SetGuidData(uint32 type, ObjectGuid data) override
|
||||
{
|
||||
if (type == DATA_PARALYZED)
|
||||
@@ -285,7 +280,7 @@ public:
|
||||
void ResetRajaxxWaves()
|
||||
{
|
||||
_rajaxWaveCounter = 0;
|
||||
_scheduler.CancelAll();
|
||||
scheduler.CancelAll();
|
||||
for (auto const& data : RajaxxWavesData)
|
||||
{
|
||||
if (Creature* creature = GetCreature(data.at(0)))
|
||||
@@ -308,7 +303,6 @@ public:
|
||||
ObjectGuid _andorovGUID;
|
||||
uint32 _rajaxWaveCounter;
|
||||
uint8 _buruPhase;
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
|
||||
@@ -210,15 +210,9 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
GuidVector CThunGraspGUIDs;
|
||||
uint32 BugTrioDeathCount;
|
||||
TaskScheduler scheduler;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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 Affero 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/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
|
||||
@@ -175,6 +175,7 @@ enum Kerlonian
|
||||
|
||||
SPELL_SLEEP_VISUAL = 25148,
|
||||
SPELL_AWAKEN = 17536,
|
||||
SPELL_BEAR_FORM = 18309,
|
||||
QUEST_SLEEPER_AWAKENED = 5321,
|
||||
NPC_LILADRIS = 11219 //attackers entries unknown
|
||||
};
|
||||
@@ -194,6 +195,8 @@ public:
|
||||
void Reset() override
|
||||
{
|
||||
FallAsleepTimer = urand(10000, 45000);
|
||||
|
||||
DoCastSelf(SPELL_BEAR_FORM);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
|
||||
+153
-187
@@ -69,219 +69,185 @@ enum Misc
|
||||
{
|
||||
GROUP_ABILITIES = 1,
|
||||
NPC_PURE_SPAWN_OF_HYDROSS = 22035,
|
||||
|
||||
EVENT_SPELL_MARK_OF_CORRUPTION1 = 1,
|
||||
EVENT_SPELL_MARK_OF_CORRUPTION2 = 2,
|
||||
EVENT_SPELL_MARK_OF_CORRUPTION3 = 3,
|
||||
EVENT_SPELL_MARK_OF_CORRUPTION4 = 4,
|
||||
EVENT_SPELL_MARK_OF_CORRUPTION5 = 5,
|
||||
EVENT_SPELL_MARK_OF_CORRUPTION6 = 6,
|
||||
EVENT_SPELL_MARK_OF_HYDROSS1 = 7,
|
||||
EVENT_SPELL_MARK_OF_HYDROSS2 = 8,
|
||||
EVENT_SPELL_MARK_OF_HYDROSS3 = 9,
|
||||
EVENT_SPELL_MARK_OF_HYDROSS4 = 10,
|
||||
EVENT_SPELL_MARK_OF_HYDROSS5 = 11,
|
||||
EVENT_SPELL_MARK_OF_HYDROSS6 = 12,
|
||||
EVENT_SPELL_WATER_TOMB = 13,
|
||||
EVENT_SPELL_VILE_SLUDGE = 14,
|
||||
EVENT_SPELL_ENRAGE = 15,
|
||||
EVENT_CHECK_AURA = 16,
|
||||
EVENT_KILL_TALK = 17
|
||||
};
|
||||
|
||||
class boss_hydross_the_unstable : public CreatureScript
|
||||
struct boss_hydross_the_unstable : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_hydross_the_unstable() : CreatureScript("boss_hydross_the_unstable") { }
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
boss_hydross_the_unstable(Creature* creature) : BossAI(creature, DATA_HYDROSS_THE_UNSTABLE)
|
||||
{
|
||||
return GetSerpentShrineAI<boss_hydross_the_unstableAI>(creature);
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_hydross_the_unstableAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_hydross_the_unstableAI(Creature* creature) : BossAI(creature, DATA_HYDROSS_THE_UNSTABLE)
|
||||
BossAI::Reset();
|
||||
|
||||
_recentlySpoken = false;
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
if (!me->HasAura(SPELL_BLUE_BEAM))
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_CLEANSING_FIELD_AURA);
|
||||
}
|
||||
}
|
||||
|
||||
void SetForm(bool corrupt, bool initial)
|
||||
{
|
||||
scheduler.CancelGroup(GROUP_ABILITIES);
|
||||
DoResetThreatList();
|
||||
|
||||
if (corrupt)
|
||||
{
|
||||
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
|
||||
DoCastSelf(SPELL_CORRUPTION, true);
|
||||
|
||||
scheduler.Schedule(0s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_CORRUPTION1);
|
||||
}).Schedule(15s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_CORRUPTION2);
|
||||
}).Schedule(30s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_CORRUPTION3);
|
||||
}).Schedule(45s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_CORRUPTION4);
|
||||
}).Schedule(60s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_CORRUPTION5);
|
||||
}).Schedule(75s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_CORRUPTION6);
|
||||
}).Schedule(12150ms, GROUP_ABILITIES, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_VILE_SLUDGE, true);
|
||||
context.Repeat(9700ms, 32800ms);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false);
|
||||
me->RemoveAurasDueToSpell(SPELL_CORRUPTION);
|
||||
|
||||
scheduler.Schedule(0s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_HYDROSS1);
|
||||
}).Schedule(15s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_HYDROSS2);
|
||||
}).Schedule(30s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_HYDROSS3);
|
||||
}).Schedule(45s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_HYDROSS4);
|
||||
}).Schedule(60s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_HYDROSS5);
|
||||
}).Schedule(75s, GROUP_ABILITIES, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_MARK_OF_HYDROSS6);
|
||||
}).Schedule(12150ms, GROUP_ABILITIES, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_WATER_TOMB, true);
|
||||
context.Repeat(9700ms, 32800ms);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
if (initial)
|
||||
{
|
||||
BossAI::Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
if (corrupt)
|
||||
{
|
||||
BossAI::JustReachedHome();
|
||||
if (!me->HasAura(SPELL_BLUE_BEAM))
|
||||
me->RemoveAurasDueToSpell(SPELL_CLEANSING_FIELD_AURA);
|
||||
}
|
||||
|
||||
void SetForm(bool corrupt, bool initial)
|
||||
{
|
||||
events.CancelEventGroup(GROUP_ABILITIES);
|
||||
DoResetThreatList();
|
||||
|
||||
if (corrupt)
|
||||
Talk(SAY_SWITCH_TO_CORRUPT);
|
||||
for (uint32 spellId = SPELL_SUMMON_CORRUPTED1; spellId <= SPELL_SUMMON_CORRUPTED4; ++spellId)
|
||||
{
|
||||
me->SetMeleeDamageSchool(SPELL_SCHOOL_NATURE);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, false);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
|
||||
me->CastSpell(me, SPELL_CORRUPTION, true);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION1, 0, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION2, 15000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION3, 30000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION4, 45000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION5, 60000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION6, 75000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_VILE_SLUDGE, 7000, GROUP_ABILITIES);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->SetMeleeDamageSchool(SPELL_SCHOOL_FROST);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, false);
|
||||
me->RemoveAurasDueToSpell(SPELL_CORRUPTION);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS1, 0, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS2, 15000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS3, 30000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS4, 45000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS5, 60000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS6, 75000, GROUP_ABILITIES);
|
||||
events.ScheduleEvent(EVENT_SPELL_WATER_TOMB, 7000, GROUP_ABILITIES);
|
||||
}
|
||||
|
||||
if (initial)
|
||||
return;
|
||||
|
||||
if (corrupt)
|
||||
{
|
||||
Talk(SAY_SWITCH_TO_CORRUPT);
|
||||
for (uint32 i = SPELL_SUMMON_CORRUPTED1; i <= SPELL_SUMMON_CORRUPTED4; ++i)
|
||||
me->CastSpell(me, i, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Talk(SAY_SWITCH_TO_CLEAN);
|
||||
for (uint32 i = SPELL_SUMMON_PURIFIED1; i <= SPELL_SUMMON_PURIFIED4; ++i)
|
||||
me->CastSpell(me, i, true);
|
||||
DoCastSelf(spellId, true);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
else
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_ENRAGE, 600000);
|
||||
events.ScheduleEvent(EVENT_CHECK_AURA, 1000);
|
||||
SetForm(false, true);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
Talk(SAY_SWITCH_TO_CLEAN);
|
||||
for (uint32 spellId = SPELL_SUMMON_PURIFIED1; spellId <= SPELL_SUMMON_PURIFIED4; ++spellId)
|
||||
{
|
||||
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
|
||||
DoCastSelf(spellId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_AGGRO);
|
||||
SetForm(false, true);
|
||||
|
||||
scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
summon->CastSpell(summon, SPELL_ELEMENTAL_SPAWNIN, true);
|
||||
summon->SetInCombatWithZone();
|
||||
|
||||
if (summon->GetEntry() == NPC_PURE_SPAWN_OF_HYDROSS)
|
||||
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
|
||||
else
|
||||
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
|
||||
}
|
||||
|
||||
void SummonedCreatureDespawn(Creature* summon) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
if (me->HasAura(SPELL_BLUE_BEAM) == me->HasAura(SPELL_CORRUPTION))
|
||||
{
|
||||
case EVENT_CHECK_AURA:
|
||||
if (me->HasAura(SPELL_BLUE_BEAM) == me->HasAura(SPELL_CORRUPTION))
|
||||
SetForm(!me->HasAura(SPELL_BLUE_BEAM), false);
|
||||
events.ScheduleEvent(EVENT_CHECK_AURA, 1000);
|
||||
break;
|
||||
case EVENT_SPELL_ENRAGE:
|
||||
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_HYDROSS1:
|
||||
me->CastSpell(me, SPELL_MARK_OF_HYDROSS1, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_HYDROSS2:
|
||||
me->CastSpell(me, SPELL_MARK_OF_HYDROSS2, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_HYDROSS3:
|
||||
me->CastSpell(me, SPELL_MARK_OF_HYDROSS3, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_HYDROSS4:
|
||||
me->CastSpell(me, SPELL_MARK_OF_HYDROSS4, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_HYDROSS5:
|
||||
me->CastSpell(me, SPELL_MARK_OF_HYDROSS5, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_HYDROSS6:
|
||||
me->CastSpell(me, SPELL_MARK_OF_HYDROSS6, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_HYDROSS6, 15000, GROUP_ABILITIES);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_CORRUPTION1:
|
||||
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION1, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_CORRUPTION2:
|
||||
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION2, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_CORRUPTION3:
|
||||
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION3, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_CORRUPTION4:
|
||||
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION4, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_CORRUPTION5:
|
||||
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION5, false);
|
||||
break;
|
||||
case EVENT_SPELL_MARK_OF_CORRUPTION6:
|
||||
me->CastSpell(me, SPELL_MARK_OF_CORRUPTION6, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK_OF_CORRUPTION6, 15000, GROUP_ABILITIES);
|
||||
break;
|
||||
case EVENT_SPELL_WATER_TOMB:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
|
||||
me->CastSpell(target, SPELL_WATER_TOMB, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_WATER_TOMB, 7000, GROUP_ABILITIES);
|
||||
break;
|
||||
case EVENT_SPELL_VILE_SLUDGE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
|
||||
me->CastSpell(target, SPELL_VILE_SLUDGE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_VILE_SLUDGE, 15000, GROUP_ABILITIES);
|
||||
break;
|
||||
SetForm(!me->HasAura(SPELL_BLUE_BEAM), false);
|
||||
}
|
||||
context.Repeat(1s);
|
||||
}).Schedule(10min, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_ENRAGE, true);
|
||||
});
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (!_recentlySpoken)
|
||||
{
|
||||
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_SLAY : SAY_CLEAN_SLAY);
|
||||
_recentlySpoken = true;
|
||||
}
|
||||
};
|
||||
scheduler.Schedule(6s, [this](TaskContext)
|
||||
{
|
||||
_recentlySpoken = false;
|
||||
});
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
summon->CastSpell(summon, SPELL_ELEMENTAL_SPAWNIN, true);
|
||||
summon->SetInCombatWithZone();
|
||||
|
||||
if (summon->GetEntry() == NPC_PURE_SPAWN_OF_HYDROSS)
|
||||
{
|
||||
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true);
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDespawn(Creature* summon) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(me->HasAura(SPELL_CORRUPTION) ? SAY_CORRUPT_DEATH : SAY_CLEAN_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
};
|
||||
|
||||
class spell_hydross_cleansing_field_aura : public SpellScriptLoader
|
||||
@@ -377,7 +343,7 @@ public:
|
||||
|
||||
void AddSC_boss_hydross_the_unstable()
|
||||
{
|
||||
new boss_hydross_the_unstable();
|
||||
RegisterSerpentShrineAI(boss_hydross_the_unstable);
|
||||
new spell_hydross_cleansing_field_aura();
|
||||
new spell_hydross_cleansing_field_command();
|
||||
new spell_hydross_mark_of_hydross();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 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
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
|
||||
@@ -55,8 +55,10 @@ enum Spells
|
||||
SPELL_QUAKE_KNOCKBACK = 30571,
|
||||
SPELL_COLLAPSE_DAMAGE = 36449,
|
||||
SPELL_CAMERA_SHAKE = 36455,
|
||||
SPELL_DEBRIS_TARGET = 30629,
|
||||
SPELL_DEBRIS_SPAWN = 30630,
|
||||
SPELL_DEBRIS_DAMAGE = 30631,
|
||||
SPELL_DEBRIS_VISUAL = 30632,
|
||||
SPELL_DEBRIS_DAMAGE = 30631
|
||||
};
|
||||
|
||||
enum Groups
|
||||
@@ -70,26 +72,9 @@ enum Actions
|
||||
ACTION_INCREASE_HELLFIRE_CHANNELER_DEATH_COUNT = 1
|
||||
};
|
||||
|
||||
class DealDebrisDamage : public BasicEvent
|
||||
{
|
||||
public:
|
||||
DealDebrisDamage(Creature& creature, ObjectGuid targetGUID) : _owner(creature), _targetGUID(targetGUID) { }
|
||||
|
||||
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(_owner, _targetGUID))
|
||||
target->CastSpell(target, SPELL_DEBRIS_DAMAGE, true, nullptr, nullptr, _owner.GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Creature& _owner;
|
||||
ObjectGuid _targetGUID;
|
||||
};
|
||||
|
||||
struct boss_magtheridon : public BossAI
|
||||
{
|
||||
boss_magtheridon(Creature* creature) : BossAI(creature, TYPE_MAGTHERIDON)
|
||||
boss_magtheridon(Creature* creature) : BossAI(creature, DATA_MAGTHERIDON)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
@@ -137,11 +122,7 @@ struct boss_magtheridon : public BossAI
|
||||
_currentPhase = 0;
|
||||
scheduler.Schedule(20s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
|
||||
{
|
||||
target->CastSpell(target, SPELL_DEBRIS_VISUAL, true, nullptr, nullptr, me->GetGUID());
|
||||
me->m_Events.AddEvent(new DealDebrisDamage(*me, target->GetGUID()), me->m_Events.CalculateTime(5000));
|
||||
}
|
||||
DoCastAOE(SPELL_DEBRIS_TARGET);
|
||||
context.Repeat(20s);
|
||||
});
|
||||
});
|
||||
@@ -170,7 +151,7 @@ struct boss_magtheridon : public BossAI
|
||||
|
||||
void ScheduleCombatEvents()
|
||||
{
|
||||
me->GetThreatMgr().ClearAllThreat();
|
||||
DoResetThreatList();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetImmuneToPC(false);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
@@ -248,7 +229,7 @@ struct boss_magtheridon : public BossAI
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_EMOTE_BEGIN);
|
||||
|
||||
instance->DoForAllMinions(TYPE_MAGTHERIDON, [&](Creature* creature) {
|
||||
instance->DoForAllMinions(DATA_MAGTHERIDON, [&](Creature* creature) {
|
||||
creature->SetInCombatWithZone();
|
||||
});
|
||||
|
||||
@@ -289,6 +270,37 @@ private:
|
||||
TaskScheduler _interruptScheduler;
|
||||
};
|
||||
|
||||
struct npc_target_trigger : public ScriptedAI
|
||||
{
|
||||
npc_target_trigger(Creature* creature) : ScriptedAI(creature), _cast(false)
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
if (!_cast)
|
||||
{
|
||||
DoCastSelf(SPELL_DEBRIS_VISUAL);
|
||||
_cast = true;
|
||||
_scheduler.Schedule(5s, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastSelf(SPELL_DEBRIS_DAMAGE);
|
||||
me->DespawnOrUnsummon(6000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
protected:
|
||||
TaskScheduler _scheduler;
|
||||
bool _cast;
|
||||
};
|
||||
|
||||
class spell_magtheridon_blaze : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_magtheridon_blaze);
|
||||
@@ -348,6 +360,33 @@ class spell_magtheridon_quake : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_magtheridon_debris_target_selector : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_magtheridon_debris_target_selector);
|
||||
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
targets.remove_if([&](WorldObject* target) -> bool
|
||||
{
|
||||
return target->GetEntry() != NPC_TARGET_TRIGGER;
|
||||
});
|
||||
|
||||
Acore::Containers::RandomResize(targets, 1);
|
||||
}
|
||||
|
||||
void HandleHit()
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
target->CastSpell(target, SPELL_DEBRIS_SPAWN);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_magtheridon_debris_target_selector::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||
OnHit += SpellHitFn(spell_magtheridon_debris_target_selector::HandleHit);
|
||||
}
|
||||
};
|
||||
|
||||
class go_manticron_cube : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
@@ -369,8 +408,10 @@ public:
|
||||
void AddSC_boss_magtheridon()
|
||||
{
|
||||
RegisterMagtheridonsLairCreatureAI(boss_magtheridon);
|
||||
RegisterMagtheridonsLairCreatureAI(npc_target_trigger);
|
||||
RegisterSpellScript(spell_magtheridon_blaze);
|
||||
RegisterSpellScript(spell_magtheridon_shadow_grasp);
|
||||
RegisterSpellScript(spell_magtheridon_quake);
|
||||
RegisterSpellScript(spell_magtheridon_debris_target_selector);
|
||||
new go_manticron_cube();
|
||||
}
|
||||
|
||||
+5
-5
@@ -21,18 +21,18 @@
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ TYPE_MAGTHERIDON, new CircleBoundary(Position(-18.70f, 2.24f), 52.30) }
|
||||
{ DATA_MAGTHERIDON, new CircleBoundary(Position(-18.70f, 2.24f), 52.30) }
|
||||
};
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_MAGTHERIDON_DOORS, TYPE_MAGTHERIDON, DOOR_TYPE_ROOM },
|
||||
{ GO_MAGTHERIDON_DOORS, DATA_MAGTHERIDON, DOOR_TYPE_ROOM },
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
MinionData const minionData[] =
|
||||
{
|
||||
{ NPC_HELLFIRE_CHANNELER, TYPE_MAGTHERIDON }
|
||||
{ NPC_HELLFIRE_CHANNELER, DATA_MAGTHERIDON }
|
||||
};
|
||||
|
||||
class instance_magtheridons_lair : public InstanceMapScript
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
if (!InstanceScript::SetBossState(id, state))
|
||||
return false;
|
||||
|
||||
if (id == TYPE_MAGTHERIDON)
|
||||
if (id == DATA_MAGTHERIDON)
|
||||
{
|
||||
if (state == IN_PROGRESS)
|
||||
{
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
switch (type)
|
||||
{
|
||||
case DATA_CHANNELER_COMBAT:
|
||||
if (GetBossState(TYPE_MAGTHERIDON) != IN_PROGRESS)
|
||||
if (GetBossState(DATA_MAGTHERIDON) != IN_PROGRESS)
|
||||
if (Creature* magtheridon = instance->GetCreature(_magtheridonGUID))
|
||||
magtheridon->SetInCombatWithZone();
|
||||
break;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
enum DataTypes
|
||||
{
|
||||
TYPE_MAGTHERIDON = 0,
|
||||
DATA_MAGTHERIDON = 0,
|
||||
MAX_ENCOUNTER = 1,
|
||||
|
||||
DATA_CHANNELER_COMBAT = 10,
|
||||
@@ -41,6 +41,7 @@ enum NpcIds
|
||||
NPC_HELLFIRE_CHANNELER = 17256,
|
||||
NPC_HELLFIRE_WARDER = 18829,
|
||||
NPC_HELLFIRE_RAID_TRIGGER = 17376,
|
||||
NPC_TARGET_TRIGGER = 17474
|
||||
};
|
||||
|
||||
enum GoIds
|
||||
|
||||
@@ -29,107 +29,94 @@ enum voidReaver
|
||||
SPELL_POUNDING = 34162,
|
||||
SPELL_ARCANE_ORB = 34172,
|
||||
SPELL_KNOCK_AWAY = 25778,
|
||||
SPELL_BERSERK = 26662,
|
||||
|
||||
EVENT_SPELL_POUNDING = 1,
|
||||
EVENT_SPELL_ARCANEORB = 2,
|
||||
EVENT_SPELL_KNOCK_AWAY = 3,
|
||||
EVENT_SPELL_BERSERK = 4
|
||||
SPELL_BERSERK = 26662
|
||||
};
|
||||
|
||||
class boss_void_reaver : public CreatureScript
|
||||
enum Groups
|
||||
{
|
||||
public:
|
||||
boss_void_reaver() : CreatureScript("boss_void_reaver") { }
|
||||
GROUP_ARCANE_ORB = 1
|
||||
};
|
||||
|
||||
struct boss_void_reaverAI : public BossAI
|
||||
struct boss_void_reaver : public BossAI
|
||||
{
|
||||
boss_void_reaver(Creature* creature) : BossAI(creature, DATA_REAVER)
|
||||
{
|
||||
boss_void_reaverAI(Creature* creature) : BossAI(creature, DATA_REAVER)
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
me->ApplySpellImmune(0, IMMUNITY_DISPEL, DISPEL_POISON, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEALTH_LEECH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_DRAIN, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_LEECH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
|
||||
}
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER && roll_chance_i(50))
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_POUNDING, 15000);
|
||||
events.ScheduleEvent(EVENT_SPELL_ARCANEORB, 3000);
|
||||
events.ScheduleEvent(EVENT_SPELL_KNOCK_AWAY, 30000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
|
||||
me->CallForHelp(105.0f);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_BERSERK:
|
||||
me->CastSpell(me, SPELL_BERSERK, true);
|
||||
break;
|
||||
case EVENT_SPELL_POUNDING:
|
||||
Talk(SAY_POUNDING);
|
||||
me->CastSpell(me, SPELL_POUNDING, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_POUNDING, 15000);
|
||||
break;
|
||||
case EVENT_SPELL_ARCANEORB:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, -18.0f, true))
|
||||
me->CastSpell(target, SPELL_ARCANE_ORB, false);
|
||||
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
|
||||
me->CastSpell(target, SPELL_ARCANE_ORB, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_ARCANEORB, 4000);
|
||||
break;
|
||||
case EVENT_SPELL_KNOCK_AWAY:
|
||||
me->CastSpell(me->GetVictim(), SPELL_KNOCK_AWAY, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_POUNDING, 25000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
bool CheckEvadeIfOutOfCombatArea() const override
|
||||
{
|
||||
return me->GetDistance2d(432.59f, 371.93f) > 105.0f;
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetTheEyeAI<boss_void_reaverAI>(creature);
|
||||
me->ApplySpellImmune(0, IMMUNITY_DISPEL, DISPEL_POISON, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_HEALTH_LEECH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_DRAIN, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_LEECH, true);
|
||||
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
_recentlySpoken = false;
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (!_recentlySpoken)
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
_recentlySpoken = true;
|
||||
scheduler.Schedule(5s, [this](TaskContext)
|
||||
{
|
||||
_recentlySpoken = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_AGGRO);
|
||||
me->CallForHelp(105.0f);
|
||||
|
||||
scheduler.Schedule(10min, [this](TaskContext)
|
||||
{
|
||||
DoCastSelf(SPELL_BERSERK);
|
||||
}).Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
Talk(SAY_POUNDING);
|
||||
DoCastSelf(SPELL_POUNDING);
|
||||
scheduler.DelayGroup(GROUP_ARCANE_ORB, 3s);
|
||||
context.Repeat(15s);
|
||||
}).Schedule(3s, GROUP_ARCANE_ORB, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, -18.0f, true))
|
||||
me->CastSpell(target, SPELL_ARCANE_ORB, false);
|
||||
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
|
||||
me->CastSpell(target, SPELL_ARCANE_ORB, false);
|
||||
context.Repeat(3s);
|
||||
}).Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCK_AWAY);
|
||||
context.Repeat(25s);
|
||||
});
|
||||
}
|
||||
|
||||
bool CheckEvadeIfOutOfCombatArea() const override
|
||||
{
|
||||
return me->GetDistance2d(432.59f, 371.93f) > 105.0f;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _recentlySpoken;
|
||||
};
|
||||
|
||||
void AddSC_boss_void_reaver()
|
||||
{
|
||||
new boss_void_reaver();
|
||||
RegisterTheEyeAI(boss_void_reaver);
|
||||
}
|
||||
|
||||
@@ -65,4 +65,6 @@ inline AI* GetTheEyeAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, TheEyeScriptName);
|
||||
}
|
||||
|
||||
#define RegisterTheEyeAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetTheEyeAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
// Ours
|
||||
enum saeed
|
||||
@@ -697,9 +699,6 @@ public:
|
||||
{
|
||||
Drained = true;
|
||||
int32 uHpPct = int32(me->GetHealthPct());
|
||||
|
||||
me->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
|
||||
|
||||
me->SetHealth(me->CountPctFromMaxHealth(uHpPct));
|
||||
me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth());
|
||||
me->SetInCombatWith(player);
|
||||
@@ -911,6 +910,45 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class spell_q10190_battery_recharging_blaster : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q10190_battery_recharging_blaster);
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
if (Unit* target = GetExplTargetUnit())
|
||||
if (target->GetHealthPct() <= 25.0f)
|
||||
return SPELL_CAST_OK;
|
||||
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_q10190_battery_recharging_blaster::CheckCast);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_q10190_battery_recharging_blaster_aura : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_q10190_battery_recharging_blaster_aura);
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
|
||||
return;
|
||||
|
||||
if (Creature* phasehunter = GetTarget()->ToCreature())
|
||||
if (phasehunter->GetEntry() == NPC_PHASE_HUNTER_ENTRY)
|
||||
phasehunter->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_q10190_battery_recharging_blaster_aura::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_netherstorm()
|
||||
{
|
||||
// Ours
|
||||
@@ -922,5 +960,5 @@ void AddSC_netherstorm()
|
||||
new npc_phase_hunter();
|
||||
new npc_bessy();
|
||||
new npc_maxx_a_million_escort();
|
||||
|
||||
RegisterSpellAndAuraScriptPair(spell_q10190_battery_recharging_blaster, spell_q10190_battery_recharging_blaster_aura);
|
||||
}
|
||||
|
||||
@@ -146,6 +146,18 @@ class spell_dk_raise_ally : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_dk_raise_ally);
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
Player* unitTarget = GetHitPlayer();
|
||||
if (!unitTarget)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (unitTarget->IsAlive()) // not discovered attributeEx5?
|
||||
return SPELL_FAILED_TARGET_NOT_DEAD;
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* unitTarget = GetHitPlayer())
|
||||
@@ -237,6 +249,7 @@ class spell_dk_raise_ally : public SpellScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_dk_raise_ally::CheckCast);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_dk_raise_ally::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -302,7 +302,8 @@ private:
|
||||
|
||||
enum Spell
|
||||
{
|
||||
PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235
|
||||
PAL_SPELL_ARDENT_DEFENDER_DEBUFF = 66233,
|
||||
PAL_SPELL_ARDENT_DEFENDER_HEAL = 66235
|
||||
};
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
@@ -329,7 +330,7 @@ private:
|
||||
int32 remainingHealth = victim->GetHealth() - dmgInfo.GetDamage();
|
||||
uint32 allowedHealth = victim->CountPctFromMaxHealth(35);
|
||||
// If damage kills us
|
||||
if (remainingHealth <= 0 && !victim->ToPlayer()->HasSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL))
|
||||
if (remainingHealth <= 0 && !victim->ToPlayer()->HasAura(PAL_SPELL_ARDENT_DEFENDER_DEBUFF))
|
||||
{
|
||||
// Cast healing spell, completely avoid damage
|
||||
absorbAmount = dmgInfo.GetDamage();
|
||||
@@ -344,7 +345,6 @@ private:
|
||||
|
||||
int32 healAmount = int32(victim->CountPctFromMaxHealth(uint32(healPct * pctFromDefense)));
|
||||
victim->CastCustomSpell(PAL_SPELL_ARDENT_DEFENDER_HEAL, SPELLVALUE_BASE_POINT0, healAmount, victim, true, nullptr, aurEff);
|
||||
victim->ToPlayer()->AddSpellCooldown(PAL_SPELL_ARDENT_DEFENDER_HEAL, 0, 120000);
|
||||
}
|
||||
else if (remainingHealth < int32(allowedHealth))
|
||||
{
|
||||
|
||||
@@ -19,12 +19,7 @@
|
||||
#include "Group.h"
|
||||
#include "Guild.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
#define LOG_CHAT(TYPE, ...) \
|
||||
if (lang != LANG_ADDON) \
|
||||
LOG_DEBUG("chat.log." TYPE, __VA_ARGS__); \
|
||||
else \
|
||||
LOG_DEBUG("chat.log.addon." TYPE, __VA_ARGS__);
|
||||
#include "Log.h"
|
||||
|
||||
class ChatLogScript : public PlayerScript
|
||||
{
|
||||
@@ -36,66 +31,67 @@ public:
|
||||
switch (type)
|
||||
{
|
||||
case CHAT_MSG_SAY:
|
||||
LOG_CHAT("say", "Player {} says (language {}): {}",
|
||||
LOG_INFO("chat.say", "Player {} says (language {}): {}",
|
||||
player->GetName(), lang, msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_EMOTE:
|
||||
LOG_CHAT("emote", "Player {} emotes: {}",
|
||||
LOG_INFO("chat.emote", "Player {} emotes: {}",
|
||||
player->GetName(), msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_YELL:
|
||||
LOG_CHAT("yell", "Player {} yells (language {}): {}",
|
||||
LOG_INFO("chat.yell", "Player {} yells (language {}): {}",
|
||||
player->GetName(), lang, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Player* receiver) override
|
||||
void OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Player* receiver) override
|
||||
{
|
||||
LOG_CHAT("whisper", "Player {} tells {}: {}",
|
||||
LOG_INFO("chat.whisper", "Player {} tells {}: {}",
|
||||
player->GetName(), receiver ? receiver->GetName() : "<unknown>", msg);
|
||||
}
|
||||
|
||||
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override
|
||||
{
|
||||
std::string str = lang != LANG_ADDON ? "chat." : "chat.addon.";
|
||||
//! NOTE:
|
||||
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
|
||||
switch (type)
|
||||
{
|
||||
case CHAT_MSG_PARTY:
|
||||
LOG_CHAT("party", "Player {} tells group with leader {}: {}",
|
||||
LOG_INFO(str + "party", "Player {} tells group with leader {}: {}",
|
||||
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_PARTY_LEADER:
|
||||
LOG_CHAT("party", "Leader {} tells group: {}",
|
||||
LOG_INFO(str + "party", "Leader {} tells group: {}",
|
||||
player->GetName(), msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_RAID:
|
||||
LOG_CHAT("raid", "Player {} tells raid with leader {}: {}",
|
||||
LOG_INFO(str + "raid", "Player {} tells raid with leader {}: {}",
|
||||
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_RAID_LEADER:
|
||||
LOG_CHAT("raid", "Leader player {} tells raid: {}",
|
||||
LOG_INFO(str + "raid", "Leader player {} tells raid: {}",
|
||||
player->GetName(), msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_RAID_WARNING:
|
||||
LOG_CHAT("raid", "Leader player {} warns raid with: {}",
|
||||
LOG_INFO(str + "raid", "Leader player {} sends raid warning: {}",
|
||||
player->GetName(), msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_BATTLEGROUND:
|
||||
LOG_CHAT("bg", "Player {} tells battleground with leader {}: {}",
|
||||
LOG_INFO(str + "bg", "Player {} tells battleground with leader {}: {}",
|
||||
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_BATTLEGROUND_LEADER:
|
||||
LOG_CHAT("bg", "Leader player {} tells battleground: {}",
|
||||
LOG_INFO(str + "bg", "Leader player {} tells battleground: {}",
|
||||
player->GetName(), msg);
|
||||
break;
|
||||
}
|
||||
@@ -103,21 +99,22 @@ public:
|
||||
|
||||
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override
|
||||
{
|
||||
std::string str = lang != LANG_ADDON ? "chat." : "chat.addon.";
|
||||
switch (type)
|
||||
{
|
||||
case CHAT_MSG_GUILD:
|
||||
LOG_CHAT("guild", "Player {} tells guild {}: {}",
|
||||
LOG_INFO(str + "guild", "Player {} tells guild {}: {}",
|
||||
player->GetName(), guild ? guild->GetName() : "<unknown>", msg);
|
||||
break;
|
||||
|
||||
case CHAT_MSG_OFFICER:
|
||||
LOG_CHAT("guild.officer", "Player {} tells guild {} officers: {}",
|
||||
LOG_INFO(str + "guild.officer", "Player {} tells guild {} officers: {}",
|
||||
player->GetName(), guild ? guild->GetName() : "<unknown>", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnChat(Player* player, uint32 /*type*/, uint32 lang, std::string& msg, Channel* channel) override
|
||||
void OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel) override
|
||||
{
|
||||
bool isSystem = channel &&
|
||||
(channel->HasFlag(CHANNEL_FLAG_TRADE) ||
|
||||
@@ -127,13 +124,15 @@ public:
|
||||
|
||||
if (isSystem)
|
||||
{
|
||||
LOG_CHAT("system", "Player {} tells channel {}: {}",
|
||||
LOG_INFO("chat.channel", "Player {} tells channel {}: {}",
|
||||
player->GetName(), channel->GetName(), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allow to log custom channels. i.e. world channel
|
||||
// in that case set config: Logger.channel.world=6,Chat
|
||||
std::string channelName = channel ? channel->GetName() : "<unknown>";
|
||||
LOG_CHAT("channel." + channelName, "Player {} tells channel {}: {}",
|
||||
LOG_INFO("chat.channel." + channelName, "Player {} tells channel {}: {}",
|
||||
player->GetName(), channelName, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +225,7 @@ enum AchievementCriteriaTypes
|
||||
ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113,
|
||||
ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114,
|
||||
ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS = 115,
|
||||
ACHIEVEMENT_CRITERIA_TYPE_ROLL_DISENCHANT = 117,
|
||||
ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS = 119,
|
||||
ACHIEVEMENT_CRITERIA_TYPE_TOTAL = 124, // 0..123 => 124 criteria types total
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user