Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-08-24 22:07:53 +08:00
96 changed files with 3271 additions and 2541 deletions

View File

@@ -24,19 +24,6 @@
set( MYSQL_FOUND 0 )
if(WIN32)
# read environment variables and change \ to /
SET(PROGRAM_FILES_32 $ENV{ProgramFiles})
if (${PROGRAM_FILES_32})
STRING(REPLACE "\\\\" "/" PROGRAM_FILES_32 ${PROGRAM_FILES_32})
endif(${PROGRAM_FILES_32})
SET(PROGRAM_FILES_64 $ENV{ProgramW6432})
if (${PROGRAM_FILES_64})
STRING(REPLACE "\\\\" "/" PROGRAM_FILES_64 ${PROGRAM_FILES_64})
endif(${PROGRAM_FILES_64})
endif(WIN32)
# Find MariaDB for Windows
if (WIN32)
# Set know versions MariaDB
@@ -55,8 +42,8 @@ if (WIN32)
mysql.h
PATHS
${MYSQL_ADD_INCLUDE_PATH}
"${PROGRAM_FILES_64}/${MariaDBVersion}/include/mysql"
"${PROGRAM_FILES_32}/${MariaDBVersion}/include/mysql"
"$ENV{ProgramW6432}/${MariaDBVersion}/include/mysql"
"$ENV{ProgramFiles}/${MariaDBVersion}/include/mysql"
"${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/mysql"
DOC
"Specify the directory containing mysql.h."
@@ -71,10 +58,9 @@ if (WIN32)
libmariadb
PATHS
${MYSQL_ADD_LIBRARIES_PATH}
"${PROGRAM_FILES_64}/${MariaDBVersion}/lib"
"${PROGRAM_FILES_64}/${MariaDBVersion}/lib/opt"
"${PROGRAM_FILES_32}/${MariaDBVersion}/lib"
"${PROGRAM_FILES_32}/${MariaDBVersion}/lib/opt"
"$ENV{ProgramW6432}/${MariaDBVersion}/lib"
"$ENV{ProgramW6432}/${MariaDBVersion}/lib/opt"
"$ENV{ProgramFiles}/${MariaDBVersion}/lib"
"$ENV{ProgramFiles}/${MariaDBVersion}/lib/opt"
"$ENV{SystemDrive}/${MariaDBVersion}/lib/opt"
"${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib"
@@ -88,10 +74,9 @@ if (WIN32)
find_program(MYSQL_EXECUTABLE mysql
PATHS
"${PROGRAM_FILES_64}/${MariaDBVersion}/bin"
"${PROGRAM_FILES_64}/${MariaDBVersion}/bin/opt"
"${PROGRAM_FILES_32}/${MariaDBVersion}/bin"
"${PROGRAM_FILES_32}/${MariaDBVersion}/bin/opt"
"$ENV{ProgramW6432}/${MariaDBVersion}/bin"
"$ENV{ProgramW6432}/${MariaDBVersion}/bin/opt"
"$ENV{ProgramFiles}/${MariaDBVersion}/bin"
"$ENV{ProgramFiles}/${MariaDBVersion}/bin/opt"
"$ENV{SystemDrive}/${MariaDBVersion}/bin/opt"
DOC
@@ -171,18 +156,17 @@ find_path(MYSQL_INCLUDE_DIR
/usr/local/include/mysql
/usr/local/mysql/include
"C:/tools/mysql/current/include" # chocolatey package
"C:/Program Files/MySQL/MySQL Server 8.0/include"
"C:/Program Files/MySQL/MySQL Server 5.7/include"
"C:/Program Files/MySQL/include"
"C:/MySQL/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/include"
"$ENV{ProgramFiles}/MySQL/*/include"
"$ENV{SystemDrive}/MySQL/*/include"
"c:/msys/local/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.1/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/include"
"$ENV{MYSQL_INCLUDE_DIR}"
"$ENV{MYSQL_DIR}/include"
DOC
"Specify the directory containing mysql.h."
)
@@ -211,23 +195,17 @@ if( WIN32 )
PATHS
${MYSQL_ADD_LIBRARIES_PATH}
"C:/tools/mysql/current/lib" # chocolatey package
"C:/Program Files/MySQL/MySQL Server 8.0/lib"
"C:/Program Files/MySQL/MySQL Server 8.0/lib/opt"
"C:/Program Files/MySQL/MySQL Server 5.7/lib/opt"
"C:/Program Files/MySQL/lib"
"C:/MySQL/lib/debug"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt"
"$ENV{ProgramFiles}/MySQL/*/lib/opt"
"$ENV{SystemDrive}/MySQL/*/lib/opt"
"c:/msys/local/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/lib"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/lib"
"$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.1/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/lib"
"$ENV{MYSQL_LIBRARY}"
"$ENV{MYSQL_DIR}/lib"
DOC "Specify the location of the mysql library here."
)
endif( WIN32 )
@@ -264,30 +242,15 @@ if( WIN32 )
find_program(MYSQL_EXECUTABLE mysql
PATHS
"C:/tools/mysql/current/bin" # chocolatey package
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin/opt"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt"
"${PROGRAM_FILES_64}/MySQL/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin/opt"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin/opt"
"${PROGRAM_FILES_32}/MySQL/bin"
"C:/MySQL/bin/debug"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin/opt"
"c:/msys/local/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/bin"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/bin"
"$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.1/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin"
"$ENV{MYSQL_ROOT}/bin"
DOC
"path to your mysql binary.")

View File

@@ -21,6 +21,7 @@
#include "StringFormat.h"
#include "Tokenize.h"
#include "Util.h"
#include <cstdlib>
#include <fstream>
#include <mutex>
#include <unordered_map>
@@ -215,6 +216,81 @@ namespace
return false;
}
// Converts ini keys to the environment variable key (upper snake case).
// Example of conversions:
// SomeConfig => SOME_CONFIG
// myNestedConfig.opt1 => MY_NESTED_CONFIG_OPT_1
// LogDB.Opt.ClearTime => LOG_DB_OPT_CLEAR_TIME
std::string IniKeyToEnvVarKey(std::string const& key)
{
std::string result;
const char* str = key.c_str();
size_t n = key.length();
char curr;
bool isEnd;
bool nextIsUpper;
bool currIsNumeric;
bool nextIsNumeric;
for (size_t i = 0; i < n; ++i)
{
curr = str[i];
if (curr == ' ' || curr == '.' || curr == '-')
{
result += '_';
continue;
}
isEnd = i == n - 1;
if (!isEnd)
{
nextIsUpper = isupper(str[i + 1]);
// handle "aB" to "A_B"
if (!isupper(curr) && nextIsUpper)
{
result += static_cast<char>(std::toupper(curr));
result += '_';
continue;
}
currIsNumeric = isNumeric(curr);
nextIsNumeric = isNumeric(str[i + 1]);
// handle "a1" to "a_1"
if (!currIsNumeric && nextIsNumeric)
{
result += static_cast<char>(std::toupper(curr));
result += '_';
continue;
}
// handle "1a" to "1_a"
if (currIsNumeric && !nextIsNumeric)
{
result += static_cast<char>(std::toupper(curr));
result += '_';
continue;
}
}
result += static_cast<char>(std::toupper(curr));
}
return result;
}
Optional<std::string> EnvVarForIniKey(std::string const& key)
{
std::string envKey = "AC_" + IniKeyToEnvVarKey(key);
char* val = std::getenv(envKey.c_str());
if (!val)
return std::nullopt;
return std::string(val);
}
}
bool ConfigMgr::LoadInitial(std::string const& file, bool isReload /*= false*/)
@@ -243,25 +319,72 @@ bool ConfigMgr::Reload()
return false;
}
return LoadModulesConfigs(true, false);
if (!LoadModulesConfigs(true, false))
{
return false;
}
OverrideWithEnvVariablesIfAny();
return true;
}
std::vector<std::string> ConfigMgr::OverrideWithEnvVariablesIfAny()
{
std::lock_guard<std::mutex> lock(_configLock);
std::vector<std::string> overriddenKeys;
for (auto& itr : _configOptions)
{
if (itr.first.empty())
continue;
Optional<std::string> envVar = EnvVarForIniKey(itr.first);
if (!envVar)
continue;
itr.second = *envVar;
overriddenKeys.push_back(itr.first);
}
return overriddenKeys;
}
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())
{
if (showLogs)
Optional<std::string> envVar = EnvVarForIniKey(name);
if (!envVar)
{
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
name, _filename, name, Acore::ToString(def));
if (showLogs)
{
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",
name, _filename, name, Acore::ToString(def));
}
return def;
}
return def;
if (showLogs)
{
LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
name.c_str(), _filename.c_str(), envVar->c_str());
}
strValue = *envVar;
}
else
{
strValue = itr->second;
}
auto value = Acore::StringTo<T>(itr->second);
auto value = Acore::StringTo<T>(strValue);
if (!value)
{
if (showLogs)
@@ -282,6 +405,18 @@ std::string ConfigMgr::GetValueDefault<std::string>(std::string const& name, std
auto const& itr = _configOptions.find(name);
if (itr == _configOptions.end())
{
Optional<std::string> envVar = EnvVarForIniKey(name);
if (envVar)
{
if (showLogs)
{
LOG_WARN("server.loading", "Missing property {} in config file {}, recovered with environment '{}' value.",
name.c_str(), _filename.c_str(), envVar->c_str());
}
return *envVar;
}
if (showLogs)
{
LOG_ERROR("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file.",

View File

@@ -39,6 +39,9 @@ public:
bool Reload();
/// Overrides configuration with environment variables and returns overridden keys
std::vector<std::string> OverrideWithEnvVariablesIfAny();
std::string const GetFilename();
std::string const GetConfigPath();
[[nodiscard]] std::vector<std::string> const& GetArguments() const;

View File

@@ -85,6 +85,8 @@ 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);
@@ -101,6 +103,9 @@ 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(); });

View File

@@ -184,6 +184,8 @@ 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
@@ -203,6 +205,9 @@ 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(); });

View File

@@ -3949,8 +3949,8 @@ AuctionHouse.SearchTimeout = 1000
Appender.Console=1,4,0,"1 9 3 6 5 8"
Appender.Server=2,5,0,Server.log,w
Appender.GM=2,5,15,gm_%s.log
Appender.DBErrors=2,5,0,DBErrors.log
# Appender.GM=2,5,15,gm_%s.log
Appender.Errors=2,5,0,Errors.log
# Appender.DB=3,5,0
# Logger config values: Given a logger "name"
@@ -3977,10 +3977,11 @@ Logger.diff=3,Console Server
Logger.mmaps=4,Server
Logger.scripts.hotswap=4,Console Server
Logger.server=4,Console Server
Logger.sql.sql=2,Console DBErrors
Logger.sql.sql=2,Console Errors
Logger.sql=4,Console Server
Logger.time.update=4,Console Server
Logger.module=4,Console Server
Logger.spells.scripts=2,Console Errors
#Logger.achievement=4,Console Server
#Logger.addon=4,Console Server

View File

@@ -27,7 +27,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_DEL_CRELINKED_RESPAWN, "DELETE FROM linked_respawn WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_REP_CREATURE_LINKED_RESPAWN, "REPLACE INTO linked_respawn (guid, linkedGuid) VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_CREATURE_TEXT, "SELECT CreatureID, GroupID, ID, Text, Type, Language, Probability, Emote, Duration, Sound, BroadcastTextId, TextRange FROM creature_text", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_param4, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, event_param6, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_param4, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z, orientation, delay FROM waypoints ORDER BY entry, pointid", CONNECTION_SYNCH);
PrepareStatement(WORLD_DEL_GAMEOBJECT, "DELETE FROM gameobject WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_DEL_EVENT_GAMEOBJECT, "DELETE FROM game_event_gameobject WHERE guid = ?", CONNECTION_ASYNC);

View File

@@ -1958,7 +1958,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
ObjectVector casters;
GetTargets(casters, CreateSmartEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, 0, 0, 0, SMART_ACTION_NONE, 0, 0, 0, 0, 0, 0, (SMARTAI_TARGETS)e.action.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0, 0), unit);
GetTargets(casters, 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.crossCast.targetType, e.action.crossCast.targetParam1, e.action.crossCast.targetParam2, e.action.crossCast.targetParam3, 0, 0), unit);
for (WorldObject* caster : casters)
{
@@ -2891,6 +2891,101 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
break;
}
case SMART_ACTION_FOLLOW_GROUP:
{
if (!e.action.followGroup.followState)
{
for (WorldObject* target : targets)
if (IsUnit(target))
target->ToCreature()->GetMotionMaster()->MoveIdle();
break;
}
uint8 membCount = targets.size();
uint8 itr = 1;
float dist = float(e.action.followGroup.dist / 100);
switch (e.action.followGroup.followType)
{
case FOLLOW_TYPE_CIRCLE:
{
float angle = (membCount > 4 ? (M_PI * 2)/membCount : (M_PI / 2)); // 90 degrees is the maximum angle
for (WorldObject* target : targets)
{
if (IsCreature(target))
{
target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist, angle * itr);
itr++;
}
}
break;
}
case FOLLOW_TYPE_SEMI_CIRCLE_BEHIND:
{
for (WorldObject* target : targets)
{
if (IsCreature(target))
{
target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist, (M_PI / 2.0f) + (M_PI / membCount) * (itr - 1));
itr++;
}
}
break;
}
case FOLLOW_TYPE_SEMI_CIRCLE_FRONT:
{
for (WorldObject* target : targets)
{
if (IsCreature(target))
{
target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist, (M_PI + (M_PI / 2.0f) + (M_PI / membCount) * (itr - 1)));
itr++;
}
}
break;
}
case FOLLOW_TYPE_LINE:
{
for (WorldObject* target : targets)
{
if (IsCreature(target))
{
target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist * (((itr - 1) / 2) + 1), itr % 2 ? 0.f : M_PI);
itr++;
}
}
break;
}
case FOLLOW_TYPE_COLUMN:
{
for (WorldObject* target : targets)
{
if (IsCreature(target))
{
target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist * (((itr - 1) / 2) + 1), itr % 2 ? (M_PI / 2) : (M_PI * 1.5f));
itr++;
}
}
break;
}
case FOLLOW_TYPE_ANGULAR:
{
for (WorldObject* target : targets)
{
if (IsCreature(target))
{
target->ToCreature()->GetMotionMaster()->MoveFollow(me, dist * (((itr - 1) / 2) + 1), itr % 2 ? M_PI - (M_PI / 4) : M_PI + (M_PI / 4));
itr++;
}
}
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;
@@ -2935,18 +3030,18 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e)
{
case SMARTAI_TEMPLATE_CASTER:
{
AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_RANGE, 0, e.action.installTtemplate.param4, 300, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_RANGE, 0, 0, e.action.installTtemplate.param4 > 10 ? e.action.installTtemplate.param4 - 10 : 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_MANA_PCT, 0, e.action.installTtemplate.param5 - 15 > 100 ? 100 : e.action.installTtemplate.param5 + 15, 100, 1000, 1000, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, SMART_ACTION_SET_EVENT_PHASE, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_RANGE, 0, e.action.installTtemplate.param4, 300, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_RANGE, 0, 0, e.action.installTtemplate.param4 > 10 ? e.action.installTtemplate.param4 - 10 : 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_MANA_PCT, 0, e.action.installTtemplate.param5 - 15 > 100 ? 100 : e.action.installTtemplate.param5 + 15, 100, 1000, 1000, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
break;
}
case SMARTAI_TEMPLATE_TURRET:
{
AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_JUST_CREATED, 0, 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_JUST_CREATED, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
break;
}
case SMARTAI_TEMPLATE_CAGED_NPC_PART:
@@ -2954,22 +3049,22 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e)
if (!me)
return;
//store cage as id1
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_GAMEOBJECT, e.action.installTtemplate.param1, 10, 0, 0, 0);
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_GAMEOBJECT, e.action.installTtemplate.param1, 10, 0, 0, 0);
//reset(close) cage on hostage(me) respawn
AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 0, 0, 0, 0, 0, SMART_ACTION_RESET_GOBJECT, 0, 0, 0, 0, 0, 0, SMART_TARGET_GAMEOBJECT_DISTANCE, e.action.installTtemplate.param1, 5, 0, 0, 0);
AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 0, 0, 0, 0, 0, 0, SMART_ACTION_RESET_GOBJECT, 0, 0, 0, 0, 0, 0, SMART_TARGET_GAMEOBJECT_DISTANCE, e.action.installTtemplate.param1, 5, 0, 0, 0);
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_RUN, e.action.installTtemplate.param3, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_RUN, e.action.installTtemplate.param3, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 1000, 1000, 0, 0, 0, SMART_ACTION_MOVE_FORWARD, e.action.installTtemplate.param4, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 1000, 1000, 0, 0, 0, 0, SMART_ACTION_MOVE_FORWARD, e.action.installTtemplate.param4, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
//phase 1: give quest credit on movepoint reached
AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 1);
AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 1);
//phase 1: despawn after time on movepoint reached
AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, SMART_ACTION_FORCE_DESPAWN, e.action.installTtemplate.param2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_FORCE_DESPAWN, e.action.installTtemplate.param2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
if (sCreatureTextMgr->TextExist(me->GetEntry(), (uint8)e.action.installTtemplate.param5))
AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, SMART_ACTION_TALK, e.action.installTtemplate.param5, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_TALK, e.action.installTtemplate.param5, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
break;
}
case SMARTAI_TEMPLATE_CAGED_GO_PART:
@@ -2977,16 +3072,16 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e)
if (!go)
return;
//store hostage as id1
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_CREATURE, e.action.installTtemplate.param1, 10, 0, 0, 0);
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_CREATURE, e.action.installTtemplate.param1, 10, 0, 0, 0);
//store invoker as id2
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
//signal hostage
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 0);
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 0);
//when hostage raeched end point, give credit to invoker
if (e.action.installTtemplate.param2)
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0);
AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0);
else
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0);
AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0);
break;
}
case SMARTAI_TEMPLATE_BASIC:
@@ -2995,12 +3090,12 @@ void SmartScript::InstallTemplate(SmartScriptHolder const& e)
}
}
void SmartScript::AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
void SmartScript::AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
{
mInstallEvents.push_back(CreateSmartEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, target_param4, phaseMask));
mInstallEvents.push_back(CreateSmartEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, event_param6, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, target_param4, phaseMask));
}
SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
{
SmartScriptHolder script;
script.event.type = e;
@@ -3009,6 +3104,7 @@ SmartScriptHolder SmartScript::CreateSmartEvent(SMART_EVENT e, uint32 event_flag
script.event.raw.param3 = event_param3;
script.event.raw.param4 = event_param4;
script.event.raw.param5 = event_param5;
script.event.raw.param6 = event_param6;
script.event.event_phase_mask = phaseMask;
script.event.event_flags = event_flags;
script.event.event_chance = 100;
@@ -4329,7 +4425,6 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (!me || !me->IsEngaged())
return;
float range = static_cast<float>(e.event.areaCasting.range);
ThreatContainer::StorageType threatList = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
{
@@ -4338,7 +4433,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (!target || target->IsPet() || target->IsTotem() || !target->IsNonMeleeSpellCast(false, false, true))
continue;
if (e.event.areaCasting.range && !me->IsWithinDistInMap(target, range))
if (e.event.areaCasting.rangeMin && !(me->IsInRange(target, (float)e.event.areaCasting.rangeMin, (float)e.event.areaCasting.rangeMax)))
continue;
ProcessAction(e, target);
@@ -4363,7 +4458,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
{
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
{
if (!(me->IsInRange(target, 0.f, (float)e.event.areaRange.range)))
if (!(me->IsInRange(target, (float)e.event.areaRange.rangeMin, (float)e.event.areaRange.rangeMax)))
continue;
ProcessAction(e, target);

View File

@@ -47,8 +47,8 @@ public:
void GetTargets(ObjectVector& targets, SmartScriptHolder const& e, Unit* invoker = nullptr) const;
void GetWorldObjectsInDist(ObjectVector& objects, float dist) const;
void InstallTemplate(SmartScriptHolder const& e);
static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask);
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask);
static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask);
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask);
void SetPathId(uint32 id) { mPathId = id; }
uint32 GetPathId() const { return mPathId; }
WorldObject* GetBaseObject() const

View File

@@ -223,24 +223,25 @@ void SmartAIMgr::LoadSmartAIFromDB()
temp.event.raw.param3 = fields[10].Get<uint32>();
temp.event.raw.param4 = fields[11].Get<uint32>();
temp.event.raw.param5 = fields[12].Get<uint32>();
temp.event.raw.param6 = fields[13].Get<uint32>();
temp.action.type = (SMART_ACTION)fields[13].Get<uint8>();
temp.action.raw.param1 = fields[14].Get<uint32>();
temp.action.raw.param2 = fields[15].Get<uint32>();
temp.action.raw.param3 = fields[16].Get<uint32>();
temp.action.raw.param4 = fields[17].Get<uint32>();
temp.action.raw.param5 = fields[18].Get<uint32>();
temp.action.raw.param6 = fields[19].Get<uint32>();
temp.action.type = (SMART_ACTION)fields[14].Get<uint8>();
temp.action.raw.param1 = fields[15].Get<uint32>();
temp.action.raw.param2 = fields[16].Get<uint32>();
temp.action.raw.param3 = fields[17].Get<uint32>();
temp.action.raw.param4 = fields[18].Get<uint32>();
temp.action.raw.param5 = fields[19].Get<uint32>();
temp.action.raw.param6 = fields[20].Get<uint32>();
temp.target.type = (SMARTAI_TARGETS)fields[20].Get<uint8>();
temp.target.raw.param1 = fields[21].Get<uint32>();
temp.target.raw.param2 = fields[22].Get<uint32>();
temp.target.raw.param3 = fields[23].Get<uint32>();
temp.target.raw.param4 = fields[24].Get<uint32>();
temp.target.x = fields[25].Get<float>();
temp.target.y = fields[26].Get<float>();
temp.target.z = fields[27].Get<float>();
temp.target.o = fields[28].Get<float>();
temp.target.type = (SMARTAI_TARGETS)fields[21].Get<uint8>();
temp.target.raw.param1 = fields[22].Get<uint32>();
temp.target.raw.param2 = fields[23].Get<uint32>();
temp.target.raw.param3 = fields[24].Get<uint32>();
temp.target.raw.param4 = fields[25].Get<uint32>();
temp.target.x = fields[26].Get<float>();
temp.target.y = fields[27].Get<float>();
temp.target.z = fields[28].Get<float>();
temp.target.o = fields[29].Get<float>();
//check target
if (!IsTargetValid(temp))
@@ -781,6 +782,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_SET_SCALE: return sizeof(SmartAction::setScale);
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);
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());
@@ -977,6 +979,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
if (!IsMinMaxValid(e, e.event.areaRange.repeatMin, e.event.areaRange.repeatMax))
return false;
if (!IsMinMaxValid(e, e.event.areaRange.rangeMin, e.event.areaRange.rangeMax))
return false;
break;
case SMART_EVENT_SPELLHIT:
case SMART_EVENT_SPELLHIT_TARGET:
@@ -1073,6 +1078,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
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:
@@ -1964,6 +1972,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SET_SCALE:
case SMART_ACTION_SUMMON_RADIAL:
case SMART_ACTION_PLAY_SPELL_VISUAL:
case SMART_ACTION_FOLLOW_GROUP:
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);

View File

@@ -523,7 +523,8 @@ struct SmartEvent
uint32 max;
uint32 repeatMin;
uint32 repeatMax;
uint32 range;
uint32 rangeMin;
uint32 rangeMax;
} areaCasting;
struct
@@ -532,7 +533,8 @@ struct SmartEvent
uint32 max;
uint32 repeatMin;
uint32 repeatMax;
uint32 range;
uint32 rangeMin;
uint32 rangeMax;
} areaRange;
struct
@@ -542,6 +544,7 @@ struct SmartEvent
uint32 param3;
uint32 param4;
uint32 param5;
uint32 param6;
} raw;
};
@@ -739,8 +742,9 @@ enum SMART_ACTION
SMART_ACTION_SET_SCALE = 227, // scale
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_AC_END = 230, // placeholder
SMART_ACTION_AC_END = 231, // placeholder
};
enum class SmartActionSummonCreatureFlags
@@ -1442,6 +1446,13 @@ struct SmartAction
{
uint32 visualId;
} spellVisual;
struct
{
uint32 followState;
uint32 followType;
uint32 dist;
} followGroup;
//! Note for any new future actions
//! All parameters must have type uint32
@@ -1880,6 +1891,16 @@ enum SmartCastFlags
SMARTCAST_THREATLIST_NOT_SINGLE = 0x80 //Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
};
enum SmartFollowType
{
FOLLOW_TYPE_CIRCLE = 1, // 360 degrees around leader, 90 degrees is the maximum angle
FOLLOW_TYPE_SEMI_CIRCLE_BEHIND = 2, // 180 degrees behind leader
FOLLOW_TYPE_SEMI_CIRCLE_FRONT = 3, // 180 degrees in front of leader
FOLLOW_TYPE_LINE = 4, // front -> back -> front -> back
FOLLOW_TYPE_COLUMN = 5, // left -> right -> left -> right
FOLLOW_TYPE_ANGULAR = 6 // geese-like formation 135 and 225 degrees behind leader
};
// one line in DB is one event
struct SmartScriptHolder
{

View File

@@ -916,9 +916,49 @@ void Battleground::EndBattleground(PvPTeamId winnerTeamId)
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, player->GetMapId());
}
if (IsEventActive(EVENT_SPIRIT_OF_COMPETITION) && isBattleground())
SpiritofCompetitionEvent(winnerTeamId);
sScriptMgr->OnBattlegroundEnd(this, GetTeamId(winnerTeamId));
}
bool Battleground::SpiritofCompetitionEvent(PvPTeamId winnerTeamId)
{
// Everyone is eligible for tabard reward
for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player* player = itr->second;
bool questStatus = player->GetQuestStatus(QUEST_FLAG_PARTICIPANT) != QUEST_STATUS_REWARDED;
if (player && questStatus)
player->CastSpell(player, SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT, true);
}
// In case of a draw nobody get rewarded
if (winnerTeamId == PVP_TEAM_NEUTRAL)
return false;
std::vector<Player*> filteredPlayers;
for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Player* player = itr->second;
bool playerTeam = player->GetBgTeamId() == GetTeamId(winnerTeamId);
bool questStatus = player->GetQuestStatus(QUEST_FLAG_WINNER) != QUEST_STATUS_REWARDED;
if (player && playerTeam && questStatus)
filteredPlayers.push_back(player);
}
if (filteredPlayers.size())
{
if (Player* wPlayer = filteredPlayers[rand() % filteredPlayers.size()])
wPlayer->CastSpell(wPlayer, SPELL_SPIRIT_OF_COMPETITION_WINNER, true);
}
return true;
}
uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const
{
//variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)

View File

@@ -238,6 +238,15 @@ enum BattlegroundStartingEventsIds
BG_STARTING_EVENT_FOURTH = 3
};
enum SpiritOfCompetitionEvent
{
EVENT_SPIRIT_OF_COMPETITION = 46,
QUEST_FLAG_PARTICIPANT = 12187,
QUEST_FLAG_WINNER = 12186,
SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT = 48163,
SPELL_SPIRIT_OF_COMPETITION_WINNER = 48164,
};
constexpr auto BG_STARTING_EVENT_COUNT = 4;
class ArenaLogEntryData
@@ -338,6 +347,9 @@ public:
[[nodiscard]] uint32 GetScriptId() const { return ScriptId; }
[[nodiscard]] uint32 GetBonusHonorFromKill(uint32 kills) const;
// Spirit of Competition event
bool SpiritofCompetitionEvent(PvPTeamId winnerTeamId);
bool IsRandom() { return m_IsRandom; }
// Set methods:

View File

@@ -48,7 +48,7 @@ Pet::Pet(Player* owner, PetType type) : Guardian(nullptr, owner ? owner->GetGUID
m_loading(false),
m_petRegenTimer(PET_FOCUS_REGEN_INTERVAL),
m_tempspellTarget(nullptr),
m_tempoldTarget(nullptr),
m_tempoldTarget(),
m_tempspellIsPositive(false),
m_tempspell(0)
{
@@ -710,7 +710,11 @@ void Pet::Update(uint32 diff)
if (m_tempspell)
{
Unit* tempspellTarget = m_tempspellTarget;
Unit* tempoldTarget = m_tempoldTarget;
Unit* tempoldTarget = nullptr;
if (!m_tempoldTarget.IsEmpty())
tempoldTarget = ObjectAccessor::GetUnit(*this, m_tempoldTarget);
bool tempspellIsPositive = m_tempspellIsPositive;
uint32 tempspell = m_tempspell;
Unit* charmer = GetCharmerOrOwner();
@@ -783,7 +787,7 @@ void Pet::Update(uint32 diff)
}
}
m_tempoldTarget = nullptr;
m_tempoldTarget = ObjectGuid::Empty;
m_tempspellIsPositive = false;
}
}
@@ -793,7 +797,7 @@ void Pet::Update(uint32 diff)
{
m_tempspell = 0;
m_tempspellTarget = nullptr;
m_tempoldTarget = nullptr;
m_tempoldTarget = ObjectGuid::Empty;
m_tempspellIsPositive = false;
Unit* victim = charmer->GetVictim();
@@ -1218,11 +1222,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
}
case NPC_INFERNAL:
{
float highAmt = petlevel / 11.0f;
float lowAmt = petlevel / 12.0f;
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, lowAmt * lowAmt * lowAmt);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, highAmt * highAmt * highAmt);
if (pInfo)
{
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(pInfo->min_dmg));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(pInfo->max_dmg));
}
AddAura(SPELL_PET_AVOIDANCE, this);
AddAura(SPELL_WARLOCK_PET_SCALING_05, this);
AddAura(SPELL_INFERNAL_SCALING_01, this);
@@ -2414,7 +2418,7 @@ void Pet::SetDisplayId(uint32 modelId)
player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID);
}
void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarget, bool spellIsPositive)
void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, ObjectGuid oldTarget, bool spellIsPositive)
{
if (!spellid)
return;
@@ -2426,7 +2430,7 @@ void Pet::CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarg
m_tempspell = spellid;
m_tempspellIsPositive = spellIsPositive;
if (oldTarget)
if (!oldTarget.IsEmpty())
m_tempoldTarget = oldTarget;
}
@@ -2435,7 +2439,7 @@ void Pet::ClearCastWhenWillAvailable()
m_tempspellIsPositive = false;
m_tempspell = 0;
m_tempspellTarget = nullptr;
m_tempoldTarget = nullptr;
m_tempoldTarget = ObjectGuid::Empty;
}
void Pet::RemoveSpellCooldown(uint32 spell_id, bool update /* = false */)

View File

@@ -96,7 +96,7 @@ public:
void LearnPetPassives();
void CastPetAuras(bool current);
void CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, Unit* oldTarget, bool spellIsPositive = false);
void CastWhenWillAvailable(uint32 spellid, Unit* spellTarget, ObjectGuid oldTarget, bool spellIsPositive = false);
void ClearCastWhenWillAvailable();
void RemoveSpellCooldown(uint32 spell_id, bool update /* = false */);
@@ -157,10 +157,10 @@ protected:
std::unique_ptr<DeclinedName> m_declinedname;
Unit* m_tempspellTarget;
Unit* m_tempoldTarget;
bool m_tempspellIsPositive;
uint32 m_tempspell;
Unit* m_tempspellTarget;
ObjectGuid m_tempoldTarget;
bool m_tempspellIsPositive;
uint32 m_tempspell;
private:
void SaveToDB(uint32, uint8, uint32) override // override of Creature::SaveToDB - must not be called

View File

@@ -39,6 +39,8 @@ MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMo
MotionTransport::~MotionTransport()
{
HashMapHolder<MotionTransport>::Remove(this);
ASSERT(_passengers.empty());
UnloadStaticPassengers();
}

View File

@@ -388,22 +388,19 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
&& unit->GetTypeId() == TYPEID_PLAYER
&& seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
{
try
// Removed try catch + ABORT() here, and make it as simple condition check.
if (!_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
{
if (!_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
ABORT();
}
catch (...)
{
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy()!");
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). not null: {}", _me ? 1 : 0);
// I assume SetCharmedBy should always be true.
// If not, let's log some debug info.
LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). not null: {}", _me ? 1 : 0);
if (!_me)
return false;
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Is: {}!", _me->IsInWorld());
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Is2: {}!", _me->IsDuringRemoveFromWorld());
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Unit {}!", _me->GetName());
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). typeid: {}!", _me->GetTypeId());
LOG_INFO("vehicles", "CRASH! Try-catch in Unit::SetCharmedBy(). Unit {}, typeid: {}, in world: {}, duringremove: {} has wrong CharmType! Charmer {}, typeid: {}, in world: {}, duringremove: {}.", _me->GetName(), _me->GetTypeId(), _me->IsInWorld(), _me->IsDuringRemoveFromWorld(), unit->GetName(), unit->GetTypeId(), unit->IsInWorld(), unit->IsDuringRemoveFromWorld());
LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Is: {}!", _me->IsInWorld());
LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Is2: {}!", _me->IsDuringRemoveFromWorld());
LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Unit {}!", _me->GetName());
LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). typeid: {}!", _me->GetTypeId());
LOG_INFO("vehicles", "Crash recovered in Unit::SetCharmedBy(). Unit {}, typeid: {}, in world: {}, duringremove: {} has wrong CharmType! Charmer {}, typeid: {}, in world: {}, duringremove: {}.", _me->GetName(), _me->GetTypeId(), _me->IsInWorld(), _me->IsDuringRemoveFromWorld(), unit->GetName(), unit->GetTypeId(), unit->IsInWorld(), unit->IsDuringRemoveFromWorld());
return false;
}
}

View File

@@ -491,7 +491,7 @@ void ObjectMgr::LoadGossipMenuItemsLocales()
{
Field* fields = result->Fetch();
uint16 MenuID = fields[0].Get<uint16>();
uint32 MenuID = fields[0].Get<uint32>();
uint16 OptionID = fields[1].Get<uint16>();
LocaleConstant locale = GetLocaleByName(fields[2].Get<std::string>());
@@ -9226,7 +9226,7 @@ void ObjectMgr::LoadGossipMenu()
GossipMenus gMenu;
gMenu.MenuID = fields[0].Get<uint16>();
gMenu.MenuID = fields[0].Get<uint32>();
gMenu.TextID = fields[1].Get<uint32>();
if (!GetGossipText(gMenu.TextID))
@@ -9266,7 +9266,7 @@ void ObjectMgr::LoadGossipMenuItems()
GossipMenuItems gMenuItem;
gMenuItem.MenuID = fields[0].Get<uint16>();
gMenuItem.MenuID = fields[0].Get<uint32>();
gMenuItem.OptionID = fields[1].Get<uint16>();
gMenuItem.OptionIcon = fields[2].Get<uint32>();
gMenuItem.OptionText = fields[3].Get<std::string>();

View File

@@ -530,7 +530,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
pet->SendPetAIReaction(guid1);
}
pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, nullptr, tempspellIsPositive);
pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, ObjectGuid::Empty, tempspellIsPositive);
}
}
else if (haspositiveeffect)
@@ -566,7 +566,11 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
pet->SendPetAIReaction(guid1);
}
pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, victim, tmpSpellIsPositive);
ObjectGuid oldTarget = ObjectGuid::Empty;
if (victim)
oldTarget = victim->GetGUID();
pet->ToPet()->CastWhenWillAvailable(spellId, unit_target, oldTarget, tmpSpellIsPositive);
}
}
}

View File

@@ -645,7 +645,10 @@ enum AcoreStrings
// End Level 3 list, continued at 1100
// 600-704 - free
LANG_EVENT_STARTED = 600,
LANG_EVENT_STOPPED = 601,
// 602-704 - free
LANG_WAIT_BEFORE_SPEAKING = 705,
LANG_NOT_EQUIPPED_ITEM = 706,

View File

@@ -4560,6 +4560,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].TriggerSpell = 62585; // Mulgore Hatchling (fear)
});
// Poultryized!
ApplySpellFix({ 30504 }, [](SpellInfo* spellInfo)
{
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_TAKE_DAMAGE;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];

View File

@@ -152,11 +152,12 @@ public:
GameEventMgr::ActiveEvents const& activeEvents = sGameEventMgr->GetActiveEventList();
if (activeEvents.find(eventId) != activeEvents.end())
{
handler->PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE, uint16(eventId));
handler->PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE, uint16(eventId), eventData.description.c_str());
handler->SetSentErrorMessage(true);
return false;
}
handler->PSendSysMessage(LANG_EVENT_STARTED, uint16(eventId), eventData.description.c_str());
sGameEventMgr->StartEvent(eventId, true);
return true;
}
@@ -184,11 +185,12 @@ public:
if (activeEvents.find(eventId) == activeEvents.end())
{
handler->PSendSysMessage(LANG_EVENT_NOT_ACTIVE, uint16(eventId));
handler->PSendSysMessage(LANG_EVENT_NOT_ACTIVE, uint16(eventId), eventData.description.c_str());
handler->SetSentErrorMessage(true);
return false;
}
handler->PSendSysMessage(LANG_EVENT_STOPPED, uint16(eventId), eventData.description.c_str());
sGameEventMgr->StopEvent(eventId, true);
return true;
}

View File

@@ -31,8 +31,8 @@ uint32 const DragonspireMobs[3] = { NPC_BLACKHAND_DREADWEAVER, NPC_BLACKHAND_SUM
enum EventIds
{
EVENT_DARGONSPIRE_ROOM_STORE = 1,
EVENT_DARGONSPIRE_ROOM_CHECK = 2,
EVENT_DRAGONSPIRE_ROOM_STORE = 1,
EVENT_DRAGONSPIRE_ROOM_CHECK = 2,
EVENT_SOLAKAR_WAVE = 3
};
@@ -352,7 +352,7 @@ public:
if (data == AREATRIGGER_DRAGONSPIRE_HALL)
{
if (GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE)
Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_STORE, 1s);
Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_STORE, 1s);
}
break;
case DATA_SOLAKAR_FLAMEWREATH:
@@ -555,14 +555,14 @@ public:
{
switch (eventId)
{
case EVENT_DARGONSPIRE_ROOM_STORE:
case EVENT_DRAGONSPIRE_ROOM_STORE:
Dragonspireroomstore();
Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3s);
Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s);
break;
case EVENT_DARGONSPIRE_ROOM_CHECK:
case EVENT_DRAGONSPIRE_ROOM_CHECK:
Dragonspireroomcheck();
if ((GetBossState(DATA_DRAGONSPIRE_ROOM) != DONE))
Events.ScheduleEvent(EVENT_DARGONSPIRE_ROOM_CHECK, 3s);
Events.ScheduleEvent(EVENT_DRAGONSPIRE_ROOM_CHECK, 3s);
break;
case EVENT_SOLAKAR_WAVE:
SummonSolakarWave(CurrentSolakarWave);

View File

@@ -38,11 +38,12 @@ enum Spells
struct boss_maiden_of_virtue : public BossAI
{
boss_maiden_of_virtue(Creature* creature) : BossAI(creature, DATA_MAIDEN) { }
void Reset() override
boss_maiden_of_virtue(Creature* creature) : BossAI(creature, DATA_MAIDEN)
{
BossAI::Reset();
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void JustEngagedWith(Unit* who) override
@@ -82,18 +83,6 @@ struct boss_maiden_of_virtue : public BossAI
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
};
void AddSC_boss_maiden_of_virtue()

View File

@@ -40,30 +40,11 @@ struct boss_servant_quarters : public BossAI
void Reset() override
{
_scheduler.CancelAll();
me->SetVisible(false);
me->SetReactState(REACT_PASSIVE);
me->SetFaction(FACTION_FRIENDLY);
_scheduler.Schedule(5s, [this](TaskContext context)
{
if (instance->GetBossState(DATA_SERVANT_QUARTERS) == DONE)
{
me->SetVisible(true);
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
}
else
{
context.Repeat(5s);
}
});
if (me->GetEntry() == NPC_HYAKISS_THE_LURKER)
{
DoCastSelf(SPELL_SNEAK, true);
}
if (instance->GetData(DATA_SELECTED_RARE) != me->GetEntry())
{
me->DespawnOrUnsummon(1);
}
}
void JustEngagedWith(Unit* /*who*/) override

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,14 @@ const Position OptionalSpawn[] =
ObjectData const creatureData[] =
{
{ NPC_ATTUMEN_THE_HUNTSMAN, DATA_ATTUMEN },
{ NPC_MIDNIGHT, DATA_MIDNIGHT }
{ NPC_MIDNIGHT, DATA_MIDNIGHT },
{ NPC_DOROTHEE, DATA_DOROTHEE },
{ NPC_TITO, DATA_TITO },
{ NPC_ROAR, DATA_ROAR },
{ NPC_STRAWMAN, DATA_STRAWMAN },
{ NPC_TINHEAD, DATA_TINHEAD },
{ NPC_ROMULO, DATA_ROMULO },
{ NPC_JULIANNE, DATA_JULIANNE },
};
class instance_karazhan : public InstanceMapScript

View File

@@ -40,11 +40,10 @@ enum KZDataTypes
DATA_MALCHEZZAR = 10,
DATA_NIGHTBANE = 11,
DATA_SERVANT_QUARTERS = 12,
DATA_SELECTED_RARE = 13,
DATA_OPERA_OZ_DEATHCOUNT = 14,
DATA_KILREK = 15,
DATA_OPERA_OZ_DEATHCOUNT = 13,
DATA_KILREK = 14,
MAX_ENCOUNTERS = 16,
MAX_ENCOUNTERS = 15,
DATA_GO_CURTAINS = 18,
DATA_GO_STAGEDOORLEFT = 19,
@@ -67,7 +66,17 @@ enum KZDataTypes
DATA_CHESS_REINIT_PIECES = 34,
DATA_CHESS_GAME_PHASE = 35,
DATA_ECHO_OF_MEDIVH = 36,
DATA_DUST_COVERED_CHEST = 37
DATA_DUST_COVERED_CHEST = 37,
// Specific Opera Data
DATA_DOROTHEE = 38,
DATA_ROMULO = 39,
DATA_JULIANNE = 40,
DATA_ROAR = 41,
DATA_STRAWMAN = 42,
DATA_TINHEAD = 43,
DATA_TITO = 44
};
enum KZOperaEvents
@@ -101,6 +110,13 @@ enum KZCreatures
NPC_KILREK = 17229,
NPC_RELAY = 17645,
NPC_BARNES = 16812,
NPC_DOROTHEE = 17535,
NPC_TITO = 17548,
NPC_ROMULO = 17533,
NPC_JULIANNE = 17534,
NPC_ROAR = 17546,
NPC_STRAWMAN = 17543,
NPC_TINHEAD = 17547,
// Chess Event
NPC_ECHO_OF_MEDIVH = 16816,

View File

@@ -112,10 +112,6 @@ struct boss_lieutenant_drake : public BossAI
{
_JustDied();
Talk(SAY_DEATH);
if (InstanceScript* instance = me->GetInstanceScript())
{
instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_DRAKE_KILLED);
}
}
void MovementInform(uint32 type, uint32 point) override

View File

@@ -257,7 +257,7 @@ public:
{
switch (param)
{
case ENCOUNTER_PROGRESS_DRAKE_KILLED:
case ENCOUNTER_PROGRESS_BARRELS:
events.ScheduleEvent(EVENT_OPEN_DOORS, 0);
events.ScheduleEvent(EVENT_START_WP, 3000);
break;

View File

@@ -74,7 +74,7 @@ enum MiscIds
ENCOUNTER_PROGRESS_NONE = 0,
ENCOUNTER_PROGRESS_BARRELS = 1,
ENCOUNTER_PROGRESS_DRAKE_KILLED = 2,
//ENCOUNTER_PROGRESS_DRAKE_KILLED = 2, No longer used. Kept as reference as DB might rely on the existing order.
ENCOUNTER_PROGRESS_THRALL_ARMORED = 3,
ENCOUNTER_PROGRESS_AMBUSHES_1 = 4,
ENCOUNTER_PROGRESS_SKARLOC_KILLED = 5,

View File

@@ -39,6 +39,8 @@ EndContentData */
#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SpellAuras.h"
#include "SpellScript.h"
/*######
## npc_draenei_survivor
@@ -522,6 +524,55 @@ public:
}
};
enum NestlewoodOwlkin
{
NPC_NESTLEWOOD_OWLKIN_ENTRY = 16518,
NPC_INOCULATED_OWLKIN_ENTRY = 16534,
TALK_OWLKIN = 0
};
class spell_inoculate_nestlewood_owlkin : public AuraScript
{
public:
PrepareAuraScript(spell_inoculate_nestlewood_owlkin)
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Creature* owlkin = GetTarget()->ToCreature())
if (owlkin->GetEntry() == NPC_NESTLEWOOD_OWLKIN_ENTRY)
owlkin->SetFacingToObject(GetCaster());
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
if (Creature* owlkin = GetTarget()->ToCreature())
{
if (owlkin->GetEntry() == NPC_NESTLEWOOD_OWLKIN_ENTRY)
{
Player* caster = GetCaster()->ToPlayer();
if (owlkin->UpdateEntry(NPC_INOCULATED_OWLKIN_ENTRY))
{
owlkin->AI()->Talk(TALK_OWLKIN);
owlkin->GetMotionMaster()->MoveRandom(15.0f);
owlkin->SetUnitFlag(UnitFlags(UNIT_FLAG_IMMUNE_TO_PC));
owlkin->DespawnOrUnsummon(15s, 0s);
caster->RewardPlayerAndGroupAtEvent(NPC_INOCULATED_OWLKIN_ENTRY, caster);
}
}
}
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_inoculate_nestlewood_owlkin::HandleEffectApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectRemoveFn(spell_inoculate_nestlewood_owlkin::HandleEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_azuremyst_isle()
{
new npc_draenei_survivor();
@@ -531,4 +582,5 @@ void AddSC_azuremyst_isle()
new go_ravager_cage();
new npc_stillpine_capitive();
new go_bristlelimb_cage();
RegisterSpellScript(spell_inoculate_nestlewood_owlkin);
}

View File

@@ -702,7 +702,6 @@ public:
}
}
me->RemoveVehicleKit(); // not Crash (;
events.ScheduleEvent(EVENT_TAKE_OFF, 2s);
me->CastSpell(passenger, VEHICLE_SPELL_PARACHUTE, true);
}

View File

@@ -73,6 +73,13 @@ struct boss_harbinger_skyriss : public BossAI
});
}
void EnterEvadeMode(EvadeReason why) override
{
BossAI::EnterEvadeMode(why);
instance->DoRespawnCreature(DATA_WARDEN_MELLICHAR, true);
me->DespawnOrUnsummon();
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);

View File

@@ -4917,6 +4917,87 @@ class spell_gen_curse_of_pain : public AuraScript
}
};
enum SpiritofCompetition
{
// Spells
SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT_EFFECT = 48056,
SPELL_SPIRIT_OF_COMPETITION_WINNER_EFFECT = 48057,
// Mail
MAIL_THE_COMPETITIORS_TABARD = 195,
MAIL_A_GOLD_MEDALLION = 196,
// NPC
NPC_SPIRIT_OF_COMPETITION = 27217,
// Items
ITEM_COMPETITORS_TABARD = 36941,
ITEM_GOLD_MEDALLION = 37297,
};
class spell_gen_spirit_of_competition_participant : public SpellScript
{
PrepareSpellScript(spell_gen_spirit_of_competition_participant);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT_EFFECT });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Player* player = GetHitPlayer())
{
player->CastSpell(player, SPELL_SPIRIT_OF_COMPETITION_PARTICIPANT_EFFECT, true);
Item* item = Item::CreateItem(ITEM_COMPETITORS_TABARD, 1);
if (!item)
return;
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
MailDraft(MAIL_THE_COMPETITIORS_TABARD)
.AddItem(item)
.SendMailTo(trans, player, MailSender(NPC_SPIRIT_OF_COMPETITION), MAIL_CHECK_MASK_HAS_BODY);
CharacterDatabase.CommitTransaction(trans);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gen_spirit_of_competition_participant::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_gen_spirit_of_competition_winner : public SpellScript
{
PrepareSpellScript(spell_gen_spirit_of_competition_winner);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SPIRIT_OF_COMPETITION_WINNER_EFFECT });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Player* player = GetHitPlayer())
{
player->CastSpell(player, SPELL_SPIRIT_OF_COMPETITION_WINNER_EFFECT, true);
Item* item = Item::CreateItem(ITEM_GOLD_MEDALLION, 1);
if (!item)
return;
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
MailDraft(MAIL_A_GOLD_MEDALLION)
.AddItem(item)
.SendMailTo(trans, player, MailSender(NPC_SPIRIT_OF_COMPETITION), MAIL_CHECK_MASK_HAS_BODY);
CharacterDatabase.CommitTransaction(trans);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gen_spirit_of_competition_winner::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5063,4 +5144,6 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_threshalisk_charge);
RegisterSpellScript(spell_gen_shriveling_gaze);
RegisterSpellScript(spell_gen_curse_of_pain);
RegisterSpellScript(spell_gen_spirit_of_competition_participant);
RegisterSpellScript(spell_gen_spirit_of_competition_winner);
}

View File

@@ -2975,8 +2975,9 @@ class spell_item_nigh_invulnerability : public SpellScript
enum Poultryzer
{
SPELL_POULTRYIZER_SUCCESS = 30501,
SPELL_POULTRYIZER_BACKFIRE = 30504,
SPELL_POULTRYIZER_SUCCESS_1 = 30501,
SPELL_POULTRYIZER_SUCCESS_2 = 30504, // malfunction
SPELL_POULTRYIZER_BACKFIRE = 30506, // Not removed on damage
};
class spell_item_poultryizer : public SpellScript
@@ -2985,13 +2986,22 @@ class spell_item_poultryizer : public SpellScript
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_POULTRYIZER_SUCCESS, SPELL_POULTRYIZER_BACKFIRE });
return ValidateSpellInfo({ SPELL_POULTRYIZER_SUCCESS_1, SPELL_POULTRYIZER_SUCCESS_2, SPELL_POULTRYIZER_BACKFIRE });
}
void HandleDummy(SpellEffIndex /* effIndex */)
{
if (GetCastItem() && GetHitUnit())
GetCaster()->CastSpell(GetHitUnit(), roll_chance_i(80) ? SPELL_POULTRYIZER_SUCCESS : SPELL_POULTRYIZER_BACKFIRE, true, GetCastItem());
{
if (roll_chance_i(80))
{
GetCaster()->CastSpell(GetHitUnit(), roll_chance_i(80) ? SPELL_POULTRYIZER_SUCCESS_1 : SPELL_POULTRYIZER_SUCCESS_2, true, GetCastItem());
}
else
{
GetCaster()->CastSpell(GetCaster(), SPELL_POULTRYIZER_BACKFIRE, true, GetCastItem());
}
}
}
void Register() override

View File

@@ -2451,6 +2451,27 @@ class spell_q4735_collect_rookery_egg : public SpellScript
}
};
enum BookOfFelNames
{
SPELL_METAMORPHOSIS = 36298
};
class spell_q10651_q10692_book_of_fel_names : public SpellScript
{
PrepareSpellScript(spell_q10651_q10692_book_of_fel_names);
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (GetHitUnit()->HasAura(SPELL_METAMORPHOSIS))
GetHitUnit()->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_q10651_q10692_book_of_fel_names::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_quest_spell_scripts()
{
RegisterSpellAndAuraScriptPair(spell_q11065_wrangle_some_aether_rays, spell_q11065_wrangle_some_aether_rays_aura);
@@ -2522,4 +2543,5 @@ void AddSC_quest_spell_scripts()
RegisterSpellScript(spell_q12919_gymers_throw);
RegisterSpellScript(spell_q5056_summon_shy_rotam);
RegisterSpellScript(spell_q4735_collect_rookery_egg);
RegisterSpellScript(spell_q10651_q10692_book_of_fel_names);
}

View File

@@ -0,0 +1,125 @@
/*
* 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 "Config.h"
#include "gtest/gtest.h"
#include <boost/filesystem.hpp>
#include <cstdlib>
#include <fstream>
#include <string>
std::string CreateConfigWithMap(std::map<std::string, std::string> const& map)
{
auto mTempFileRel = boost::filesystem::unique_path("deleteme.ini");
auto mTempFileAbs = boost::filesystem::temp_directory_path() / mTempFileRel;
std::ofstream iniStream;
iniStream.open(mTempFileAbs.c_str());
iniStream << "[test]\n";
for (auto const& itr : map)
iniStream << itr.first << " = " << itr.second << "\n";
iniStream.close();
return mTempFileAbs.native();
}
class ConfigEnvTest : public testing::Test {
protected:
void SetUp() override {
std::map<std::string, std::string> config;
config["Int.Nested"] = "4242";
config["lower"] = "simpleString";
config["UPPER"] = "simpleString";
config["SomeLong.NestedNameWithNumber.Like1"] = "1";
config["GM.InGMList.Level"] = "50";
confFilePath = CreateConfigWithMap(config);
sConfigMgr->Configure(confFilePath, std::vector<std::string>());
sConfigMgr->LoadAppConfigs();
}
void TearDown() override {
std::remove(confFilePath.c_str());
}
std::string confFilePath;
};
TEST_F(ConfigEnvTest, NestedInt)
{
EXPECT_EQ(sConfigMgr->GetOption<int32>("Int.Nested", 10), 4242);
setenv("AC_INT_NESTED", "8080", 1);
EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false);
EXPECT_EQ(sConfigMgr->GetOption<int32>("Int.Nested", 10), 8080);
}
TEST_F(ConfigEnvTest, SimpleLowerString)
{
EXPECT_EQ(sConfigMgr->GetOption<std::string>("lower", ""), "simpleString");
setenv("AC_LOWER", "envstring", 1);
EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false);
EXPECT_EQ(sConfigMgr->GetOption<std::string>("lower", ""), "envstring");
}
TEST_F(ConfigEnvTest, SimpleUpperString)
{
EXPECT_EQ(sConfigMgr->GetOption<std::string>("UPPER", ""), "simpleString");
setenv("AC_UPPER", "envupperstring", 1);
EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false);
EXPECT_EQ(sConfigMgr->GetOption<std::string>("UPPER", ""), "envupperstring");
}
TEST_F(ConfigEnvTest, LongNestedNameWithNumber)
{
EXPECT_EQ(sConfigMgr->GetOption<float>("SomeLong.NestedNameWithNumber.Like1", 0), 1);
setenv("AC_SOME_LONG_NESTED_NAME_WITH_NUMBER_LIKE_1", "42", 1);
EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false);
EXPECT_EQ(sConfigMgr->GetOption<float>("SomeLong.NestedNameWithNumber.Like1", 0), 42);
}
TEST_F(ConfigEnvTest, ValueWithSeveralUpperlLaters)
{
EXPECT_EQ(sConfigMgr->GetOption<int>("GM.InGMList.Level", 1), 50);
setenv("AC_GM_IN_GMLIST_LEVEL", "42", 1);
EXPECT_EQ(sConfigMgr->OverrideWithEnvVariablesIfAny().empty(), false);
EXPECT_EQ(sConfigMgr->GetOption<int>("GM.InGMList.Level", 0), 42);
}
TEST_F(ConfigEnvTest, StringThatNotExistInConfig)
{
setenv("AC_UNIQUE_STRING", "somevalue", 1);
EXPECT_EQ(sConfigMgr->GetOption<std::string>("Unique.String", ""), "somevalue");
}
TEST_F(ConfigEnvTest, IntThatNotExistInConfig)
{
setenv("AC_UNIQUE_INT", "100", 1);
EXPECT_EQ(sConfigMgr->GetOption<int>("Unique.Int", 1), 100);
}
TEST_F(ConfigEnvTest, NotExistingString)
{
EXPECT_EQ(sConfigMgr->GetOption<std::string>("NotFound.String", "none"), "none");
}
TEST_F(ConfigEnvTest, NotExistingInt)
{
EXPECT_EQ(sConfigMgr->GetOption<int>("NotFound.Int", 1), 1);
}

View File

@@ -62,6 +62,8 @@ int main(int argc, char** argv)
if (!sConfigMgr->LoadAppConfigs())
return 1;
std::vector<std::string> overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny();
// Init logging
sLog->Initialize();
@@ -78,6 +80,9 @@ int main(int argc, char** argv)
}
);
for (std::string const& key : overriddenKeys)
LOG_INFO("dbimport", "Configuration field {} was overridden with environment variable.", key);
OpenSSLCrypto::threadsSetup();
std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });