mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 06:06:23 +00:00
Refactoring part 2 [W.I.P]
This commit is contained in:
@@ -1,33 +0,0 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
# Enforce compileparameters for corebuilds under GCC
|
||||
# This to stop a few silly crashes that could have been avoided IF people
|
||||
# weren't doing some -O3 psychooptimizations etc.
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW)
|
||||
add_definitions(-fno-delete-null-pointer-checks)
|
||||
endif()
|
||||
|
||||
if( SERVERS )
|
||||
set(sources_windows_Debugging
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Debugging/WheatyExceptionReport.cpp
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Debugging/WheatyExceptionReport.h
|
||||
)
|
||||
add_subdirectory(game)
|
||||
add_subdirectory(authserver)
|
||||
add_subdirectory(scripts)
|
||||
add_subdirectory(worldserver)
|
||||
else()
|
||||
if( TOOLS )
|
||||
add_subdirectory(collision)
|
||||
add_subdirectory(shared)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) MaNGOS, TrinityCore, SunwellCore and AzerothCore
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AuthCodes.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace AuthHelper
|
||||
{
|
||||
static RealmBuildInfo const PostBcAcceptedClientBuilds[] =
|
||||
{
|
||||
{15595, 4, 3, 4, ' '},
|
||||
{14545, 4, 2, 2, ' '},
|
||||
{13623, 4, 0, 6, 'a'},
|
||||
{12340, 3, 3, 5, 'a'},
|
||||
{11723, 3, 3, 3, 'a'},
|
||||
{11403, 3, 3, 2, ' '},
|
||||
{11159, 3, 3, 0, 'a'},
|
||||
{10505, 3, 2, 2, 'a'},
|
||||
{9947, 3, 1, 3, ' '},
|
||||
{8606, 2, 4, 3, ' '},
|
||||
{0, 0, 0, 0, ' '} // terminator
|
||||
};
|
||||
|
||||
static RealmBuildInfo const PreBcAcceptedClientBuilds[] =
|
||||
{
|
||||
{6141, 1, 12, 3, ' '},
|
||||
{6005, 1, 12, 2, ' '},
|
||||
{5875, 1, 12, 1, ' '},
|
||||
{0, 0, 0, 0, ' '} // terminator
|
||||
};
|
||||
|
||||
bool IsPreBCAcceptedClientBuild(int build)
|
||||
{
|
||||
for (int i = 0; PreBcAcceptedClientBuilds[i].Build; ++i)
|
||||
if (PreBcAcceptedClientBuilds[i].Build == build)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsPostBCAcceptedClientBuild(int build)
|
||||
{
|
||||
for (int i = 0; PostBcAcceptedClientBuilds[i].Build; ++i)
|
||||
if (PostBcAcceptedClientBuilds[i].Build == build)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAcceptedClientBuild(int build)
|
||||
{
|
||||
return (IsPostBCAcceptedClientBuild(build) || IsPreBCAcceptedClientBuild(build));
|
||||
}
|
||||
|
||||
RealmBuildInfo const* GetBuildInfo(int build)
|
||||
{
|
||||
for (int i = 0; PostBcAcceptedClientBuilds[i].Build; ++i)
|
||||
if (PostBcAcceptedClientBuilds[i].Build == build)
|
||||
return &PostBcAcceptedClientBuilds[i];
|
||||
|
||||
for (int i = 0; PreBcAcceptedClientBuilds[i].Build; ++i)
|
||||
if (PreBcAcceptedClientBuilds[i].Build == build)
|
||||
return &PreBcAcceptedClientBuilds[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _AUTHCODES_H
|
||||
#define _AUTHCODES_H
|
||||
|
||||
enum AuthResult
|
||||
{
|
||||
WOW_SUCCESS = 0x00,
|
||||
WOW_FAIL_BANNED = 0x03,
|
||||
WOW_FAIL_UNKNOWN_ACCOUNT = 0x04,
|
||||
WOW_FAIL_INCORRECT_PASSWORD = 0x05,
|
||||
WOW_FAIL_ALREADY_ONLINE = 0x06,
|
||||
WOW_FAIL_NO_TIME = 0x07,
|
||||
WOW_FAIL_DB_BUSY = 0x08,
|
||||
WOW_FAIL_VERSION_INVALID = 0x09,
|
||||
WOW_FAIL_VERSION_UPDATE = 0x0A,
|
||||
WOW_FAIL_INVALID_SERVER = 0x0B,
|
||||
WOW_FAIL_SUSPENDED = 0x0C,
|
||||
WOW_FAIL_FAIL_NOACCESS = 0x0D,
|
||||
WOW_SUCCESS_SURVEY = 0x0E,
|
||||
WOW_FAIL_PARENTCONTROL = 0x0F,
|
||||
WOW_FAIL_LOCKED_ENFORCED = 0x10,
|
||||
WOW_FAIL_TRIAL_ENDED = 0x11,
|
||||
WOW_FAIL_USE_BATTLENET = 0x12,
|
||||
WOW_FAIL_ANTI_INDULGENCE = 0x13,
|
||||
WOW_FAIL_EXPIRED = 0x14,
|
||||
WOW_FAIL_NO_GAME_ACCOUNT = 0x15,
|
||||
WOW_FAIL_CHARGEBACK = 0x16,
|
||||
WOW_FAIL_INTERNET_GAME_ROOM_WITHOUT_BNET = 0x17,
|
||||
WOW_FAIL_GAME_ACCOUNT_LOCKED = 0x18,
|
||||
WOW_FAIL_UNLOCKABLE_LOCK = 0x19,
|
||||
WOW_FAIL_CONVERSION_REQUIRED = 0x20,
|
||||
WOW_FAIL_DISCONNECTED = 0xFF
|
||||
};
|
||||
|
||||
enum LoginResult
|
||||
{
|
||||
LOGIN_OK = 0x00,
|
||||
LOGIN_FAILED = 0x01,
|
||||
LOGIN_FAILED2 = 0x02,
|
||||
LOGIN_BANNED = 0x03,
|
||||
LOGIN_UNKNOWN_ACCOUNT = 0x04,
|
||||
LOGIN_UNKNOWN_ACCOUNT3 = 0x05,
|
||||
LOGIN_ALREADYONLINE = 0x06,
|
||||
LOGIN_NOTIME = 0x07,
|
||||
LOGIN_DBBUSY = 0x08,
|
||||
LOGIN_BADVERSION = 0x09,
|
||||
LOGIN_DOWNLOAD_FILE = 0x0A,
|
||||
LOGIN_FAILED3 = 0x0B,
|
||||
LOGIN_SUSPENDED = 0x0C,
|
||||
LOGIN_FAILED4 = 0x0D,
|
||||
LOGIN_CONNECTED = 0x0E,
|
||||
LOGIN_PARENTALCONTROL = 0x0F,
|
||||
LOGIN_LOCKED_ENFORCED = 0x10
|
||||
};
|
||||
|
||||
enum ExpansionFlags
|
||||
{
|
||||
POST_BC_EXP_FLAG = 0x2,
|
||||
PRE_BC_EXP_FLAG = 0x1,
|
||||
NO_VALID_EXP_FLAG = 0x0
|
||||
};
|
||||
|
||||
struct RealmBuildInfo
|
||||
{
|
||||
int Build;
|
||||
int MajorVersion;
|
||||
int MinorVersion;
|
||||
int BugfixVersion;
|
||||
int HotfixVersion;
|
||||
};
|
||||
|
||||
namespace AuthHelper
|
||||
{
|
||||
RealmBuildInfo const* GetBuildInfo(int build);
|
||||
bool IsAcceptedClientBuild(int build);
|
||||
bool IsPostBCAcceptedClientBuild(int build);
|
||||
bool IsPreBCAcceptedClientBuild(int build);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
# Copyright (C)
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
########### authserver ###############
|
||||
|
||||
file(GLOB_RECURSE sources_authentication Authentication/*.cpp Authentication/*.h)
|
||||
file(GLOB_RECURSE sources_realms Realms/*.cpp Realms/*.h)
|
||||
file(GLOB_RECURSE sources_server Server/*.cpp Server/*.h)
|
||||
file(GLOB sources_localdir *.cpp *.h)
|
||||
|
||||
if (USE_COREPCH)
|
||||
set(authserver_PCH_HDR PrecompiledHeaders/authPCH.h)
|
||||
set(authserver_PCH_SRC PrecompiledHeaders/authPCH.cpp)
|
||||
endif()
|
||||
|
||||
set(authserver_SRCS
|
||||
${authserver_SRCS}
|
||||
${sources_authentication}
|
||||
${sources_realms}
|
||||
${sources_server}
|
||||
${sources_localdir}
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
set(authserver_SRCS
|
||||
${authserver_SRCS}
|
||||
${sources_windows_Debugging}
|
||||
)
|
||||
if ( MSVC )
|
||||
set(authserver_SRCS
|
||||
${authserver_SRCS}
|
||||
authserver.rc
|
||||
)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Database
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Debugging
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Packets
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Cryptography
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Cryptography/Authentication
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Logging
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Threading
|
||||
${CMAKE_SOURCE_DIR}/modules/acore/framework/Utilities
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Authentication
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Realms
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Server
|
||||
${ACE_INCLUDE_DIR}
|
||||
${MYSQL_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_executable(authserver
|
||||
${authserver_SRCS}
|
||||
${authserver_PCH_SRC}
|
||||
)
|
||||
|
||||
add_dependencies(authserver revision.h)
|
||||
|
||||
if( NOT WIN32 )
|
||||
set_target_properties(authserver PROPERTIES
|
||||
COMPILE_DEFINITIONS _TRINITY_REALM_CONFIG="${CONF_DIR}/authserver.conf"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(authserver
|
||||
shared
|
||||
${MYSQL_LIBRARY}
|
||||
${OPENSSL_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${ACE_LIBRARY}
|
||||
)
|
||||
|
||||
if( WIN32 )
|
||||
if ( MSVC )
|
||||
add_custom_command(TARGET authserver
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
|
||||
)
|
||||
elseif ( MINGW )
|
||||
add_custom_command(TARGET authserver
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( UNIX )
|
||||
install(TARGETS authserver DESTINATION bin)
|
||||
elseif( WIN32 )
|
||||
install(TARGETS authserver DESTINATION "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
|
||||
install(FILES authserver.conf.dist DESTINATION ${CONF_DIR})
|
||||
|
||||
# Generate precompiled header
|
||||
if (USE_COREPCH)
|
||||
add_cxx_pch(authserver ${authserver_PCH_HDR} ${authserver_PCH_SRC})
|
||||
endif()
|
||||
|
||||
CU_RUN_HOOK("AFTER_AUTHSERVER_CMAKE")
|
||||
@@ -1,354 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file main.cpp
|
||||
* @brief Authentication Server main program
|
||||
*
|
||||
* This file contains the main program for the
|
||||
* authentication server
|
||||
*/
|
||||
|
||||
#include <ace/Dev_Poll_Reactor.h>
|
||||
#include <ace/TP_Reactor.h>
|
||||
#include <ace/ACE.h>
|
||||
#include <ace/Sig_Handler.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Configuration/Config.h"
|
||||
#include "Log.h"
|
||||
#include "SystemConfig.h"
|
||||
#include "Util.h"
|
||||
#include "SignalHandler.h"
|
||||
#include "RealmList.h"
|
||||
#include "RealmAcceptor.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sched.h>
|
||||
#include <sys/resource.h>
|
||||
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
|
||||
#endif
|
||||
|
||||
#ifndef _TRINITY_REALM_CONFIG
|
||||
# define _TRINITY_REALM_CONFIG "authserver.conf"
|
||||
#endif
|
||||
|
||||
bool StartDB();
|
||||
void StopDB();
|
||||
|
||||
bool stopEvent = false; // Setting it to true stops the server
|
||||
|
||||
LoginDatabaseWorkerPool LoginDatabase; // Accessor to the authserver database
|
||||
|
||||
/// Handle authserver's termination signals
|
||||
class AuthServerSignalHandler : public Trinity::SignalHandler
|
||||
{
|
||||
public:
|
||||
virtual void HandleSignal(int sigNum)
|
||||
{
|
||||
switch (sigNum)
|
||||
{
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
stopEvent = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Print out the usage string for this program on the console.
|
||||
void usage(const char* prog)
|
||||
{
|
||||
sLog->outString("Usage: \n %s [<options>]\n"
|
||||
" -c config_file use config_file as configuration file\n\r",
|
||||
prog);
|
||||
}
|
||||
|
||||
/// Launch the auth server
|
||||
extern int main(int argc, char** argv)
|
||||
{
|
||||
// Command line parsing to get the configuration file name
|
||||
char const* configFile = _TRINITY_REALM_CONFIG;
|
||||
int count = 1;
|
||||
while (count < argc)
|
||||
{
|
||||
if (strcmp(argv[count], "-c") == 0)
|
||||
{
|
||||
if (++count >= argc)
|
||||
{
|
||||
printf("Runtime-Error: -c option requires an input argument\n");
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
configFile = argv[count];
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
std::string cfg_def_file=_TRINITY_REALM_CONFIG;
|
||||
cfg_def_file += ".dist";
|
||||
|
||||
if (!sConfigMgr->LoadInitial(cfg_def_file.c_str())) {
|
||||
printf("Invalid or missing default configuration file : %s\n", cfg_def_file.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!sConfigMgr->LoadMore(configFile))
|
||||
{
|
||||
printf("Invalid or missing configuration file : %s\n", configFile);
|
||||
printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sLog->outString("%s (authserver)", _FULLVERSION);
|
||||
sLog->outString("<Ctrl-C> to stop.\n");
|
||||
|
||||
sLog->outString(" █████╗ ███████╗███████╗██████╗ ██████╗ ████████╗██╗ ██╗");
|
||||
sLog->outString(" ██╔══██╗╚══███╔╝██╔════╝██╔══██╗██╔═══██╗╚══██╔══╝██║ ██║");
|
||||
sLog->outString(" ███████║ ███╔╝ █████╗ ██████╔╝██║ ██║ ██║ ███████║");
|
||||
sLog->outString(" ██╔══██║ ███╔╝ ██╔══╝ ██╔══██╗██║ ██║ ██║ ██╔══██║");
|
||||
sLog->outString(" ██║ ██║███████╗███████╗██║ ██║╚██████╔╝ ██║ ██║ ██║");
|
||||
sLog->outString(" ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝");
|
||||
sLog->outString(" ██████╗ ██████╗ ██████╗ ███████╗");
|
||||
sLog->outString(" ██╔════╝██╔═══██╗██╔══██╗██╔════╝");
|
||||
sLog->outString(" ██║ ██║ ██║██████╔╝█████╗");
|
||||
sLog->outString(" ██║ ██║ ██║██╔══██╗██╔══╝");
|
||||
sLog->outString(" ╚██████╗╚██████╔╝██║ ██║███████╗");
|
||||
sLog->outString(" ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝\n");
|
||||
|
||||
sLog->outString(" AzerothCore 3.3.5a - www.azerothcore.org\n");
|
||||
|
||||
sLog->outString("Using configuration file %s.", configFile);
|
||||
|
||||
sLog->outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
|
||||
|
||||
#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL)
|
||||
ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true);
|
||||
#else
|
||||
ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true);
|
||||
#endif
|
||||
|
||||
sLog->outBasic("Max allowed open files is %d", ACE::max_handles());
|
||||
|
||||
// authserver PID file creation
|
||||
std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
|
||||
if (!pidFile.empty())
|
||||
{
|
||||
if (uint32 pid = CreatePIDFile(pidFile))
|
||||
sLog->outError("Daemon PID: %u\n", pid);
|
||||
else
|
||||
{
|
||||
sLog->outError("Cannot create PID file %s.\n", pidFile.c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the database connection
|
||||
if (!StartDB())
|
||||
return 1;
|
||||
|
||||
// Initialize the log database
|
||||
sLog->SetLogDB(false);
|
||||
sLog->SetRealmID(0); // ensure we've set realm to 0 (authserver realmid)
|
||||
|
||||
// Get the list of realms for the server
|
||||
sRealmList->Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
|
||||
if (sRealmList->size() == 0)
|
||||
{
|
||||
sLog->outError("No valid realms specified.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Launch the listening network socket
|
||||
RealmAcceptor acceptor;
|
||||
|
||||
int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724);
|
||||
if (rmport < 0 || rmport > 0xFFFF)
|
||||
{
|
||||
sLog->outError("Specified port out of allowed range (1-65535)");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string bind_ip = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
|
||||
|
||||
ACE_INET_Addr bind_addr(uint16(rmport), bind_ip.c_str());
|
||||
|
||||
if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1)
|
||||
{
|
||||
sLog->outError("Auth server can not bind to %s:%d", bind_ip.c_str(), rmport);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize the signal handlers
|
||||
AuthServerSignalHandler SignalINT, SignalTERM;
|
||||
|
||||
// Register authservers's signal handlers
|
||||
ACE_Sig_Handler Handler;
|
||||
Handler.register_handler(SIGINT, &SignalINT);
|
||||
Handler.register_handler(SIGTERM, &SignalTERM);
|
||||
|
||||
#if defined(_WIN32) || defined(__linux__)
|
||||
|
||||
///- Handle affinity for multiple processors and process priority
|
||||
uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0);
|
||||
bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false);
|
||||
|
||||
#ifdef _WIN32 // Windows
|
||||
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
if (affinity > 0)
|
||||
{
|
||||
ULONG_PTR appAff;
|
||||
ULONG_PTR sysAff;
|
||||
|
||||
if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
|
||||
{
|
||||
// remove non accessible processors
|
||||
ULONG_PTR currentAffinity = affinity & appAff;
|
||||
|
||||
if (!currentAffinity)
|
||||
sLog->outError("server.authserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x", affinity, appAff);
|
||||
else if (SetProcessAffinityMask(hProcess, currentAffinity))
|
||||
sLog->outString("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity);
|
||||
else
|
||||
sLog->outError("server.authserver", "Can't set used processors (hex): %x", currentAffinity);
|
||||
}
|
||||
}
|
||||
|
||||
if (highPriority)
|
||||
{
|
||||
if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
|
||||
sLog->outString("server.authserver", "authserver process priority class set to HIGH");
|
||||
else
|
||||
sLog->outError("server.authserver", "Can't set authserver process priority class.");
|
||||
}
|
||||
|
||||
#else // Linux
|
||||
|
||||
if (affinity > 0)
|
||||
{
|
||||
cpu_set_t mask;
|
||||
CPU_ZERO(&mask);
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i)
|
||||
if (affinity & (1 << i))
|
||||
CPU_SET(i, &mask);
|
||||
|
||||
if (sched_setaffinity(0, sizeof(mask), &mask))
|
||||
sLog->outError("server.authserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
|
||||
else
|
||||
{
|
||||
CPU_ZERO(&mask);
|
||||
sched_getaffinity(0, sizeof(mask), &mask);
|
||||
sLog->outString("server.authserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
|
||||
}
|
||||
}
|
||||
|
||||
if (highPriority)
|
||||
{
|
||||
if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
|
||||
sLog->outError("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno));
|
||||
else
|
||||
sLog->outString("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0));
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// maximum counter for next ping
|
||||
uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000));
|
||||
uint32 loopCounter = 0;
|
||||
|
||||
// possibly enable db logging; avoid massive startup spam by doing it here.
|
||||
if (sConfigMgr->GetBoolDefault("EnableLogDB", false))
|
||||
{
|
||||
sLog->outString("Enabling database logging...");
|
||||
sLog->SetLogDB(true);
|
||||
}
|
||||
|
||||
// Wait for termination signal
|
||||
while (!stopEvent)
|
||||
{
|
||||
// dont move this outside the loop, the reactor will modify it
|
||||
ACE_Time_Value interval(0, 100000);
|
||||
|
||||
if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1)
|
||||
break;
|
||||
|
||||
if ((++loopCounter) == numLoops)
|
||||
{
|
||||
loopCounter = 0;
|
||||
sLog->outDetail("Ping MySQL to keep connection alive");
|
||||
LoginDatabase.KeepAlive();
|
||||
}
|
||||
}
|
||||
|
||||
// Close the Database Pool and library
|
||||
StopDB();
|
||||
|
||||
sLog->outString("Halting process...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Initialize connection to the database
|
||||
bool StartDB()
|
||||
{
|
||||
MySQL::Library_Init();
|
||||
|
||||
std::string dbstring = sConfigMgr->GetStringDefault("LoginDatabaseInfo", "");
|
||||
if (dbstring.empty())
|
||||
{
|
||||
sLog->outError("Database not specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 worker_threads = sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1);
|
||||
if (worker_threads < 1 || worker_threads > 32)
|
||||
{
|
||||
sLog->outError("Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1.");
|
||||
worker_threads = 1;
|
||||
}
|
||||
|
||||
int32 synch_threads = sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1);
|
||||
if (synch_threads < 1 || synch_threads > 32)
|
||||
{
|
||||
sLog->outError("Improper value specified for LoginDatabase.SynchThreads, defaulting to 1.");
|
||||
synch_threads = 1;
|
||||
}
|
||||
|
||||
// NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever.
|
||||
if (!LoginDatabase.Open(dbstring.c_str(), uint8(worker_threads), uint8(synch_threads)))
|
||||
{
|
||||
sLog->outError("Cannot connect to database");
|
||||
return false;
|
||||
}
|
||||
|
||||
sLog->outString("Started auth database connection pool.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Close the connection to the database
|
||||
void StopDB()
|
||||
{
|
||||
LoginDatabase.Close();
|
||||
MySQL::Library_End();
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include "authPCH.h"
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "Configuration/Config.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "RealmList.h"
|
||||
#include "RealmSocket.h"
|
||||
#include "Common.h"
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "RealmList.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
|
||||
RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { }
|
||||
|
||||
// Load the realm list from the database
|
||||
void RealmList::Initialize(uint32 updateInterval)
|
||||
{
|
||||
m_UpdateInterval = updateInterval;
|
||||
|
||||
// Get the content of the realmlist table in the database
|
||||
UpdateRealms(true);
|
||||
}
|
||||
|
||||
void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build)
|
||||
{
|
||||
// Create new if not exist or update existed
|
||||
Realm& realm = m_realms[name];
|
||||
|
||||
realm.m_ID = id;
|
||||
realm.name = name;
|
||||
realm.icon = icon;
|
||||
realm.flag = flag;
|
||||
realm.timezone = timezone;
|
||||
realm.allowedSecurityLevel = allowedSecurityLevel;
|
||||
realm.populationLevel = popu;
|
||||
|
||||
// Append port to IP address.
|
||||
realm.ExternalAddress = address;
|
||||
realm.LocalAddress = localAddr;
|
||||
realm.LocalSubnetMask = localSubmask;
|
||||
realm.gamebuild = build;
|
||||
}
|
||||
|
||||
void RealmList::UpdateIfNeed()
|
||||
{
|
||||
// maybe disabled or updated recently
|
||||
if (!m_UpdateInterval || m_NextUpdateTime > time(NULL))
|
||||
return;
|
||||
|
||||
m_NextUpdateTime = time(NULL) + m_UpdateInterval;
|
||||
|
||||
// Clears Realm list
|
||||
m_realms.clear();
|
||||
|
||||
// Get the content of the realmlist table in the database
|
||||
UpdateRealms();
|
||||
}
|
||||
|
||||
void RealmList::UpdateRealms(bool init)
|
||||
{
|
||||
sLog->outString("Updating Realm List...");
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
// Circle through results and add them to the realm map
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 realmId = fields[0].GetUInt32();
|
||||
std::string name = fields[1].GetString();
|
||||
std::string externalAddress = fields[2].GetString();
|
||||
std::string localAddress = fields[3].GetString();
|
||||
std::string localSubmask = fields[4].GetString();
|
||||
uint16 port = fields[5].GetUInt16();
|
||||
uint8 icon = fields[6].GetUInt8();
|
||||
RealmFlags flag = RealmFlags(fields[7].GetUInt8());
|
||||
uint8 timezone = fields[8].GetUInt8();
|
||||
uint8 allowedSecurityLevel = fields[9].GetUInt8();
|
||||
float pop = fields[10].GetFloat();
|
||||
uint32 build = fields[11].GetUInt32();
|
||||
|
||||
ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET);
|
||||
ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET);
|
||||
ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET);
|
||||
|
||||
UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build);
|
||||
|
||||
if (init)
|
||||
sLog->outString("Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _REALMLIST_H
|
||||
#define _REALMLIST_H
|
||||
|
||||
#include <ace/Singleton.h>
|
||||
#include <ace/Null_Mutex.h>
|
||||
#include <ace/INET_Addr.h>
|
||||
#include "Common.h"
|
||||
|
||||
enum RealmFlags
|
||||
{
|
||||
REALM_FLAG_NONE = 0x00,
|
||||
REALM_FLAG_INVALID = 0x01,
|
||||
REALM_FLAG_OFFLINE = 0x02,
|
||||
REALM_FLAG_SPECIFYBUILD = 0x04,
|
||||
REALM_FLAG_UNK1 = 0x08,
|
||||
REALM_FLAG_UNK2 = 0x10,
|
||||
REALM_FLAG_RECOMMENDED = 0x20,
|
||||
REALM_FLAG_NEW = 0x40,
|
||||
REALM_FLAG_FULL = 0x80
|
||||
};
|
||||
|
||||
// Storage object for a realm
|
||||
struct Realm
|
||||
{
|
||||
ACE_INET_Addr ExternalAddress;
|
||||
ACE_INET_Addr LocalAddress;
|
||||
ACE_INET_Addr LocalSubnetMask;
|
||||
std::string name;
|
||||
uint8 icon;
|
||||
RealmFlags flag;
|
||||
uint8 timezone;
|
||||
uint32 m_ID;
|
||||
AccountTypes allowedSecurityLevel;
|
||||
float populationLevel;
|
||||
uint32 gamebuild;
|
||||
};
|
||||
|
||||
/// Storage object for the list of realms on the server
|
||||
class RealmList
|
||||
{
|
||||
public:
|
||||
typedef std::map<std::string, Realm> RealmMap;
|
||||
|
||||
RealmList();
|
||||
~RealmList() { }
|
||||
|
||||
void Initialize(uint32 updateInterval);
|
||||
|
||||
void UpdateIfNeed();
|
||||
|
||||
void AddRealm(const Realm& NewRealm) { m_realms[NewRealm.name] = NewRealm; }
|
||||
|
||||
RealmMap::const_iterator begin() const { return m_realms.begin(); }
|
||||
RealmMap::const_iterator end() const { return m_realms.end(); }
|
||||
uint32 size() const { return m_realms.size(); }
|
||||
|
||||
private:
|
||||
void UpdateRealms(bool init=false);
|
||||
void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build);
|
||||
|
||||
RealmMap m_realms;
|
||||
uint32 m_UpdateInterval;
|
||||
time_t m_NextUpdateTime;
|
||||
};
|
||||
|
||||
#define sRealmList ACE_Singleton<RealmList, ACE_Null_Mutex>::instance()
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _AUTHSOCKET_H
|
||||
#define _AUTHSOCKET_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "BigNumber.h"
|
||||
#include "RealmSocket.h"
|
||||
|
||||
class ACE_INET_Addr;
|
||||
struct Realm;
|
||||
|
||||
// Handle login commands
|
||||
class AuthSocket: public RealmSocket::Session
|
||||
{
|
||||
public:
|
||||
const static int s_BYTE_SIZE = 32;
|
||||
|
||||
AuthSocket(RealmSocket& socket);
|
||||
virtual ~AuthSocket(void);
|
||||
|
||||
virtual void OnRead(void);
|
||||
virtual void OnAccept(void);
|
||||
virtual void OnClose(void);
|
||||
|
||||
static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr);
|
||||
|
||||
bool _HandleLogonChallenge();
|
||||
bool _HandleLogonProof();
|
||||
bool _HandleReconnectChallenge();
|
||||
bool _HandleReconnectProof();
|
||||
bool _HandleRealmList();
|
||||
|
||||
//data transfer handle for patch
|
||||
bool _HandleXferResume();
|
||||
bool _HandleXferCancel();
|
||||
bool _HandleXferAccept();
|
||||
|
||||
void _SetVSFields(const std::string& rI);
|
||||
|
||||
FILE* pPatch;
|
||||
ACE_Thread_Mutex patcherLock;
|
||||
|
||||
private:
|
||||
RealmSocket& socket_;
|
||||
RealmSocket& socket(void) { return socket_; }
|
||||
|
||||
BigNumber N, s, g, v;
|
||||
BigNumber b, B;
|
||||
BigNumber K;
|
||||
BigNumber _reconnectProof;
|
||||
|
||||
bool _authed;
|
||||
|
||||
std::string _login;
|
||||
|
||||
// Since GetLocaleByName() is _NOT_ bijective, we have to store the locale as a string. Otherwise we can't differ
|
||||
// between enUS and enGB, which is important for the patch system
|
||||
std::string _localizationName;
|
||||
std::string _os;
|
||||
uint16 _build;
|
||||
uint8 _expversion;
|
||||
AccountTypes _accountSecurityLevel;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __REALMACCEPTOR_H__
|
||||
#define __REALMACCEPTOR_H__
|
||||
|
||||
#include <ace/Acceptor.h>
|
||||
#include <ace/SOCK_Acceptor.h>
|
||||
|
||||
#include "RealmSocket.h"
|
||||
#include "AuthSocket.h"
|
||||
|
||||
class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor>
|
||||
{
|
||||
public:
|
||||
RealmAcceptor(void) { }
|
||||
virtual ~RealmAcceptor(void)
|
||||
{
|
||||
if (reactor())
|
||||
reactor()->cancel_timer(this, 1);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int make_svc_handler(RealmSocket* &sh)
|
||||
{
|
||||
if (sh == 0)
|
||||
ACE_NEW_RETURN(sh, RealmSocket, -1);
|
||||
|
||||
sh->reactor(reactor());
|
||||
sh->set_session(new AuthSocket(*sh));
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int handle_timeout(const ACE_Time_Value& /*current_time*/, const void* /*act = 0*/)
|
||||
{
|
||||
sLog->outBasic("Resuming acceptor");
|
||||
reactor()->cancel_timer(this, 1);
|
||||
return reactor()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK);
|
||||
}
|
||||
|
||||
virtual int handle_accept_error(void)
|
||||
{
|
||||
#if defined(ENFILE) && defined(EMFILE)
|
||||
if (errno == ENFILE || errno == EMFILE)
|
||||
{
|
||||
sLog->outError("Out of file descriptors, suspending incoming connections for 10 seconds");
|
||||
reactor()->remove_handler(this, ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL);
|
||||
reactor()->schedule_timer(this, NULL, ACE_Time_Value(10));
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,291 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ace/OS_NS_string.h>
|
||||
#include <ace/INET_Addr.h>
|
||||
#include <ace/SString.h>
|
||||
|
||||
#include "RealmSocket.h"
|
||||
#include "Log.h"
|
||||
|
||||
RealmSocket::Session::Session(void) { }
|
||||
|
||||
RealmSocket::Session::~Session(void) { }
|
||||
|
||||
RealmSocket::RealmSocket(void) :
|
||||
input_buffer_(4096), session_(NULL),
|
||||
_remoteAddress(), _remotePort(0)
|
||||
{
|
||||
reference_counting_policy().value(ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
|
||||
|
||||
msg_queue()->high_water_mark(8 * 1024 * 1024);
|
||||
msg_queue()->low_water_mark(8 * 1024 * 1024);
|
||||
}
|
||||
|
||||
RealmSocket::~RealmSocket(void)
|
||||
{
|
||||
if (msg_queue())
|
||||
msg_queue()->close();
|
||||
|
||||
// delete RealmSocketObject must never be called from our code.
|
||||
closing_ = true;
|
||||
|
||||
delete session_;
|
||||
|
||||
peer().close();
|
||||
}
|
||||
|
||||
int RealmSocket::open(void * arg)
|
||||
{
|
||||
ACE_INET_Addr addr;
|
||||
|
||||
if (peer().get_remote_addr(addr) == -1)
|
||||
{
|
||||
sLog->outError("Error %s while opening realm socket!", ACE_OS::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
_remoteAddress = addr.get_host_addr();
|
||||
_remotePort = addr.get_port_number();
|
||||
|
||||
// Register with ACE Reactor
|
||||
if (Base::open(arg) == -1)
|
||||
return -1;
|
||||
|
||||
if (session_)
|
||||
session_->OnAccept();
|
||||
|
||||
// reactor takes care of the socket from now on
|
||||
remove_reference();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RealmSocket::close(u_long)
|
||||
{
|
||||
shutdown();
|
||||
|
||||
closing_ = true;
|
||||
|
||||
remove_reference();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string& RealmSocket::getRemoteAddress(void) const
|
||||
{
|
||||
return _remoteAddress;
|
||||
}
|
||||
|
||||
uint16 RealmSocket::getRemotePort(void) const
|
||||
{
|
||||
return _remotePort;
|
||||
}
|
||||
|
||||
size_t RealmSocket::recv_len(void) const
|
||||
{
|
||||
return input_buffer_.length();
|
||||
}
|
||||
|
||||
bool RealmSocket::recv_soft(char *buf, size_t len)
|
||||
{
|
||||
if (input_buffer_.length() < len)
|
||||
return false;
|
||||
|
||||
ACE_OS::memcpy(buf, input_buffer_.rd_ptr(), len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RealmSocket::recv(char *buf, size_t len)
|
||||
{
|
||||
bool ret = recv_soft(buf, len);
|
||||
|
||||
if (ret)
|
||||
recv_skip(len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RealmSocket::recv_skip(size_t len)
|
||||
{
|
||||
input_buffer_.rd_ptr(len);
|
||||
}
|
||||
|
||||
ssize_t RealmSocket::noblk_send(ACE_Message_Block &message_block)
|
||||
{
|
||||
const size_t len = message_block.length();
|
||||
|
||||
if (len == 0)
|
||||
return -1;
|
||||
|
||||
// Try to send the message directly.
|
||||
#ifdef MSG_NOSIGNAL
|
||||
ssize_t n = peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL);
|
||||
#else
|
||||
ssize_t n = peer().send(message_block.rd_ptr(), len);
|
||||
#endif // MSG_NOSIGNAL
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
if (errno == EWOULDBLOCK) // Blocking signal
|
||||
return 0;
|
||||
else // Error happened
|
||||
return -1;
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
// Can this happen ?
|
||||
return -1;
|
||||
}
|
||||
|
||||
// return bytes transmitted
|
||||
return n;
|
||||
}
|
||||
|
||||
bool RealmSocket::send(const char *buf, size_t len)
|
||||
{
|
||||
if (buf == NULL || len == 0)
|
||||
return true;
|
||||
|
||||
ACE_Data_Block db(len, ACE_Message_Block::MB_DATA, (const char*)buf, 0, 0, ACE_Message_Block::DONT_DELETE, 0);
|
||||
ACE_Message_Block message_block(&db, ACE_Message_Block::DONT_DELETE, 0);
|
||||
|
||||
message_block.wr_ptr(len);
|
||||
|
||||
if (msg_queue()->is_empty())
|
||||
{
|
||||
// Try to send it directly.
|
||||
ssize_t n = noblk_send(message_block);
|
||||
|
||||
if (n < 0)
|
||||
return false;
|
||||
|
||||
size_t un = size_t(n);
|
||||
if (un == len)
|
||||
return true;
|
||||
|
||||
// fall down
|
||||
message_block.rd_ptr(un);
|
||||
}
|
||||
|
||||
ACE_Message_Block* mb = message_block.clone();
|
||||
|
||||
if (msg_queue()->enqueue_tail(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1)
|
||||
{
|
||||
mb->release();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int RealmSocket::handle_output(ACE_HANDLE)
|
||||
{
|
||||
if (closing_)
|
||||
return -1;
|
||||
|
||||
ACE_Message_Block* mb = 0;
|
||||
|
||||
if (msg_queue()->is_empty())
|
||||
{
|
||||
reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (msg_queue()->dequeue_head(mb, (ACE_Time_Value *)(&ACE_Time_Value::zero)) == -1)
|
||||
return -1;
|
||||
|
||||
ssize_t n = noblk_send(*mb);
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
mb->release();
|
||||
return -1;
|
||||
}
|
||||
else if (size_t(n) == mb->length())
|
||||
{
|
||||
mb->release();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mb->rd_ptr(n);
|
||||
|
||||
if (msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
|
||||
{
|
||||
mb->release();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ACE_NOTREACHED(return -1);
|
||||
}
|
||||
|
||||
int RealmSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask)
|
||||
{
|
||||
// As opposed to WorldSocket::handle_close, we don't need locks here.
|
||||
closing_ = true;
|
||||
|
||||
if (h == ACE_INVALID_HANDLE)
|
||||
peer().close_writer();
|
||||
|
||||
if (session_)
|
||||
session_->OnClose();
|
||||
|
||||
reactor()->remove_handler(this, ACE_Event_Handler::DONT_CALL | ACE_Event_Handler::ALL_EVENTS_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RealmSocket::handle_input(ACE_HANDLE)
|
||||
{
|
||||
if (closing_)
|
||||
return -1;
|
||||
|
||||
const ssize_t space = input_buffer_.space();
|
||||
|
||||
ssize_t n = peer().recv(input_buffer_.wr_ptr(), space);
|
||||
|
||||
if (n < 0)
|
||||
return errno == EWOULDBLOCK ? 0 : -1;
|
||||
else if (n == 0) // EOF
|
||||
return -1;
|
||||
|
||||
input_buffer_.wr_ptr((size_t)n);
|
||||
|
||||
if (session_ != NULL)
|
||||
{
|
||||
session_->OnRead();
|
||||
input_buffer_.crunch();
|
||||
}
|
||||
|
||||
// return 1 in case there is more data to read from OS
|
||||
return n == space ? 1 : 0;
|
||||
}
|
||||
|
||||
void RealmSocket::set_session(Session* session)
|
||||
{
|
||||
delete session_;
|
||||
|
||||
session_ = session;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __REALMSOCKET_H__
|
||||
#define __REALMSOCKET_H__
|
||||
|
||||
#include <ace/Synch_Traits.h>
|
||||
#include <ace/Svc_Handler.h>
|
||||
#include <ace/SOCK_Stream.h>
|
||||
#include <ace/Message_Block.h>
|
||||
#include <ace/Basic_Types.h>
|
||||
#include "Common.h"
|
||||
|
||||
class RealmSocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
|
||||
{
|
||||
private:
|
||||
typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> Base;
|
||||
|
||||
public:
|
||||
class Session
|
||||
{
|
||||
public:
|
||||
Session(void);
|
||||
virtual ~Session(void);
|
||||
|
||||
virtual void OnRead(void) = 0;
|
||||
virtual void OnAccept(void) = 0;
|
||||
virtual void OnClose(void) = 0;
|
||||
};
|
||||
|
||||
RealmSocket(void);
|
||||
virtual ~RealmSocket(void);
|
||||
|
||||
size_t recv_len(void) const;
|
||||
bool recv_soft(char *buf, size_t len);
|
||||
bool recv(char *buf, size_t len);
|
||||
void recv_skip(size_t len);
|
||||
|
||||
bool send(const char *buf, size_t len);
|
||||
|
||||
const std::string& getRemoteAddress(void) const;
|
||||
|
||||
uint16 getRemotePort(void) const;
|
||||
|
||||
virtual int open(void *);
|
||||
|
||||
virtual int close(u_long);
|
||||
|
||||
virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE);
|
||||
virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE);
|
||||
|
||||
virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK);
|
||||
|
||||
void set_session(Session* session);
|
||||
|
||||
private:
|
||||
ssize_t noblk_send(ACE_Message_Block &message_block);
|
||||
|
||||
ACE_Message_Block input_buffer_;
|
||||
Session* session_;
|
||||
std::string _remoteAddress;
|
||||
uint16 _remotePort;
|
||||
};
|
||||
|
||||
#endif /* __REALMSOCKET_H__ */
|
||||
Binary file not shown.
@@ -1,260 +0,0 @@
|
||||
###############################################
|
||||
# Trinity Core Auth Server configuration file #
|
||||
###############################################
|
||||
[authserver]
|
||||
|
||||
###################################################################################################
|
||||
# SECTION INDEX
|
||||
#
|
||||
# EXAMPLE CONFIG
|
||||
# AUTH SERVER SETTINGS
|
||||
# MYSQL SETTINGS
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
###################################################################################################
|
||||
# EXAMPLE CONFIG
|
||||
#
|
||||
# Variable
|
||||
# Description: Brief description what the variable is doing.
|
||||
# Important: Annotation for important things about this variable.
|
||||
# Example: "Example, i.e. if the value is a string"
|
||||
# Default: 10 - (Enabled|Comment|Variable name in case of grouped config options)
|
||||
# 0 - (Disabled|Comment|Variable name in case of grouped config options)
|
||||
#
|
||||
# Note to developers:
|
||||
# - Copy this example to keep the formatting.
|
||||
# - Line breaks should be at column 100.
|
||||
###################################################################################################
|
||||
|
||||
###################################################################################################
|
||||
# AUTH SERVER SETTINGS
|
||||
#
|
||||
# LogsDir
|
||||
# Description: Logs directory setting.
|
||||
# Important: LogsDir needs to be quoted, as the string might contain space characters.
|
||||
# Logs directory must exists, or log file creation will be disabled.
|
||||
# Default: "" - (Log files will be stored in the current path)
|
||||
|
||||
LogsDir = ""
|
||||
|
||||
#
|
||||
# MaxPingTime
|
||||
# Description: Time (in minutes) between database pings.
|
||||
# Default: 30
|
||||
|
||||
MaxPingTime = 30
|
||||
|
||||
#
|
||||
# RealmServerPort
|
||||
# Description: TCP port to reach the auth server.
|
||||
# Default: 3724
|
||||
|
||||
RealmServerPort = 3724
|
||||
|
||||
#
|
||||
#
|
||||
# BindIP
|
||||
# Description: Bind auth server to IP/hostname
|
||||
# Default: "0.0.0.0" - (Bind to all IPs on the system)
|
||||
|
||||
BindIP = "0.0.0.0"
|
||||
|
||||
#
|
||||
# PidFile
|
||||
# Description: Auth server PID file.
|
||||
# Example: "./authserver.pid" - (Enabled)
|
||||
# Default: "" - (Disabled)
|
||||
|
||||
PidFile = ""
|
||||
|
||||
#
|
||||
# LogLevel
|
||||
# Description: Server console level of logging
|
||||
# Default: 0 - (Minimum)
|
||||
# 1 - (Basic)
|
||||
# 2 - (Detail)
|
||||
# 3 - (Full/Debug)
|
||||
|
||||
LogLevel = 0
|
||||
|
||||
#
|
||||
# LogFile
|
||||
# Description: Log file for main server log.
|
||||
# Default: "Auth.log" - (Enabled)
|
||||
# "" - (Disabled)
|
||||
|
||||
LogFile = "Auth.log"
|
||||
|
||||
#
|
||||
# Debug Log Mask
|
||||
# Description: Bitmask that determines which debug log output (level 3)
|
||||
# will be logged.
|
||||
# Possible flags:
|
||||
#
|
||||
# 64 - Anything related to network input/output,
|
||||
# such as packet handlers and netcode logs
|
||||
#
|
||||
# Simply add the values together to create a bitmask.
|
||||
# For more info see enum DebugLogFilters in Log.h
|
||||
#
|
||||
# Default: 0 (nothing)
|
||||
|
||||
DebugLogMask = 64
|
||||
|
||||
#
|
||||
# SQLDriverLogFile
|
||||
# Description: Log file for SQL driver events.
|
||||
# Example: "SQLDriver.log" - (Enabled)
|
||||
# Default: "" - (Disabled)
|
||||
|
||||
SQLDriverLogFile = ""
|
||||
|
||||
#
|
||||
# SQLDriverQueryLogging
|
||||
# Description: Log SQL queries to the SQLDriverLogFile and console.
|
||||
# Default: 0 - (Disabled, Query errors only)
|
||||
# 1 - (Enabled, Full query logging - may have performance impact)
|
||||
|
||||
SQLDriverQueryLogging = 0
|
||||
|
||||
#
|
||||
# LogTimestamp
|
||||
# Description: Append timestamp to the server log file name.
|
||||
# Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
|
||||
# Default: 0 - (Disabled)
|
||||
# 1 - (Enabled)
|
||||
|
||||
LogTimestamp = 0
|
||||
|
||||
#
|
||||
# LogFileLevel
|
||||
# Description: Server file level of logging
|
||||
# Default: 0 - (Minimum)
|
||||
# 1 - (Basic)
|
||||
# 2 - (Detail)
|
||||
# 3 - (Full/Debug)
|
||||
|
||||
LogFileLevel = 0
|
||||
|
||||
#
|
||||
# LogColors
|
||||
# Description: Colors for log messages (Format: "normal basic detail debug").
|
||||
# Colors: 0 - Black
|
||||
# 1 - Red
|
||||
# 2 - Green
|
||||
# 3 - Brown
|
||||
# 4 - Blue
|
||||
# 5 - Magenta
|
||||
# 6 - Cyan
|
||||
# 7 - Grey
|
||||
# 8 - Yellow
|
||||
# 9 - Lred
|
||||
# 10 - Lgreen
|
||||
# 11 - Lblue
|
||||
# 12 - Lmagenta
|
||||
# 13 - Lcyan
|
||||
# 14 - White
|
||||
# Example: "13 11 9 5" - (Enabled)
|
||||
# Default: "" - (Disabled)
|
||||
|
||||
LogColors = ""
|
||||
|
||||
#
|
||||
# EnableLogDB
|
||||
# Description: Write log messages to database (LogDatabaseInfo).
|
||||
# Default: 0 - (Disabled)
|
||||
# 1 - (Enabled)
|
||||
|
||||
EnableLogDB = 0
|
||||
|
||||
#
|
||||
# DBLogLevel
|
||||
# Description: Log level of databases logging.
|
||||
# Default: 1 - (Basic)
|
||||
# 0 - (Minimum)
|
||||
# 2 - (Detail)
|
||||
# 3 - (Full/Debug)
|
||||
|
||||
DBLogLevel = 1
|
||||
|
||||
#
|
||||
# UseProcessors
|
||||
# Description: Processors mask for Windows and Linux based multi-processor systems.
|
||||
# Example: A computer with 2 CPUs:
|
||||
# 1 - 1st CPU only, 2 - 2nd CPU only, 3 - 1st and 2nd CPU, because 1 | 2 is 3
|
||||
# Default: 0 - (Selected by OS)
|
||||
# 1+ - (Bit mask value of selected processors)
|
||||
|
||||
UseProcessors = 0
|
||||
|
||||
#
|
||||
# ProcessPriority
|
||||
# Description: Process priority setting for Windows and Linux based systems.
|
||||
# Details: On Linux, a nice value of -15 is used. (requires superuser). On Windows, process is set to HIGH class.
|
||||
# Default: 0 - (Normal)
|
||||
# 1 - (High)
|
||||
|
||||
ProcessPriority = 0
|
||||
|
||||
#
|
||||
# RealmsStateUpdateDelay
|
||||
# Description: Time (in seconds) between realm list updates.
|
||||
# Default: 20 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
|
||||
RealmsStateUpdateDelay = 20
|
||||
|
||||
#
|
||||
# WrongPass.MaxCount
|
||||
# Description: Number of login attemps with wrong password before the account or IP will be
|
||||
# banned.
|
||||
# Default: 0 - (Disabled)
|
||||
# 1+ - (Enabled)
|
||||
|
||||
WrongPass.MaxCount = 0
|
||||
|
||||
#
|
||||
# WrongPass.BanTime
|
||||
# Description: Time (in seconds) for banning account or IP for invalid login attempts.
|
||||
# Default: 600 - (10 minutes)
|
||||
# 0 - (Permanent ban)
|
||||
|
||||
WrongPass.BanTime = 600
|
||||
|
||||
#
|
||||
# WrongPass.BanType
|
||||
# Description: Ban type for invalid login attempts.
|
||||
# Default: 0 - (Ban IP)
|
||||
# 1 - (Ban Account)
|
||||
|
||||
WrongPass.BanType = 0
|
||||
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
###################################################################################################
|
||||
# MYSQL SETTINGS
|
||||
#
|
||||
# LoginDatabaseInfo
|
||||
# Description: Database connection settings for the realm server.
|
||||
# Example: "hostname;port;username;password;database"
|
||||
# ".;somenumber;username;password;database" - (Use named pipes on Windows
|
||||
# "enable-named-pipe" to [mysqld]
|
||||
# section my.ini)
|
||||
# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on
|
||||
# Unix/Linux)
|
||||
# Default: "127.0.0.1;3306;root;root;auth"
|
||||
|
||||
LoginDatabaseInfo = "127.0.0.1;3306;root;root;auth"
|
||||
|
||||
#
|
||||
# LoginDatabase.WorkerThreads
|
||||
# Description: The amount of worker threads spawned to handle asynchronous (delayed) MySQL
|
||||
# statements. Each worker thread is mirrored with its own connection to the
|
||||
# Default: 1
|
||||
|
||||
LoginDatabase.WorkerThreads = 1
|
||||
|
||||
#
|
||||
###################################################################################################
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 133 KiB |
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "resource.h"
|
||||
#include "revision.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "windows.h" //"afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
IDI_APPICON ICON "authserver.ico"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Neutre (Par défaut système) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
PRODUCTVERSION VER_PRODUCTVERSION
|
||||
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
|
||||
#ifndef _DEBUG
|
||||
FILEFLAGS 0
|
||||
#else
|
||||
#define VER_PRERELEASE VS_FF_PRERELEASE
|
||||
#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
|
||||
#define VER_DEBUG 0
|
||||
FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG)
|
||||
#endif
|
||||
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080004b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VER_COMPANYNAME_STR
|
||||
VALUE "FileDescription", "Authentication Server Daemon"
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "InternalName", "authserver"
|
||||
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
|
||||
VALUE "OriginalFilename", "authserver.exe"
|
||||
VALUE "ProductName", "Authentication Server"
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x800, 1200
|
||||
END
|
||||
END
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by SunwellCore.rc
|
||||
//
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,323 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CombatAI.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Vehicle.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
|
||||
/////////////////
|
||||
// AggressorAI
|
||||
/////////////////
|
||||
|
||||
int AggressorAI::Permissible(const Creature* creature)
|
||||
{
|
||||
// have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
|
||||
if (!creature->IsCivilian() && !creature->IsNeutralToAll())
|
||||
return PERMIT_BASE_PROACTIVE;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
void AggressorAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// CombatAI
|
||||
/////////////////
|
||||
|
||||
void CombatAI::InitializeAI()
|
||||
{
|
||||
for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
if (me->m_spells[i] && sSpellMgr->GetSpellInfo(me->m_spells[i]))
|
||||
spells.push_back(me->m_spells[i]);
|
||||
|
||||
CreatureAI::InitializeAI();
|
||||
}
|
||||
|
||||
void CombatAI::Reset()
|
||||
{
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void CombatAI::JustDied(Unit* killer)
|
||||
{
|
||||
for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
|
||||
if (AISpellInfo[*i].condition == AICOND_DIE)
|
||||
me->CastSpell(killer, *i, true);
|
||||
}
|
||||
|
||||
void CombatAI::EnterCombat(Unit* who)
|
||||
{
|
||||
for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
|
||||
{
|
||||
if (AISpellInfo[*i].condition == AICOND_AGGRO)
|
||||
me->CastSpell(who, *i, false);
|
||||
else if (AISpellInfo[*i].condition == AICOND_COMBAT)
|
||||
events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown);
|
||||
}
|
||||
}
|
||||
|
||||
void CombatAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (uint32 spellId = events.ExecuteEvent())
|
||||
{
|
||||
DoCast(spellId);
|
||||
events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown);
|
||||
}
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// CasterAI
|
||||
/////////////////
|
||||
|
||||
void CasterAI::InitializeAI()
|
||||
{
|
||||
CombatAI::InitializeAI();
|
||||
|
||||
m_attackDist = 30.0f;
|
||||
for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr)
|
||||
if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange)
|
||||
m_attackDist = GetAISpellInfo(*itr)->maxRange;
|
||||
if (m_attackDist == 30.0f)
|
||||
m_attackDist = MELEE_RANGE;
|
||||
}
|
||||
|
||||
void CasterAI::EnterCombat(Unit* who)
|
||||
{
|
||||
if (spells.empty())
|
||||
return;
|
||||
|
||||
uint32 spell = rand()%spells.size();
|
||||
uint32 count = 0;
|
||||
for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count)
|
||||
{
|
||||
if (AISpellInfo[*itr].condition == AICOND_AGGRO)
|
||||
me->CastSpell(who, *itr, false);
|
||||
else if (AISpellInfo[*itr].condition == AICOND_COMBAT)
|
||||
{
|
||||
uint32 cooldown = GetAISpellInfo(*itr)->realCooldown;
|
||||
if (count == spell)
|
||||
{
|
||||
DoCast(spells[spell]);
|
||||
cooldown += me->GetCurrentSpellCastTime(*itr);
|
||||
}
|
||||
events.ScheduleEvent(*itr, cooldown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CasterAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->GetVictim()->HasBreakableByDamageCrowdControlAura(me))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (uint32 spellId = events.ExecuteEvent())
|
||||
{
|
||||
DoCast(spellId);
|
||||
uint32 casttime = me->GetCurrentSpellCastTime(spellId);
|
||||
events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////
|
||||
// ArcherAI
|
||||
//////////////
|
||||
|
||||
ArcherAI::ArcherAI(Creature* c) : CreatureAI(c)
|
||||
{
|
||||
if (!me->m_spells[0])
|
||||
sLog->outError("ArcherAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry());
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0]);
|
||||
m_minRange = spellInfo ? spellInfo->GetMinRange(false) : 0;
|
||||
|
||||
if (!m_minRange)
|
||||
m_minRange = MELEE_RANGE;
|
||||
me->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0;
|
||||
me->m_SightDistance = me->m_CombatDistance;
|
||||
}
|
||||
|
||||
void ArcherAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->IsWithinCombatRange(who, m_minRange))
|
||||
{
|
||||
if (me->Attack(who, true) && !who->IsFlying())
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me->Attack(who, false) && !who->IsFlying())
|
||||
me->GetMotionMaster()->MoveChase(who, me->m_CombatDistance);
|
||||
}
|
||||
|
||||
if (who->IsFlying())
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
|
||||
void ArcherAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!me->IsWithinCombatRange(me->GetVictim(), m_minRange))
|
||||
DoSpellAttackIfReady(me->m_spells[0]);
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
//////////////
|
||||
// TurretAI
|
||||
//////////////
|
||||
|
||||
TurretAI::TurretAI(Creature* c) : CreatureAI(c)
|
||||
{
|
||||
if (!me->m_spells[0])
|
||||
sLog->outError("TurretAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry());
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0]);
|
||||
m_minRange = spellInfo ? spellInfo->GetMinRange(false) : 0;
|
||||
me->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0;
|
||||
me->m_SightDistance = me->m_CombatDistance;
|
||||
}
|
||||
|
||||
bool TurretAI::CanAIAttack(const Unit* /*who*/) const
|
||||
{
|
||||
// TODO: use one function to replace it
|
||||
if (!me->IsWithinCombatRange(me->GetVictim(), me->m_CombatDistance)
|
||||
|| (m_minRange && me->IsWithinCombatRange(me->GetVictim(), m_minRange)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TurretAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (who)
|
||||
me->Attack(who, false);
|
||||
}
|
||||
|
||||
void TurretAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if( me->m_spells[0] )
|
||||
DoSpellAttackIfReady(me->m_spells[0]);
|
||||
}
|
||||
|
||||
//////////////
|
||||
// VehicleAI
|
||||
//////////////
|
||||
|
||||
VehicleAI::VehicleAI(Creature* c) : CreatureAI(c), m_ConditionsTimer(VEHICLE_CONDITION_CHECK_TIME)
|
||||
{
|
||||
LoadConditions();
|
||||
m_DoDismiss = false;
|
||||
m_DismissTimer = VEHICLE_DISMISS_TIME;
|
||||
}
|
||||
|
||||
//NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted
|
||||
void VehicleAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
CheckConditions(diff);
|
||||
|
||||
if (m_DoDismiss)
|
||||
{
|
||||
if (m_DismissTimer < diff)
|
||||
{
|
||||
m_DoDismiss = false;
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
else
|
||||
m_DismissTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
void VehicleAI::OnCharmed(bool apply)
|
||||
{
|
||||
if (!me->GetVehicleKit()->IsVehicleInUse() && !apply && !conditions.empty()) // was used and has conditions
|
||||
m_DoDismiss = true; // needs reset
|
||||
else if (apply)
|
||||
m_DoDismiss = false; // in use again
|
||||
|
||||
m_DismissTimer = VEHICLE_DISMISS_TIME;//reset timer
|
||||
}
|
||||
|
||||
void VehicleAI::LoadConditions()
|
||||
{
|
||||
conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry());
|
||||
//if (!conditions.empty())
|
||||
;//sLog->outDebug(LOG_FILTER_CONDITIONSYS, "VehicleAI::LoadConditions: loaded %u conditions", uint32(conditions.size()));
|
||||
}
|
||||
|
||||
void VehicleAI::CheckConditions(uint32 diff)
|
||||
{
|
||||
if (m_ConditionsTimer < diff)
|
||||
{
|
||||
if (!conditions.empty())
|
||||
{
|
||||
if (Vehicle* vehicleKit = me->GetVehicleKit())
|
||||
for (SeatMap::iterator itr = vehicleKit->Seats.begin(); itr != vehicleKit->Seats.end(); ++itr)
|
||||
if (Unit* passenger = ObjectAccessor::GetUnit(*me, itr->second.Passenger.Guid))
|
||||
{
|
||||
if (Player* player = passenger->ToPlayer())
|
||||
{
|
||||
if (!sConditionMgr->IsObjectMeetToConditions(player, me, conditions))
|
||||
{
|
||||
player->ExitVehicle();
|
||||
return; // check other pessanger in next tick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME;
|
||||
}
|
||||
else
|
||||
m_ConditionsTimer -= diff;
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_COMBATAI_H
|
||||
#define TRINITY_COMBATAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "ConditionMgr.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
class AggressorAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit AggressorAI(Creature* c) : CreatureAI(c) {}
|
||||
|
||||
void UpdateAI(uint32);
|
||||
static int Permissible(const Creature*);
|
||||
};
|
||||
|
||||
typedef std::vector<uint32> SpellVct;
|
||||
|
||||
class CombatAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit CombatAI(Creature* c) : CreatureAI(c) {}
|
||||
|
||||
void InitializeAI();
|
||||
void Reset();
|
||||
void EnterCombat(Unit* who);
|
||||
void JustDied(Unit* killer);
|
||||
void UpdateAI(uint32 diff);
|
||||
|
||||
static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
|
||||
|
||||
protected:
|
||||
EventMap events;
|
||||
SpellVct spells;
|
||||
};
|
||||
|
||||
class CasterAI : public CombatAI
|
||||
{
|
||||
public:
|
||||
explicit CasterAI(Creature* c) : CombatAI(c) { m_attackDist = MELEE_RANGE; }
|
||||
void InitializeAI();
|
||||
void AttackStart(Unit* victim) { AttackStartCaster(victim, m_attackDist); }
|
||||
void UpdateAI(uint32 diff);
|
||||
void EnterCombat(Unit* /*who*/);
|
||||
private:
|
||||
float m_attackDist;
|
||||
};
|
||||
|
||||
struct ArcherAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit ArcherAI(Creature* c);
|
||||
void AttackStart(Unit* who);
|
||||
void UpdateAI(uint32 diff);
|
||||
|
||||
|
||||
static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
|
||||
|
||||
protected:
|
||||
float m_minRange;
|
||||
};
|
||||
|
||||
struct TurretAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit TurretAI(Creature* c);
|
||||
bool CanAIAttack(const Unit* who) const;
|
||||
void AttackStart(Unit* who);
|
||||
void UpdateAI(uint32 diff);
|
||||
|
||||
static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
|
||||
|
||||
protected:
|
||||
float m_minRange;
|
||||
};
|
||||
|
||||
#define VEHICLE_CONDITION_CHECK_TIME 1000
|
||||
#define VEHICLE_DISMISS_TIME 5000
|
||||
struct VehicleAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit VehicleAI(Creature* creature);
|
||||
|
||||
void UpdateAI(uint32 diff);
|
||||
void MoveInLineOfSight(Unit*) {}
|
||||
void AttackStart(Unit*) {}
|
||||
void OnCharmed(bool apply);
|
||||
|
||||
static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
|
||||
|
||||
private:
|
||||
void LoadConditions();
|
||||
void CheckConditions(uint32 diff);
|
||||
ConditionList conditions;
|
||||
uint32 m_ConditionsTimer;
|
||||
bool m_DoDismiss;
|
||||
uint32 m_DismissTimer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
//GameObjectAI::GameObjectAI(GameObject* g) : go(g) {}
|
||||
int GameObjectAI::Permissible(const GameObject* go)
|
||||
{
|
||||
if (go->GetAIName() == "GameObjectAI")
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
NullGameObjectAI::NullGameObjectAI(GameObject* g) : GameObjectAI(g) {}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_GAMEOBJECTAI_H
|
||||
#define TRINITY_GAMEOBJECTAI_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <list>
|
||||
#include "Object.h"
|
||||
#include "QuestDef.h"
|
||||
#include "GameObject.h"
|
||||
#include "CreatureAI.h"
|
||||
|
||||
class GameObjectAI
|
||||
{
|
||||
protected:
|
||||
GameObject* const go;
|
||||
public:
|
||||
explicit GameObjectAI(GameObject* g) : go(g) {}
|
||||
virtual ~GameObjectAI() {}
|
||||
|
||||
virtual void UpdateAI(uint32 /*diff*/) {}
|
||||
|
||||
virtual void InitializeAI() { Reset(); }
|
||||
|
||||
virtual void Reset() { }
|
||||
|
||||
// Pass parameters between AI
|
||||
virtual void DoAction(int32 /*param = 0 */) {}
|
||||
virtual void SetGUID(uint64 /*guid*/, int32 /*id = 0 */) {}
|
||||
virtual uint64 GetGUID(int32 /*id = 0 */) const { return 0; }
|
||||
|
||||
static int Permissible(GameObject const* go);
|
||||
|
||||
virtual bool GossipHello(Player* /*player*/, bool reportUse) { return false; }
|
||||
virtual bool GossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { return false; }
|
||||
virtual bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) { return false; }
|
||||
virtual bool QuestAccept(Player* /*player*/, Quest const* /*quest*/) { return false; }
|
||||
virtual bool QuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) { return false; }
|
||||
virtual uint32 GetDialogStatus(Player* /*player*/) { return DIALOG_STATUS_SCRIPTED_NO_STATUS; }
|
||||
virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) {}
|
||||
virtual uint32 GetData(uint32 /*id*/) const { return 0; }
|
||||
virtual void SetData64(uint32 /*id*/, uint64 /*value*/) {}
|
||||
virtual uint64 GetData64(uint32 /*id*/) const { return 0; }
|
||||
virtual void SetData(uint32 /*id*/, uint32 /*value*/) {}
|
||||
virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) {}
|
||||
virtual void OnStateChanged(uint32 /*state*/, Unit* /*unit*/) {}
|
||||
virtual void EventInform(uint32 /*eventId*/) {}
|
||||
virtual void SpellHit(Unit* unit, const SpellInfo* spellInfo) {}
|
||||
};
|
||||
|
||||
class NullGameObjectAI : public GameObjectAI
|
||||
{
|
||||
public:
|
||||
explicit NullGameObjectAI(GameObject* g);
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) {}
|
||||
|
||||
static int Permissible(GameObject const* /*go*/) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "GuardAI.h"
|
||||
#include "Errors.h"
|
||||
#include "Player.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "World.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
int GuardAI::Permissible(Creature const* creature)
|
||||
{
|
||||
if (creature->IsGuard())
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
GuardAI::GuardAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void GuardAI::Reset()
|
||||
{
|
||||
ScriptedAI::Reset();
|
||||
me->CastSpell(me, 18950 /*SPELL_INVISIBILITY_AND_STEALTH_DETECTION*/, true);
|
||||
}
|
||||
|
||||
void GuardAI::EnterEvadeMode()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
{
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->CombatStop(true);
|
||||
me->DeleteThreatList();
|
||||
return;
|
||||
}
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Guard entry: %u enters evade mode.", me->GetEntry());
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop(true);
|
||||
|
||||
// Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
void GuardAI::JustDied(Unit* killer)
|
||||
{
|
||||
if (Player* player = killer->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
me->SendZoneUnderAttackMessage(player);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_GUARDAI_H
|
||||
#define TRINITY_GUARDAI_H
|
||||
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
class GuardAI : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
explicit GuardAI(Creature* creature);
|
||||
|
||||
static int Permissible(Creature const* creature);
|
||||
|
||||
void Reset();
|
||||
void EnterEvadeMode();
|
||||
void JustDied(Unit* killer);
|
||||
};
|
||||
#endif
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PassiveAI.h"
|
||||
#include "Creature.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
PassiveAI::PassiveAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); }
|
||||
PossessedAI::PossessedAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); }
|
||||
NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); }
|
||||
|
||||
void PassiveAI::UpdateAI(uint32)
|
||||
{
|
||||
if (me->IsInCombat() && me->getAttackers().empty())
|
||||
EnterEvadeMode();
|
||||
}
|
||||
|
||||
void PossessedAI::AttackStart(Unit* target)
|
||||
{
|
||||
me->Attack(target, true);
|
||||
}
|
||||
|
||||
void PossessedAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
{
|
||||
if (!me->IsValidAttackTarget(me->GetVictim()))
|
||||
me->AttackStop();
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
void PossessedAI::JustDied(Unit* /*u*/)
|
||||
{
|
||||
// We died while possessed, disable our loot
|
||||
me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
}
|
||||
|
||||
void PossessedAI::KilledUnit(Unit* victim)
|
||||
{
|
||||
// We killed a creature, disable victim's loot
|
||||
//if (victim->GetTypeId() == TYPEID_UNIT)
|
||||
// victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
|
||||
}
|
||||
|
||||
void CritterAI::DamageTaken(Unit*, uint32&, DamageEffectType, SpellSchoolMask)
|
||||
{
|
||||
if (!me->HasUnitState(UNIT_STATE_FLEEING))
|
||||
me->SetControlled(true, UNIT_STATE_FLEEING);
|
||||
|
||||
_combatTimer = 1;
|
||||
}
|
||||
|
||||
void CritterAI::EnterEvadeMode()
|
||||
{
|
||||
if (me->HasUnitState(UNIT_STATE_FLEEING))
|
||||
me->SetControlled(false, UNIT_STATE_FLEEING);
|
||||
CreatureAI::EnterEvadeMode();
|
||||
_combatTimer = 0;
|
||||
}
|
||||
|
||||
void CritterAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (me->IsInCombat())
|
||||
{
|
||||
_combatTimer += diff;
|
||||
if (_combatTimer >= 5000)
|
||||
EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
|
||||
void TriggerAI::IsSummonedBy(Unit* summoner)
|
||||
{
|
||||
if (me->m_spells[0])
|
||||
me->CastSpell(me, me->m_spells[0], false, 0, 0, summoner ? summoner->GetGUID() : 0);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_PASSIVEAI_H
|
||||
#define TRINITY_PASSIVEAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
//#include "CreatureAIImpl.h"
|
||||
|
||||
class PassiveAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit PassiveAI(Creature* c);
|
||||
|
||||
void MoveInLineOfSight(Unit*) {}
|
||||
void AttackStart(Unit*) {}
|
||||
void UpdateAI(uint32);
|
||||
|
||||
static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
|
||||
class PossessedAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit PossessedAI(Creature* c);
|
||||
|
||||
void MoveInLineOfSight(Unit*) {}
|
||||
void AttackStart(Unit* target);
|
||||
void UpdateAI(uint32);
|
||||
void EnterEvadeMode() {}
|
||||
|
||||
void JustDied(Unit*);
|
||||
void KilledUnit(Unit* victim);
|
||||
|
||||
static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
|
||||
class NullCreatureAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit NullCreatureAI(Creature* c);
|
||||
|
||||
void MoveInLineOfSight(Unit*) {}
|
||||
void AttackStart(Unit*) {}
|
||||
void UpdateAI(uint32) {}
|
||||
void EnterEvadeMode() {}
|
||||
void OnCharmed(bool /*apply*/) {}
|
||||
|
||||
static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
|
||||
class CritterAI : public PassiveAI
|
||||
{
|
||||
public:
|
||||
explicit CritterAI(Creature* c) : PassiveAI(c) { _combatTimer = 0; }
|
||||
|
||||
void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask);
|
||||
void EnterEvadeMode();
|
||||
void UpdateAI(uint32);
|
||||
|
||||
// Xinef: Added
|
||||
private:
|
||||
uint32 _combatTimer;
|
||||
};
|
||||
|
||||
class TriggerAI : public NullCreatureAI
|
||||
{
|
||||
public:
|
||||
explicit TriggerAI(Creature* c) : NullCreatureAI(c) {}
|
||||
void IsSummonedBy(Unit* summoner);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,744 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PetAI.h"
|
||||
#include "Errors.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "DBCStores.h"
|
||||
#include "Spell.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "World.h"
|
||||
#include "Util.h"
|
||||
#include "Group.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
int PetAI::Permissible(const Creature* creature)
|
||||
{
|
||||
if (creature->IsPet())
|
||||
return PERMIT_BASE_SPECIAL;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK)
|
||||
{
|
||||
UpdateAllies();
|
||||
}
|
||||
|
||||
bool PetAI::_needToStop()
|
||||
{
|
||||
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
|
||||
if (me->IsCharmed() && me->GetVictim() == me->GetCharmer())
|
||||
return true;
|
||||
|
||||
// xinef: dont allow to follow targets out of visibility range
|
||||
if (me->GetExactDist(me->GetVictim()) > me->GetVisibilityRange()-5.0f)
|
||||
return true;
|
||||
|
||||
// dont allow pets to follow targets far away from owner
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
if (owner->GetExactDist(me) >= (owner->GetVisibilityRange()-10.0f))
|
||||
return true;
|
||||
|
||||
if (!me->_CanDetectFeignDeathOf(me->GetVictim()))
|
||||
return true;
|
||||
|
||||
if (me->isTargetNotAcceptableByMMaps(me->GetVictim()->GetGUID(), sWorld->GetGameTime(), me->GetVictim()))
|
||||
return true;
|
||||
|
||||
return !me->CanCreatureAttack(me->GetVictim());
|
||||
}
|
||||
|
||||
void PetAI::_stopAttack()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
{
|
||||
;//sLog->outStaticDebug("Creature stoped attacking cuz his dead [guid=%u]", me->GetGUIDLow());
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->CombatStop();
|
||||
me->getHostileRefManager().deleteReferences();
|
||||
return;
|
||||
}
|
||||
|
||||
me->AttackStop();
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
me->GetCharmInfo()->SetIsCommandAttack(false);
|
||||
ClearCharmInfoFlags();
|
||||
HandleReturnMovement();
|
||||
}
|
||||
|
||||
void PetAI::_doMeleeAttack()
|
||||
{
|
||||
// Xinef: Imps cannot attack with melee
|
||||
if (!_canMeleeAttack())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
bool PetAI::_canMeleeAttack() const
|
||||
{
|
||||
return me->GetEntry() != 416 /*ENTRY_IMP*/ &&
|
||||
me->GetEntry() != 510 /*ENTRY_WATER_ELEMENTAL*/ &&
|
||||
me->GetEntry() != 37994 /*ENTRY_WATER_ELEMENTAL_PERM*/;
|
||||
}
|
||||
|
||||
void PetAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!me->IsAlive() || !me->GetCharmInfo())
|
||||
return;
|
||||
|
||||
Unit* owner = me->GetCharmerOrOwner();
|
||||
|
||||
if (m_updateAlliesTimer <= diff)
|
||||
// UpdateAllies self set update timer
|
||||
UpdateAllies();
|
||||
else
|
||||
m_updateAlliesTimer -= diff;
|
||||
|
||||
if (me->GetVictim() && me->GetVictim()->IsAlive())
|
||||
{
|
||||
// is only necessary to stop casting, the pet must not exit combat
|
||||
if (me->GetVictim()->HasBreakableByDamageCrowdControlAura(me))
|
||||
{
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_needToStop())
|
||||
{
|
||||
;//sLog->outStaticDebug("Pet AI stopped attacking [guid=%u]", me->GetGUIDLow());
|
||||
_stopAttack();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check before attacking to prevent pets from leaving stay position
|
||||
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
|
||||
{
|
||||
if (me->GetCharmInfo()->IsCommandAttack() || (me->GetCharmInfo()->IsAtStay() && me->IsWithinMeleeRange(me->GetVictim())))
|
||||
_doMeleeAttack();
|
||||
}
|
||||
else
|
||||
_doMeleeAttack();
|
||||
}
|
||||
else if (!me->GetCharmInfo() || (!me->GetCharmInfo()->GetForcedSpell() && !me->HasUnitState(UNIT_STATE_CASTING)))
|
||||
{
|
||||
if (me->HasReactState(REACT_AGGRESSIVE) || me->GetCharmInfo()->IsAtStay())
|
||||
{
|
||||
// Every update we need to check targets only in certain cases
|
||||
// Aggressive - Allow auto select if owner or pet don't have a target
|
||||
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
|
||||
// while chasing our owner. Don't do auto select.
|
||||
// All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc.
|
||||
Unit* nextTarget = SelectNextTarget(me->HasReactState(REACT_AGGRESSIVE));
|
||||
|
||||
if (nextTarget)
|
||||
AttackStart(nextTarget);
|
||||
else
|
||||
HandleReturnMovement();
|
||||
}
|
||||
else
|
||||
HandleReturnMovement();
|
||||
}
|
||||
|
||||
// xinef: charm info must be always available
|
||||
if (!me->GetCharmInfo())
|
||||
return;
|
||||
|
||||
// Autocast (casted only in combat or persistent spells in any state)
|
||||
if (!me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
if (owner && owner->GetTypeId() == TYPEID_PLAYER && me->GetCharmInfo()->GetForcedSpell() && me->GetCharmInfo()->GetForcedTarget())
|
||||
{
|
||||
owner->ToPlayer()->GetSession()->HandlePetActionHelper(me, me->GetGUID(), abs(me->GetCharmInfo()->GetForcedSpell()), ACT_ENABLED, me->GetCharmInfo()->GetForcedTarget());
|
||||
|
||||
// xinef: if spell was casted properly and we are in passive mode, handle return
|
||||
if (!me->GetCharmInfo()->GetForcedSpell() && me->HasReactState(REACT_PASSIVE))
|
||||
{
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->StopMoving();
|
||||
}
|
||||
else
|
||||
_stopAttack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// xinef: dont allow ghouls to cast spells below 75 energy
|
||||
if (me->IsPet() && me->ToPet()->IsPetGhoul() && me->GetPower(POWER_ENERGY) < 75)
|
||||
return;
|
||||
|
||||
typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList;
|
||||
TargetSpellList targetSpellStore;
|
||||
|
||||
for (uint8 i = 0; i < me->GetPetAutoSpellSize(); ++i)
|
||||
{
|
||||
uint32 spellID = me->GetPetAutoSpellOnPos(i);
|
||||
if (!spellID)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo))
|
||||
continue;
|
||||
|
||||
// check spell cooldown, this should be checked in CheckCast...
|
||||
if (me->HasSpellCooldown(spellInfo->Id))
|
||||
continue;
|
||||
|
||||
if (spellInfo->IsPositive())
|
||||
{
|
||||
if (spellInfo->CanBeUsedInCombat())
|
||||
{
|
||||
// Check if we're in combat or commanded to attack
|
||||
if (!me->IsInCombat() && !me->GetCharmInfo()->IsCommandAttack())
|
||||
continue;
|
||||
}
|
||||
|
||||
Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE, 0);
|
||||
spell->LoadScripts(); // xinef: load for CanAutoCast (calling CheckPetCast)
|
||||
bool spellUsed = false;
|
||||
|
||||
// Some spells can target enemy or friendly (DK Ghoul's Leap)
|
||||
// Check for enemy first (pet then owner)
|
||||
Unit* target = me->getAttackerForHelper();
|
||||
if (!target && owner)
|
||||
target = owner->getAttackerForHelper();
|
||||
|
||||
if (target)
|
||||
{
|
||||
if (CanAttack(target) && spell->CanAutoCast(target))
|
||||
{
|
||||
targetSpellStore.push_back(std::make_pair(target, spell));
|
||||
spellUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// No enemy, check friendly
|
||||
if (!spellUsed)
|
||||
{
|
||||
for (std::set<uint64>::const_iterator tar = m_AllySet.begin(); tar != m_AllySet.end(); ++tar)
|
||||
{
|
||||
Unit* ally = ObjectAccessor::GetUnit(*me, *tar);
|
||||
|
||||
//only buff targets that are in combat, unless the spell can only be cast while out of combat
|
||||
if (!ally)
|
||||
continue;
|
||||
|
||||
if (spell->CanAutoCast(ally))
|
||||
{
|
||||
targetSpellStore.push_back(std::make_pair(ally, spell));
|
||||
spellUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No valid targets at all
|
||||
if (!spellUsed)
|
||||
delete spell;
|
||||
}
|
||||
else if (me->GetVictim() && CanAttack(me->GetVictim(), spellInfo) && spellInfo->CanBeUsedInCombat())
|
||||
{
|
||||
Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE, 0);
|
||||
if (spell->CanAutoCast(me->GetVictim()))
|
||||
targetSpellStore.push_back(std::make_pair(me->GetVictim(), spell));
|
||||
else
|
||||
delete spell;
|
||||
}
|
||||
}
|
||||
|
||||
//found units to cast on to
|
||||
if (!targetSpellStore.empty())
|
||||
{
|
||||
uint32 index = urand(0, targetSpellStore.size() - 1);
|
||||
|
||||
Spell* spell = targetSpellStore[index].second;
|
||||
Unit* target = targetSpellStore[index].first;
|
||||
|
||||
targetSpellStore.erase(targetSpellStore.begin() + index);
|
||||
|
||||
SpellCastTargets targets;
|
||||
targets.SetUnitTarget(target);
|
||||
|
||||
if (!me->HasInArc(M_PI, target))
|
||||
{
|
||||
me->SetInFront(target);
|
||||
if (target && target->GetTypeId() == TYPEID_PLAYER)
|
||||
me->SendUpdateToPlayer(target->ToPlayer());
|
||||
|
||||
if (owner && owner->GetTypeId() == TYPEID_PLAYER)
|
||||
me->SendUpdateToPlayer(owner->ToPlayer());
|
||||
}
|
||||
|
||||
me->AddSpellCooldown(spell->m_spellInfo->Id, 0, 0);
|
||||
|
||||
spell->prepare(&targets);
|
||||
}
|
||||
|
||||
// deleted cached Spell objects
|
||||
for (TargetSpellList::const_iterator itr = targetSpellStore.begin(); itr != targetSpellStore.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
void PetAI::UpdateAllies()
|
||||
{
|
||||
Unit* owner = me->GetCharmerOrOwner();
|
||||
Group* group = NULL;
|
||||
|
||||
m_updateAlliesTimer = 10*IN_MILLISECONDS; //update friendly targets every 10 seconds, lesser checks increase performance
|
||||
|
||||
if (!owner)
|
||||
return;
|
||||
else if (owner->GetTypeId() == TYPEID_PLAYER)
|
||||
group = owner->ToPlayer()->GetGroup();
|
||||
|
||||
//only pet and owner/not in group->ok
|
||||
if (m_AllySet.size() == 2 && !group)
|
||||
return;
|
||||
//owner is in group; group members filled in already (no raid -> subgroupcount = whole count)
|
||||
if (group && !group->isRaidGroup() && m_AllySet.size() == (group->GetMembersCount() + 2))
|
||||
return;
|
||||
|
||||
m_AllySet.clear();
|
||||
m_AllySet.insert(me->GetGUID());
|
||||
if (group) //add group
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player* Target = itr->GetSource();
|
||||
if (!Target || !Target->IsInMap(owner) || !group->SameSubGroup(owner->ToPlayer(), Target))
|
||||
continue;
|
||||
|
||||
if (Target->GetGUID() == owner->GetGUID())
|
||||
continue;
|
||||
|
||||
m_AllySet.insert(Target->GetGUID());
|
||||
}
|
||||
}
|
||||
else //remove group
|
||||
m_AllySet.insert(owner->GetGUID());
|
||||
}
|
||||
|
||||
void PetAI::KilledUnit(Unit* victim)
|
||||
{
|
||||
// Called from Unit::Kill() in case where pet or owner kills something
|
||||
// if owner killed this victim, pet may still be attacking something else
|
||||
if (me->GetVictim() && me->GetVictim() != victim)
|
||||
return;
|
||||
|
||||
// Xinef: if pet is channeling a spell and owner killed something different, dont interrupt it
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING) && me->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT) && me->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT) != victim->GetGUID())
|
||||
return;
|
||||
|
||||
// Clear target just in case. May help problem where health / focus / mana
|
||||
// regen gets stuck. Also resets attack command.
|
||||
// Can't use _stopAttack() because that activates movement handlers and ignores
|
||||
// next target selection
|
||||
me->AttackStop();
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
|
||||
// Before returning to owner, see if there are more things to attack
|
||||
if (Unit* nextTarget = SelectNextTarget(false))
|
||||
AttackStart(nextTarget);
|
||||
else
|
||||
HandleReturnMovement(); // Return
|
||||
}
|
||||
|
||||
void PetAI::AttackStart(Unit* target)
|
||||
{
|
||||
// Overrides Unit::AttackStart to correctly evaluate Pet states
|
||||
|
||||
// Check all pet states to decide if we can attack this target
|
||||
if (!CanAttack(target))
|
||||
return;
|
||||
|
||||
// Only chase if not commanded to stay or if stay but commanded to attack
|
||||
DoAttack(target, (!me->GetCharmInfo()->HasCommandState(COMMAND_STAY) || me->GetCharmInfo()->IsCommandAttack()));
|
||||
}
|
||||
|
||||
void PetAI::OwnerAttackedBy(Unit* attacker)
|
||||
{
|
||||
// Called when owner takes damage. This function helps keep pets from running off
|
||||
// simply due to owner gaining aggro.
|
||||
|
||||
if (!attacker)
|
||||
return;
|
||||
|
||||
// Passive pets don't do anything
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
return;
|
||||
|
||||
// Prevent pet from disengaging from current target
|
||||
if (me->GetVictim() && me->GetVictim()->IsAlive())
|
||||
return;
|
||||
|
||||
// Continue to evaluate and attack if necessary
|
||||
AttackStart(attacker);
|
||||
}
|
||||
|
||||
void PetAI::OwnerAttacked(Unit* target)
|
||||
{
|
||||
// Called when owner attacks something. Allows defensive pets to know
|
||||
// that they need to assist
|
||||
|
||||
// Target might be NULL if called from spell with invalid cast targets
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
// Passive pets don't do anything
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
return;
|
||||
|
||||
// Prevent pet from disengaging from current target
|
||||
if (me->GetVictim() && me->GetVictim()->IsAlive())
|
||||
return;
|
||||
|
||||
// Continue to evaluate and attack if necessary
|
||||
AttackStart(target);
|
||||
}
|
||||
|
||||
Unit* PetAI::SelectNextTarget(bool allowAutoSelect) const
|
||||
{
|
||||
// Provides next target selection after current target death.
|
||||
// This function should only be called internally by the AI
|
||||
// Targets are not evaluated here for being valid targets, that is done in _CanAttack()
|
||||
// The parameter: allowAutoSelect lets us disable aggressive pet auto targeting for certain situations
|
||||
|
||||
// Passive pets don't do next target selection
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
return NULL;
|
||||
|
||||
// Check pet attackers first so we don't drag a bunch of targets to the owner
|
||||
if (Unit* myAttacker = me->getAttackerForHelper())
|
||||
if (!myAttacker->HasBreakableByDamageCrowdControlAura() && me->_CanDetectFeignDeathOf(myAttacker) && me->CanCreatureAttack(myAttacker) && !me->isTargetNotAcceptableByMMaps(myAttacker->GetGUID(), sWorld->GetGameTime(), myAttacker))
|
||||
return myAttacker;
|
||||
|
||||
// Check pet's attackers first to prevent dragging mobs back to owner
|
||||
if (me->HasAuraType(SPELL_AURA_MOD_TAUNT))
|
||||
{
|
||||
const Unit::AuraEffectList& tauntAuras = me->GetAuraEffectsByType(SPELL_AURA_MOD_TAUNT);
|
||||
if (!tauntAuras.empty())
|
||||
for (Unit::AuraEffectList::const_reverse_iterator itr = tauntAuras.rbegin(); itr != tauntAuras.rend(); ++itr)
|
||||
if (Unit* caster = (*itr)->GetCaster())
|
||||
if (me->_CanDetectFeignDeathOf(caster) && me->CanCreatureAttack(caster) && !caster->HasAuraTypeWithCaster(SPELL_AURA_IGNORED, me->GetGUID()))
|
||||
return caster;
|
||||
}
|
||||
|
||||
// Not sure why we wouldn't have an owner but just in case...
|
||||
Unit* owner = me->GetCharmerOrOwner();
|
||||
if (!owner)
|
||||
return NULL;
|
||||
|
||||
// Check owner attackers
|
||||
if (Unit* ownerAttacker = owner->getAttackerForHelper())
|
||||
if (!ownerAttacker->HasBreakableByDamageCrowdControlAura() && me->_CanDetectFeignDeathOf(ownerAttacker) && me->CanCreatureAttack(ownerAttacker) && !me->isTargetNotAcceptableByMMaps(ownerAttacker->GetGUID(), sWorld->GetGameTime(), ownerAttacker))
|
||||
return ownerAttacker;
|
||||
|
||||
// Check owner victim
|
||||
// 3.0.2 - Pets now start attacking their owners victim in defensive mode as soon as the hunter does
|
||||
if (Unit* ownerVictim = owner->GetVictim())
|
||||
if (me->_CanDetectFeignDeathOf(ownerVictim) && me->CanCreatureAttack(ownerVictim) && !me->isTargetNotAcceptableByMMaps(ownerVictim->GetGUID(), sWorld->GetGameTime(), ownerVictim))
|
||||
return ownerVictim;
|
||||
|
||||
// Neither pet or owner had a target and aggressive pets can pick any target
|
||||
// To prevent aggressive pets from chain selecting targets and running off, we
|
||||
// only select a random target if certain conditions are met.
|
||||
if (allowAutoSelect)
|
||||
if (!me->GetCharmInfo()->IsReturning() || me->GetCharmInfo()->IsFollowing() || me->GetCharmInfo()->IsAtStay())
|
||||
if (Unit* nearTarget = me->ToCreature()->SelectNearestTargetInAttackDistance(MAX_AGGRO_RADIUS))
|
||||
return nearTarget;
|
||||
|
||||
// Default - no valid targets
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PetAI::HandleReturnMovement()
|
||||
{
|
||||
// Handles moving the pet back to stay or owner
|
||||
|
||||
// Prevent activating movement when under control of spells
|
||||
// such as "Eyes of the Beast"
|
||||
if (me->isPossessed())
|
||||
return;
|
||||
|
||||
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
|
||||
{
|
||||
if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning())
|
||||
{
|
||||
if (me->GetCharmInfo()->HasStayPosition())
|
||||
{
|
||||
// Return to previous position where stay was clicked
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
{
|
||||
float x, y, z;
|
||||
me->GetCharmInfo()->GetStayPosition(x, y, z);
|
||||
ClearCharmInfoFlags();
|
||||
me->GetCharmInfo()->SetIsReturning(true);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MovePoint(me->GetUInt32Value(OBJECT_FIELD_GUID), x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // COMMAND_FOLLOW
|
||||
{
|
||||
if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning())
|
||||
{
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me->GetCharmInfo()->SetIsReturning(true);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
me->GetCharmInfo()->SetForcedSpell(0);
|
||||
me->GetCharmInfo()->SetForcedTargetGUID(0);
|
||||
|
||||
// xinef: remember that npcs summoned by npcs can also be pets
|
||||
me->DeleteThreatList();
|
||||
me->ClearInPetCombat();
|
||||
}
|
||||
|
||||
void PetAI::SpellHit(Unit* caster, const SpellInfo* spellInfo)
|
||||
{
|
||||
// Xinef: taunt behavior code
|
||||
if (spellInfo->HasAura(SPELL_AURA_MOD_TAUNT) && !me->HasReactState(REACT_PASSIVE))
|
||||
{
|
||||
me->GetCharmInfo()->SetForcedSpell(0);
|
||||
me->GetCharmInfo()->SetForcedTargetGUID(0);
|
||||
AttackStart(caster);
|
||||
}
|
||||
}
|
||||
|
||||
void PetAI::DoAttack(Unit* target, bool chase)
|
||||
{
|
||||
// Handles attack with or without chase and also resets flags
|
||||
// for next update / creature kill
|
||||
|
||||
if (me->Attack(target, true))
|
||||
{
|
||||
// xinef: properly fix fake combat after pet is sent to attack
|
||||
if (Unit* owner = me->GetOwner())
|
||||
owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
|
||||
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
|
||||
|
||||
// Play sound to let the player know the pet is attacking something it picked on its own
|
||||
if (me->HasReactState(REACT_AGGRESSIVE) && !me->GetCharmInfo()->IsCommandAttack())
|
||||
me->SendPetAIReaction(me->GetGUID());
|
||||
|
||||
if (CharmInfo* ci = me->GetCharmInfo())
|
||||
{
|
||||
ci->SetIsAtStay(false);
|
||||
ci->SetIsCommandFollow(false);
|
||||
ci->SetIsFollowing(false);
|
||||
ci->SetIsReturning(false);
|
||||
}
|
||||
|
||||
if (chase)
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(target, !_canMeleeAttack() ? 20.0f: 0.0f, me->GetAngle(target));
|
||||
}
|
||||
else // (Stay && ((Aggressive || Defensive) && In Melee Range)))
|
||||
{
|
||||
me->GetCharmInfo()->SetIsAtStay(true);
|
||||
me->GetMotionMaster()->MovementExpiredOnSlot(MOTION_SLOT_ACTIVE, false);
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PetAI::MovementInform(uint32 moveType, uint32 data)
|
||||
{
|
||||
// Receives notification when pet reaches stay or follow owner
|
||||
switch (moveType)
|
||||
{
|
||||
case POINT_MOTION_TYPE:
|
||||
{
|
||||
// Pet is returning to where stay was clicked. data should be
|
||||
// pet's GUIDLow since we set that as the waypoint ID
|
||||
if (data == me->GetGUIDLow() && me->GetCharmInfo()->IsReturning())
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me->GetCharmInfo()->SetIsAtStay(true);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FOLLOW_MOTION_TYPE:
|
||||
{
|
||||
// If data is owner's GUIDLow then we've reached follow point,
|
||||
// otherwise we're probably chasing a creature
|
||||
if (me->GetCharmerOrOwner() && me->GetCharmInfo() && data == me->GetCharmerOrOwner()->GetGUIDLow() && me->GetCharmInfo()->IsReturning())
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me->GetCharmInfo()->SetIsFollowing(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool PetAI::CanAttack(Unit* target, const SpellInfo* spellInfo)
|
||||
{
|
||||
// Evaluates wether a pet can attack a specific target based on CommandState, ReactState and other flags
|
||||
// IMPORTANT: The order in which things are checked is important, be careful if you add or remove checks
|
||||
|
||||
// Hmmm...
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!target->IsAlive())
|
||||
{
|
||||
// xinef: if target is invalid, pet should evade automaticly
|
||||
// Clear target to prevent getting stuck on dead targets
|
||||
//me->AttackStop();
|
||||
//me->InterruptNonMeleeSpells(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// xinef: check unit states of pet
|
||||
if (me->HasUnitState(UNIT_STATE_LOST_CONTROL))
|
||||
return false;
|
||||
|
||||
// xinef: pets of mounted players have stunned flag only, check this also
|
||||
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED))
|
||||
return false;
|
||||
|
||||
// pussywizard: ZOMG! TEMP!
|
||||
if (!me->GetCharmInfo())
|
||||
{
|
||||
sLog->outMisc("PetAI::CanAttack (A1) - %u, %u", me->GetEntry(), GUID_LOPART(me->GetOwnerGUID()));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passive - passive pets can attack if told to
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
return me->GetCharmInfo()->IsCommandAttack();
|
||||
|
||||
// CC - mobs under crowd control can be attacked if owner commanded
|
||||
if (target->HasBreakableByDamageCrowdControlAura() && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS)))
|
||||
return me->GetCharmInfo()->IsCommandAttack();
|
||||
|
||||
// Returning - pets ignore attacks only if owner clicked follow
|
||||
if (me->GetCharmInfo()->IsReturning())
|
||||
return !me->GetCharmInfo()->IsCommandFollow();
|
||||
|
||||
// Stay - can attack if target is within range or commanded to
|
||||
if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY))
|
||||
return (me->IsWithinMeleeRange(target) || me->GetCharmInfo()->IsCommandAttack());
|
||||
|
||||
// Pets attacking something (or chasing) should only switch targets if owner tells them to
|
||||
if (me->GetVictim() && me->GetVictim() != target)
|
||||
{
|
||||
// Check if our owner selected this target and clicked "attack"
|
||||
Unit* ownerTarget = NULL;
|
||||
if (Player* owner = me->GetCharmerOrOwner()->ToPlayer())
|
||||
ownerTarget = owner->GetSelectedUnit();
|
||||
else
|
||||
ownerTarget = me->GetCharmerOrOwner()->GetVictim();
|
||||
|
||||
if (ownerTarget && me->GetCharmInfo()->IsCommandAttack())
|
||||
return (target->GetGUID() == ownerTarget->GetGUID());
|
||||
}
|
||||
|
||||
// Follow
|
||||
if (me->GetCharmInfo()->HasCommandState(COMMAND_FOLLOW))
|
||||
return !me->GetCharmInfo()->IsReturning();
|
||||
|
||||
// default, though we shouldn't ever get here
|
||||
return false;
|
||||
}
|
||||
|
||||
void PetAI::ReceiveEmote(Player* player, uint32 emote)
|
||||
{
|
||||
if (me->GetOwnerGUID() && me->GetOwnerGUID() == player->GetGUID())
|
||||
switch (emote)
|
||||
{
|
||||
case TEXT_EMOTE_COWER:
|
||||
if (me->IsPet() && me->ToPet()->IsPetGhoul())
|
||||
me->HandleEmoteCommand(/*EMOTE_ONESHOT_ROAR*/EMOTE_ONESHOT_OMNICAST_GHOUL);
|
||||
break;
|
||||
case TEXT_EMOTE_ANGRY:
|
||||
if (me->IsPet() && me->ToPet()->IsPetGhoul())
|
||||
me->HandleEmoteCommand(/*EMOTE_ONESHOT_COWER*/EMOTE_STATE_STUN);
|
||||
break;
|
||||
case TEXT_EMOTE_GLARE:
|
||||
if (me->IsPet() && me->ToPet()->IsPetGhoul())
|
||||
me->HandleEmoteCommand(EMOTE_STATE_STUN);
|
||||
break;
|
||||
case TEXT_EMOTE_SOOTHE:
|
||||
if (me->IsPet() && me->ToPet()->IsPetGhoul())
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_OMNICAST_GHOUL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PetAI::ClearCharmInfoFlags()
|
||||
{
|
||||
// Quick access to set all flags to FALSE
|
||||
|
||||
CharmInfo* ci = me->GetCharmInfo();
|
||||
|
||||
if (ci)
|
||||
{
|
||||
ci->SetIsAtStay(false);
|
||||
ci->SetIsCommandAttack(false);
|
||||
ci->SetIsCommandFollow(false);
|
||||
ci->SetIsFollowing(false);
|
||||
ci->SetIsReturning(false);
|
||||
}
|
||||
}
|
||||
|
||||
void PetAI::AttackedBy(Unit* attacker)
|
||||
{
|
||||
// Called when pet takes damage. This function helps keep pets from running off
|
||||
// simply due to gaining aggro.
|
||||
|
||||
if (!attacker)
|
||||
return;
|
||||
|
||||
// Passive pets don't do anything
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
return;
|
||||
|
||||
// Prevent pet from disengaging from current target
|
||||
if (me->GetVictim() && me->GetVictim()->IsAlive())
|
||||
return;
|
||||
|
||||
// Continue to evaluate and attack if necessary
|
||||
AttackStart(attacker);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_PETAI_H
|
||||
#define TRINITY_PETAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class Creature;
|
||||
class Spell;
|
||||
|
||||
class PetAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
|
||||
explicit PetAI(Creature* c);
|
||||
|
||||
void UpdateAI(uint32);
|
||||
static int Permissible(const Creature*);
|
||||
|
||||
void KilledUnit(Unit* /*victim*/);
|
||||
void AttackStart(Unit* target);
|
||||
void MovementInform(uint32 moveType, uint32 data);
|
||||
void OwnerAttackedBy(Unit* attacker);
|
||||
void OwnerAttacked(Unit* target);
|
||||
void AttackedBy(Unit* attacker);
|
||||
void ReceiveEmote(Player* player, uint32 textEmote);
|
||||
|
||||
// The following aren't used by the PetAI but need to be defined to override
|
||||
// default CreatureAI functions which interfere with the PetAI
|
||||
//
|
||||
void MoveInLineOfSight(Unit* /*who*/) {} // CreatureAI interferes with returning pets
|
||||
void MoveInLineOfSight_Safe(Unit* /*who*/) {} // CreatureAI interferes with returning pets
|
||||
void EnterEvadeMode() {} // For fleeing, pets don't use this type of Evade mechanic
|
||||
void SpellHit(Unit* caster, const SpellInfo* spellInfo);
|
||||
|
||||
private:
|
||||
bool _isVisible(Unit*) const;
|
||||
bool _needToStop(void);
|
||||
void _stopAttack(void);
|
||||
void _doMeleeAttack();
|
||||
bool _canMeleeAttack() const;
|
||||
|
||||
void UpdateAllies();
|
||||
|
||||
TimeTracker i_tracker;
|
||||
std::set<uint64> m_AllySet;
|
||||
uint32 m_updateAlliesTimer;
|
||||
|
||||
Unit* SelectNextTarget(bool allowAutoSelect) const;
|
||||
void HandleReturnMovement();
|
||||
void DoAttack(Unit* target, bool chase);
|
||||
bool CanAttack(Unit* target, const SpellInfo* spellInfo = NULL);
|
||||
void ClearCharmInfoFlags();
|
||||
};
|
||||
#endif
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "ReactorAI.h"
|
||||
#include "Errors.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
int ReactorAI::Permissible(const Creature* creature)
|
||||
{
|
||||
if (creature->IsCivilian() || creature->IsNeutralToAll())
|
||||
return PERMIT_BASE_REACTIVE;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
void ReactorAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_REACTORAI_H
|
||||
#define TRINITY_REACTORAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
|
||||
class Unit;
|
||||
|
||||
class ReactorAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
|
||||
explicit ReactorAI(Creature* c) : CreatureAI(c) {}
|
||||
|
||||
void MoveInLineOfSight(Unit*) {}
|
||||
void UpdateAI(uint32 diff);
|
||||
|
||||
static int Permissible(const Creature*);
|
||||
};
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TotemAI.h"
|
||||
#include "Totem.h"
|
||||
#include "Creature.h"
|
||||
#include "DBCStores.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "CellImpl.h"
|
||||
|
||||
int TotemAI::Permissible(Creature const* creature)
|
||||
{
|
||||
if (creature->IsTotem())
|
||||
return PERMIT_BASE_PROACTIVE;
|
||||
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
TotemAI::TotemAI(Creature* c) : CreatureAI(c), i_victimGuid(0)
|
||||
{
|
||||
ASSERT(c->IsTotem());
|
||||
}
|
||||
|
||||
void TotemAI::SpellHit(Unit* /*caster*/, const SpellInfo* spellInfo)
|
||||
{
|
||||
}
|
||||
|
||||
void TotemAI::DoAction(int32 param)
|
||||
{
|
||||
}
|
||||
|
||||
void TotemAI::MoveInLineOfSight(Unit* /*who*/)
|
||||
{
|
||||
}
|
||||
|
||||
void TotemAI::EnterEvadeMode()
|
||||
{
|
||||
me->CombatStop(true);
|
||||
}
|
||||
|
||||
void TotemAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE)
|
||||
return;
|
||||
|
||||
if (!me->IsAlive() || me->IsNonMeleeSpellCast(false))
|
||||
return;
|
||||
|
||||
// Search spell
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->ToTotem()->GetSpell());
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
// Get spell range
|
||||
float max_range = spellInfo->GetMaxRange(false);
|
||||
|
||||
// SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems
|
||||
|
||||
// pointer to appropriate target if found any
|
||||
Unit* victim = i_victimGuid ? ObjectAccessor::GetUnit(*me, i_victimGuid) : NULL;
|
||||
|
||||
// Search victim if no, not attackable, or out of range, or friendly (possible in case duel end)
|
||||
if (!victim ||
|
||||
!victim->isTargetableForAttack(true, me) || !me->IsWithinDistInMap(victim, max_range) ||
|
||||
me->IsFriendlyTo(victim) || !me->CanSeeOrDetect(victim))
|
||||
{
|
||||
victim = NULL;
|
||||
Trinity::NearestAttackableUnitInObjectRangeCheck u_check(me, me, max_range);
|
||||
Trinity::UnitLastSearcher<Trinity::NearestAttackableUnitInObjectRangeCheck> checker(me, victim, u_check);
|
||||
me->VisitNearbyObject(max_range, checker);
|
||||
}
|
||||
|
||||
// If have target
|
||||
if (victim)
|
||||
{
|
||||
// remember
|
||||
i_victimGuid = victim->GetGUID();
|
||||
|
||||
// attack
|
||||
me->SetInFront(victim); // client change orientation by self
|
||||
me->CastSpell(victim, me->ToTotem()->GetSpell(), false);
|
||||
}
|
||||
else
|
||||
i_victimGuid = 0;
|
||||
}
|
||||
|
||||
void TotemAI::AttackStart(Unit* /*victim*/)
|
||||
{
|
||||
// Sentry totem sends ping on attack
|
||||
if (me->GetEntry() == SENTRY_TOTEM_ENTRY && me->GetOwner()->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
WorldPacket data(MSG_MINIMAP_PING, (8+4+4));
|
||||
data << me->GetGUID();
|
||||
data << me->GetPositionX();
|
||||
data << me->GetPositionY();
|
||||
me->GetOwner()->ToPlayer()->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_TOTEMAI_H
|
||||
#define TRINITY_TOTEMAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class Creature;
|
||||
class Totem;
|
||||
|
||||
class TotemAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
|
||||
explicit TotemAI(Creature* c);
|
||||
|
||||
void MoveInLineOfSight(Unit* who);
|
||||
void AttackStart(Unit* victim);
|
||||
void EnterEvadeMode();
|
||||
void SpellHit(Unit* /*caster*/, const SpellInfo* /*spellInfo*/);
|
||||
void DoAction(int32 param);
|
||||
|
||||
void UpdateAI(uint32 diff);
|
||||
static int Permissible(Creature const* creature);
|
||||
|
||||
private:
|
||||
uint64 i_victimGuid;
|
||||
};
|
||||
|
||||
class KillMagnetEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
KillMagnetEvent(Unit& self) : _self(self) { }
|
||||
bool Execute(uint64 e_time, uint32 p_time)
|
||||
{
|
||||
_self.setDeathState(JUST_DIED);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
Unit& _self;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "UnitAI.h"
|
||||
#include "Player.h"
|
||||
#include "Creature.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Spell.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
void UnitAI::AttackStart(Unit* victim)
|
||||
{
|
||||
if (victim && me->Attack(victim, true))
|
||||
me->GetMotionMaster()->MoveChase(victim);
|
||||
}
|
||||
|
||||
void UnitAI::AttackStartCaster(Unit* victim, float dist)
|
||||
{
|
||||
if (victim && me->Attack(victim, false))
|
||||
me->GetMotionMaster()->MoveChase(victim, dist);
|
||||
}
|
||||
|
||||
void UnitAI::DoMeleeAttackIfReady()
|
||||
{
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
Unit *victim = me->GetVictim();
|
||||
if (!victim || !victim->IsInWorld())
|
||||
return;
|
||||
|
||||
if (!me->IsWithinMeleeRange(victim))
|
||||
return;
|
||||
|
||||
//Make sure our attack is ready and we aren't currently casting before checking distance
|
||||
if (me->isAttackReady())
|
||||
{
|
||||
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec
|
||||
if (me->haveOffhandWeapon())
|
||||
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
me->AttackerStateUpdate(victim);
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
|
||||
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
|
||||
{
|
||||
// xinef: delay main hand attack if both will hit at the same time (players code)
|
||||
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
me->AttackerStateUpdate(victim, OFF_ATTACK);
|
||||
me->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
}
|
||||
|
||||
bool UnitAI::DoSpellAttackIfReady(uint32 spell)
|
||||
{
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady())
|
||||
return true;
|
||||
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell))
|
||||
{
|
||||
if (me->IsWithinCombatRange(me->GetVictim(), spellInfo->GetMaxRange(false)))
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), spell, false);
|
||||
me->resetAttackTimer();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura)
|
||||
{
|
||||
return SelectTarget(targetType, position, DefaultTargetSelector(me, dist, playerOnly, aura));
|
||||
}
|
||||
|
||||
void UnitAI::SelectTargetList(std::list<Unit*>& targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
|
||||
{
|
||||
SelectTargetList(targetList, DefaultTargetSelector(me, dist, playerOnly, aura), num, targetType);
|
||||
}
|
||||
|
||||
float UnitAI::DoGetSpellMaxRange(uint32 spellId, bool positive)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
return spellInfo ? spellInfo->GetMaxRange(positive) : 0;
|
||||
}
|
||||
|
||||
void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid)
|
||||
{
|
||||
if (me->IsInCombat())
|
||||
{
|
||||
ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
|
||||
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
|
||||
{
|
||||
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
|
||||
if (unit->GetTypeId() == TYPEID_PLAYER)
|
||||
me->AddAura(spellid, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered)
|
||||
{
|
||||
if (me->IsInCombat())
|
||||
{
|
||||
ThreatContainer::StorageType threatlist = me->getThreatManager().getThreatList();
|
||||
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
|
||||
{
|
||||
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
|
||||
if (unit->GetTypeId() == TYPEID_PLAYER)
|
||||
me->CastSpell(unit, spellid, triggered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnitAI::DoCast(uint32 spellId)
|
||||
{
|
||||
Unit* target = NULL;
|
||||
//sLog->outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target);
|
||||
switch (AISpellInfo[spellId].target)
|
||||
{
|
||||
default:
|
||||
case AITARGET_SELF: target = me; break;
|
||||
case AITARGET_VICTIM: target = me->GetVictim(); break;
|
||||
case AITARGET_ENEMY:
|
||||
{
|
||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS);
|
||||
//float range = GetSpellMaxRange(spellInfo, false);
|
||||
target = SelectTarget(SELECT_TARGET_RANDOM, 0, spellInfo->GetMaxRange(false), playerOnly);
|
||||
break;
|
||||
}
|
||||
case AITARGET_ALLY: target = me; break;
|
||||
case AITARGET_BUFF: target = me; break;
|
||||
case AITARGET_DEBUFF:
|
||||
{
|
||||
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
bool playerOnly = spellInfo->HasAttribute(SPELL_ATTR3_ONLY_TARGET_PLAYERS);
|
||||
float range = spellInfo->GetMaxRange(false);
|
||||
|
||||
DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId);
|
||||
if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM)
|
||||
&& targetSelector(me->GetVictim()))
|
||||
target = me->GetVictim();
|
||||
else
|
||||
target = SelectTarget(SELECT_TARGET_RANDOM, 0, targetSelector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target)
|
||||
me->CastSpell(target, spellId, false);
|
||||
}
|
||||
|
||||
void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
|
||||
{
|
||||
if (!victim || (me->HasUnitState(UNIT_STATE_CASTING) && !triggered))
|
||||
return;
|
||||
|
||||
me->CastSpell(victim, spellId, triggered);
|
||||
}
|
||||
|
||||
void UnitAI::DoCastVictim(uint32 spellId, bool triggered)
|
||||
{
|
||||
if (!me->GetVictim() || (me->HasUnitState(UNIT_STATE_CASTING) && !triggered))
|
||||
return;
|
||||
|
||||
me->CastSpell(me->GetVictim(), spellId, triggered);
|
||||
}
|
||||
|
||||
void UnitAI::DoCastAOE(uint32 spellId, bool triggered)
|
||||
{
|
||||
if (!triggered && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
me->CastSpell((Unit*)NULL, spellId, triggered);
|
||||
}
|
||||
|
||||
#define UPDATE_TARGET(a) {if (AIInfo->target<a) AIInfo->target=a;}
|
||||
|
||||
void UnitAI::FillAISpellInfo()
|
||||
{
|
||||
AISpellInfo = new AISpellInfoType[sSpellMgr->GetSpellInfoStoreSize()];
|
||||
|
||||
AISpellInfoType* AIInfo = AISpellInfo;
|
||||
const SpellInfo* spellInfo;
|
||||
|
||||
for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i, ++AIInfo)
|
||||
{
|
||||
spellInfo = sSpellMgr->GetSpellInfo(i);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_DEAD))
|
||||
AIInfo->condition = AICOND_DIE;
|
||||
else if (spellInfo->IsPassive() || spellInfo->GetDuration() == -1)
|
||||
AIInfo->condition = AICOND_AGGRO;
|
||||
else
|
||||
AIInfo->condition = AICOND_COMBAT;
|
||||
|
||||
if (AIInfo->cooldown < spellInfo->RecoveryTime)
|
||||
AIInfo->cooldown = spellInfo->RecoveryTime;
|
||||
|
||||
if (!spellInfo->GetMaxRange(false))
|
||||
UPDATE_TARGET(AITARGET_SELF)
|
||||
else
|
||||
{
|
||||
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
|
||||
{
|
||||
uint32 targetType = spellInfo->Effects[j].TargetA.GetTarget();
|
||||
|
||||
if (targetType == TARGET_UNIT_TARGET_ENEMY
|
||||
|| targetType == TARGET_DEST_TARGET_ENEMY)
|
||||
UPDATE_TARGET(AITARGET_VICTIM)
|
||||
else if (targetType == TARGET_UNIT_DEST_AREA_ENEMY)
|
||||
UPDATE_TARGET(AITARGET_ENEMY)
|
||||
|
||||
if (spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA)
|
||||
{
|
||||
if (targetType == TARGET_UNIT_TARGET_ENEMY)
|
||||
UPDATE_TARGET(AITARGET_DEBUFF)
|
||||
else if (spellInfo->IsPositive())
|
||||
UPDATE_TARGET(AITARGET_BUFF)
|
||||
}
|
||||
}
|
||||
}
|
||||
AIInfo->realCooldown = spellInfo->RecoveryTime + spellInfo->StartRecoveryTime;
|
||||
AIInfo->maxRange = spellInfo->GetMaxRange(false) * 3 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
//Enable PlayerAI when charmed
|
||||
void PlayerAI::OnCharmed(bool apply)
|
||||
{
|
||||
me->IsAIEnabled = apply;
|
||||
}
|
||||
|
||||
void SimpleCharmedAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
Creature* charmer = me->GetCharmer()->ToCreature();
|
||||
|
||||
//kill self if charm aura has infinite duration
|
||||
if (charmer->IsInEvadeMode())
|
||||
{
|
||||
Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
|
||||
for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
|
||||
if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
|
||||
{
|
||||
Unit::Kill(charmer, me);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!charmer->IsInCombat())
|
||||
me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle());
|
||||
|
||||
Unit* target = me->GetVictim();
|
||||
if (!target || !charmer->IsValidAttackTarget(target))
|
||||
AttackStart(charmer->SelectNearestTargetInAttackDistance(ATTACK_DISTANCE));
|
||||
}
|
||||
|
||||
SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) :
|
||||
_caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster))
|
||||
{
|
||||
ASSERT(_spellInfo);
|
||||
}
|
||||
|
||||
bool SpellTargetSelector::operator()(Unit const* target) const
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (_spellInfo->CheckTarget(_caster, target) != SPELL_CAST_OK)
|
||||
return false;
|
||||
|
||||
// copypasta from Spell::CheckRange
|
||||
uint32 range_type = _spellInfo->RangeEntry ? _spellInfo->RangeEntry->type : 0;
|
||||
float max_range = _caster->GetSpellMaxRangeForTarget(target, _spellInfo);
|
||||
float min_range = _caster->GetSpellMinRangeForTarget(target, _spellInfo);
|
||||
|
||||
|
||||
if (target && target != _caster)
|
||||
{
|
||||
if (range_type == SPELL_RANGE_MELEE)
|
||||
{
|
||||
// Because of lag, we can not check too strictly here.
|
||||
if (!_caster->IsWithinMeleeRange(target, max_range))
|
||||
return false;
|
||||
}
|
||||
else if (!_caster->IsWithinCombatRange(target, max_range))
|
||||
return false;
|
||||
|
||||
if (range_type == SPELL_RANGE_RANGED)
|
||||
{
|
||||
if (_caster->IsWithinMeleeRange(target))
|
||||
return false;
|
||||
}
|
||||
else if (min_range && _caster->IsWithinCombatRange(target, min_range)) // skip this check if min_range = 0
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NonTankTargetSelector::operator()(Unit const* target) const
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (_playerOnly && target->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
return target != _source->GetVictim();
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_UNITAI_H
|
||||
#define TRINITY_UNITAI_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "Unit.h"
|
||||
#include "Containers.h"
|
||||
#include <list>
|
||||
|
||||
class Player;
|
||||
class Quest;
|
||||
class Unit;
|
||||
struct AISpellInfoType;
|
||||
|
||||
//Selection method used by SelectTarget
|
||||
enum SelectAggroTarget
|
||||
{
|
||||
SELECT_TARGET_RANDOM = 0, //Just selects a random target
|
||||
SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
|
||||
SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
|
||||
SELECT_TARGET_NEAREST,
|
||||
SELECT_TARGET_FARTHEST,
|
||||
};
|
||||
|
||||
// default predicate function to select target based on distance, player and/or aura criteria
|
||||
struct DefaultTargetSelector : public std::unary_function<Unit*, bool>
|
||||
{
|
||||
const Unit* me;
|
||||
float m_dist;
|
||||
bool m_playerOnly;
|
||||
int32 m_aura;
|
||||
|
||||
// unit: the reference unit
|
||||
// dist: if 0: ignored, if > 0: maximum distance to the reference unit, if < 0: minimum distance to the reference unit
|
||||
// playerOnly: self explaining
|
||||
// aura: if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura
|
||||
DefaultTargetSelector(Unit const* unit, float dist, bool playerOnly, int32 aura) : me(unit), m_dist(dist), m_playerOnly(playerOnly), m_aura(aura) {}
|
||||
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
if (!me)
|
||||
return false;
|
||||
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (m_playerOnly && (target->GetTypeId() != TYPEID_PLAYER))
|
||||
return false;
|
||||
|
||||
if (m_dist > 0.0f && !me->IsWithinCombatRange(target, m_dist))
|
||||
return false;
|
||||
|
||||
if (m_dist < 0.0f && me->IsWithinCombatRange(target, -m_dist))
|
||||
return false;
|
||||
|
||||
if (m_aura)
|
||||
{
|
||||
if (m_aura > 0)
|
||||
{
|
||||
if (!target->HasAura(m_aura))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target->HasAura(-m_aura))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Target selector for spell casts checking range, auras and attributes
|
||||
// TODO: Add more checks from Spell::CheckCast
|
||||
struct SpellTargetSelector : public std::unary_function<Unit*, bool>
|
||||
{
|
||||
public:
|
||||
SpellTargetSelector(Unit* caster, uint32 spellId);
|
||||
bool operator()(Unit const* target) const;
|
||||
|
||||
private:
|
||||
Unit const* _caster;
|
||||
SpellInfo const* _spellInfo;
|
||||
};
|
||||
|
||||
// Very simple target selector, will just skip main target
|
||||
// NOTE: When passing to UnitAI::SelectTarget remember to use 0 as position for random selection
|
||||
// because tank will not be in the temporary list
|
||||
struct NonTankTargetSelector : public std::unary_function<Unit*, bool>
|
||||
{
|
||||
public:
|
||||
NonTankTargetSelector(Creature* source, bool playerOnly = true) : _source(source), _playerOnly(playerOnly) { }
|
||||
bool operator()(Unit const* target) const;
|
||||
|
||||
private:
|
||||
Creature const* _source;
|
||||
bool _playerOnly;
|
||||
};
|
||||
|
||||
// Simple selector for units using mana
|
||||
struct PowerUsersSelector : public std::unary_function<Unit*, bool>
|
||||
{
|
||||
Unit const* _me;
|
||||
float const _dist;
|
||||
bool const _playerOnly;
|
||||
Powers const _power;
|
||||
|
||||
|
||||
PowerUsersSelector(Unit const* unit, Powers power, float dist, bool playerOnly) : _me(unit), _power(power), _dist(dist), _playerOnly(playerOnly) { }
|
||||
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
if (!_me || !target)
|
||||
return false;
|
||||
|
||||
if (target->getPowerType() != _power)
|
||||
return false;
|
||||
|
||||
if (_playerOnly && target->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
if (_dist > 0.0f && !_me->IsWithinCombatRange(target, _dist))
|
||||
return false;
|
||||
|
||||
if (_dist < 0.0f && _me->IsWithinCombatRange(target, -_dist))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct FarthestTargetSelector : public std::unary_function<Unit*, bool>
|
||||
{
|
||||
FarthestTargetSelector(Unit const* unit, float dist, bool playerOnly, bool inLos) : _me(unit), _dist(dist), _playerOnly(playerOnly), _inLos(inLos) {}
|
||||
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
if (!_me || !target)
|
||||
return false;
|
||||
|
||||
if (_playerOnly && target->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
if (_dist > 0.0f && !_me->IsWithinCombatRange(target, _dist))
|
||||
return false;
|
||||
|
||||
if (_inLos && !_me->IsWithinLOSInMap(target))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const Unit* _me;
|
||||
float _dist;
|
||||
bool _playerOnly;
|
||||
bool _inLos;
|
||||
};
|
||||
|
||||
class UnitAI
|
||||
{
|
||||
protected:
|
||||
Unit* const me;
|
||||
public:
|
||||
explicit UnitAI(Unit* unit) : me(unit) {}
|
||||
virtual ~UnitAI() {}
|
||||
|
||||
virtual bool CanAIAttack(Unit const* /*target*/) const { return true; }
|
||||
virtual void AttackStart(Unit* /*target*/);
|
||||
virtual void UpdateAI(uint32 diff) = 0;
|
||||
|
||||
virtual void InitializeAI() { if (!me->isDead()) Reset(); }
|
||||
|
||||
virtual void Reset() {};
|
||||
|
||||
// Called when unit is charmed
|
||||
virtual void OnCharmed(bool apply) = 0;
|
||||
|
||||
// Pass parameters between AI
|
||||
virtual void DoAction(int32 /*param*/) {}
|
||||
virtual uint32 GetData(uint32 /*id = 0*/) const { return 0; }
|
||||
virtual void SetData(uint32 /*id*/, uint32 /*value*/) {}
|
||||
virtual void SetGUID(uint64 /*guid*/, int32 /*id*/ = 0) {}
|
||||
virtual uint64 GetGUID(int32 /*id*/ = 0) const { return 0; }
|
||||
|
||||
Unit* SelectTarget(SelectAggroTarget targetType, uint32 position = 0, float dist = 0.0f, bool playerOnly = false, int32 aura = 0);
|
||||
// Select the targets satifying the predicate.
|
||||
// predicate shall extend std::unary_function<Unit*, bool>
|
||||
template <class PREDICATE> Unit* SelectTarget(SelectAggroTarget targetType, uint32 position, PREDICATE const& predicate)
|
||||
{
|
||||
ThreatContainer::StorageType const& threatlist = me->getThreatManager().getThreatList();
|
||||
if (position >= threatlist.size())
|
||||
return NULL;
|
||||
|
||||
std::list<Unit*> targetList;
|
||||
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
|
||||
if (predicate((*itr)->getTarget()))
|
||||
targetList.push_back((*itr)->getTarget());
|
||||
|
||||
if (position >= targetList.size())
|
||||
return NULL;
|
||||
|
||||
if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
|
||||
targetList.sort(Trinity::ObjectDistanceOrderPred(me));
|
||||
|
||||
switch (targetType)
|
||||
{
|
||||
case SELECT_TARGET_NEAREST:
|
||||
case SELECT_TARGET_TOPAGGRO:
|
||||
{
|
||||
std::list<Unit*>::iterator itr = targetList.begin();
|
||||
std::advance(itr, position);
|
||||
return *itr;
|
||||
}
|
||||
case SELECT_TARGET_FARTHEST:
|
||||
case SELECT_TARGET_BOTTOMAGGRO:
|
||||
{
|
||||
std::list<Unit*>::reverse_iterator ritr = targetList.rbegin();
|
||||
std::advance(ritr, position);
|
||||
return *ritr;
|
||||
}
|
||||
case SELECT_TARGET_RANDOM:
|
||||
{
|
||||
std::list<Unit*>::iterator itr = targetList.begin();
|
||||
std::advance(itr, urand(position, targetList.size() - 1));
|
||||
return *itr;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SelectTargetList(std::list<Unit*>& targetList, uint32 num, SelectAggroTarget targetType, float dist = 0.0f, bool playerOnly = false, int32 aura = 0);
|
||||
|
||||
// Select the targets satifying the predicate.
|
||||
// predicate shall extend std::unary_function<Unit*, bool>
|
||||
template <class PREDICATE> void SelectTargetList(std::list<Unit*>& targetList, PREDICATE const& predicate, uint32 maxTargets, SelectAggroTarget targetType)
|
||||
{
|
||||
ThreatContainer::StorageType const& threatlist = me->getThreatManager().getThreatList();
|
||||
if (threatlist.empty())
|
||||
return;
|
||||
|
||||
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
|
||||
if (predicate((*itr)->getTarget()))
|
||||
targetList.push_back((*itr)->getTarget());
|
||||
|
||||
if (targetList.size() < maxTargets)
|
||||
return;
|
||||
|
||||
if (targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
|
||||
targetList.sort(Trinity::ObjectDistanceOrderPred(me));
|
||||
|
||||
if (targetType == SELECT_TARGET_FARTHEST || targetType == SELECT_TARGET_BOTTOMAGGRO)
|
||||
targetList.reverse();
|
||||
|
||||
if (targetType == SELECT_TARGET_RANDOM)
|
||||
Trinity::Containers::RandomResizeList(targetList, maxTargets);
|
||||
else
|
||||
targetList.resize(maxTargets);
|
||||
}
|
||||
|
||||
// Called at any Damage to any victim (before damage apply)
|
||||
virtual void DamageDealt(Unit* /*victim*/, uint32& /*damage*/, DamageEffectType /*damageType*/) { }
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
// Note: it for recalculation damage or special reaction at damage
|
||||
// for attack reaction use AttackedBy called for not DOT damage in Unit::DealDamage also
|
||||
virtual void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) {}
|
||||
|
||||
// Called when the creature receives heal
|
||||
virtual void HealReceived(Unit* /*done_by*/, uint32& /*addhealth*/) {}
|
||||
|
||||
// Called when the unit heals
|
||||
virtual void HealDone(Unit* /*done_to*/, uint32& /*addhealth*/) {}
|
||||
|
||||
void AttackStartCaster(Unit* victim, float dist);
|
||||
|
||||
void DoAddAuraToAllHostilePlayers(uint32 spellid);
|
||||
void DoCast(uint32 spellId);
|
||||
void DoCast(Unit* victim, uint32 spellId, bool triggered = false);
|
||||
void DoCastToAllHostilePlayers(uint32 spellid, bool triggered = false);
|
||||
void DoCastVictim(uint32 spellId, bool triggered = false);
|
||||
void DoCastAOE(uint32 spellId, bool triggered = false);
|
||||
|
||||
float DoGetSpellMaxRange(uint32 spellId, bool positive = false);
|
||||
|
||||
void DoMeleeAttackIfReady();
|
||||
bool DoSpellAttackIfReady(uint32 spell);
|
||||
|
||||
static AISpellInfoType* AISpellInfo;
|
||||
static void FillAISpellInfo();
|
||||
|
||||
virtual void sGossipHello(Player* /*player*/) {}
|
||||
virtual void sGossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) {}
|
||||
virtual void sGossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) {}
|
||||
virtual void sQuestAccept(Player* /*player*/, Quest const* /*quest*/) {}
|
||||
virtual void sQuestSelect(Player* /*player*/, Quest const* /*quest*/) {}
|
||||
virtual void sQuestComplete(Player* /*player*/, Quest const* /*quest*/) {}
|
||||
virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) {}
|
||||
virtual void sOnGameEvent(bool /*start*/, uint16 /*eventId*/) {}
|
||||
};
|
||||
|
||||
class PlayerAI : public UnitAI
|
||||
{
|
||||
protected:
|
||||
Player* const me;
|
||||
public:
|
||||
explicit PlayerAI(Player* player) : UnitAI((Unit*)player), me(player) {}
|
||||
|
||||
void OnCharmed(bool apply);
|
||||
};
|
||||
|
||||
class SimpleCharmedAI : public PlayerAI
|
||||
{
|
||||
public:
|
||||
void UpdateAI(uint32 diff);
|
||||
SimpleCharmedAI(Player* player): PlayerAI(player) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,268 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "Creature.h"
|
||||
#include "World.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Log.h"
|
||||
#include "MapReference.h"
|
||||
#include "Player.h"
|
||||
#include "CreatureTextMgr.h"
|
||||
|
||||
//Disable CreatureAI when charmed
|
||||
void CreatureAI::OnCharmed(bool /*apply*/)
|
||||
{
|
||||
//me->IsAIEnabled = !apply;*/
|
||||
me->NeedChangeAI = true;
|
||||
me->IsAIEnabled = false;
|
||||
}
|
||||
|
||||
AISpellInfoType* UnitAI::AISpellInfo;
|
||||
AISpellInfoType* GetAISpellInfo(uint32 i) { return &CreatureAI::AISpellInfo[i]; }
|
||||
|
||||
void CreatureAI::Talk(uint8 id, WorldObject const* whisperTarget /*= NULL*/)
|
||||
{
|
||||
sCreatureTextMgr->SendChat(me, id, whisperTarget);
|
||||
}
|
||||
|
||||
void CreatureAI::DoZoneInCombat(Creature* creature /*= NULL*/, float maxRangeToNearestTarget /* = 50.0f*/)
|
||||
{
|
||||
if (!creature)
|
||||
creature = me;
|
||||
|
||||
if (!creature->CanHaveThreatList())
|
||||
return;
|
||||
|
||||
Map* map = creature->GetMap();
|
||||
if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
|
||||
{
|
||||
sLog->outError("DoZoneInCombat call for map that isn't an instance (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? creature->ToCreature()->GetEntry() : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Xinef: Skip creatures in evade mode
|
||||
if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim() && !creature->IsInEvadeMode())
|
||||
{
|
||||
if (Unit* nearTarget = creature->SelectNearestTarget(maxRangeToNearestTarget))
|
||||
creature->AI()->AttackStart(nearTarget);
|
||||
else if (creature->IsSummon())
|
||||
{
|
||||
if (Unit* summoner = creature->ToTempSummon()->GetSummoner())
|
||||
{
|
||||
Unit* target = summoner->getAttackerForHelper();
|
||||
if (!target && summoner->CanHaveThreatList() && !summoner->getThreatManager().isThreatListEmpty())
|
||||
target = summoner->getThreatManager().getHostilTarget();
|
||||
if (target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target)))
|
||||
creature->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
|
||||
{
|
||||
sLog->outError("DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
Map::PlayerList const& playerList = map->GetPlayers();
|
||||
|
||||
if (playerList.isEmpty())
|
||||
return;
|
||||
|
||||
for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
|
||||
{
|
||||
if (Player* player = itr->GetSource())
|
||||
{
|
||||
if (player->IsGameMaster())
|
||||
continue;
|
||||
|
||||
if (player->IsAlive())
|
||||
{
|
||||
creature->SetInCombatWith(player);
|
||||
player->SetInCombatWith(creature);
|
||||
creature->AddThreat(player, 0.0f);
|
||||
}
|
||||
|
||||
/* Causes certain things to never leave the threat list (Priest Lightwell, etc):
|
||||
for (Unit::ControlSet::const_iterator itr = player->m_Controlled.begin(); itr != player->m_Controlled.end(); ++itr)
|
||||
{
|
||||
creature->SetInCombatWith(*itr);
|
||||
(*itr)->SetInCombatWith(creature);
|
||||
creature->AddThreat(*itr, 0.0f);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scripts does not take care about MoveInLineOfSight loops
|
||||
// MoveInLineOfSight can be called inside another MoveInLineOfSight and cause stack overflow
|
||||
void CreatureAI::MoveInLineOfSight_Safe(Unit* who)
|
||||
{
|
||||
if (m_MoveInLineOfSight_locked == true)
|
||||
return;
|
||||
m_MoveInLineOfSight_locked = true;
|
||||
MoveInLineOfSight(who);
|
||||
m_MoveInLineOfSight_locked = false;
|
||||
}
|
||||
|
||||
void CreatureAI::MoveInLineOfSight(Unit* who)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
return;
|
||||
|
||||
// pussywizard: civilian, non-combat pet or any other NOT HOSTILE TO ANYONE (!)
|
||||
if (me->IsMoveInLineOfSightDisabled())
|
||||
if (me->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET || // nothing more to do, return
|
||||
!who->IsInCombat() || // if not in combat, nothing more to do
|
||||
!me->IsWithinDist(who, ATTACK_DISTANCE)) // if in combat and in dist - neutral to all can actually assist other creatures
|
||||
return;
|
||||
|
||||
if (me->CanStartAttack(who))
|
||||
AttackStart(who);
|
||||
}
|
||||
|
||||
void CreatureAI::EnterEvadeMode()
|
||||
{
|
||||
if (!_EnterEvadeMode())
|
||||
return;
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_UNITS, "Creature %u enters evade mode.", me->GetEntry());
|
||||
|
||||
if (!me->GetVehicle()) // otherwise me will be in evade mode forever
|
||||
{
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Required to prevent attacking creatures that are evading and cause them to reenter combat
|
||||
// Does not apply to MoveFollow
|
||||
me->AddUnitState(UNIT_STATE_EVADE);
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
if (me->IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons!
|
||||
me->GetVehicleKit()->Reset(true);
|
||||
}
|
||||
|
||||
/*void CreatureAI::AttackedBy(Unit* attacker)
|
||||
{
|
||||
if (!me->GetVictim())
|
||||
AttackStart(attacker);
|
||||
}*/
|
||||
|
||||
void CreatureAI::SetGazeOn(Unit* target)
|
||||
{
|
||||
if (me->IsValidAttackTarget(target))
|
||||
{
|
||||
AttackStart(target);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
bool CreatureAI::UpdateVictimWithGaze()
|
||||
{
|
||||
if (!me->IsInCombat())
|
||||
return false;
|
||||
|
||||
if (me->HasReactState(REACT_PASSIVE))
|
||||
{
|
||||
if (me->GetVictim())
|
||||
return true;
|
||||
else
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
if (Unit* victim = me->SelectVictim())
|
||||
AttackStart(victim);
|
||||
return me->GetVictim();
|
||||
}
|
||||
|
||||
bool CreatureAI::UpdateVictim()
|
||||
{
|
||||
if (!me->IsInCombat())
|
||||
return false;
|
||||
|
||||
if (!me->HasReactState(REACT_PASSIVE))
|
||||
{
|
||||
if (Unit* victim = me->SelectVictim())
|
||||
AttackStart(victim);
|
||||
return me->GetVictim();
|
||||
}
|
||||
// xinef: if we have any victim, just return true
|
||||
else if (me->GetVictim() && me->GetExactDist(me->GetVictim()) < 30.0f)
|
||||
return true;
|
||||
else if (me->getThreatManager().isThreatListEmpty())
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreatureAI::_EnterEvadeMode()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
return false;
|
||||
|
||||
// don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
|
||||
// don't remove clone caster on evade (to be verified)
|
||||
me->RemoveEvadeAuras();
|
||||
|
||||
// sometimes bosses stuck in combat?
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop(true);
|
||||
me->LoadCreaturesAddon(true);
|
||||
me->SetLootRecipient(NULL);
|
||||
me->ResetPlayerDamageReq();
|
||||
me->SetLastDamagedTime(0);
|
||||
|
||||
if (me->IsInEvadeMode())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Creature* CreatureAI::DoSummon(uint32 entry, const Position& pos, uint32 despawnTime, TempSummonType summonType)
|
||||
{
|
||||
return me->SummonCreature(entry, pos, summonType, despawnTime);
|
||||
}
|
||||
|
||||
Creature* CreatureAI::DoSummon(uint32 entry, WorldObject* obj, float radius, uint32 despawnTime, TempSummonType summonType)
|
||||
{
|
||||
Position pos;
|
||||
obj->GetRandomNearPosition(pos, radius);
|
||||
return me->SummonCreature(entry, pos, summonType, despawnTime);
|
||||
}
|
||||
|
||||
Creature* CreatureAI::DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius, uint32 despawnTime, TempSummonType summonType)
|
||||
{
|
||||
Position pos;
|
||||
obj->GetRandomNearPosition(pos, radius);
|
||||
pos.m_positionZ += flightZ;
|
||||
return me->SummonCreature(entry, pos, summonType, despawnTime);
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_CREATUREAI_H
|
||||
#define TRINITY_CREATUREAI_H
|
||||
|
||||
#include "Creature.h"
|
||||
#include "UnitAI.h"
|
||||
#include "Common.h"
|
||||
|
||||
class WorldObject;
|
||||
class Unit;
|
||||
class Creature;
|
||||
class Player;
|
||||
class SpellInfo;
|
||||
|
||||
#define TIME_INTERVAL_LOOK 5000
|
||||
#define VISIBILITY_RANGE 10000
|
||||
|
||||
//Spell targets used by SelectSpell
|
||||
enum SelectTargetType
|
||||
{
|
||||
SELECT_TARGET_DONTCARE = 0, //All target types allowed
|
||||
|
||||
SELECT_TARGET_SELF, //Only Self casting
|
||||
|
||||
SELECT_TARGET_SINGLE_ENEMY, //Only Single Enemy
|
||||
SELECT_TARGET_AOE_ENEMY, //Only AoE Enemy
|
||||
SELECT_TARGET_ANY_ENEMY, //AoE or Single Enemy
|
||||
|
||||
SELECT_TARGET_SINGLE_FRIEND, //Only Single Friend
|
||||
SELECT_TARGET_AOE_FRIEND, //Only AoE Friend
|
||||
SELECT_TARGET_ANY_FRIEND, //AoE or Single Friend
|
||||
};
|
||||
|
||||
//Spell Effects used by SelectSpell
|
||||
enum SelectEffect
|
||||
{
|
||||
SELECT_EFFECT_DONTCARE = 0, //All spell effects allowed
|
||||
SELECT_EFFECT_DAMAGE, //Spell does damage
|
||||
SELECT_EFFECT_HEALING, //Spell does healing
|
||||
SELECT_EFFECT_AURA, //Spell applies an aura
|
||||
};
|
||||
|
||||
enum SCEquip
|
||||
{
|
||||
EQUIP_NO_CHANGE = -1,
|
||||
EQUIP_UNEQUIP = 0
|
||||
};
|
||||
|
||||
class CreatureAI : public UnitAI
|
||||
{
|
||||
protected:
|
||||
Creature* const me;
|
||||
|
||||
bool UpdateVictim();
|
||||
bool UpdateVictimWithGaze();
|
||||
|
||||
void SetGazeOn(Unit* target);
|
||||
|
||||
Creature* DoSummon(uint32 entry, Position const& pos, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
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:
|
||||
void Talk(uint8 id, WorldObject const* whisperTarget = NULL);
|
||||
explicit CreatureAI(Creature* creature) : UnitAI(creature), me(creature), m_MoveInLineOfSight_locked(false) {}
|
||||
|
||||
virtual ~CreatureAI() {}
|
||||
|
||||
/// == Reactions At =================================
|
||||
|
||||
// Called if IsVisible(Unit* who) is true at each who move, reaction at visibility zone enter
|
||||
void MoveInLineOfSight_Safe(Unit* who);
|
||||
|
||||
// Called in Creature::Update when deathstate = DEAD. Inherited classes may maniuplate the ability to respawn based on scripted events.
|
||||
virtual bool CanRespawn() { return true; }
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
virtual void EnterEvadeMode();
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
|
||||
virtual void EnterCombat(Unit* /*victim*/) {}
|
||||
|
||||
// Called when the creature is killed
|
||||
virtual void JustDied(Unit* /*killer*/) {}
|
||||
|
||||
// Called when the creature kills a unit
|
||||
virtual void KilledUnit(Unit* /*victim*/) {}
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
virtual void JustSummoned(Creature* /*summon*/) {}
|
||||
virtual void IsSummonedBy(Unit* /*summoner*/) {}
|
||||
|
||||
virtual void SummonedCreatureDespawn(Creature* /*summon*/) {}
|
||||
virtual void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) {}
|
||||
|
||||
// Called when hit by a spell
|
||||
virtual void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/) {}
|
||||
|
||||
// Called when spell hits a target
|
||||
virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) {}
|
||||
|
||||
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
|
||||
virtual void AttackedBy(Unit* /*attacker*/) {}
|
||||
virtual bool IsEscorted() { return false; }
|
||||
|
||||
// Called when creature is spawned or respawned (for reseting variables)
|
||||
virtual void JustRespawned() { Reset(); }
|
||||
|
||||
// Called at waypoint reached or point movement finished
|
||||
virtual void MovementInform(uint32 /*type*/, uint32 /*id*/) {}
|
||||
|
||||
void OnCharmed(bool apply);
|
||||
|
||||
// Called at reaching home after evade
|
||||
virtual void JustReachedHome() {}
|
||||
|
||||
void DoZoneInCombat(Creature* creature = NULL, float maxRangeToNearestTarget = 50.0f);
|
||||
|
||||
// Called at text emote receive from player
|
||||
virtual void ReceiveEmote(Player* /*player*/, uint32 /*emoteId*/) {}
|
||||
|
||||
// Called when owner takes damage
|
||||
virtual void OwnerAttackedBy(Unit* /*attacker*/) {}
|
||||
|
||||
// Called when owner attacks something
|
||||
virtual void OwnerAttacked(Unit* /*target*/) {}
|
||||
|
||||
/// == Triggered Actions Requested ==================
|
||||
|
||||
// Called when creature attack expected (if creature can and no have current victim)
|
||||
// Note: for reaction at hostile action must be called AttackedBy function.
|
||||
//virtual void AttackStart(Unit*) {}
|
||||
|
||||
// Called at World update tick
|
||||
//virtual void UpdateAI(uint32 /*diff*/) {}
|
||||
|
||||
/// == State checks =================================
|
||||
|
||||
// Is unit visible for MoveInLineOfSight
|
||||
//virtual bool IsVisible(Unit*) const { return false; }
|
||||
|
||||
// called when the corpse of this creature gets removed
|
||||
virtual void CorpseRemoved(uint32& /*respawnDelay*/) {}
|
||||
|
||||
// Called when victim entered water and creature can not enter water
|
||||
//virtual bool CanReachByRangeAttack(Unit*) { return false; }
|
||||
|
||||
/// == Fields =======================================
|
||||
virtual void PassengerBoarded(Unit* /*passenger*/, int8 /*seatId*/, bool /*apply*/) {}
|
||||
|
||||
virtual void OnSpellClick(Unit* /*clicker*/, bool& /*result*/) { }
|
||||
|
||||
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
|
||||
|
||||
virtual bool CanBeSeen(Player const* /*seer*/) { return true; }
|
||||
|
||||
protected:
|
||||
virtual void MoveInLineOfSight(Unit* /*who*/);
|
||||
|
||||
bool _EnterEvadeMode();
|
||||
|
||||
private:
|
||||
bool m_MoveInLineOfSight_locked;
|
||||
};
|
||||
|
||||
enum Permitions
|
||||
{
|
||||
PERMIT_BASE_NO = -1,
|
||||
PERMIT_BASE_IDLE = 1,
|
||||
PERMIT_BASE_REACTIVE = 100,
|
||||
PERMIT_BASE_PROACTIVE = 200,
|
||||
PERMIT_BASE_FACTION_SPECIFIC = 400,
|
||||
PERMIT_BASE_SPECIAL = 800
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef TRINITY_CREATUREAIFACTORY_H
|
||||
#define TRINITY_CREATUREAIFACTORY_H
|
||||
|
||||
//#include "Policies/Singleton.h"
|
||||
#include "ObjectRegistry.h"
|
||||
#include "FactoryHolder.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
|
||||
{
|
||||
SelectableAI(const char* id) : FactoryHolder<CreatureAI>(id) {}
|
||||
};
|
||||
|
||||
template<class REAL_AI>
|
||||
struct CreatureAIFactory : public SelectableAI
|
||||
{
|
||||
CreatureAIFactory(const char* name) : SelectableAI(name) {}
|
||||
|
||||
CreatureAI* Create(void*) const;
|
||||
|
||||
int Permit(const Creature* c) const { return REAL_AI::Permissible(c); }
|
||||
};
|
||||
|
||||
template<class REAL_AI>
|
||||
inline CreatureAI*
|
||||
CreatureAIFactory<REAL_AI>::Create(void* data) const
|
||||
{
|
||||
Creature* creature = reinterpret_cast<Creature*>(data);
|
||||
return (new REAL_AI(creature));
|
||||
}
|
||||
|
||||
typedef FactoryHolder<CreatureAI> CreatureAICreator;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository;
|
||||
|
||||
//GO
|
||||
struct SelectableGameObjectAI : public FactoryHolder<GameObjectAI>, public Permissible<GameObject>
|
||||
{
|
||||
SelectableGameObjectAI(const char* id) : FactoryHolder<GameObjectAI>(id) {}
|
||||
};
|
||||
|
||||
template<class REAL_GO_AI>
|
||||
struct GameObjectAIFactory : public SelectableGameObjectAI
|
||||
{
|
||||
GameObjectAIFactory(const char* name) : SelectableGameObjectAI(name) {}
|
||||
|
||||
GameObjectAI* Create(void*) const;
|
||||
|
||||
int Permit(const GameObject* g) const { return REAL_GO_AI::Permissible(g); }
|
||||
};
|
||||
|
||||
template<class REAL_GO_AI>
|
||||
inline GameObjectAI*
|
||||
GameObjectAIFactory<REAL_GO_AI>::Create(void* data) const
|
||||
{
|
||||
GameObject* go = reinterpret_cast<GameObject*>(data);
|
||||
return (new REAL_GO_AI(go));
|
||||
}
|
||||
|
||||
typedef FactoryHolder<GameObjectAI> GameObjectAICreator;
|
||||
typedef FactoryHolder<GameObjectAI>::FactoryHolderRegistry GameObjectAIRegistry;
|
||||
typedef FactoryHolder<GameObjectAI>::FactoryHolderRepository GameObjectAIRepository;
|
||||
#endif
|
||||
@@ -1,347 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CREATUREAIIMPL_H
|
||||
#define CREATUREAIIMPL_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Define.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2)
|
||||
{
|
||||
return (urand(0, 1)) ? v1 : v2;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3)
|
||||
{
|
||||
switch (urand(0, 2))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4)
|
||||
{
|
||||
switch (urand(0, 3))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5)
|
||||
{
|
||||
switch (urand(0, 4))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6)
|
||||
{
|
||||
switch (urand(0, 5))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7)
|
||||
{
|
||||
switch (urand(0, 6))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8)
|
||||
{
|
||||
switch (urand(0, 7))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9)
|
||||
{
|
||||
switch (urand(0, 8))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10)
|
||||
{
|
||||
switch (urand(0, 9))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10, const T& v11)
|
||||
{
|
||||
switch (urand(0, 10))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
case 10: return v11;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10, const T& v11, const T& v12)
|
||||
{
|
||||
switch (urand(0, 11))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
case 10: return v11;
|
||||
case 11: return v12;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10, const T& v11, const T& v12, const T& v13)
|
||||
{
|
||||
switch (urand(0, 12))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
case 10: return v11;
|
||||
case 11: return v12;
|
||||
case 12: return v13;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14)
|
||||
{
|
||||
switch (urand(0, 13))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
case 10: return v11;
|
||||
case 11: return v12;
|
||||
case 12: return v13;
|
||||
case 13: return v14;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14, const T& v15)
|
||||
{
|
||||
switch (urand(0, 14))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
case 10: return v11;
|
||||
case 11: return v12;
|
||||
case 12: return v13;
|
||||
case 13: return v14;
|
||||
case 14: return v15;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
|
||||
const T& v9, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14, const T& v15, const T& v16)
|
||||
{
|
||||
switch (urand(0, 15))
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
case 5: return v6;
|
||||
case 6: return v7;
|
||||
case 7: return v8;
|
||||
case 8: return v9;
|
||||
case 9: return v10;
|
||||
case 10: return v11;
|
||||
case 11: return v12;
|
||||
case 12: return v13;
|
||||
case 13: return v14;
|
||||
case 14: return v15;
|
||||
case 15: return v16;
|
||||
}
|
||||
}
|
||||
|
||||
enum AITarget
|
||||
{
|
||||
AITARGET_SELF,
|
||||
AITARGET_VICTIM,
|
||||
AITARGET_ENEMY,
|
||||
AITARGET_ALLY,
|
||||
AITARGET_BUFF,
|
||||
AITARGET_DEBUFF,
|
||||
};
|
||||
|
||||
enum AICondition
|
||||
{
|
||||
AICOND_AGGRO,
|
||||
AICOND_COMBAT,
|
||||
AICOND_DIE,
|
||||
};
|
||||
|
||||
#define AI_DEFAULT_COOLDOWN 5000
|
||||
|
||||
struct AISpellInfoType
|
||||
{
|
||||
AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT)
|
||||
, cooldown(AI_DEFAULT_COOLDOWN), realCooldown(0), maxRange(0.0f){}
|
||||
AITarget target;
|
||||
AICondition condition;
|
||||
uint32 cooldown;
|
||||
uint32 realCooldown;
|
||||
float maxRange;
|
||||
};
|
||||
|
||||
AISpellInfoType* GetAISpellInfo(uint32 i);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PassiveAI.h"
|
||||
#include "ReactorAI.h"
|
||||
#include "CombatAI.h"
|
||||
#include "GuardAI.h"
|
||||
#include "PetAI.h"
|
||||
#include "TotemAI.h"
|
||||
#include "RandomMovementGenerator.h"
|
||||
#include "MovementGeneratorImpl.h"
|
||||
#include "CreatureAIRegistry.h"
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "CreatureAIFactory.h"
|
||||
#include "SmartAI.h"
|
||||
|
||||
//#include "CreatureAIImpl.h"
|
||||
namespace AIRegistry
|
||||
{
|
||||
void Initialize()
|
||||
{
|
||||
(new CreatureAIFactory<NullCreatureAI>("NullCreatureAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<TriggerAI>("TriggerAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<AggressorAI>("AggressorAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<ReactorAI>("ReactorAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<PassiveAI>("PassiveAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<CritterAI>("CritterAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<GuardAI>("GuardAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<CombatAI>("CombatAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<ArcherAI>("ArcherAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<TurretAI>("TurretAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<VehicleAI>("VehicleAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<SmartAI>("SmartAI"))->RegisterSelf();
|
||||
|
||||
(new GameObjectAIFactory<GameObjectAI>("GameObjectAI"))->RegisterSelf();
|
||||
(new GameObjectAIFactory<SmartGameObjectAI>("SmartGameObjectAI"))->RegisterSelf();
|
||||
|
||||
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
|
||||
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_CREATUREAIREGISTRY_H
|
||||
#define TRINITY_CREATUREAIREGISTRY_H
|
||||
|
||||
namespace AIRegistry
|
||||
{
|
||||
void Initialize(void);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Creature.h"
|
||||
#include "CreatureAISelector.h"
|
||||
#include "PassiveAI.h"
|
||||
|
||||
#include "MovementGenerator.h"
|
||||
#include "Pet.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "CreatureAIFactory.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
namespace FactorySelector
|
||||
{
|
||||
CreatureAI* selectAI(Creature* creature)
|
||||
{
|
||||
const CreatureAICreator* ai_factory = NULL;
|
||||
CreatureAIRegistry& ai_registry(*CreatureAIRepository::instance());
|
||||
|
||||
// xinef: if we have controlable guardian, define petai for players as they can steer him, otherwise db / normal ai
|
||||
// xinef: dont remember why i changed this qq commented out as may break some quests
|
||||
if (creature->IsPet()/* || (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)*/)
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
|
||||
//scriptname in db
|
||||
if (!ai_factory)
|
||||
if (CreatureAI* scriptedAI = sScriptMgr->GetCreatureAI(creature))
|
||||
return scriptedAI;
|
||||
|
||||
// AIname in db
|
||||
std::string ainame=creature->GetAIName();
|
||||
if (!ai_factory && !ainame.empty())
|
||||
ai_factory = ai_registry.GetRegistryItem(ainame);
|
||||
|
||||
// select by NPC flags
|
||||
if (!ai_factory)
|
||||
{
|
||||
if (creature->IsVehicle())
|
||||
ai_factory = ai_registry.GetRegistryItem("VehicleAI");
|
||||
else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
else if (creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK))
|
||||
ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
|
||||
else if (creature->IsGuard())
|
||||
ai_factory = ai_registry.GetRegistryItem("GuardAI");
|
||||
else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
|
||||
ai_factory = ai_registry.GetRegistryItem("PetAI");
|
||||
else if (creature->IsTotem())
|
||||
ai_factory = ai_registry.GetRegistryItem("TotemAI");
|
||||
else if (creature->IsTrigger())
|
||||
{
|
||||
if (creature->m_spells[0])
|
||||
ai_factory = ai_registry.GetRegistryItem("TriggerAI");
|
||||
else
|
||||
ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
|
||||
}
|
||||
else if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
|
||||
ai_factory = ai_registry.GetRegistryItem("CritterAI");
|
||||
}
|
||||
|
||||
// select by permit check
|
||||
if (!ai_factory)
|
||||
{
|
||||
int best_val = -1;
|
||||
typedef CreatureAIRegistry::RegistryMapType RMT;
|
||||
RMT const& l = ai_registry.GetRegisteredItems();
|
||||
for (RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter)
|
||||
{
|
||||
const CreatureAICreator* factory = iter->second;
|
||||
const SelectableAI* p = dynamic_cast<const SelectableAI*>(factory);
|
||||
ASSERT(p);
|
||||
int val = p->Permit(creature);
|
||||
if (val > best_val)
|
||||
{
|
||||
best_val = val;
|
||||
ai_factory = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// select NullCreatureAI if not another cases
|
||||
// xinef: unused
|
||||
// ainame = (ai_factory == NULL) ? "NullCreatureAI" : ai_factory->key();
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "Creature %u used AI is %s.", creature->GetGUIDLow(), ainame.c_str());
|
||||
return (ai_factory == NULL ? new NullCreatureAI(creature) : ai_factory->Create(creature));
|
||||
}
|
||||
|
||||
MovementGenerator* selectMovementGenerator(Creature* creature)
|
||||
{
|
||||
MovementGeneratorRegistry& mv_registry(*MovementGeneratorRepository::instance());
|
||||
ASSERT(creature->GetCreatureTemplate());
|
||||
const MovementGeneratorCreator* mv_factory = mv_registry.GetRegistryItem(creature->GetDefaultMovementType());
|
||||
|
||||
/* if (mv_factory == NULL)
|
||||
{
|
||||
int best_val = -1;
|
||||
StringVector l;
|
||||
mv_registry.GetRegisteredItems(l);
|
||||
for (StringVector::iterator iter = l.begin(); iter != l.end(); ++iter)
|
||||
{
|
||||
const MovementGeneratorCreator *factory = mv_registry.GetRegistryItem((*iter).c_str());
|
||||
const SelectableMovement *p = dynamic_cast<const SelectableMovement *>(factory);
|
||||
ASSERT(p != NULL);
|
||||
int val = p->Permit(creature);
|
||||
if (val > best_val)
|
||||
{
|
||||
best_val = val;
|
||||
mv_factory = p;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return (mv_factory == NULL ? NULL : mv_factory->Create(creature));
|
||||
|
||||
}
|
||||
|
||||
GameObjectAI* SelectGameObjectAI(GameObject* go)
|
||||
{
|
||||
const GameObjectAICreator* ai_factory = NULL;
|
||||
GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance());
|
||||
|
||||
if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go))
|
||||
return scriptedAI;
|
||||
|
||||
ai_factory = ai_registry.GetRegistryItem(go->GetAIName());
|
||||
|
||||
//future goAI types go here
|
||||
|
||||
// xinef: unused
|
||||
//std::string ainame = (ai_factory == NULL || go->GetScriptId()) ? "NullGameObjectAI" : ai_factory->key();
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "GameObject %u used AI is %s.", go->GetGUIDLow(), ainame.c_str());
|
||||
|
||||
return (ai_factory == NULL ? new NullGameObjectAI(go) : ai_factory->Create(go));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_CREATUREAISELECTOR_H
|
||||
#define TRINITY_CREATUREAISELECTOR_H
|
||||
|
||||
class CreatureAI;
|
||||
class Creature;
|
||||
class MovementGenerator;
|
||||
class GameObjectAI;
|
||||
class GameObject;
|
||||
|
||||
namespace FactorySelector
|
||||
{
|
||||
CreatureAI* selectAI(Creature*);
|
||||
MovementGenerator* selectMovementGenerator(Creature*);
|
||||
GameObjectAI* SelectGameObjectAI(GameObject*);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,668 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
*
|
||||
*
|
||||
* This program is free software licensed under GPL version 2
|
||||
* Please see the included DOCS/LICENSE.TXT for more information */
|
||||
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Item.h"
|
||||
#include "Spell.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
// Spell summary for ScriptedAI::SelectSpell
|
||||
struct TSpellSummary
|
||||
{
|
||||
uint8 Targets; // set of enum SelectTarget
|
||||
uint8 Effects; // set of enum SelectEffect
|
||||
} extern* SpellSummary;
|
||||
|
||||
void SummonList::DoZoneInCombat(uint32 entry)
|
||||
{
|
||||
for (StorageType::iterator i = storage_.begin(); i != storage_.end();)
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, *i);
|
||||
++i;
|
||||
if (summon && summon->IsAIEnabled
|
||||
&& (!entry || summon->GetEntry() == entry))
|
||||
{
|
||||
summon->AI()->DoZoneInCombat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SummonList::DespawnEntry(uint32 entry)
|
||||
{
|
||||
for (StorageType::iterator i = storage_.begin(); i != storage_.end();)
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, *i);
|
||||
if (!summon)
|
||||
i = storage_.erase(i);
|
||||
else if (summon->GetEntry() == entry)
|
||||
{
|
||||
i = storage_.erase(i);
|
||||
summon->DespawnOrUnsummon();
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void SummonList::DespawnAll()
|
||||
{
|
||||
while (!storage_.empty())
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, storage_.front());
|
||||
storage_.pop_front();
|
||||
if (summon)
|
||||
summon->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
void SummonList::RemoveNotExisting()
|
||||
{
|
||||
for (StorageType::iterator i = storage_.begin(); i != storage_.end();)
|
||||
{
|
||||
if (ObjectAccessor::GetCreature(*me, *i))
|
||||
++i;
|
||||
else
|
||||
i = storage_.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool SummonList::HasEntry(uint32 entry) const
|
||||
{
|
||||
for (StorageType::const_iterator i = storage_.begin(); i != storage_.end(); ++i)
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, *i);
|
||||
if (summon && summon->GetEntry() == entry)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 SummonList::GetEntryCount(uint32 entry) const
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (StorageType::const_iterator i = storage_.begin(); i != storage_.end(); ++i)
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, *i);
|
||||
if (summon && summon->GetEntry() == entry)
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void SummonList::Respawn()
|
||||
{
|
||||
for (StorageType::iterator i = storage_.begin(); i != storage_.end();)
|
||||
{
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, *i))
|
||||
{
|
||||
summon->Respawn(true);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
i = storage_.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
Creature* SummonList::GetCreatureWithEntry(uint32 entry) const
|
||||
{
|
||||
for (StorageType::const_iterator i = storage_.begin(); i != storage_.end(); ++i)
|
||||
{
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, *i))
|
||||
if (summon->GetEntry() == entry)
|
||||
return summon;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
|
||||
me(creature),
|
||||
IsFleeing(false),
|
||||
_evadeCheckCooldown(2500),
|
||||
_isCombatMovementAllowed(true)
|
||||
{
|
||||
_isHeroic = me->GetMap()->IsHeroic();
|
||||
_difficulty = Difficulty(me->GetMap()->GetSpawnMode());
|
||||
}
|
||||
|
||||
void ScriptedAI::AttackStartNoMove(Unit* who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
DoStartNoMovement(who);
|
||||
}
|
||||
|
||||
void ScriptedAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (IsCombatMovementAllowed())
|
||||
CreatureAI::AttackStart(who);
|
||||
else
|
||||
AttackStartNoMove(who);
|
||||
}
|
||||
|
||||
void ScriptedAI::UpdateAI(uint32 /*diff*/)
|
||||
{
|
||||
//Check if we have a current target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle)
|
||||
{
|
||||
if (victim)
|
||||
me->GetMotionMaster()->MoveChase(victim, distance, angle);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoStartNoMovement(Unit* victim)
|
||||
{
|
||||
if (!victim)
|
||||
return;
|
||||
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
|
||||
void ScriptedAI::DoStopAttack()
|
||||
{
|
||||
if (me->GetVictim())
|
||||
me->AttackStop();
|
||||
}
|
||||
|
||||
void ScriptedAI::DoCastSpell(Unit* target, SpellInfo const* spellInfo, bool triggered)
|
||||
{
|
||||
if (!target || me->IsNonMeleeSpellCast(false))
|
||||
return;
|
||||
|
||||
me->StopMoving();
|
||||
me->CastSpell(target, spellInfo, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoPlaySoundToSet(WorldObject* source, uint32 soundId)
|
||||
{
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
if (!sSoundEntriesStore.LookupEntry(soundId))
|
||||
{
|
||||
sLog->outError("TSCR: Invalid soundId %u used in DoPlaySoundToSet (Source: TypeId %u, GUID %u)", soundId, source->GetTypeId(), source->GetGUIDLow());
|
||||
return;
|
||||
}
|
||||
|
||||
source->PlayDirectSound(soundId);
|
||||
}
|
||||
|
||||
Creature* ScriptedAI::DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, uint32 despawntime)
|
||||
{
|
||||
return me->SummonCreature(entry, me->GetPositionX() + offsetX, me->GetPositionY() + offsetY, me->GetPositionZ() + offsetZ, angle, TempSummonType(type), despawntime);
|
||||
}
|
||||
|
||||
SpellInfo const* ScriptedAI::SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effects)
|
||||
{
|
||||
//No target so we can't cast
|
||||
if (!target)
|
||||
return NULL;
|
||||
|
||||
//Silenced so we can't cast
|
||||
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
|
||||
return NULL;
|
||||
|
||||
//Using the extended script system we first create a list of viable spells
|
||||
SpellInfo const* apSpell[CREATURE_MAX_SPELLS];
|
||||
memset(apSpell, 0, CREATURE_MAX_SPELLS * sizeof(SpellInfo*));
|
||||
|
||||
uint32 spellCount = 0;
|
||||
|
||||
SpellInfo const* tempSpell = NULL;
|
||||
|
||||
//Check if each spell is viable(set it to null if not)
|
||||
for (uint32 i = 0; i < CREATURE_MAX_SPELLS; i++)
|
||||
{
|
||||
tempSpell = sSpellMgr->GetSpellInfo(me->m_spells[i]);
|
||||
|
||||
//This spell doesn't exist
|
||||
if (!tempSpell)
|
||||
continue;
|
||||
|
||||
// Targets and Effects checked first as most used restrictions
|
||||
//Check the spell targets if specified
|
||||
if (targets && !(SpellSummary[me->m_spells[i]].Targets & (1 << (targets-1))))
|
||||
continue;
|
||||
|
||||
//Check the type of spell if we are looking for a specific spell type
|
||||
if (effects && !(SpellSummary[me->m_spells[i]].Effects & (1 << (effects-1))))
|
||||
continue;
|
||||
|
||||
//Check for school if specified
|
||||
if (school && (tempSpell->SchoolMask & school) == 0)
|
||||
continue;
|
||||
|
||||
//Check for spell mechanic if specified
|
||||
if (mechanic && tempSpell->Mechanic != mechanic)
|
||||
continue;
|
||||
|
||||
//Make sure that the spell uses the requested amount of power
|
||||
if (powerCostMin && tempSpell->ManaCost < powerCostMin)
|
||||
continue;
|
||||
|
||||
if (powerCostMax && tempSpell->ManaCost > powerCostMax)
|
||||
continue;
|
||||
|
||||
//Continue if we don't have the mana to actually cast this spell
|
||||
if (tempSpell->ManaCost > me->GetPower(Powers(tempSpell->PowerType)))
|
||||
continue;
|
||||
|
||||
//Check if the spell meets our range requirements
|
||||
if (rangeMin && me->GetSpellMinRangeForTarget(target, tempSpell) < rangeMin)
|
||||
continue;
|
||||
if (rangeMax && me->GetSpellMaxRangeForTarget(target, tempSpell) > rangeMax)
|
||||
continue;
|
||||
|
||||
//Check if our target is in range
|
||||
if (me->IsWithinDistInMap(target, float(me->GetSpellMinRangeForTarget(target, tempSpell))) || !me->IsWithinDistInMap(target, float(me->GetSpellMaxRangeForTarget(target, tempSpell))))
|
||||
continue;
|
||||
|
||||
//All good so lets add it to the spell list
|
||||
apSpell[spellCount] = tempSpell;
|
||||
++spellCount;
|
||||
}
|
||||
|
||||
//We got our usable spells so now lets randomly pick one
|
||||
if (!spellCount)
|
||||
return NULL;
|
||||
|
||||
return apSpell[urand(0, spellCount - 1)];
|
||||
}
|
||||
|
||||
void ScriptedAI::DoResetThreat()
|
||||
{
|
||||
if (!me->CanHaveThreatList() || me->getThreatManager().isThreatListEmpty())
|
||||
{
|
||||
sLog->outError("DoResetThreat called for creature that either cannot have threat list or has empty threat list (me entry = %d)", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
me->getThreatManager().resetAllAggro();
|
||||
}
|
||||
|
||||
float ScriptedAI::DoGetThreat(Unit* unit)
|
||||
{
|
||||
if (!unit)
|
||||
return 0.0f;
|
||||
return me->getThreatManager().getThreat(unit);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoModifyThreatPercent(Unit* unit, int32 pct)
|
||||
{
|
||||
if (!unit)
|
||||
return;
|
||||
me->getThreatManager().modifyThreatPercent(unit, pct);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoTeleportPlayer(Unit* unit, float x, float y, float z, float o)
|
||||
{
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
if (Player* player = unit->ToPlayer())
|
||||
player->TeleportTo(unit->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT);
|
||||
else
|
||||
sLog->outError("TSCR: Creature " UI64FMTD " (Entry: %u) Tried to teleport non-player unit (Type: %u GUID: " UI64FMTD ") to x: %f y:%f z: %f o: %f. Aborted.", me->GetGUID(), me->GetEntry(), unit->GetTypeId(), unit->GetGUID(), x, y, z, o);
|
||||
}
|
||||
|
||||
void ScriptedAI::DoTeleportAll(float x, float y, float z, float o)
|
||||
{
|
||||
Map* map = me->GetMap();
|
||||
if (!map->IsDungeon())
|
||||
return;
|
||||
|
||||
Map::PlayerList const& PlayerList = map->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
|
||||
if (Player* player = itr->GetSource())
|
||||
if (player->IsAlive())
|
||||
player->TeleportTo(me->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT);
|
||||
}
|
||||
|
||||
Unit* ScriptedAI::DoSelectLowestHpFriendly(float range, uint32 minHPDiff)
|
||||
{
|
||||
Unit* unit = NULL;
|
||||
Trinity::MostHPMissingInRange u_check(me, range, minHPDiff);
|
||||
Trinity::UnitLastSearcher<Trinity::MostHPMissingInRange> searcher(me, unit, u_check);
|
||||
me->VisitNearbyObject(range, searcher);
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
std::list<Creature*> ScriptedAI::DoFindFriendlyCC(float range)
|
||||
{
|
||||
std::list<Creature*> list;
|
||||
Trinity::FriendlyCCedInRange u_check(me, range);
|
||||
Trinity::CreatureListSearcher<Trinity::FriendlyCCedInRange> searcher(me, list, u_check);
|
||||
me->VisitNearbyObject(range, searcher);
|
||||
return list;
|
||||
}
|
||||
|
||||
std::list<Creature*> ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 uiSpellid)
|
||||
{
|
||||
std::list<Creature*> list;
|
||||
Trinity::FriendlyMissingBuffInRange u_check(me, range, uiSpellid);
|
||||
Trinity::CreatureListSearcher<Trinity::FriendlyMissingBuffInRange> searcher(me, list, u_check);
|
||||
me->VisitNearbyObject(range, searcher);
|
||||
return list;
|
||||
}
|
||||
|
||||
Player* ScriptedAI::GetPlayerAtMinimumRange(float minimumRange)
|
||||
{
|
||||
Player* player = NULL;
|
||||
|
||||
CellCoord pair(Trinity::ComputeCellCoord(me->GetPositionX(), me->GetPositionY()));
|
||||
Cell cell(pair);
|
||||
cell.SetNoCreate();
|
||||
|
||||
Trinity::PlayerAtMinimumRangeAway check(me, minimumRange);
|
||||
Trinity::PlayerSearcher<Trinity::PlayerAtMinimumRangeAway> searcher(me, player, check);
|
||||
TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::PlayerAtMinimumRangeAway>, GridTypeMapContainer> visitor(searcher);
|
||||
|
||||
cell.Visit(pair, visitor, *me->GetMap(), *me, minimumRange);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO_CHANGE*/, int32 offHand /*= EQUIP_NO_CHANGE*/, int32 ranged /*= EQUIP_NO_CHANGE*/)
|
||||
{
|
||||
if (loadDefault)
|
||||
{
|
||||
me->LoadEquipment(me->GetOriginalEquipmentId(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainHand >= 0)
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(mainHand));
|
||||
|
||||
if (offHand >= 0)
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(offHand));
|
||||
|
||||
if (ranged >= 0)
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(ranged));
|
||||
}
|
||||
|
||||
void ScriptedAI::SetCombatMovement(bool allowMovement)
|
||||
{
|
||||
_isCombatMovementAllowed = allowMovement;
|
||||
}
|
||||
|
||||
enum eNPCs
|
||||
{
|
||||
NPC_BROODLORD = 12017,
|
||||
NPC_JAN_ALAI = 23578,
|
||||
NPC_SARTHARION = 28860,
|
||||
NPC_FREYA = 32906,
|
||||
};
|
||||
|
||||
bool ScriptedAI::EnterEvadeIfOutOfCombatArea()
|
||||
{
|
||||
if (me->IsInEvadeMode() || !me->IsInCombat())
|
||||
return false;
|
||||
|
||||
if (_evadeCheckCooldown == time(NULL))
|
||||
return false;
|
||||
_evadeCheckCooldown = time(NULL);
|
||||
|
||||
if (!CheckEvadeIfOutOfCombatArea())
|
||||
return false;
|
||||
|
||||
EnterEvadeMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* ScriptedAI::SelectTargetFromPlayerList(float maxdist, uint32 excludeAura, bool mustBeInLOS) const
|
||||
{
|
||||
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
|
||||
std::vector<Player*> tList;
|
||||
for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
|
||||
{
|
||||
if (me->GetDistance(itr->GetSource()) > maxdist || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster())
|
||||
continue;
|
||||
if (excludeAura && itr->GetSource()->HasAura(excludeAura))
|
||||
continue;
|
||||
if (mustBeInLOS && !me->IsWithinLOSInMap(itr->GetSource()))
|
||||
continue;
|
||||
tList.push_back(itr->GetSource());
|
||||
}
|
||||
if (!tList.empty())
|
||||
return tList[urand(0,tList.size()-1)];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// BossAI - for instanced bosses
|
||||
|
||||
BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature),
|
||||
instance(creature->GetInstanceScript()),
|
||||
summons(creature),
|
||||
_boundary(instance ? instance->GetBossBoundary(bossId) : NULL),
|
||||
_bossId(bossId)
|
||||
{
|
||||
}
|
||||
|
||||
void BossAI::_Reset()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
return;
|
||||
|
||||
me->ResetLootMode();
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
if (instance)
|
||||
instance->SetBossState(_bossId, NOT_STARTED);
|
||||
}
|
||||
|
||||
void BossAI::_JustDied()
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
if (instance)
|
||||
{
|
||||
instance->SetBossState(_bossId, DONE);
|
||||
instance->SaveToDB();
|
||||
}
|
||||
}
|
||||
|
||||
void BossAI::_EnterCombat()
|
||||
{
|
||||
me->setActive(true);
|
||||
DoZoneInCombat();
|
||||
if (instance)
|
||||
{
|
||||
// bosses do not respawn, check only on enter combat
|
||||
if (!instance->CheckRequiredBosses(_bossId))
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
instance->SetBossState(_bossId, IN_PROGRESS);
|
||||
}
|
||||
}
|
||||
|
||||
void BossAI::TeleportCheaters()
|
||||
{
|
||||
float x, y, z;
|
||||
me->GetPosition(x, y, z);
|
||||
|
||||
ThreatContainer::StorageType threatList = me->getThreatManager().getThreatList();
|
||||
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
|
||||
if (Unit* target = (*itr)->getTarget())
|
||||
if (target->GetTypeId() == TYPEID_PLAYER && !CheckBoundary(target))
|
||||
target->NearTeleportTo(x, y, z, 0);
|
||||
}
|
||||
|
||||
bool BossAI::CheckBoundary(Unit* who)
|
||||
{
|
||||
if (!GetBoundary() || !who)
|
||||
return true;
|
||||
|
||||
for (BossBoundaryMap::const_iterator itr = GetBoundary()->begin(); itr != GetBoundary()->end(); ++itr)
|
||||
{
|
||||
switch (itr->first)
|
||||
{
|
||||
case BOUNDARY_N:
|
||||
if (who->GetPositionX() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_S:
|
||||
if (who->GetPositionX() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_E:
|
||||
if (who->GetPositionY() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_W:
|
||||
if (who->GetPositionY() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_NW:
|
||||
if (who->GetPositionX() + who->GetPositionY() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_SE:
|
||||
if (who->GetPositionX() + who->GetPositionY() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_NE:
|
||||
if (who->GetPositionX() - who->GetPositionY() > itr->second)
|
||||
return false;
|
||||
break;
|
||||
case BOUNDARY_SW:
|
||||
if (who->GetPositionX() - who->GetPositionY() < itr->second)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BossAI::JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (me->IsInCombat())
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
|
||||
void BossAI::SummonedCreatureDespawn(Creature* summon)
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
void BossAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
ExecuteEvent(eventId);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
// WorldBossAI - for non-instanced bosses
|
||||
|
||||
WorldBossAI::WorldBossAI(Creature* creature) :
|
||||
ScriptedAI(creature),
|
||||
summons(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void WorldBossAI::_Reset()
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
return;
|
||||
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void WorldBossAI::_JustDied()
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void WorldBossAI::_EnterCombat()
|
||||
{
|
||||
Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true);
|
||||
if (target)
|
||||
AttackStart(target);
|
||||
}
|
||||
|
||||
void WorldBossAI::JustSummoned(Creature* summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true);
|
||||
if (target)
|
||||
summon->AI()->AttackStart(target);
|
||||
}
|
||||
|
||||
void WorldBossAI::SummonedCreatureDespawn(Creature* summon)
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
void WorldBossAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
ExecuteEvent(eventId);
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
// SD2 grid searchers.
|
||||
Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive /*= true*/)
|
||||
{
|
||||
return source->FindNearestCreature(entry, maxSearchRange, alive);
|
||||
}
|
||||
|
||||
GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange)
|
||||
{
|
||||
return source->FindNearestGameObject(entry, maxSearchRange);
|
||||
}
|
||||
|
||||
void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange)
|
||||
{
|
||||
source->GetCreatureListWithEntryInGrid(list, entry, maxSearchRange);
|
||||
}
|
||||
|
||||
void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange)
|
||||
{
|
||||
source->GetGameObjectListWithEntryInGrid(list, entry, maxSearchRange);
|
||||
}
|
||||
@@ -1,457 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCRIPTEDCREATURE_H_
|
||||
#define SCRIPTEDCREATURE_H_
|
||||
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "InstanceScript.h"
|
||||
|
||||
#define CAST_AI(a, b) (dynamic_cast<a*>(b))
|
||||
|
||||
class InstanceScript;
|
||||
|
||||
class SummonList
|
||||
{
|
||||
public:
|
||||
typedef std::list<uint64> StorageType;
|
||||
typedef StorageType::iterator iterator;
|
||||
typedef StorageType::const_iterator const_iterator;
|
||||
typedef StorageType::size_type size_type;
|
||||
typedef StorageType::value_type value_type;
|
||||
|
||||
explicit SummonList(Creature* creature)
|
||||
: me(creature)
|
||||
{ }
|
||||
|
||||
// And here we see a problem of original inheritance approach. People started
|
||||
// to exploit presence of std::list members, so I have to provide wrappers
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return storage_.begin();
|
||||
}
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return storage_.begin();
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return storage_.end();
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return storage_.end();
|
||||
}
|
||||
|
||||
iterator erase(iterator i)
|
||||
{
|
||||
return storage_.erase(i);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return storage_.empty();
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return storage_.size();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
storage_.clear();
|
||||
}
|
||||
|
||||
void Summon(Creature const* summon) { storage_.push_back(summon->GetGUID()); }
|
||||
void Despawn(Creature const* summon) { storage_.remove(summon->GetGUID()); }
|
||||
void DespawnEntry(uint32 entry);
|
||||
void DespawnAll();
|
||||
|
||||
template <typename T>
|
||||
void DespawnIf(T const &predicate)
|
||||
{
|
||||
storage_.remove_if(predicate);
|
||||
}
|
||||
|
||||
void DoAction(int32 info, uint16 max = 0)
|
||||
{
|
||||
if (max)
|
||||
RemoveNotExisting(); // pussywizard: when max is set, non existing can be chosen and nothing will happen
|
||||
|
||||
StorageType listCopy = storage_;
|
||||
for (StorageType::const_iterator i = listCopy.begin(); i != listCopy.end(); ++i)
|
||||
{
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, *i))
|
||||
if (summon->IsAIEnabled)
|
||||
summon->AI()->DoAction(info);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Predicate>
|
||||
void DoAction(int32 info, Predicate& predicate, uint16 max = 0)
|
||||
{
|
||||
if (max)
|
||||
RemoveNotExisting(); // pussywizard: when max is set, non existing can be chosen and nothing will happen
|
||||
|
||||
// We need to use a copy of SummonList here, otherwise original SummonList would be modified
|
||||
StorageType listCopy = storage_;
|
||||
Trinity::Containers::RandomResizeList<uint64, Predicate>(listCopy, predicate, max);
|
||||
for (StorageType::iterator i = listCopy.begin(); i != listCopy.end(); ++i)
|
||||
{
|
||||
Creature* summon = ObjectAccessor::GetCreature(*me, *i);
|
||||
if (summon)
|
||||
{
|
||||
if (summon->IsAIEnabled)
|
||||
summon->AI()->DoAction(info);
|
||||
}
|
||||
else
|
||||
storage_.remove(*i);
|
||||
}
|
||||
}
|
||||
|
||||
void DoZoneInCombat(uint32 entry = 0);
|
||||
void RemoveNotExisting();
|
||||
bool HasEntry(uint32 entry) const;
|
||||
uint32 GetEntryCount(uint32 entry) const;
|
||||
void Respawn();
|
||||
Creature* GetCreatureWithEntry(uint32 entry) const;
|
||||
|
||||
private:
|
||||
Creature* me;
|
||||
StorageType storage_;
|
||||
};
|
||||
|
||||
class EntryCheckPredicate
|
||||
{
|
||||
public:
|
||||
EntryCheckPredicate(uint32 entry) : _entry(entry) {}
|
||||
bool operator()(uint64 guid) { return GUID_ENPART(guid) == _entry; }
|
||||
|
||||
private:
|
||||
uint32 _entry;
|
||||
};
|
||||
|
||||
class PlayerOrPetCheck
|
||||
{
|
||||
public:
|
||||
bool operator() (WorldObject* unit) const
|
||||
{
|
||||
if (unit->GetTypeId() != TYPEID_PLAYER)
|
||||
if (!IS_PLAYER_GUID(unit->ToUnit()->GetOwnerGUID()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct ScriptedAI : public CreatureAI
|
||||
{
|
||||
explicit ScriptedAI(Creature* creature);
|
||||
virtual ~ScriptedAI() {}
|
||||
|
||||
// *************
|
||||
//CreatureAI Functions
|
||||
// *************
|
||||
|
||||
void AttackStartNoMove(Unit* target);
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) {}
|
||||
|
||||
//Called at World update tick
|
||||
virtual void UpdateAI(uint32 diff);
|
||||
|
||||
//Called at creature death
|
||||
void JustDied(Unit* /*killer*/) {}
|
||||
|
||||
//Called at creature killing another unit
|
||||
void KilledUnit(Unit* /*victim*/) {}
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
void JustSummoned(Creature* /*summon*/) {}
|
||||
|
||||
// Called when a summoned creature is despawned
|
||||
void SummonedCreatureDespawn(Creature* /*summon*/) {}
|
||||
|
||||
// Called when hit by a spell
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/) {}
|
||||
|
||||
// Called when spell hits a target
|
||||
void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spell*/) {}
|
||||
|
||||
//Called at waypoint reached or PointMovement end
|
||||
void MovementInform(uint32 /*type*/, uint32 /*id*/) {}
|
||||
|
||||
// Called when AI is temporarily replaced or put back when possess is applied or removed
|
||||
void OnPossess(bool /*apply*/) {}
|
||||
|
||||
// *************
|
||||
// Variables
|
||||
// *************
|
||||
|
||||
//Pointer to creature we are manipulating
|
||||
Creature* me;
|
||||
|
||||
//For fleeing
|
||||
bool IsFleeing;
|
||||
|
||||
// *************
|
||||
//Pure virtual functions
|
||||
// *************
|
||||
|
||||
//Called at creature reset either by death or evade
|
||||
void Reset() {}
|
||||
|
||||
//Called at creature aggro either by MoveInLOS or Attack Start
|
||||
void EnterCombat(Unit* /*victim*/) {}
|
||||
|
||||
// Called before EnterCombat even before the creature is in combat.
|
||||
void AttackStart(Unit* /*target*/);
|
||||
|
||||
// *************
|
||||
//AI Helper Functions
|
||||
// *************
|
||||
|
||||
//Start movement toward victim
|
||||
void DoStartMovement(Unit* target, float distance = 0.0f, float angle = 0.0f);
|
||||
|
||||
//Start no movement on victim
|
||||
void DoStartNoMovement(Unit* target);
|
||||
|
||||
//Stop attack of current victim
|
||||
void DoStopAttack();
|
||||
|
||||
//Cast spell by spell info
|
||||
void DoCastSpell(Unit* target, SpellInfo const* spellInfo, bool triggered = false);
|
||||
|
||||
//Plays a sound to all nearby players
|
||||
void DoPlaySoundToSet(WorldObject* source, uint32 soundId);
|
||||
|
||||
//Drops all threat to 0%. Does not remove players from the threat list
|
||||
void DoResetThreat();
|
||||
|
||||
float DoGetThreat(Unit* unit);
|
||||
void DoModifyThreatPercent(Unit* unit, int32 pct);
|
||||
|
||||
//Teleports a player without dropping threat (only teleports to same map)
|
||||
void DoTeleportPlayer(Unit* unit, float x, float y, float z, float o);
|
||||
void DoTeleportAll(float x, float y, float z, float o);
|
||||
|
||||
//Returns friendly unit with the most amount of hp missing from max hp
|
||||
Unit* DoSelectLowestHpFriendly(float range, uint32 minHPDiff = 1);
|
||||
|
||||
//Returns a list of friendly CC'd units within range
|
||||
std::list<Creature*> DoFindFriendlyCC(float range);
|
||||
|
||||
//Returns a list of all friendly units missing a specific buff within range
|
||||
std::list<Creature*> DoFindFriendlyMissingBuff(float range, uint32 spellId);
|
||||
|
||||
//Return a player with at least minimumRange from me
|
||||
Player* GetPlayerAtMinimumRange(float minRange);
|
||||
|
||||
//Spawns a creature relative to me
|
||||
Creature* DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, uint32 despawntime);
|
||||
|
||||
bool HealthBelowPct(uint32 pct) const { return me->HealthBelowPct(pct); }
|
||||
bool HealthAbovePct(uint32 pct) const { return me->HealthAbovePct(pct); }
|
||||
|
||||
//Returns spells that meet the specified criteria from the creatures spell list
|
||||
SpellInfo const* SelectSpell(Unit* target, uint32 school, uint32 mechanic, SelectTargetType targets, uint32 powerCostMin, uint32 powerCostMax, float rangeMin, float rangeMax, SelectEffect effect);
|
||||
|
||||
void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE);
|
||||
|
||||
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
|
||||
// NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
|
||||
// You should make the necessary to make it happen so.
|
||||
// Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
|
||||
// It will keep the last value you set.
|
||||
void SetCombatMovement(bool allowMovement);
|
||||
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
|
||||
|
||||
bool EnterEvadeIfOutOfCombatArea();
|
||||
virtual bool CheckEvadeIfOutOfCombatArea() const { return false; }
|
||||
|
||||
// return true for heroic mode. i.e.
|
||||
// - for dungeon in mode 10-heroic,
|
||||
// - for raid in mode 10-Heroic
|
||||
// - for raid in mode 25-heroic
|
||||
// DO NOT USE to check raid in mode 25-normal.
|
||||
bool IsHeroic() const { return _isHeroic; }
|
||||
|
||||
// return the dungeon or raid difficulty
|
||||
Difficulty GetDifficulty() const { return _difficulty; }
|
||||
|
||||
// return true for 25 man or 25 man heroic mode
|
||||
bool Is25ManRaid() const { return _difficulty & RAID_DIFFICULTY_MASK_25MAN; }
|
||||
|
||||
template<class T> inline
|
||||
const T& DUNGEON_MODE(const T& normal5, const T& heroic10) const
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
case DUNGEON_DIFFICULTY_NORMAL:
|
||||
return normal5;
|
||||
case DUNGEON_DIFFICULTY_HEROIC:
|
||||
return heroic10;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return heroic10;
|
||||
}
|
||||
|
||||
template<class T> inline
|
||||
const T& RAID_MODE(const T& normal10, const T& normal25) const
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
case RAID_DIFFICULTY_10MAN_NORMAL:
|
||||
return normal10;
|
||||
case RAID_DIFFICULTY_25MAN_NORMAL:
|
||||
return normal25;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return normal25;
|
||||
}
|
||||
|
||||
template<class T> inline
|
||||
const T& RAID_MODE(const T& normal10, const T& normal25, const T& heroic10, const T& heroic25) const
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
case RAID_DIFFICULTY_10MAN_NORMAL:
|
||||
return normal10;
|
||||
case RAID_DIFFICULTY_25MAN_NORMAL:
|
||||
return normal25;
|
||||
case RAID_DIFFICULTY_10MAN_HEROIC:
|
||||
return heroic10;
|
||||
case RAID_DIFFICULTY_25MAN_HEROIC:
|
||||
return heroic25;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return heroic25;
|
||||
}
|
||||
|
||||
Player* SelectTargetFromPlayerList(float maxdist, uint32 excludeAura = 0, bool mustBeInLOS = false) const;
|
||||
|
||||
private:
|
||||
Difficulty _difficulty;
|
||||
uint32 _evadeCheckCooldown;
|
||||
bool _isCombatMovementAllowed;
|
||||
bool _isHeroic;
|
||||
};
|
||||
|
||||
class BossAI : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
BossAI(Creature* creature, uint32 bossId);
|
||||
virtual ~BossAI() {}
|
||||
|
||||
InstanceScript* const instance;
|
||||
BossBoundaryMap const* GetBoundary() const { return _boundary; }
|
||||
|
||||
void JustSummoned(Creature* summon);
|
||||
void SummonedCreatureDespawn(Creature* summon);
|
||||
|
||||
virtual void UpdateAI(uint32 diff);
|
||||
|
||||
// Hook used to execute events scheduled into EventMap without the need
|
||||
// to override UpdateAI
|
||||
// note: You must re-schedule the event within this method if the event
|
||||
// is supposed to run more than once
|
||||
virtual void ExecuteEvent(uint32 /*eventId*/) { }
|
||||
|
||||
void Reset() { _Reset(); }
|
||||
void EnterCombat(Unit* /*who*/) { _EnterCombat(); }
|
||||
void JustDied(Unit* /*killer*/) { _JustDied(); }
|
||||
void JustReachedHome() { _JustReachedHome(); }
|
||||
|
||||
protected:
|
||||
void _Reset();
|
||||
void _EnterCombat();
|
||||
void _JustDied();
|
||||
void _JustReachedHome() { me->setActive(false); }
|
||||
|
||||
bool CheckInRoom()
|
||||
{
|
||||
if (CheckBoundary(me))
|
||||
return true;
|
||||
|
||||
EnterEvadeMode();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckBoundary(Unit* who);
|
||||
void TeleportCheaters();
|
||||
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
|
||||
private:
|
||||
BossBoundaryMap const* const _boundary;
|
||||
uint32 const _bossId;
|
||||
};
|
||||
|
||||
class WorldBossAI : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
WorldBossAI(Creature* creature);
|
||||
virtual ~WorldBossAI() {}
|
||||
|
||||
void JustSummoned(Creature* summon);
|
||||
void SummonedCreatureDespawn(Creature* summon);
|
||||
|
||||
virtual void UpdateAI(uint32 diff);
|
||||
|
||||
// Hook used to execute events scheduled into EventMap without the need
|
||||
// to override UpdateAI
|
||||
// note: You must re-schedule the event within this method if the event
|
||||
// is supposed to run more than once
|
||||
virtual void ExecuteEvent(uint32 /*eventId*/) { }
|
||||
|
||||
void Reset() { _Reset(); }
|
||||
void EnterCombat(Unit* /*who*/) { _EnterCombat(); }
|
||||
void JustDied(Unit* /*killer*/) { _JustDied(); }
|
||||
|
||||
protected:
|
||||
void _Reset();
|
||||
void _EnterCombat();
|
||||
void _JustDied();
|
||||
|
||||
EventMap events;
|
||||
SummonList summons;
|
||||
};
|
||||
|
||||
// SD2 grid searchers.
|
||||
Creature* GetClosestCreatureWithEntry(WorldObject* source, uint32 entry, float maxSearchRange, bool alive = true);
|
||||
GameObject* GetClosestGameObjectWithEntry(WorldObject* source, uint32 entry, float maxSearchRange);
|
||||
void GetCreatureListWithEntryInGrid(std::list<Creature*>& list, WorldObject* source, uint32 entry, float maxSearchRange);
|
||||
void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& list, WorldObject* source, uint32 entry, float maxSearchRange);
|
||||
|
||||
#endif // SCRIPTEDCREATURE_H_
|
||||
@@ -1,584 +0,0 @@
|
||||
/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
|
||||
* This program is free software licensed under GPL version 2
|
||||
* Please see the included DOCS/LICENSE.TXT for more information */
|
||||
|
||||
/* ScriptData
|
||||
SDName: Npc_EscortAI
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Npc
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "Group.h"
|
||||
#include "Player.h"
|
||||
|
||||
enum ePoints
|
||||
{
|
||||
POINT_LAST_POINT = 0xFFFFFF,
|
||||
POINT_HOME = 0xFFFFFE
|
||||
};
|
||||
|
||||
npc_escortAI::npc_escortAI(Creature* creature) : ScriptedAI(creature),
|
||||
m_uiPlayerGUID(0),
|
||||
m_uiWPWaitTimer(1000),
|
||||
m_uiPlayerCheckTimer(0),
|
||||
m_uiEscortState(STATE_ESCORT_NONE),
|
||||
MaxPlayerDistance(DEFAULT_MAX_PLAYER_DISTANCE),
|
||||
m_pQuestForEscort(NULL),
|
||||
m_bIsActiveAttacker(true),
|
||||
m_bIsRunning(false),
|
||||
m_bCanInstantRespawn(false),
|
||||
m_bCanReturnToStart(false),
|
||||
DespawnAtEnd(true),
|
||||
DespawnAtFar(true),
|
||||
ScriptWP(false),
|
||||
HasImmuneToNPCFlags(false)
|
||||
{}
|
||||
|
||||
void npc_escortAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
{
|
||||
MovementGeneratorType type = me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE);
|
||||
if (type == ESCORT_MOTION_TYPE || type == POINT_MOTION_TYPE)
|
||||
{
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
//me->DisableSpline();
|
||||
me->StopMoving();
|
||||
}
|
||||
|
||||
if (IsCombatMovementAllowed())
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
}
|
||||
}
|
||||
|
||||
//see followerAI
|
||||
bool npc_escortAI::AssistPlayerInCombat(Unit* who)
|
||||
{
|
||||
if (!who || !who->GetVictim())
|
||||
return false;
|
||||
|
||||
//experimental (unknown) flag not present
|
||||
if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_AID_PLAYERS))
|
||||
return false;
|
||||
|
||||
//not a player
|
||||
if (!who->GetVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
return false;
|
||||
|
||||
//never attack friendly
|
||||
if (!me->IsValidAttackTarget(who))
|
||||
return false;
|
||||
|
||||
//too far away and no free sight?
|
||||
if (me->IsWithinDistInMap(who, GetMaxPlayerDistance()) && me->IsWithinLOSInMap(who))
|
||||
{
|
||||
AttackStart(who);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void npc_escortAI::MoveInLineOfSight(Unit* who)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
return;
|
||||
|
||||
if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack(true, me) && who->isInAccessiblePlaceFor(me))
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(who))
|
||||
return;
|
||||
|
||||
if (me->CanStartAttack(who))
|
||||
AttackStart(who);
|
||||
}
|
||||
|
||||
void npc_escortAI::JustDied(Unit* /*killer*/)
|
||||
{
|
||||
if (!HasEscortState(STATE_ESCORT_ESCORTING) || !m_uiPlayerGUID || !m_pQuestForEscort)
|
||||
return;
|
||||
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
{
|
||||
if (Group* group = player->GetGroup())
|
||||
{
|
||||
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
|
||||
if (Player* member = groupRef->GetSource())
|
||||
if (member->IsInMap(player) && member->GetQuestStatus(m_pQuestForEscort->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
|
||||
member->FailQuest(m_pQuestForEscort->GetQuestId());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->GetQuestStatus(m_pQuestForEscort->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
|
||||
player->FailQuest(m_pQuestForEscort->GetQuestId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void npc_escortAI::JustRespawned()
|
||||
{
|
||||
RemoveEscortState(STATE_ESCORT_ESCORTING|STATE_ESCORT_RETURNING|STATE_ESCORT_PAUSED);
|
||||
|
||||
if (!IsCombatMovementAllowed())
|
||||
SetCombatMovement(true);
|
||||
|
||||
//add a small delay before going to first waypoint, normal in near all cases
|
||||
m_uiWPWaitTimer = 1000;
|
||||
|
||||
if (me->getFaction() != me->GetCreatureTemplate()->faction)
|
||||
me->RestoreFaction();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void npc_escortAI::ReturnToLastPoint()
|
||||
{
|
||||
float x, y, z, o;
|
||||
me->SetWalk(false);
|
||||
me->GetHomePosition(x, y, z, o);
|
||||
me->GetMotionMaster()->MovePoint(POINT_LAST_POINT, x, y, z);
|
||||
}
|
||||
|
||||
void npc_escortAI::EnterEvadeMode()
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop(true);
|
||||
me->SetLootRecipient(NULL);
|
||||
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
AddEscortState(STATE_ESCORT_RETURNING);
|
||||
ReturnToLastPoint();
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI has left combat and is now returning to last point");
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
if (HasImmuneToNPCFlags)
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool npc_escortAI::IsPlayerOrGroupInRange()
|
||||
{
|
||||
if (Player* player = GetPlayerForEscort())
|
||||
{
|
||||
if (Group* group = player->GetGroup())
|
||||
{
|
||||
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
|
||||
if (Player* member = groupRef->GetSource())
|
||||
if (me->IsWithinDistInMap(member, GetMaxPlayerDistance()))
|
||||
return true;
|
||||
}
|
||||
else if (me->IsWithinDistInMap(player, GetMaxPlayerDistance()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void npc_escortAI::UpdateAI(uint32 diff)
|
||||
{
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING) && !me->GetVictim() && m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_RETURNING))
|
||||
{
|
||||
if (m_uiWPWaitTimer <= diff)
|
||||
{
|
||||
if (CurrentWP == WaypointList.end())
|
||||
{
|
||||
if (DespawnAtEnd)
|
||||
{
|
||||
if (m_bCanReturnToStart)
|
||||
{
|
||||
float fRetX, fRetY, fRetZ;
|
||||
me->GetRespawnPosition(fRetX, fRetY, fRetZ);
|
||||
me->GetMotionMaster()->MovePoint(POINT_HOME, fRetX, fRetY, fRetZ);
|
||||
|
||||
m_uiWPWaitTimer = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bCanInstantRespawn)
|
||||
{
|
||||
me->setDeathState(JUST_DIED);
|
||||
me->Respawn();
|
||||
}
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
// xinef: remove escort state, escort was finished (lack of this line resulted in skipping UpdateEscortAI calls after finished escort)
|
||||
RemoveEscortState(STATE_ESCORT_ESCORTING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!HasEscortState(STATE_ESCORT_PAUSED))
|
||||
{
|
||||
// xinef, start escort if there is no spline active
|
||||
if (me->movespline->Finalized())
|
||||
{
|
||||
Movement::PointsArray pathPoints;
|
||||
GenerateWaypointArray(&pathPoints);
|
||||
me->GetMotionMaster()->MoveSplinePath(&pathPoints);
|
||||
}
|
||||
|
||||
WaypointStart(CurrentWP->id);
|
||||
m_uiWPWaitTimer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_uiWPWaitTimer -= diff;
|
||||
}
|
||||
|
||||
//Check if player or any member of his group is within range
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING) && m_uiPlayerGUID && !me->GetVictim() && !HasEscortState(STATE_ESCORT_RETURNING))
|
||||
{
|
||||
m_uiPlayerCheckTimer += diff;
|
||||
if (m_uiPlayerCheckTimer > 1000)
|
||||
{
|
||||
if (DespawnAtFar && !IsPlayerOrGroupInRange())
|
||||
{
|
||||
if (m_bCanInstantRespawn)
|
||||
{
|
||||
me->setDeathState(JUST_DIED);
|
||||
me->Respawn();
|
||||
}
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_uiPlayerCheckTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateEscortAI(diff);
|
||||
}
|
||||
|
||||
void npc_escortAI::UpdateEscortAI(uint32 /*diff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void npc_escortAI::MovementInform(uint32 moveType, uint32 pointId)
|
||||
{
|
||||
// xinef: no action allowed if there is no escort
|
||||
if (!HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
return;
|
||||
|
||||
if (moveType == POINT_MOTION_TYPE)
|
||||
{
|
||||
//Combat start position reached, continue waypoint movement
|
||||
if (pointId == POINT_LAST_POINT)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI has returned to original position before combat");
|
||||
|
||||
me->SetWalk(!m_bIsRunning);
|
||||
RemoveEscortState(STATE_ESCORT_RETURNING);
|
||||
|
||||
if (!m_uiWPWaitTimer)
|
||||
m_uiWPWaitTimer = 1;
|
||||
}
|
||||
else if (pointId == POINT_HOME)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI has returned to original home location and will continue from beginning of waypoint list.");
|
||||
|
||||
CurrentWP = WaypointList.begin();
|
||||
m_uiWPWaitTimer = 1;
|
||||
}
|
||||
}
|
||||
else if (moveType == ESCORT_MOTION_TYPE)
|
||||
{
|
||||
if (m_uiWPWaitTimer <= 1 && !HasEscortState(STATE_ESCORT_PAUSED) && CurrentWP != WaypointList.end())
|
||||
{
|
||||
//Call WP function
|
||||
me->SetPosition(CurrentWP->x, CurrentWP->y, CurrentWP->z, me->GetOrientation());
|
||||
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
WaypointReached(CurrentWP->id);
|
||||
|
||||
m_uiWPWaitTimer = CurrentWP->WaitTimeMs + 1;
|
||||
|
||||
++CurrentWP;
|
||||
|
||||
if (m_uiWPWaitTimer > 1 || HasEscortState(STATE_ESCORT_PAUSED))
|
||||
{
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == ESCORT_MOTION_TYPE)
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
me->StopMovingOnCurrentPos();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void npc_escortAI::OnPossess(bool apply)
|
||||
{
|
||||
// We got possessed in the middle of being escorted, store the point
|
||||
// where we left off to come back to when possess is removed
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
if (apply)
|
||||
me->GetPosition(LastPos.x, LastPos.y, LastPos.z);
|
||||
else
|
||||
{
|
||||
Returning = true;
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
me->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void npc_escortAI::AddWaypoint(uint32 id, float x, float y, float z, uint32 waitTime)
|
||||
{
|
||||
Escort_Waypoint t(id, x, y, z, waitTime);
|
||||
|
||||
WaypointList.push_back(t);
|
||||
|
||||
// i think SD2 no longer uses this function
|
||||
ScriptWP = true;
|
||||
/*PointMovement wp;
|
||||
wp.m_uiCreatureEntry = me->GetEntry();
|
||||
wp.m_uiPointId = id;
|
||||
wp.m_fX = x;
|
||||
wp.m_fY = y;
|
||||
wp.m_fZ = z;
|
||||
wp.m_uiWaitTime = WaitTimeMs;
|
||||
PointMovementMap[wp.m_uiCreatureEntry].push_back(wp);*/
|
||||
}
|
||||
|
||||
void npc_escortAI::FillPointMovementListForCreature()
|
||||
{
|
||||
ScriptPointVector const& movePoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
|
||||
if (movePoints.empty())
|
||||
return;
|
||||
|
||||
ScriptPointVector::const_iterator itrEnd = movePoints.end();
|
||||
for (ScriptPointVector::const_iterator itr = movePoints.begin(); itr != itrEnd; ++itr)
|
||||
{
|
||||
Escort_Waypoint point(itr->uiPointId, itr->fX, itr->fY, itr->fZ, itr->uiWaitTime);
|
||||
WaypointList.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
void npc_escortAI::SetRun(bool on)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
if (!m_bIsRunning)
|
||||
me->SetWalk(false);
|
||||
else
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI attempt to set run mode, but is already running.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bIsRunning)
|
||||
me->SetWalk(true);
|
||||
else
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI attempt to set walk mode, but is already walking.");
|
||||
}
|
||||
|
||||
m_bIsRunning = on;
|
||||
}
|
||||
|
||||
//TODO: get rid of this many variables passed in function.
|
||||
void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, uint64 playerGUID /* = 0 */, Quest const* quest /* = NULL */, bool instantRespawn /* = false */, bool canLoopPath /* = false */, bool resetWaypoints /* = true */)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
{
|
||||
sLog->outError("TSCR ERROR: EscortAI (script: %s, creature entry: %u) attempts to Start while in combat", me->GetScriptName().c_str(), me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
sLog->outError("TSCR: EscortAI (script: %s, creature entry: %u) attempts to Start while already escorting", me->GetScriptName().c_str(), me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ScriptWP && resetWaypoints) // sd2 never adds wp in script, but tc does
|
||||
{
|
||||
if (!WaypointList.empty())
|
||||
WaypointList.clear();
|
||||
FillPointMovementListForCreature();
|
||||
}
|
||||
|
||||
if (WaypointList.empty())
|
||||
{
|
||||
sLog->outErrorDb("TSCR: EscortAI (script: %s, creature entry: %u) starts with 0 waypoints (possible missing entry in script_waypoint. Quest: %u).",
|
||||
me->GetScriptName().c_str(), me->GetEntry(), quest ? quest->GetQuestId() : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
//set variables
|
||||
m_bIsActiveAttacker = isActiveAttacker;
|
||||
m_bIsRunning = run;
|
||||
|
||||
m_uiPlayerGUID = playerGUID;
|
||||
m_pQuestForEscort = quest;
|
||||
|
||||
m_bCanInstantRespawn = instantRespawn;
|
||||
m_bCanReturnToStart = canLoopPath;
|
||||
|
||||
//if (m_bCanReturnToStart && m_bCanInstantRespawn)
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.");
|
||||
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
{
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
|
||||
}
|
||||
|
||||
//disable npcflags
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))
|
||||
{
|
||||
HasImmuneToNPCFlags = true;
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
}
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: EscortAI started with " UI64FMTD " waypoints. ActiveAttacker = %d, Run = %d, PlayerGUID = " UI64FMTD "", uint64(WaypointList.size()), m_bIsActiveAttacker, m_bIsRunning, m_uiPlayerGUID);
|
||||
|
||||
CurrentWP = WaypointList.begin();
|
||||
|
||||
//Set initial speed
|
||||
if (m_bIsRunning)
|
||||
me->SetWalk(false);
|
||||
else
|
||||
me->SetWalk(true);
|
||||
|
||||
AddEscortState(STATE_ESCORT_ESCORTING);
|
||||
if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_ACTIVE) == ESCORT_MOTION_TYPE)
|
||||
me->GetMotionMaster()->MovementExpired();
|
||||
me->DisableSpline();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
|
||||
void npc_escortAI::SetEscortPaused(bool on)
|
||||
{
|
||||
if (!HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
return;
|
||||
|
||||
if (on)
|
||||
AddEscortState(STATE_ESCORT_PAUSED);
|
||||
else
|
||||
RemoveEscortState(STATE_ESCORT_PAUSED);
|
||||
}
|
||||
|
||||
bool npc_escortAI::SetNextWaypoint(uint32 pointId, float x, float y, float z, float orientation)
|
||||
{
|
||||
me->UpdatePosition(x, y, z, orientation);
|
||||
return SetNextWaypoint(pointId, false);
|
||||
}
|
||||
|
||||
bool npc_escortAI::SetNextWaypoint(uint32 pointId, bool setPosition)
|
||||
{
|
||||
if (!WaypointList.empty())
|
||||
WaypointList.clear();
|
||||
|
||||
FillPointMovementListForCreature();
|
||||
|
||||
if (WaypointList.empty())
|
||||
return false;
|
||||
|
||||
size_t const size = WaypointList.size();
|
||||
Escort_Waypoint waypoint(0, 0, 0, 0, 0);
|
||||
for (CurrentWP = WaypointList.begin(); CurrentWP != WaypointList.end(); ++CurrentWP)
|
||||
{
|
||||
if (CurrentWP->id == pointId)
|
||||
{
|
||||
if (setPosition)
|
||||
me->UpdatePosition(CurrentWP->x, CurrentWP->y, CurrentWP->z, me->GetOrientation());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool npc_escortAI::GetWaypointPosition(uint32 pointId, float& x, float& y, float& z)
|
||||
{
|
||||
ScriptPointVector const& waypoints = sScriptSystemMgr->GetPointMoveList(me->GetEntry());
|
||||
if (waypoints.empty())
|
||||
return false;
|
||||
|
||||
for (ScriptPointVector::const_iterator itr = waypoints.begin(); itr != waypoints.end(); ++itr)
|
||||
{
|
||||
if (itr->uiPointId == pointId)
|
||||
{
|
||||
x = itr->fX;
|
||||
y = itr->fY;
|
||||
z = itr->fZ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void npc_escortAI::GenerateWaypointArray(Movement::PointsArray* points)
|
||||
{
|
||||
if (WaypointList.empty())
|
||||
return;
|
||||
|
||||
uint32 startingWaypointId = CurrentWP->id;
|
||||
|
||||
// Flying unit, just fill array
|
||||
if (me->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY|MOVEMENTFLAG_DISABLE_GRAVITY)))
|
||||
{
|
||||
// xinef: first point in vector is unit real position
|
||||
points->clear();
|
||||
points->push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
for (std::list<Escort_Waypoint>::const_iterator itr = CurrentWP; itr != WaypointList.end(); ++itr)
|
||||
points->push_back(G3D::Vector3(itr->x, itr->y, itr->z));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (float size = 1.0f; size; size *= 0.5f)
|
||||
{
|
||||
std::vector<G3D::Vector3> pVector;
|
||||
// xinef: first point in vector is unit real position
|
||||
pVector.push_back(G3D::Vector3(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()));
|
||||
uint32 length = (WaypointList.size() - startingWaypointId)*size;
|
||||
|
||||
uint32 cnt = 0;
|
||||
for (std::list<Escort_Waypoint>::const_iterator itr = CurrentWP; itr != WaypointList.end() && cnt <= length; ++itr, ++cnt)
|
||||
pVector.push_back(G3D::Vector3(itr->x, itr->y, itr->z));
|
||||
|
||||
if (pVector.size() > 2) // more than source + dest
|
||||
{
|
||||
G3D::Vector3 middle = (pVector[0] + pVector[pVector.size()-1]) / 2.f;
|
||||
G3D::Vector3 offset;
|
||||
|
||||
bool continueLoop = false;
|
||||
for (uint32 i = 1; i < pVector.size()-1; ++i)
|
||||
{
|
||||
offset = middle - pVector[i];
|
||||
if (fabs(offset.x) >= 0xFF || fabs(offset.y) >= 0xFF || fabs(offset.z) >= 0x7F)
|
||||
{
|
||||
// offset is too big, split points
|
||||
continueLoop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (continueLoop)
|
||||
continue;
|
||||
}
|
||||
// everything ok
|
||||
*points = pVector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
|
||||
* This program is free software licensed under GPL version 2
|
||||
* Please see the included DOCS/LICENSE.TXT for more information */
|
||||
|
||||
#ifndef SC_ESCORTAI_H
|
||||
#define SC_ESCORTAI_H
|
||||
|
||||
#include "ScriptSystem.h"
|
||||
|
||||
#define DEFAULT_MAX_PLAYER_DISTANCE 50
|
||||
|
||||
struct Escort_Waypoint
|
||||
{
|
||||
Escort_Waypoint(uint32 _id, float _x, float _y, float _z, uint32 _w)
|
||||
{
|
||||
id = _id;
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
WaitTimeMs = _w;
|
||||
}
|
||||
|
||||
uint32 id;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
uint32 WaitTimeMs;
|
||||
};
|
||||
|
||||
enum eEscortState
|
||||
{
|
||||
STATE_ESCORT_NONE = 0x000, //nothing in progress
|
||||
STATE_ESCORT_ESCORTING = 0x001, //escort are in progress
|
||||
STATE_ESCORT_RETURNING = 0x002, //escort is returning after being in combat
|
||||
STATE_ESCORT_PAUSED = 0x004 //will not proceed with waypoints before state is removed
|
||||
};
|
||||
|
||||
struct npc_escortAI : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
explicit npc_escortAI(Creature* creature);
|
||||
~npc_escortAI() {}
|
||||
|
||||
// CreatureAI functions
|
||||
void AttackStart(Unit* who);
|
||||
|
||||
void MoveInLineOfSight(Unit* who);
|
||||
|
||||
void JustDied(Unit*);
|
||||
|
||||
void JustRespawned();
|
||||
|
||||
void ReturnToLastPoint();
|
||||
|
||||
void EnterEvadeMode();
|
||||
|
||||
void UpdateAI(uint32 diff); //the "internal" update, calls UpdateEscortAI()
|
||||
virtual void UpdateEscortAI(uint32 diff); //used when it's needed to add code in update (abilities, scripted events, etc)
|
||||
|
||||
void MovementInform(uint32, uint32);
|
||||
|
||||
// EscortAI functions
|
||||
void AddWaypoint(uint32 id, float x, float y, float z, uint32 waitTime = 0); // waitTime is in ms
|
||||
|
||||
//this will set the current position to x/y/z/o, and the current WP to pointId.
|
||||
bool SetNextWaypoint(uint32 pointId, float x, float y, float z, float orientation);
|
||||
|
||||
//this will set the current position to WP start position (if setPosition == true),
|
||||
//and the current WP to pointId
|
||||
bool SetNextWaypoint(uint32 pointId, bool setPosition = true);
|
||||
|
||||
bool GetWaypointPosition(uint32 pointId, float& x, float& y, float& z);
|
||||
|
||||
void GenerateWaypointArray(Movement::PointsArray* points);
|
||||
|
||||
virtual void WaypointReached(uint32 pointId) = 0;
|
||||
virtual void WaypointStart(uint32 /*pointId*/) {}
|
||||
|
||||
void Start(bool isActiveAttacker = true, bool run = false, uint64 playerGUID = 0, Quest const* quest = NULL, bool instantRespawn = false, bool canLoopPath = false, bool resetWaypoints = true);
|
||||
|
||||
void SetRun(bool on = true);
|
||||
void SetEscortPaused(bool on);
|
||||
|
||||
bool HasEscortState(uint32 escortState) { return (m_uiEscortState & escortState); }
|
||||
virtual bool IsEscorted() { return (m_uiEscortState & STATE_ESCORT_ESCORTING); }
|
||||
|
||||
void SetMaxPlayerDistance(float newMax) { MaxPlayerDistance = newMax; }
|
||||
float GetMaxPlayerDistance() { return MaxPlayerDistance; }
|
||||
|
||||
void SetDespawnAtEnd(bool despawn) { DespawnAtEnd = despawn; }
|
||||
void SetDespawnAtFar(bool despawn) { DespawnAtFar = despawn; }
|
||||
bool GetAttack() { return m_bIsActiveAttacker; }//used in EnterEvadeMode override
|
||||
void SetCanAttack(bool attack) { m_bIsActiveAttacker = attack; }
|
||||
uint64 GetEventStarterGUID() { return m_uiPlayerGUID; }
|
||||
|
||||
void AddEscortState(uint32 escortState) { m_uiEscortState |= escortState; }
|
||||
void RemoveEscortState(uint32 escortState) { m_uiEscortState &= ~escortState; }
|
||||
|
||||
protected:
|
||||
Player* GetPlayerForEscort() { return ObjectAccessor::GetPlayer(*me, m_uiPlayerGUID); }
|
||||
|
||||
private:
|
||||
bool AssistPlayerInCombat(Unit* who);
|
||||
bool IsPlayerOrGroupInRange();
|
||||
void FillPointMovementListForCreature();
|
||||
|
||||
uint64 m_uiPlayerGUID;
|
||||
uint32 m_uiWPWaitTimer;
|
||||
uint32 m_uiPlayerCheckTimer;
|
||||
uint32 m_uiEscortState;
|
||||
float MaxPlayerDistance;
|
||||
|
||||
Quest const* m_pQuestForEscort; //generally passed in Start() when regular escort script.
|
||||
|
||||
std::list<Escort_Waypoint> WaypointList;
|
||||
std::list<Escort_Waypoint>::iterator CurrentWP;
|
||||
|
||||
bool m_bIsActiveAttacker; //obsolete, determined by faction.
|
||||
bool m_bIsRunning; //all creatures are walking by default (has flag MOVEMENTFLAG_WALK)
|
||||
bool m_bCanInstantRespawn; //if creature should respawn instantly after escort over (if not, database respawntime are used)
|
||||
bool m_bCanReturnToStart; //if creature can walk same path (loop) without despawn. Not for regular escort quests.
|
||||
bool DespawnAtEnd;
|
||||
bool DespawnAtFar;
|
||||
bool ScriptWP;
|
||||
bool HasImmuneToNPCFlags;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,362 +0,0 @@
|
||||
/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
|
||||
* This program is free software licensed under GPL version 2
|
||||
* Please see the included DOCS/LICENSE.TXT for more information */
|
||||
|
||||
/* ScriptData
|
||||
SDName: FollowerAI
|
||||
SD%Complete: 50
|
||||
SDComment: This AI is under development
|
||||
SDCategory: Npc
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedFollowerAI.h"
|
||||
#include "Group.h"
|
||||
#include "Player.h"
|
||||
|
||||
const float MAX_PLAYER_DISTANCE = 100.0f;
|
||||
|
||||
enum ePoints
|
||||
{
|
||||
POINT_COMBAT_START = 0xFFFFFF
|
||||
};
|
||||
|
||||
FollowerAI::FollowerAI(Creature* creature) : ScriptedAI(creature),
|
||||
m_uiLeaderGUID(0),
|
||||
m_uiUpdateFollowTimer(2500),
|
||||
m_uiFollowState(STATE_FOLLOW_NONE),
|
||||
m_pQuestForFollow(NULL)
|
||||
{}
|
||||
|
||||
void FollowerAI::AttackStart(Unit* who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
{
|
||||
// This is done in Unit::Attack function which wont bug npcs by not adding threat upon combat start...
|
||||
//me->AddThreat(who, 0.0f);
|
||||
//me->SetInCombatWith(who);
|
||||
//who->SetInCombatWith(me);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_FOLLOW))
|
||||
me->ClearUnitState(UNIT_STATE_FOLLOW);
|
||||
|
||||
if (IsCombatMovementAllowed())
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
}
|
||||
}
|
||||
|
||||
//This part provides assistance to a player that are attacked by who, even if out of normal aggro range
|
||||
//It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi)
|
||||
//The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
|
||||
bool FollowerAI::AssistPlayerInCombat(Unit* who)
|
||||
{
|
||||
if (!who || !who->GetVictim())
|
||||
return false;
|
||||
|
||||
//experimental (unknown) flag not present
|
||||
if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_AID_PLAYERS))
|
||||
return false;
|
||||
|
||||
//not a player
|
||||
if (!who->GetVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
return false;
|
||||
|
||||
//never attack friendly
|
||||
if (me->IsFriendlyTo(who))
|
||||
return false;
|
||||
|
||||
//too far away and no free sight?
|
||||
if (me->IsWithinDistInMap(who, MAX_PLAYER_DISTANCE) && me->IsWithinLOSInMap(who))
|
||||
{
|
||||
AttackStart(who);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FollowerAI::MoveInLineOfSight(Unit* who)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
return;
|
||||
|
||||
if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack(true, me) && who->isInAccessiblePlaceFor(me))
|
||||
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(who))
|
||||
return;
|
||||
|
||||
if (me->CanStartAttack(who))
|
||||
AttackStart(who);
|
||||
}
|
||||
|
||||
void FollowerAI::JustDied(Unit* /*pKiller*/)
|
||||
{
|
||||
if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || !m_uiLeaderGUID || !m_pQuestForFollow)
|
||||
return;
|
||||
|
||||
//TODO: need a better check for quests with time limit.
|
||||
if (Player* player = GetLeaderForFollower())
|
||||
{
|
||||
if (Group* group = player->GetGroup())
|
||||
{
|
||||
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
|
||||
{
|
||||
if (Player* member = groupRef->GetSource())
|
||||
{
|
||||
if (member->IsInMap(player) && member->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
|
||||
member->FailQuest(m_pQuestForFollow->GetQuestId());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->GetQuestStatus(m_pQuestForFollow->GetQuestId()) == QUEST_STATUS_INCOMPLETE)
|
||||
player->FailQuest(m_pQuestForFollow->GetQuestId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FollowerAI::JustRespawned()
|
||||
{
|
||||
m_uiFollowState = STATE_FOLLOW_NONE;
|
||||
|
||||
if (!IsCombatMovementAllowed())
|
||||
SetCombatMovement(true);
|
||||
|
||||
if (me->getFaction() != me->GetCreatureTemplate()->faction)
|
||||
me->setFaction(me->GetCreatureTemplate()->faction);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void FollowerAI::EnterEvadeMode()
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop(true);
|
||||
me->SetLootRecipient(NULL);
|
||||
|
||||
if (HasFollowState(STATE_FOLLOW_INPROGRESS))
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI left combat, returning to CombatStartPosition.");
|
||||
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
||||
{
|
||||
float fPosX, fPosY, fPosZ;
|
||||
me->GetPosition(fPosX, fPosY, fPosZ);
|
||||
me->GetMotionMaster()->MovePoint(POINT_COMBAT_START, fPosX, fPosY, fPosZ);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void FollowerAI::UpdateAI(uint32 uiDiff)
|
||||
{
|
||||
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && !me->GetVictim())
|
||||
{
|
||||
if (m_uiUpdateFollowTimer <= uiDiff)
|
||||
{
|
||||
if (HasFollowState(STATE_FOLLOW_COMPLETE) && !HasFollowState(STATE_FOLLOW_POSTEVENT))
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI is set completed, despawns.");
|
||||
me->DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
|
||||
bool bIsMaxRangeExceeded = true;
|
||||
|
||||
if (Player* player = GetLeaderForFollower())
|
||||
{
|
||||
if (HasFollowState(STATE_FOLLOW_RETURNING))
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI is returning to leader.");
|
||||
|
||||
RemoveFollowState(STATE_FOLLOW_RETURNING);
|
||||
me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Group* group = player->GetGroup())
|
||||
{
|
||||
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
|
||||
{
|
||||
Player* member = groupRef->GetSource();
|
||||
|
||||
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE))
|
||||
{
|
||||
bIsMaxRangeExceeded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me->IsWithinDistInMap(player, MAX_PLAYER_DISTANCE))
|
||||
bIsMaxRangeExceeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsMaxRangeExceeded)
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI failed because player/group was to far away or not found");
|
||||
me->DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
|
||||
m_uiUpdateFollowTimer = 1000;
|
||||
}
|
||||
else
|
||||
m_uiUpdateFollowTimer -= uiDiff;
|
||||
}
|
||||
|
||||
UpdateFollowerAI(uiDiff);
|
||||
}
|
||||
|
||||
void FollowerAI::UpdateFollowerAI(uint32 /*uiDiff*/)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void FollowerAI::MovementInform(uint32 motionType, uint32 pointId)
|
||||
{
|
||||
if (motionType != POINT_MOTION_TYPE || !HasFollowState(STATE_FOLLOW_INPROGRESS))
|
||||
return;
|
||||
|
||||
if (pointId == POINT_COMBAT_START)
|
||||
{
|
||||
if (GetLeaderForFollower())
|
||||
{
|
||||
if (!HasFollowState(STATE_FOLLOW_PAUSED))
|
||||
AddFollowState(STATE_FOLLOW_RETURNING);
|
||||
}
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Quest* quest)
|
||||
{
|
||||
if (me->GetVictim())
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI attempt to StartFollow while in combat.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasFollowState(STATE_FOLLOW_INPROGRESS))
|
||||
{
|
||||
sLog->outError("TSCR: FollowerAI attempt to StartFollow while already following.");
|
||||
return;
|
||||
}
|
||||
|
||||
//set variables
|
||||
m_uiLeaderGUID = player->GetGUID();
|
||||
|
||||
if (factionForFollower)
|
||||
me->setFaction(factionForFollower);
|
||||
|
||||
m_pQuestForFollow = quest;
|
||||
|
||||
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI start with WAYPOINT_MOTION_TYPE, set to MoveIdle.");
|
||||
}
|
||||
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
|
||||
AddFollowState(STATE_FOLLOW_INPROGRESS);
|
||||
|
||||
me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI start follow %s (GUID " UI64FMTD ")", player->GetName().c_str(), m_uiLeaderGUID);
|
||||
}
|
||||
|
||||
Player* FollowerAI::GetLeaderForFollower()
|
||||
{
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, m_uiLeaderGUID))
|
||||
{
|
||||
if (player->IsAlive())
|
||||
return player;
|
||||
else
|
||||
{
|
||||
if (Group* group = player->GetGroup())
|
||||
{
|
||||
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != NULL; groupRef = groupRef->next())
|
||||
{
|
||||
Player* member = groupRef->GetSource();
|
||||
|
||||
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE) && member->IsAlive())
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI GetLeader changed and returned new leader.");
|
||||
m_uiLeaderGUID = member->GetGUID();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_TSCR, "TSCR: FollowerAI GetLeader can not find suitable leader.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void FollowerAI::SetFollowComplete(bool bWithEndEvent)
|
||||
{
|
||||
if (me->HasUnitState(UNIT_STATE_FOLLOW))
|
||||
{
|
||||
me->ClearUnitState(UNIT_STATE_FOLLOW);
|
||||
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
|
||||
if (bWithEndEvent)
|
||||
AddFollowState(STATE_FOLLOW_POSTEVENT);
|
||||
else
|
||||
{
|
||||
if (HasFollowState(STATE_FOLLOW_POSTEVENT))
|
||||
RemoveFollowState(STATE_FOLLOW_POSTEVENT);
|
||||
}
|
||||
|
||||
AddFollowState(STATE_FOLLOW_COMPLETE);
|
||||
}
|
||||
|
||||
void FollowerAI::SetFollowPaused(bool paused)
|
||||
{
|
||||
if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || HasFollowState(STATE_FOLLOW_COMPLETE))
|
||||
return;
|
||||
|
||||
if (paused)
|
||||
{
|
||||
AddFollowState(STATE_FOLLOW_PAUSED);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_FOLLOW))
|
||||
{
|
||||
me->ClearUnitState(UNIT_STATE_FOLLOW);
|
||||
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveFollowState(STATE_FOLLOW_PAUSED);
|
||||
|
||||
if (Player* leader = GetLeaderForFollower())
|
||||
me->GetMotionMaster()->MoveFollow(leader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
|
||||
* This program is free software licensed under GPL version 2
|
||||
* Please see the included DOCS/LICENSE.TXT for more information */
|
||||
|
||||
#ifndef SC_FOLLOWERAI_H
|
||||
#define SC_FOLLOWERAI_H
|
||||
|
||||
#include "ScriptSystem.h"
|
||||
|
||||
enum eFollowState
|
||||
{
|
||||
STATE_FOLLOW_NONE = 0x000,
|
||||
STATE_FOLLOW_INPROGRESS = 0x001, //must always have this state for any follow
|
||||
STATE_FOLLOW_RETURNING = 0x002, //when returning to combat start after being in combat
|
||||
STATE_FOLLOW_PAUSED = 0x004, //disables following
|
||||
STATE_FOLLOW_COMPLETE = 0x008, //follow is completed and may end
|
||||
STATE_FOLLOW_PREEVENT = 0x010, //not implemented (allow pre event to run, before follow is initiated)
|
||||
STATE_FOLLOW_POSTEVENT = 0x020 //can be set at complete and allow post event to run
|
||||
};
|
||||
|
||||
class FollowerAI : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
explicit FollowerAI(Creature* creature);
|
||||
~FollowerAI() {}
|
||||
|
||||
//virtual void WaypointReached(uint32 uiPointId) = 0;
|
||||
|
||||
void MovementInform(uint32 motionType, uint32 pointId);
|
||||
|
||||
void AttackStart(Unit*);
|
||||
|
||||
void MoveInLineOfSight(Unit*);
|
||||
|
||||
void EnterEvadeMode();
|
||||
|
||||
void JustDied(Unit*);
|
||||
|
||||
void JustRespawned();
|
||||
|
||||
void UpdateAI(uint32); //the "internal" update, calls UpdateFollowerAI()
|
||||
virtual void UpdateFollowerAI(uint32); //used when it's needed to add code in update (abilities, scripted events, etc)
|
||||
|
||||
void StartFollow(Player* player, uint32 factionForFollower = 0, const Quest* quest = NULL);
|
||||
|
||||
void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow
|
||||
void SetFollowComplete(bool bWithEndEvent = false);
|
||||
|
||||
bool HasFollowState(uint32 uiFollowState) { return (m_uiFollowState & uiFollowState); }
|
||||
|
||||
protected:
|
||||
Player* GetLeaderForFollower();
|
||||
|
||||
private:
|
||||
void AddFollowState(uint32 uiFollowState) { m_uiFollowState |= uiFollowState; }
|
||||
void RemoveFollowState(uint32 uiFollowState) { m_uiFollowState &= ~uiFollowState; }
|
||||
|
||||
bool AssistPlayerInCombat(Unit* who);
|
||||
|
||||
uint64 m_uiLeaderGUID;
|
||||
uint32 m_uiUpdateFollowTimer;
|
||||
uint32 m_uiFollowState;
|
||||
|
||||
const Quest* m_pQuestForFollow; //normally we have a quest
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,90 +0,0 @@
|
||||
/* Copyright (C)
|
||||
*
|
||||
*
|
||||
*
|
||||
* This program is free software licensed under GPL version 2
|
||||
* Please see the included DOCS/LICENSE.TXT for more information */
|
||||
|
||||
#ifndef SC_GOSSIP_H
|
||||
#define SC_GOSSIP_H
|
||||
|
||||
#include "GossipDef.h"
|
||||
#include "QuestDef.h"
|
||||
|
||||
// Gossip Item Text
|
||||
#define GOSSIP_TEXT_BROWSE_GOODS "I'd like to browse your goods."
|
||||
#define GOSSIP_TEXT_TRAIN "Train me!"
|
||||
|
||||
enum eTradeskill
|
||||
{
|
||||
// Skill defines
|
||||
TRADESKILL_ALCHEMY = 1,
|
||||
TRADESKILL_BLACKSMITHING = 2,
|
||||
TRADESKILL_COOKING = 3,
|
||||
TRADESKILL_ENCHANTING = 4,
|
||||
TRADESKILL_ENGINEERING = 5,
|
||||
TRADESKILL_FIRSTAID = 6,
|
||||
TRADESKILL_HERBALISM = 7,
|
||||
TRADESKILL_LEATHERWORKING = 8,
|
||||
TRADESKILL_POISONS = 9,
|
||||
TRADESKILL_TAILORING = 10,
|
||||
TRADESKILL_MINING = 11,
|
||||
TRADESKILL_FISHING = 12,
|
||||
TRADESKILL_SKINNING = 13,
|
||||
TRADESKILL_JEWLCRAFTING = 14,
|
||||
TRADESKILL_INSCRIPTION = 15,
|
||||
|
||||
TRADESKILL_LEVEL_NONE = 0,
|
||||
TRADESKILL_LEVEL_APPRENTICE = 1,
|
||||
TRADESKILL_LEVEL_JOURNEYMAN = 2,
|
||||
TRADESKILL_LEVEL_EXPERT = 3,
|
||||
TRADESKILL_LEVEL_ARTISAN = 4,
|
||||
TRADESKILL_LEVEL_MASTER = 5,
|
||||
TRADESKILL_LEVEL_GRAND_MASTER = 6,
|
||||
|
||||
// Gossip defines
|
||||
GOSSIP_ACTION_TRADE = 1,
|
||||
GOSSIP_ACTION_TRAIN = 2,
|
||||
GOSSIP_ACTION_TAXI = 3,
|
||||
GOSSIP_ACTION_GUILD = 4,
|
||||
GOSSIP_ACTION_BATTLE = 5,
|
||||
GOSSIP_ACTION_BANK = 6,
|
||||
GOSSIP_ACTION_INN = 7,
|
||||
GOSSIP_ACTION_HEAL = 8,
|
||||
GOSSIP_ACTION_TABARD = 9,
|
||||
GOSSIP_ACTION_AUCTION = 10,
|
||||
GOSSIP_ACTION_INN_INFO = 11,
|
||||
GOSSIP_ACTION_UNLEARN = 12,
|
||||
GOSSIP_ACTION_INFO_DEF = 1000,
|
||||
|
||||
GOSSIP_SENDER_MAIN = 1,
|
||||
GOSSIP_SENDER_INN_INFO = 2,
|
||||
GOSSIP_SENDER_INFO = 3,
|
||||
GOSSIP_SENDER_SEC_PROFTRAIN = 4,
|
||||
GOSSIP_SENDER_SEC_CLASSTRAIN = 5,
|
||||
GOSSIP_SENDER_SEC_BATTLEINFO = 6,
|
||||
GOSSIP_SENDER_SEC_BANK = 7,
|
||||
GOSSIP_SENDER_SEC_INN = 8,
|
||||
GOSSIP_SENDER_SEC_MAILBOX = 9,
|
||||
GOSSIP_SENDER_SEC_STABLEMASTER = 10
|
||||
};
|
||||
|
||||
// Defined fuctions to use with player.
|
||||
|
||||
// This fuction add's a menu item,
|
||||
// a - Icon Id
|
||||
// b - Text
|
||||
// c - Sender(this is to identify the current Menu with this item)
|
||||
// d - Action (identifys this Menu Item)
|
||||
// e - Text to be displayed in pop up box
|
||||
// f - Money value in pop up box
|
||||
#define ADD_GOSSIP_ITEM(a, b, c, d) PlayerTalkClass->GetGossipMenu().AddMenuItem(-1, a, b, c, d, "", 0)
|
||||
#define ADD_GOSSIP_ITEM_EXTENDED(a, b, c, d, e, f, g) PlayerTalkClass->GetGossipMenu().AddMenuItem(-1, a, b, c, d, e, f, g)
|
||||
|
||||
// This fuction Sends the current menu to show to client, a - NPCTEXTID(uint32), b - npc guid(uint64)
|
||||
#define SEND_GOSSIP_MENU(a, b) PlayerTalkClass->SendGossipMenu(a, b)
|
||||
|
||||
// Closes the Menu
|
||||
#define CLOSE_GOSSIP_MENU() PlayerTalkClass->SendCloseGossip()
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_SMARTAI_H
|
||||
#define TRINITY_SMARTAI_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Unit.h"
|
||||
#include "Spell.h"
|
||||
|
||||
#include "SmartScript.h"
|
||||
#include "SmartScriptMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
|
||||
enum SmartEscortState
|
||||
{
|
||||
SMART_ESCORT_NONE = 0x000, //nothing in progress
|
||||
SMART_ESCORT_ESCORTING = 0x001, //escort is in progress
|
||||
SMART_ESCORT_RETURNING = 0x002, //escort is returning after being in combat
|
||||
SMART_ESCORT_PAUSED = 0x004 //will not proceed with waypoints before state is removed
|
||||
};
|
||||
|
||||
enum SmartEscortVars
|
||||
{
|
||||
SMART_ESCORT_MAX_PLAYER_DIST = 60,
|
||||
SMART_MAX_AID_DIST = SMART_ESCORT_MAX_PLAYER_DIST / 2,
|
||||
};
|
||||
|
||||
class SmartAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
~SmartAI(){};
|
||||
explicit SmartAI(Creature* c);
|
||||
|
||||
// Start moving to the desired MovePoint
|
||||
void StartPath(bool run = false, uint32 path = 0, bool repeat = false, Unit* invoker = NULL);
|
||||
bool LoadPath(uint32 entry);
|
||||
void PausePath(uint32 delay, bool forced = false);
|
||||
void StopPath(uint32 DespawnTime = 0, uint32 quest = 0, bool fail = false);
|
||||
void EndPath(bool fail = false);
|
||||
void ResumePath();
|
||||
WayPoint* GetNextWayPoint();
|
||||
void GenerateWayPointArray(Movement::PointsArray* points);
|
||||
bool HasEscortState(uint32 uiEscortState) { return (mEscortState & uiEscortState); }
|
||||
void AddEscortState(uint32 uiEscortState) { mEscortState |= uiEscortState; }
|
||||
virtual bool IsEscorted() { return (mEscortState & SMART_ESCORT_ESCORTING); }
|
||||
void RemoveEscortState(uint32 uiEscortState) { mEscortState &= ~uiEscortState; }
|
||||
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
|
||||
void SetCombatMove(bool on);
|
||||
bool CanCombatMove() { return mCanCombatMove; }
|
||||
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0, bool aliveState = true);
|
||||
void StopFollow(bool complete);
|
||||
|
||||
void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);
|
||||
SmartScript* GetScript() { return &mScript; }
|
||||
bool IsEscortInvokerInRange();
|
||||
|
||||
// Called when creature is spawned or respawned
|
||||
void JustRespawned();
|
||||
|
||||
// Called at reaching home after evade, InitializeAI(), EnterEvadeMode() for resetting variables
|
||||
void JustReachedHome();
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
|
||||
void EnterCombat(Unit* enemy);
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
void EnterEvadeMode();
|
||||
|
||||
// Called when the creature is killed
|
||||
void JustDied(Unit* killer);
|
||||
|
||||
// Called when the creature kills a unit
|
||||
void KilledUnit(Unit* victim);
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
void JustSummoned(Creature* creature);
|
||||
|
||||
// Tell creature to attack and follow the victim
|
||||
void AttackStart(Unit* who);
|
||||
|
||||
// Called if IsVisible(Unit* who) is true at each *who move, reaction at visibility zone enter
|
||||
void MoveInLineOfSight(Unit* who);
|
||||
|
||||
// Called when hit by a spell
|
||||
void SpellHit(Unit* unit, const SpellInfo* spellInfo);
|
||||
|
||||
// Called when spell hits a target
|
||||
void SpellHitTarget(Unit* target, const SpellInfo* spellInfo);
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
void DamageTaken(Unit* done_by, uint32 &damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask);
|
||||
|
||||
// Called when the creature receives heal
|
||||
void HealReceived(Unit* doneBy, uint32& addhealth);
|
||||
|
||||
// Called at World update tick
|
||||
void UpdateAI(uint32 diff);
|
||||
|
||||
// Called at text emote receive from player
|
||||
void ReceiveEmote(Player* player, uint32 textEmote);
|
||||
|
||||
// Called at waypoint reached or point movement finished
|
||||
void MovementInform(uint32 MovementType, uint32 Data);
|
||||
|
||||
// Called when creature is summoned by another unit
|
||||
void IsSummonedBy(Unit* summoner);
|
||||
|
||||
// Called at any Damage to any victim (before damage apply)
|
||||
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType damagetyp);
|
||||
|
||||
// Called when a summoned creature dissapears (UnSommoned)
|
||||
void SummonedCreatureDespawn(Creature* unit);
|
||||
|
||||
// called when the corpse of this creature gets removed
|
||||
void CorpseRemoved(uint32& respawnDelay);
|
||||
|
||||
// Called at World update tick if creature is charmed
|
||||
void UpdateAIWhileCharmed(const uint32 diff);
|
||||
|
||||
// Called when a Player/Creature enters the creature (vehicle)
|
||||
void PassengerBoarded(Unit* who, int8 seatId, bool apply);
|
||||
|
||||
// Called when gets initialized, when creature is added to world
|
||||
void InitializeAI();
|
||||
|
||||
// Called when creature gets charmed by another unit
|
||||
void OnCharmed(bool apply);
|
||||
|
||||
// Called when victim is in line of sight
|
||||
bool CanAIAttack(const Unit* who) const;
|
||||
|
||||
// Used in scripts to share variables
|
||||
void DoAction(int32 param = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
uint32 GetData(uint32 id = 0) const;
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetData(uint32 id, uint32 value);
|
||||
|
||||
// Used in scripts to share variables
|
||||
void SetGUID(uint64 guid, int32 id = 0);
|
||||
|
||||
// Used in scripts to share variables
|
||||
uint64 GetGUID(int32 id = 0) const;
|
||||
|
||||
//core related
|
||||
static int32 Permissible(const Creature*);
|
||||
|
||||
// Called at movepoint reached
|
||||
void MovepointReached(uint32 id);
|
||||
|
||||
// Makes the creature run/walk
|
||||
void SetRun(bool run = true);
|
||||
|
||||
void SetFly(bool fly = true);
|
||||
|
||||
void SetSwim(bool swim = true);
|
||||
|
||||
void SetInvincibilityHpLevel(uint32 level) { mInvincibilityHpLevel = level; }
|
||||
|
||||
void sGossipHello(Player* player);
|
||||
void sGossipSelect(Player* player, uint32 sender, uint32 action);
|
||||
void sGossipSelectCode(Player* player, uint32 sender, uint32 action, const char* code);
|
||||
void sQuestAccept(Player* player, Quest const* quest);
|
||||
//void sQuestSelect(Player* player, Quest const* quest);
|
||||
//void sQuestComplete(Player* player, Quest const* quest);
|
||||
void sQuestReward(Player* player, Quest const* quest, uint32 opt);
|
||||
void sOnGameEvent(bool start, uint16 eventId);
|
||||
|
||||
uint32 mEscortQuestID;
|
||||
|
||||
void SetDespawnTime (uint32 t)
|
||||
{
|
||||
mDespawnTime = t;
|
||||
mDespawnState = t ? 1 : 0;
|
||||
}
|
||||
void StartDespawn() { mDespawnState = 2; }
|
||||
|
||||
void OnSpellClick(Unit* clicker, bool& result);
|
||||
|
||||
// Xinef
|
||||
void SetWPPauseTimer(uint32 time) { mWPPauseTimer = time; }
|
||||
void SetForcedCombatMove(float dist);
|
||||
|
||||
private:
|
||||
uint32 mFollowCreditType;
|
||||
uint32 mFollowArrivedTimer;
|
||||
uint32 mFollowCredit;
|
||||
uint32 mFollowArrivedEntry;
|
||||
bool mFollowArrivedAlive;
|
||||
uint64 mFollowGuid;
|
||||
float mFollowDist;
|
||||
float mFollowAngle;
|
||||
|
||||
void ReturnToLastOOCPos();
|
||||
void UpdatePath(const uint32 diff);
|
||||
SmartScript mScript;
|
||||
WPPath* mWayPoints;
|
||||
uint32 mEscortState;
|
||||
uint32 mCurrentWPID;
|
||||
bool mWPReached;
|
||||
bool mOOCReached;
|
||||
uint32 mWPPauseTimer;
|
||||
WayPoint* mLastWP;
|
||||
uint32 mEscortNPCFlags;
|
||||
uint32 GetWPCount() { return mWayPoints ? mWayPoints->size() : 0; }
|
||||
bool mCanRepeatPath;
|
||||
bool mRun;
|
||||
bool mCanAutoAttack;
|
||||
bool mCanCombatMove;
|
||||
bool mForcedPaused;
|
||||
uint32 mInvincibilityHpLevel;
|
||||
|
||||
bool AssistPlayerInCombat(Unit* who);
|
||||
|
||||
uint32 mDespawnTime;
|
||||
uint32 mDespawnState;
|
||||
void UpdateDespawn(const uint32 diff);
|
||||
uint32 mEscortInvokerCheckTimer;
|
||||
bool mJustReset;
|
||||
|
||||
// Xinef: Vehicle conditions
|
||||
void CheckConditions(const uint32 diff);
|
||||
ConditionList conditions;
|
||||
uint32 m_ConditionsTimer;
|
||||
};
|
||||
|
||||
class SmartGameObjectAI : public GameObjectAI
|
||||
{
|
||||
public:
|
||||
SmartGameObjectAI(GameObject* g) : GameObjectAI(g) {}
|
||||
~SmartGameObjectAI() {}
|
||||
|
||||
void UpdateAI(uint32 diff);
|
||||
void InitializeAI();
|
||||
void Reset();
|
||||
SmartScript* GetScript() { return &mScript; }
|
||||
static int32 Permissible(const GameObject* g);
|
||||
|
||||
bool GossipHello(Player* player, bool reportUse);
|
||||
bool GossipSelect(Player* player, uint32 sender, uint32 action);
|
||||
bool GossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/);
|
||||
bool QuestAccept(Player* player, Quest const* quest);
|
||||
bool QuestReward(Player* player, Quest const* quest, uint32 opt);
|
||||
void Destroyed(Player* player, uint32 eventId);
|
||||
void SetData(uint32 id, uint32 value);
|
||||
void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker);
|
||||
void OnGameEvent(bool start, uint16 eventId);
|
||||
void OnStateChanged(uint32 state, Unit* unit);
|
||||
void EventInform(uint32 eventId);
|
||||
void SpellHit(Unit* unit, const SpellInfo* spellInfo);
|
||||
|
||||
protected:
|
||||
SmartScript mScript;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,343 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_SMARTSCRIPT_H
|
||||
#define TRINITY_SMARTSCRIPT_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
#include "Unit.h"
|
||||
#include "Spell.h"
|
||||
#include "GridNotifiers.h"
|
||||
|
||||
#include "SmartScriptMgr.h"
|
||||
//#include "SmartAI.h"
|
||||
|
||||
class SmartScript
|
||||
{
|
||||
public:
|
||||
SmartScript();
|
||||
~SmartScript();
|
||||
|
||||
void OnInitialize(WorldObject* obj, AreaTriggerEntry const* at = NULL);
|
||||
void GetScript();
|
||||
void FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at);
|
||||
|
||||
void ProcessEventsFor(SMART_EVENT e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
|
||||
void ProcessEvent(SmartScriptHolder& e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
|
||||
bool CheckTimer(SmartScriptHolder const& e) const;
|
||||
void RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max);
|
||||
void UpdateTimer(SmartScriptHolder& e, uint32 const diff);
|
||||
void InitTimer(SmartScriptHolder& e);
|
||||
void ProcessAction(SmartScriptHolder& e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
|
||||
void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
|
||||
ObjectList* GetTargets(SmartScriptHolder const& e, Unit* invoker = NULL);
|
||||
ObjectList* GetWorldObjectsInDist(float dist);
|
||||
void InstallTemplate(SmartScriptHolder const& e);
|
||||
SmartScriptHolder CreateEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, 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 phaseMask = 0);
|
||||
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, 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 phaseMask = 0);
|
||||
void SetPathId(uint32 id) { mPathId = id; }
|
||||
uint32 GetPathId() const { return mPathId; }
|
||||
WorldObject* GetBaseObject()
|
||||
{
|
||||
WorldObject* obj = NULL;
|
||||
if (me)
|
||||
obj = me;
|
||||
else if (go)
|
||||
obj = go;
|
||||
return obj;
|
||||
}
|
||||
|
||||
bool IsUnit(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->IsInWorld() && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
|
||||
}
|
||||
|
||||
bool IsPlayer(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
bool IsCreature(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_UNIT;
|
||||
}
|
||||
|
||||
bool IsGameObject(WorldObject* obj)
|
||||
{
|
||||
return obj && obj->IsInWorld() && obj->GetTypeId() == TYPEID_GAMEOBJECT;
|
||||
}
|
||||
|
||||
void OnUpdate(const uint32 diff);
|
||||
void OnMoveInLineOfSight(Unit* who);
|
||||
|
||||
Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff);
|
||||
void DoFindFriendlyCC(std::list<Creature*>& _list, float range);
|
||||
void DoFindFriendlyMissingBuff(std::list<Creature*>& list, float range, uint32 spellid);
|
||||
Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly);
|
||||
|
||||
void StoreTargetList(ObjectList* targets, uint32 id)
|
||||
{
|
||||
if (!targets)
|
||||
return;
|
||||
|
||||
if (mTargetStorage->find(id) != mTargetStorage->end())
|
||||
{
|
||||
// check if already stored
|
||||
if ((*mTargetStorage)[id]->Equals(targets))
|
||||
return;
|
||||
|
||||
delete (*mTargetStorage)[id];
|
||||
}
|
||||
|
||||
(*mTargetStorage)[id] = new ObjectGuidList(targets, GetBaseObject());
|
||||
}
|
||||
|
||||
bool IsSmart(Creature* c = NULL)
|
||||
{
|
||||
bool smart = true;
|
||||
if (c && c->GetAIName() != "SmartAI")
|
||||
smart = false;
|
||||
|
||||
if (!me || me->GetAIName() != "SmartAI")
|
||||
smart = false;
|
||||
|
||||
if (!smart)
|
||||
sLog->outErrorDb("SmartScript: Action target Creature(entry: %u) is not using SmartAI, action skipped to prevent crash.", c ? c->GetEntry() : (me ? me->GetEntry() : 0));
|
||||
|
||||
return smart;
|
||||
}
|
||||
|
||||
bool IsSmartGO(GameObject* g = NULL)
|
||||
{
|
||||
bool smart = true;
|
||||
if (g && g->GetAIName() != "SmartGameObjectAI")
|
||||
smart = false;
|
||||
|
||||
if (!go || go->GetAIName() != "SmartGameObjectAI")
|
||||
smart = false;
|
||||
if (!smart)
|
||||
sLog->outErrorDb("SmartScript: Action target GameObject(entry: %u) is not using SmartGameObjectAI, action skipped to prevent crash.", g ? g->GetEntry() : (go ? go->GetEntry() : 0));
|
||||
|
||||
return smart;
|
||||
}
|
||||
|
||||
ObjectList* GetTargetList(uint32 id)
|
||||
{
|
||||
ObjectListMap::iterator itr = mTargetStorage->find(id);
|
||||
if (itr != mTargetStorage->end())
|
||||
return (*itr).second->GetObjectList();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void StoreCounter(uint32 id, uint32 value, uint32 reset)
|
||||
{
|
||||
CounterMap::iterator itr = mCounterList.find(id);
|
||||
if (itr != mCounterList.end())
|
||||
{
|
||||
if (reset == 0)
|
||||
itr->second += value;
|
||||
else
|
||||
itr->second = value;
|
||||
}
|
||||
else
|
||||
mCounterList.insert(std::make_pair(id, value));
|
||||
|
||||
ProcessEventsFor(SMART_EVENT_COUNTER_SET, NULL, id);
|
||||
}
|
||||
|
||||
uint32 GetCounterValue(uint32 id)
|
||||
{
|
||||
CounterMap::iterator itr = mCounterList.find(id);
|
||||
if (itr != mCounterList.end())
|
||||
return itr->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
GameObject* FindGameObjectNear(WorldObject* searchObject, uint32 guid) const
|
||||
{
|
||||
GameObject* gameObject = NULL;
|
||||
|
||||
CellCoord p(Trinity::ComputeCellCoord(searchObject->GetPositionX(), searchObject->GetPositionY()));
|
||||
Cell cell(p);
|
||||
|
||||
Trinity::GameObjectWithDbGUIDCheck goCheck(*searchObject, guid);
|
||||
Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(searchObject, gameObject, goCheck);
|
||||
|
||||
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > objectChecker(checker);
|
||||
cell.Visit(p, objectChecker, *searchObject->GetMap(), *searchObject, searchObject->GetVisibilityRange());
|
||||
|
||||
return gameObject;
|
||||
}
|
||||
|
||||
Creature* FindCreatureNear(WorldObject* searchObject, uint32 guid) const
|
||||
{
|
||||
Creature* creature = NULL;
|
||||
CellCoord p(Trinity::ComputeCellCoord(searchObject->GetPositionX(), searchObject->GetPositionY()));
|
||||
Cell cell(p);
|
||||
|
||||
Trinity::CreatureWithDbGUIDCheck target_check(searchObject, guid);
|
||||
Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(searchObject, creature, target_check);
|
||||
|
||||
TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
|
||||
cell.Visit(p, unit_checker, *searchObject->GetMap(), *searchObject, searchObject->GetVisibilityRange());
|
||||
|
||||
return creature;
|
||||
}
|
||||
|
||||
ObjectListMap* mTargetStorage;
|
||||
|
||||
void OnReset();
|
||||
void ResetBaseObject()
|
||||
{
|
||||
if (meOrigGUID)
|
||||
{
|
||||
if (Creature* m = HashMapHolder<Creature>::Find(meOrigGUID))
|
||||
{
|
||||
me = m;
|
||||
go = NULL;
|
||||
}
|
||||
}
|
||||
if (goOrigGUID)
|
||||
{
|
||||
if (GameObject* o = HashMapHolder<GameObject>::Find(goOrigGUID))
|
||||
{
|
||||
me = NULL;
|
||||
go = o;
|
||||
}
|
||||
}
|
||||
goOrigGUID = 0;
|
||||
meOrigGUID = 0;
|
||||
}
|
||||
|
||||
//TIMED_ACTIONLIST (script type 9 aka script9)
|
||||
void SetScript9(SmartScriptHolder& e, uint32 entry);
|
||||
Unit* GetLastInvoker(Unit* invoker = NULL);
|
||||
uint64 mLastInvoker;
|
||||
typedef UNORDERED_MAP<uint32, uint32> CounterMap;
|
||||
CounterMap mCounterList;
|
||||
|
||||
// Xinef: Fix Combat Movement
|
||||
void SetActualCombatDist(uint32 dist) { mActualCombatDist = dist; }
|
||||
void RestoreMaxCombatDist() { mActualCombatDist = mMaxCombatDist; }
|
||||
uint32 GetActualCombatDist() const { return mActualCombatDist; }
|
||||
uint32 GetMaxCombatDist() const { return mMaxCombatDist; }
|
||||
|
||||
// Xinef: SmartCasterAI, replace above
|
||||
void SetCasterActualDist(float dist) { smartCasterActualDist = dist; }
|
||||
void RestoreCasterMaxDist() { smartCasterActualDist = smartCasterMaxDist; }
|
||||
Powers GetCasterPowerType() const { return smartCasterPowerType; }
|
||||
float GetCasterActualDist() const { return smartCasterActualDist; }
|
||||
float GetCasterMaxDist() const { return smartCasterMaxDist; }
|
||||
|
||||
bool AllowPhaseReset() const { return _allowPhaseReset; }
|
||||
void SetPhaseReset(bool allow) { _allowPhaseReset = allow; }
|
||||
|
||||
private:
|
||||
void IncPhase(uint32 p)
|
||||
{
|
||||
// Xinef: protect phase from overflowing
|
||||
mEventPhase = std::min<uint32>(SMART_EVENT_PHASE_12, mEventPhase + p);
|
||||
}
|
||||
|
||||
void DecPhase(uint32 p)
|
||||
{
|
||||
if (p >= mEventPhase)
|
||||
mEventPhase = 0;
|
||||
else
|
||||
mEventPhase -= p;
|
||||
}
|
||||
bool IsInPhase(uint32 p) const
|
||||
{
|
||||
if (mEventPhase == 0)
|
||||
return false;
|
||||
return (1 << (mEventPhase - 1)) & p;
|
||||
}
|
||||
void SetPhase(uint32 p = 0) { mEventPhase = p; }
|
||||
|
||||
SmartAIEventList mEvents;
|
||||
SmartAIEventList mInstallEvents;
|
||||
SmartAIEventList mTimedActionList;
|
||||
bool isProcessingTimedActionList;
|
||||
Creature* me;
|
||||
uint64 meOrigGUID;
|
||||
GameObject* go;
|
||||
uint64 goOrigGUID;
|
||||
AreaTriggerEntry const* trigger;
|
||||
SmartScriptType mScriptType;
|
||||
uint32 mEventPhase;
|
||||
|
||||
UNORDERED_MAP<int32, int32> mStoredDecimals;
|
||||
uint32 mPathId;
|
||||
SmartAIEventStoredList mStoredEvents;
|
||||
std::list<uint32> mRemIDs;
|
||||
|
||||
uint32 mTextTimer;
|
||||
uint32 mLastTextID;
|
||||
uint32 mTalkerEntry;
|
||||
bool mUseTextTimer;
|
||||
|
||||
// Xinef: Fix Combat Movement
|
||||
uint32 mActualCombatDist;
|
||||
uint32 mMaxCombatDist;
|
||||
|
||||
// Xinef: SmartCasterAI, replace above in future
|
||||
uint32 smartCasterActualDist;
|
||||
uint32 smartCasterMaxDist;
|
||||
Powers smartCasterPowerType;
|
||||
|
||||
// Xinef: misc
|
||||
bool _allowPhaseReset;
|
||||
|
||||
SMARTAI_TEMPLATE mTemplate;
|
||||
void InstallEvents();
|
||||
|
||||
void RemoveStoredEvent (uint32 id)
|
||||
{
|
||||
if (!mStoredEvents.empty())
|
||||
{
|
||||
for (SmartAIEventStoredList::iterator i = mStoredEvents.begin(); i != mStoredEvents.end(); ++i)
|
||||
{
|
||||
if (i->event_id == id)
|
||||
{
|
||||
mStoredEvents.erase(i);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
SmartScriptHolder FindLinkedEvent (uint32 link)
|
||||
{
|
||||
if (!mEvents.empty())
|
||||
{
|
||||
for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
|
||||
{
|
||||
if (i->event_id == link)
|
||||
{
|
||||
return (*i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
SmartScriptHolder s;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,302 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AccountMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
#include "SHA1.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
namespace AccountMgr
|
||||
{
|
||||
|
||||
AccountOpResult CreateAccount(std::string username, std::string password)
|
||||
{
|
||||
if (utf8length(username) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG; // username's too long
|
||||
|
||||
normalizeString(username);
|
||||
normalizeString(password);
|
||||
|
||||
if (GetId(username))
|
||||
return AOR_NAME_ALREDY_EXIST; // username does already exist
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT);
|
||||
|
||||
stmt->setString(0, username);
|
||||
stmt->setString(1, CalculateShaPassHash(username, password));
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT);
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
return AOR_OK; // everything's fine
|
||||
}
|
||||
|
||||
AccountOpResult DeleteAccount(uint32 accountId)
|
||||
{
|
||||
// Check if accounts exists
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID);
|
||||
stmt->setUInt32(0, accountId);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
return AOR_NAME_NOT_EXIST;
|
||||
|
||||
// Obtain accounts characters
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
|
||||
|
||||
stmt->setUInt32(0, accountId);
|
||||
|
||||
result = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
uint32 guidLow = (*result)[0].GetUInt32();
|
||||
uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER);
|
||||
|
||||
// Kick if player is online
|
||||
if (Player* p = ObjectAccessor::FindPlayer(guid))
|
||||
{
|
||||
WorldSession* s = p->GetSession();
|
||||
s->KickPlayer(); // mark session to remove at next session list update
|
||||
s->LogoutPlayer(false); // logout player without waiting next session list update
|
||||
}
|
||||
|
||||
Player::DeleteFromDB(guid, accountId, false, true); // no need to update realm characters
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
// table realm specific but common for all characters of account for realm
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS);
|
||||
stmt->setUInt32(0, accountId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA);
|
||||
stmt->setUInt32(0, accountId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN);
|
||||
stmt->setUInt32(0, accountId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
SQLTransaction trans = LoginDatabase.BeginTransaction();
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT);
|
||||
stmt->setUInt32(0, accountId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS);
|
||||
stmt->setUInt32(0, accountId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS);
|
||||
stmt->setUInt32(0, accountId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_BANNED);
|
||||
stmt->setUInt32(0, accountId);
|
||||
trans->Append(stmt);
|
||||
|
||||
LoginDatabase.CommitTransaction(trans);
|
||||
|
||||
return AOR_OK;
|
||||
}
|
||||
|
||||
|
||||
AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword)
|
||||
{
|
||||
// Check if accounts exists
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID);
|
||||
stmt->setUInt32(0, accountId);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
return AOR_NAME_NOT_EXIST;
|
||||
|
||||
if (utf8length(newUsername) > MAX_ACCOUNT_STR)
|
||||
return AOR_NAME_TOO_LONG;
|
||||
|
||||
if (utf8length(newPassword) > MAX_ACCOUNT_STR)
|
||||
return AOR_PASS_TOO_LONG;
|
||||
|
||||
normalizeString(newUsername);
|
||||
normalizeString(newPassword);
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME);
|
||||
|
||||
stmt->setString(0, newUsername);
|
||||
stmt->setString(1, CalculateShaPassHash(newUsername, newPassword));
|
||||
stmt->setUInt32(2, accountId);
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
return AOR_OK;
|
||||
}
|
||||
|
||||
AccountOpResult ChangePassword(uint32 accountId, std::string newPassword)
|
||||
{
|
||||
std::string username;
|
||||
|
||||
if (!GetName(accountId, username))
|
||||
return AOR_NAME_NOT_EXIST; // account doesn't exist
|
||||
|
||||
if (utf8length(newPassword) > MAX_ACCOUNT_STR)
|
||||
return AOR_PASS_TOO_LONG;
|
||||
|
||||
normalizeString(username);
|
||||
normalizeString(newPassword);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD);
|
||||
|
||||
stmt->setString(0, CalculateShaPassHash(username, newPassword));
|
||||
stmt->setUInt32(1, accountId);
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
return AOR_OK;
|
||||
}
|
||||
|
||||
uint32 GetId(std::string const& username)
|
||||
{
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME);
|
||||
stmt->setString(0, username);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
return (result) ? (*result)[0].GetUInt32() : 0;
|
||||
}
|
||||
|
||||
uint32 GetSecurity(uint32 accountId)
|
||||
{
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL);
|
||||
stmt->setUInt32(0, accountId);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER);
|
||||
}
|
||||
|
||||
uint32 GetSecurity(uint32 accountId, int32 realmId)
|
||||
{
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);
|
||||
stmt->setUInt32(0, accountId);
|
||||
stmt->setInt32(1, realmId);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER);
|
||||
}
|
||||
|
||||
bool GetName(uint32 accountId, std::string& name)
|
||||
{
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID);
|
||||
stmt->setUInt32(0, accountId);
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (result)
|
||||
{
|
||||
name = (*result)[0].GetString();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CheckPassword(uint32 accountId, std::string password)
|
||||
{
|
||||
std::string username;
|
||||
|
||||
if (!GetName(accountId, username))
|
||||
return false;
|
||||
|
||||
normalizeString(username);
|
||||
normalizeString(password);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD);
|
||||
stmt->setUInt32(0, accountId);
|
||||
stmt->setString(1, CalculateShaPassHash(username, password));
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
return (result) ? true : false;
|
||||
}
|
||||
|
||||
uint32 GetCharactersCount(uint32 accountId)
|
||||
{
|
||||
// check character count
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS);
|
||||
stmt->setUInt32(0, accountId);
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
return (result) ? (*result)[0].GetUInt64() : 0;
|
||||
}
|
||||
|
||||
bool normalizeString(std::string& utf8String)
|
||||
{
|
||||
wchar_t buffer[MAX_ACCOUNT_STR + 1];
|
||||
|
||||
size_t maxLength = MAX_ACCOUNT_STR;
|
||||
if (!Utf8toWStr(utf8String, buffer, maxLength))
|
||||
return false;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4996)
|
||||
#endif
|
||||
std::transform(&buffer[0], buffer + maxLength, &buffer[0], wcharToUpperOnlyLatin);
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(default: 4996)
|
||||
#endif
|
||||
|
||||
return WStrToUtf8(buffer, maxLength, utf8String);
|
||||
}
|
||||
|
||||
std::string CalculateShaPassHash(std::string const& name, std::string const& password)
|
||||
{
|
||||
SHA1Hash sha;
|
||||
sha.Initialize();
|
||||
sha.UpdateData(name);
|
||||
sha.UpdateData(":");
|
||||
sha.UpdateData(password);
|
||||
sha.Finalize();
|
||||
|
||||
return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength());
|
||||
}
|
||||
|
||||
bool IsPlayerAccount(uint32 gmlevel)
|
||||
{
|
||||
return gmlevel == SEC_PLAYER;
|
||||
}
|
||||
|
||||
bool IsGMAccount(uint32 gmlevel)
|
||||
{
|
||||
return gmlevel >= SEC_GAMEMASTER && gmlevel <= SEC_CONSOLE;
|
||||
}
|
||||
|
||||
bool IsAdminAccount(uint32 gmlevel)
|
||||
{
|
||||
return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE;
|
||||
}
|
||||
|
||||
bool IsConsoleAccount(uint32 gmlevel)
|
||||
{
|
||||
return gmlevel == SEC_CONSOLE;
|
||||
}
|
||||
|
||||
} // Namespace AccountMgr
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ACCMGR_H
|
||||
#define _ACCMGR_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
|
||||
enum AccountOpResult
|
||||
{
|
||||
AOR_OK,
|
||||
AOR_NAME_TOO_LONG,
|
||||
AOR_PASS_TOO_LONG,
|
||||
AOR_NAME_ALREDY_EXIST,
|
||||
AOR_NAME_NOT_EXIST,
|
||||
AOR_DB_INTERNAL_ERROR
|
||||
};
|
||||
|
||||
#define MAX_ACCOUNT_STR 20
|
||||
|
||||
namespace AccountMgr
|
||||
{
|
||||
AccountOpResult CreateAccount(std::string username, std::string password);
|
||||
AccountOpResult DeleteAccount(uint32 accountId);
|
||||
AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
|
||||
AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
|
||||
bool CheckPassword(uint32 accountId, std::string password);
|
||||
|
||||
uint32 GetId(std::string const& username);
|
||||
uint32 GetSecurity(uint32 accountId);
|
||||
uint32 GetSecurity(uint32 accountId, int32 realmId);
|
||||
bool GetName(uint32 accountId, std::string& name);
|
||||
uint32 GetCharactersCount(uint32 accountId);
|
||||
std::string CalculateShaPassHash(std::string const& name, std::string const& password);
|
||||
|
||||
bool normalizeString(std::string& utf8String);
|
||||
bool IsPlayerAccount(uint32 gmlevel);
|
||||
bool IsGMAccount(uint32 gmlevel);
|
||||
bool IsAdminAccount(uint32 gmlevel);
|
||||
bool IsConsoleAccount(uint32 gmlevel);
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,403 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __TRINITY_ACHIEVEMENTMGR_H
|
||||
#define __TRINITY_ACHIEVEMENTMGR_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
#include <ace/Singleton.h>
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DBCEnums.h"
|
||||
#include "DBCStores.h"
|
||||
|
||||
typedef std::list<AchievementCriteriaEntry const*> AchievementCriteriaEntryList;
|
||||
typedef std::list<AchievementEntry const*> AchievementEntryList;
|
||||
|
||||
typedef UNORDERED_MAP<uint32, AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
|
||||
typedef std::map<uint32, AchievementEntryList> AchievementListByReferencedId;
|
||||
|
||||
struct CriteriaProgress
|
||||
{
|
||||
uint32 counter;
|
||||
time_t date; // latest update time.
|
||||
bool changed;
|
||||
};
|
||||
|
||||
enum AchievementCriteriaDataType
|
||||
{ // value1 value2 comment
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4, // own_team 0 not corpse (not released body), own_team == false if enemy team expected
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10, // gender 0=male; 1=female
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT = 11, // scripted requirement
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12, // difficulty normal/heroic difficulty for current event map
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13, // count "with less than %u people in the zone"
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14, // team HORDE(67), ALLIANCE(469)
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15, // drunken_state 0 (enum DrunkenState) of player
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16, // holiday_id 0 event in holiday time
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE = 17, // min_score max_score player's team win bg and opposition team have team score in range
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18, // 0 0 maker instance script call for check current criteria requirements fit
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20, // map_id 0 player must be on map with id in map_id
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // class_id race_id
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday
|
||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE = 23 // title_id known (pvp) title, values from dbc
|
||||
};
|
||||
|
||||
#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum
|
||||
|
||||
class Player;
|
||||
class Unit;
|
||||
|
||||
struct AchievementCriteriaData
|
||||
{
|
||||
AchievementCriteriaDataType dataType;
|
||||
union
|
||||
{
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0 (no data)
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1
|
||||
struct
|
||||
{
|
||||
uint32 id;
|
||||
} creature;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21
|
||||
struct
|
||||
{
|
||||
uint32 class_id;
|
||||
uint32 race_id;
|
||||
} classRace;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH = 3
|
||||
struct
|
||||
{
|
||||
uint32 percent;
|
||||
} health;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4
|
||||
struct
|
||||
{
|
||||
uint32 own_team_flag;
|
||||
} player_dead;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7
|
||||
struct
|
||||
{
|
||||
uint32 spell_id;
|
||||
uint32 effect_idx;
|
||||
} aura;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6
|
||||
struct
|
||||
{
|
||||
uint32 id;
|
||||
} area;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8
|
||||
struct
|
||||
{
|
||||
uint32 value;
|
||||
uint32 compType;
|
||||
} value;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9
|
||||
struct
|
||||
{
|
||||
uint32 minlevel;
|
||||
} level;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10
|
||||
struct
|
||||
{
|
||||
uint32 gender;
|
||||
} gender;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT = 11 (no data)
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12
|
||||
struct
|
||||
{
|
||||
uint32 difficulty;
|
||||
} difficulty;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13
|
||||
struct
|
||||
{
|
||||
uint32 maxcount;
|
||||
} map_players;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14
|
||||
struct
|
||||
{
|
||||
uint32 team;
|
||||
} team;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK = 15
|
||||
struct
|
||||
{
|
||||
uint32 state;
|
||||
} drunk;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY = 16
|
||||
struct
|
||||
{
|
||||
uint32 id;
|
||||
} holiday;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE= 17
|
||||
struct
|
||||
{
|
||||
uint32 min_score;
|
||||
uint32 max_score;
|
||||
} bg_loss_team_score;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT = 18 (no data)
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19
|
||||
struct
|
||||
{
|
||||
uint32 item_level;
|
||||
uint32 item_quality;
|
||||
} equipped_item;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20
|
||||
struct
|
||||
{
|
||||
uint32 mapId;
|
||||
} map_id;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY = 21
|
||||
struct
|
||||
{
|
||||
uint32 nth_birthday;
|
||||
} birthday_login;
|
||||
// ACHIEVEMENT_CRITERIA_DATA_TYPE_KNOWN_TITLE = 22
|
||||
struct
|
||||
{
|
||||
uint32 title_id;
|
||||
} known_title;
|
||||
// ...
|
||||
struct
|
||||
{
|
||||
uint32 value1;
|
||||
uint32 value2;
|
||||
} raw;
|
||||
};
|
||||
uint32 ScriptId;
|
||||
|
||||
AchievementCriteriaData() : dataType(ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE)
|
||||
{
|
||||
raw.value1 = 0;
|
||||
raw.value2 = 0;
|
||||
ScriptId = 0;
|
||||
}
|
||||
|
||||
AchievementCriteriaData(uint32 _dataType, uint32 _value1, uint32 _value2, uint32 _scriptId) : dataType(AchievementCriteriaDataType(_dataType))
|
||||
{
|
||||
raw.value1 = _value1;
|
||||
raw.value2 = _value2;
|
||||
ScriptId = _scriptId;
|
||||
}
|
||||
|
||||
bool IsValid(AchievementCriteriaEntry const* criteria);
|
||||
bool Meets(uint32 criteria_id, Player const* source, Unit const* target, uint32 miscvalue1 = 0) const;
|
||||
};
|
||||
|
||||
struct AchievementCriteriaDataSet
|
||||
{
|
||||
AchievementCriteriaDataSet() : criteria_id(0) {}
|
||||
typedef std::vector<AchievementCriteriaData> Storage;
|
||||
void Add(AchievementCriteriaData const& data) { storage.push_back(data); }
|
||||
bool Meets(Player const* source, Unit const* target, uint32 miscvalue = 0) const;
|
||||
void SetCriteriaId(uint32 id) {criteria_id = id;}
|
||||
private:
|
||||
uint32 criteria_id;
|
||||
Storage storage;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, AchievementCriteriaDataSet> AchievementCriteriaDataMap;
|
||||
|
||||
struct AchievementReward
|
||||
{
|
||||
uint32 titleId[2];
|
||||
uint32 itemId;
|
||||
uint32 sender;
|
||||
std::string subject;
|
||||
std::string text;
|
||||
uint32 mailTemplate;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, AchievementReward> AchievementRewards;
|
||||
|
||||
struct AchievementRewardLocale
|
||||
{
|
||||
StringVector subject;
|
||||
StringVector text;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, AchievementRewardLocale> AchievementRewardLocales;
|
||||
|
||||
struct CompletedAchievementData
|
||||
{
|
||||
time_t date;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
typedef UNORDERED_MAP<uint32, CriteriaProgress> CriteriaProgressMap;
|
||||
typedef UNORDERED_MAP<uint32, CompletedAchievementData> CompletedAchievementMap;
|
||||
|
||||
class Unit;
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
|
||||
class AchievementMgr
|
||||
{
|
||||
public:
|
||||
AchievementMgr(Player* player);
|
||||
~AchievementMgr();
|
||||
|
||||
void Reset();
|
||||
static void DeleteFromDB(uint32 lowguid);
|
||||
void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult);
|
||||
void SaveToDB(SQLTransaction& trans);
|
||||
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint32 value, bool evenIfCriteriaComplete = false);
|
||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 = 0, uint32 miscValue2 = 0, Unit* unit = NULL);
|
||||
void CompletedAchievement(AchievementEntry const* entry);
|
||||
void CheckAllAchievementCriteria();
|
||||
void SendAllAchievementData() const;
|
||||
void SendRespondInspectAchievements(Player* player) const;
|
||||
bool HasAchieved(uint32 achievementId) const;
|
||||
Player* GetPlayer() const { return m_player; }
|
||||
void UpdateTimedAchievements(uint32 timeDiff);
|
||||
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0);
|
||||
void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); // used for quest and scripted timed achievements
|
||||
|
||||
void RemoveCriteriaProgress(AchievementCriteriaEntry const* entry);
|
||||
private:
|
||||
enum ProgressType { PROGRESS_SET, PROGRESS_ACCUMULATE, PROGRESS_HIGHEST, PROGRESS_RESET };
|
||||
void SendAchievementEarned(AchievementEntry const* achievement) const;
|
||||
void SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const;
|
||||
CriteriaProgress* GetCriteriaProgress(AchievementCriteriaEntry const* entry);
|
||||
void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET);
|
||||
void CompletedCriteriaFor(AchievementEntry const* achievement);
|
||||
bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement);
|
||||
bool IsCompletedAchievement(AchievementEntry const* entry);
|
||||
bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement);
|
||||
void BuildAllDataPacket(WorldPacket* data, bool inspect = false) const;
|
||||
|
||||
Player* m_player;
|
||||
CriteriaProgressMap m_criteriaProgress;
|
||||
CompletedAchievementMap m_completedAchievements;
|
||||
typedef std::map<uint32, uint32> TimedAchievementMap;
|
||||
TimedAchievementMap m_timedAchievements; // Criteria id/time left in MS
|
||||
};
|
||||
|
||||
class AchievementGlobalMgr
|
||||
{
|
||||
friend class ACE_Singleton<AchievementGlobalMgr, ACE_Null_Mutex>;
|
||||
AchievementGlobalMgr() {}
|
||||
~AchievementGlobalMgr() {}
|
||||
|
||||
public:
|
||||
AchievementCriteriaEntryList const* GetAchievementCriteriaByType(AchievementCriteriaTypes type) const
|
||||
{
|
||||
return &m_AchievementCriteriasByType[type];
|
||||
}
|
||||
|
||||
AchievementCriteriaEntryList const* GetSpecialAchievementCriteriaByType(AchievementCriteriaTypes type, uint32 val)
|
||||
{
|
||||
if (m_SpecialList[type].find(val) != m_SpecialList[type].end())
|
||||
return &m_SpecialList[type][val];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AchievementCriteriaEntryList const* GetAchievementCriteriaByCondition(AchievementCriteriaCondition condition, uint32 val)
|
||||
{
|
||||
if (m_AchievementCriteriasByCondition[condition].find(val) != m_AchievementCriteriasByCondition[condition].end())
|
||||
return &m_AchievementCriteriasByCondition[condition][val];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AchievementCriteriaEntryList const& GetTimedAchievementCriteriaByType(AchievementCriteriaTimedTypes type) const
|
||||
{
|
||||
return m_AchievementCriteriasByTimedType[type];
|
||||
}
|
||||
|
||||
AchievementCriteriaEntryList const* GetAchievementCriteriaByAchievement(uint32 id) const
|
||||
{
|
||||
AchievementCriteriaListByAchievement::const_iterator itr = m_AchievementCriteriaListByAchievement.find(id);
|
||||
return itr != m_AchievementCriteriaListByAchievement.end() ? &itr->second : NULL;
|
||||
}
|
||||
|
||||
AchievementEntryList const* GetAchievementByReferencedId(uint32 id) const
|
||||
{
|
||||
AchievementListByReferencedId::const_iterator itr = m_AchievementListByReferencedId.find(id);
|
||||
return itr != m_AchievementListByReferencedId.end() ? &itr->second : NULL;
|
||||
}
|
||||
|
||||
AchievementReward const* GetAchievementReward(AchievementEntry const* achievement) const
|
||||
{
|
||||
AchievementRewards::const_iterator iter = m_achievementRewards.find(achievement->ID);
|
||||
return iter != m_achievementRewards.end() ? &iter->second : NULL;
|
||||
}
|
||||
|
||||
AchievementRewardLocale const* GetAchievementRewardLocale(AchievementEntry const* achievement) const
|
||||
{
|
||||
AchievementRewardLocales::const_iterator iter = m_achievementRewardLocales.find(achievement->ID);
|
||||
return iter != m_achievementRewardLocales.end() ? &iter->second : NULL;
|
||||
}
|
||||
|
||||
AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteriaEntry const* achievementCriteria) const
|
||||
{
|
||||
AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID);
|
||||
return iter != m_criteriaDataMap.end() ? &iter->second : NULL;
|
||||
}
|
||||
|
||||
bool IsRealmCompleted(AchievementEntry const* achievement) const
|
||||
{
|
||||
return m_allCompletedAchievements.find(achievement->ID) != m_allCompletedAchievements.end();
|
||||
}
|
||||
|
||||
void SetRealmCompleted(AchievementEntry const* achievement)
|
||||
{
|
||||
m_allCompletedAchievements.insert(achievement->ID);
|
||||
}
|
||||
|
||||
void LoadAchievementCriteriaList();
|
||||
void LoadAchievementCriteriaData();
|
||||
void LoadAchievementReferenceList();
|
||||
void LoadCompletedAchievements();
|
||||
void LoadRewards();
|
||||
void LoadRewardLocales();
|
||||
private:
|
||||
AchievementCriteriaDataMap m_criteriaDataMap;
|
||||
|
||||
// store achievement criterias by type to speed up lookup
|
||||
AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
|
||||
AchievementCriteriaEntryList m_AchievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX];
|
||||
// store achievement criterias by achievement to speed up lookup
|
||||
AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement;
|
||||
// store achievements by referenced achievement id to speed up lookup
|
||||
AchievementListByReferencedId m_AchievementListByReferencedId;
|
||||
|
||||
typedef std::set<uint32> AllCompletedAchievements;
|
||||
AllCompletedAchievements m_allCompletedAchievements;
|
||||
|
||||
AchievementRewards m_achievementRewards;
|
||||
AchievementRewardLocales m_achievementRewardLocales;
|
||||
|
||||
// pussywizard:
|
||||
std::map<uint32, AchievementCriteriaEntryList> m_SpecialList[ACHIEVEMENT_CRITERIA_TYPE_TOTAL];
|
||||
std::map<uint32, AchievementCriteriaEntryList> m_AchievementCriteriasByCondition[ACHIEVEMENT_CRITERIA_CONDITION_TOTAL];
|
||||
};
|
||||
|
||||
#define sAchievementMgr ACE_Singleton<AchievementGlobalMgr, ACE_Null_Mutex>::instance()
|
||||
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AddonMgr.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace AddonMgr
|
||||
{
|
||||
|
||||
// Anonymous namespace ensures file scope of all the stuff inside it, even
|
||||
// if you add something more to this namespace somewhere else.
|
||||
namespace
|
||||
{
|
||||
// List of saved addons (in DB).
|
||||
typedef std::list<SavedAddon> SavedAddonsList;
|
||||
|
||||
SavedAddonsList m_knownAddons;
|
||||
}
|
||||
|
||||
void LoadFromDB()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT name, crc FROM addons");
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 known addons. DB table `addons` is empty!");
|
||||
sLog->outString();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
std::string name = fields[0].GetString();
|
||||
uint32 crc = fields[1].GetUInt32();
|
||||
|
||||
m_knownAddons.push_back(SavedAddon(name, crc));
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u known addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
void SaveAddon(AddonInfo const& addon)
|
||||
{
|
||||
std::string name = addon.Name;
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ADDON);
|
||||
|
||||
stmt->setString(0, name);
|
||||
stmt->setUInt32(1, addon.CRC);
|
||||
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
m_knownAddons.push_back(SavedAddon(addon.Name, addon.CRC));
|
||||
}
|
||||
|
||||
SavedAddon const* GetAddonInfo(const std::string& name)
|
||||
{
|
||||
for (SavedAddonsList::const_iterator it = m_knownAddons.begin(); it != m_knownAddons.end(); ++it)
|
||||
{
|
||||
SavedAddon const& addon = (*it);
|
||||
if (addon.Name == name)
|
||||
return &addon;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ADDONMGR_H
|
||||
#define _ADDONMGR_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
|
||||
struct AddonInfo
|
||||
{
|
||||
AddonInfo(const std::string& name, uint8 enabled, uint32 crc, uint8 state, bool crcOrPubKey)
|
||||
: Name(name), Enabled(enabled), CRC(crc), State(state), UsePublicKeyOrCRC(crcOrPubKey) {}
|
||||
|
||||
std::string Name;
|
||||
uint8 Enabled;
|
||||
uint32 CRC;
|
||||
uint8 State;
|
||||
bool UsePublicKeyOrCRC;
|
||||
};
|
||||
|
||||
struct SavedAddon
|
||||
{
|
||||
SavedAddon(const std::string& name, uint32 crc) : Name(name)
|
||||
{
|
||||
CRC = crc;
|
||||
}
|
||||
|
||||
std::string Name;
|
||||
uint32 CRC;
|
||||
};
|
||||
|
||||
#define STANDARD_ADDON_CRC 0x4c1c776d
|
||||
|
||||
namespace AddonMgr
|
||||
{
|
||||
void LoadFromDB();
|
||||
void SaveAddon(AddonInfo const& addon);
|
||||
SavedAddon const* GetAddonInfo(const std::string& name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
|
||||
#ifndef AZEROTHCORE_ARENASPECTATOR_H
|
||||
#define AZEROTHCORE_ARENASPECTATOR_H
|
||||
|
||||
#include "Player.h"
|
||||
#include "World.h"
|
||||
#include "Map.h"
|
||||
#include "Battleground.h"
|
||||
#include "Pet.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "Chat.h"
|
||||
#include "LFGMgr.h"
|
||||
|
||||
#define SPECTATOR_ADDON_VERSION 27
|
||||
#define SPECTATOR_BUFFER_LEN 150
|
||||
#define SPECTATOR_ADDON_PREFIX "ASSUN\x09"
|
||||
#define SPECTATOR_COOLDOWN_MIN 20
|
||||
#define SPECTATOR_COOLDOWN_MAX 900
|
||||
#define SPECTATOR_SPELL_BINDSIGHT 6277
|
||||
#define SPECTATOR_SPELL_SPEED 1557
|
||||
|
||||
namespace ArenaSpectator
|
||||
{
|
||||
template<class T> inline void SendCommand(T* o, const char* format, ...) ATTR_PRINTF(2, 3);
|
||||
inline void CreatePacket(WorldPacket& data, const char* m);
|
||||
inline void SendPacketTo(const Player* p, const char* m);
|
||||
inline void SendPacketTo(const Map* map, const char* m);
|
||||
inline void HandleResetCommand(Player* p);
|
||||
inline bool ShouldSendAura(Aura* aura, uint8 effMask, uint64 targetGUID, bool remove);
|
||||
|
||||
template<class T> inline void SendCommand_String(T* p, uint64 targetGUID, const char* prefix, const std::string& c);
|
||||
template<class T> inline void SendCommand_UInt32Value(T* o, uint64 targetGUID, const char* prefix, uint32 t);
|
||||
template<class T> inline void SendCommand_GUID(T* o, uint64 targetGUID, const char* prefix, uint64 t);
|
||||
template<class T> inline void SendCommand_Spell(T* o, uint64 targetGUID, const char* prefix, uint32 id, int32 casttime);
|
||||
template<class T> inline void SendCommand_Cooldown(T* o, uint64 targetGUID, const char* prefix, uint32 id, uint32 dur, uint32 maxdur);
|
||||
template<class T> inline void SendCommand_Aura(T* o, uint64 targetGUID, const char* prefix, uint64 caster, uint32 id, bool isDebuff, uint32 dispel, int32 dur, int32 maxdur, uint32 stack, bool remove);
|
||||
|
||||
bool HandleSpectatorSpectateCommand(ChatHandler* handler, char const* args);
|
||||
bool HandleSpectatorWatchCommand(ChatHandler* handler, char const* args);
|
||||
|
||||
// definitions below:
|
||||
|
||||
template<class T>
|
||||
void SendCommand(T* o, const char* format, ...)
|
||||
{
|
||||
if (!format)
|
||||
return;
|
||||
char buffer[SPECTATOR_BUFFER_LEN];
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, SPECTATOR_BUFFER_LEN, format, ap);
|
||||
va_end(ap);
|
||||
SendPacketTo(o, buffer);
|
||||
}
|
||||
|
||||
void CreatePacket(WorldPacket& data, const char* m)
|
||||
{
|
||||
size_t len = strlen(m);
|
||||
data.Initialize(SMSG_MESSAGECHAT, 1+4+8+4+8+4+1+len+1);
|
||||
data << uint8(CHAT_MSG_WHISPER);
|
||||
data << uint32(LANG_ADDON);
|
||||
data << uint64(0);
|
||||
data << uint32(0);
|
||||
data << uint64(0);
|
||||
data << uint32(len + 1);
|
||||
data << m;
|
||||
data << uint8(0);
|
||||
}
|
||||
|
||||
void SendPacketTo(const Player* p, const char* m)
|
||||
{
|
||||
WorldPacket data;
|
||||
CreatePacket(data, m);
|
||||
p->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void SendPacketTo(const Map* map, const char* m)
|
||||
{
|
||||
if (!map->IsBattleArena())
|
||||
return;
|
||||
Battleground* bg = ((BattlegroundMap*)map)->GetBG();
|
||||
if (!bg || bg->GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
WorldPacket data;
|
||||
CreatePacket(data, m);
|
||||
bg->SpectatorsSendPacket(data);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SendCommand_String(T* o, uint64 targetGUID, const char* prefix, const char* c)
|
||||
{
|
||||
if (!IS_PLAYER_GUID(targetGUID))
|
||||
return;
|
||||
SendCommand(o, "%s0x%016llX;%s=%s;", SPECTATOR_ADDON_PREFIX, targetGUID, prefix, c);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SendCommand_UInt32Value(T* o, uint64 targetGUID, const char* prefix, uint32 t)
|
||||
{
|
||||
if (!IS_PLAYER_GUID(targetGUID))
|
||||
return;
|
||||
SendCommand(o, "%s0x%016llX;%s=%u;", SPECTATOR_ADDON_PREFIX, targetGUID, prefix, t);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SendCommand_GUID(T* o, uint64 targetGUID, const char* prefix, uint64 t)
|
||||
{
|
||||
if (!IS_PLAYER_GUID(targetGUID))
|
||||
return;
|
||||
SendCommand(o, "%s0x%016llX;%s=0x%016llX;", SPECTATOR_ADDON_PREFIX, targetGUID, prefix, t);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SendCommand_Spell(T* o, uint64 targetGUID, const char* prefix, uint32 id, int32 casttime)
|
||||
{
|
||||
if (!IS_PLAYER_GUID(targetGUID))
|
||||
return;
|
||||
SendCommand(o, "%s0x%016llX;%s=%u,%i;", SPECTATOR_ADDON_PREFIX, targetGUID, prefix, id, casttime);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SendCommand_Cooldown(T* o, uint64 targetGUID, const char* prefix, uint32 id, uint32 dur, uint32 maxdur)
|
||||
{
|
||||
if (!IS_PLAYER_GUID(targetGUID))
|
||||
return;
|
||||
if (const SpellInfo* si = sSpellMgr->GetSpellInfo(id))
|
||||
if (si->SpellIconID == 1)
|
||||
return;
|
||||
SendCommand(o, "%s0x%016llX;%s=%u,%u,%u;", SPECTATOR_ADDON_PREFIX, targetGUID, prefix, id, dur, maxdur);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void SendCommand_Aura(T* o, uint64 targetGUID, const char* prefix, uint64 caster, uint32 id, bool isDebuff, uint32 dispel, int32 dur, int32 maxdur, uint32 stack, bool remove)
|
||||
{
|
||||
if (!IS_PLAYER_GUID(targetGUID))
|
||||
return;
|
||||
SendCommand(o, "%s0x%016llX;%s=%u,%u,%i,%i,%u,%u,%u,0x%016llX;", SPECTATOR_ADDON_PREFIX, targetGUID, prefix, remove ? 1 : 0, stack, dur, maxdur, id, dispel, isDebuff ? 1 : 0, caster);
|
||||
}
|
||||
|
||||
void HandleResetCommand(Player* p)
|
||||
{
|
||||
if (!p->FindMap() || !p->IsInWorld() || !p->FindMap()->IsBattleArena())
|
||||
return;
|
||||
Battleground* bg = ((BattlegroundMap*)p->FindMap())->GetBG();
|
||||
if (!bg || bg->GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
Battleground::BattlegroundPlayerMap const& pl = bg->GetPlayers();
|
||||
for (Battleground::BattlegroundPlayerMap::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
|
||||
{
|
||||
if (p->HasReceivedSpectatorResetFor(GUID_LOPART(itr->first)))
|
||||
continue;
|
||||
|
||||
Player* plr = itr->second;
|
||||
p->AddReceivedSpectatorResetFor(GUID_LOPART(itr->first));
|
||||
|
||||
SendCommand_String(p, itr->first, "NME", plr->GetName().c_str());
|
||||
// Xinef: addon compatibility
|
||||
SendCommand_UInt32Value(p, itr->first, "TEM", plr->GetBgTeamId() == TEAM_ALLIANCE ? ALLIANCE : HORDE);
|
||||
SendCommand_UInt32Value(p, itr->first, "CLA", plr->getClass());
|
||||
SendCommand_UInt32Value(p, itr->first, "MHP", plr->GetMaxHealth());
|
||||
SendCommand_UInt32Value(p, itr->first, "CHP", plr->GetHealth());
|
||||
SendCommand_UInt32Value(p, itr->first, "STA", plr->IsAlive() ? 1 : 0);
|
||||
Powers ptype = plr->getPowerType();
|
||||
SendCommand_UInt32Value(p, itr->first, "PWT", ptype);
|
||||
SendCommand_UInt32Value(p, itr->first, "MPW", ptype == POWER_RAGE || ptype == POWER_RUNIC_POWER ? plr->GetMaxPower(ptype)/10 : plr->GetMaxPower(ptype));
|
||||
SendCommand_UInt32Value(p, itr->first, "CPW", ptype == POWER_RAGE || ptype == POWER_RUNIC_POWER ? plr->GetPower(ptype)/10 : plr->GetPower(ptype));
|
||||
Pet* pet = plr->GetPet();
|
||||
SendCommand_UInt32Value(p, itr->first, "PHP", pet && pet->GetCreatureTemplate()->family ? (uint32)pet->GetHealthPct() : 0);
|
||||
SendCommand_UInt32Value(p, itr->first, "PET", pet ? pet->GetCreatureTemplate()->family : 0);
|
||||
SendCommand_GUID(p, itr->first, "TRG", plr->GetTarget());
|
||||
SendCommand_UInt32Value(p, itr->first, "RES", 1);
|
||||
SendCommand_UInt32Value(p, itr->first, "CDC", 1);
|
||||
SendCommand_UInt32Value(p, itr->first, "TIM", (bg->GetStartTime() < 46*MINUTE*IN_MILLISECONDS) ? (46*MINUTE*IN_MILLISECONDS-bg->GetStartTime())/IN_MILLISECONDS : 0);
|
||||
// "SPE" not here (only possible to send starting a new cast)
|
||||
|
||||
// send all "CD"
|
||||
SpellCooldowns const& sc = plr->GetSpellCooldownMap();
|
||||
for (SpellCooldowns::const_iterator itrc = sc.begin(); itrc != sc.end(); ++itrc)
|
||||
if (itrc->second.sendToSpectator && itrc->second.maxduration >= SPECTATOR_COOLDOWN_MIN*IN_MILLISECONDS && itrc->second.maxduration <= SPECTATOR_COOLDOWN_MAX*IN_MILLISECONDS)
|
||||
if (uint32 cd = (getMSTimeDiff(World::GetGameTimeMS(), itrc->second.end)/1000))
|
||||
SendCommand_Cooldown(p, itr->first, "ACD", itrc->first, cd, itrc->second.maxduration/1000);
|
||||
|
||||
// send all visible "AUR"
|
||||
Unit::VisibleAuraMap const *visibleAuras = plr->GetVisibleAuras();
|
||||
for (Unit::VisibleAuraMap::const_iterator aitr = visibleAuras->begin(); aitr != visibleAuras->end(); ++aitr)
|
||||
{
|
||||
Aura *aura = aitr->second->GetBase();
|
||||
if (ShouldSendAura(aura, aitr->second->GetEffectMask(), plr->GetGUID(), false))
|
||||
SendCommand_Aura(p, itr->first, "AUR", aura->GetCasterGUID(), aura->GetSpellInfo()->Id, aura->GetSpellInfo()->IsPositive(), aura->GetSpellInfo()->Dispel, aura->GetDuration(), aura->GetMaxDuration(), (aura->GetCharges() > 1 ? aura->GetCharges() : aura->GetStackAmount()), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldSendAura(Aura* aura, uint8 effMask, uint64 targetGUID, bool remove)
|
||||
{
|
||||
if (aura->GetSpellInfo()->SpellIconID == 1 || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR))
|
||||
return false;
|
||||
|
||||
if (remove || aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC) || aura->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC)
|
||||
return true;
|
||||
|
||||
for(uint8 i=EFFECT_0; i<MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (effMask & (1<<i))
|
||||
{
|
||||
AuraType at = aura->GetEffect(i)->GetAuraType();
|
||||
if (aura->GetEffect(i)->GetAmount() && (aura->GetSpellInfo()->IsPositive() || targetGUID != aura->GetCasterGUID()) ||
|
||||
at == SPELL_AURA_MECHANIC_IMMUNITY || at == SPELL_AURA_EFFECT_IMMUNITY || at == SPELL_AURA_STATE_IMMUNITY || at == SPELL_AURA_SCHOOL_IMMUNITY || at == SPELL_AURA_DISPEL_IMMUNITY)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,823 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DBCStores.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "AuctionHouseMgr.h"
|
||||
#include "Item.h"
|
||||
#include "Language.h"
|
||||
#include "Logging/Log.h"
|
||||
#include <vector>
|
||||
#include "AvgDiffTracker.h"
|
||||
#include "AsyncAuctionListing.h"
|
||||
|
||||
enum eAuctionHouse
|
||||
{
|
||||
AH_MINIMUM_DEPOSIT = 100,
|
||||
};
|
||||
|
||||
AuctionHouseMgr::AuctionHouseMgr()
|
||||
{
|
||||
}
|
||||
|
||||
AuctionHouseMgr::~AuctionHouseMgr()
|
||||
{
|
||||
for (ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
AuctionHouseObject* AuctionHouseMgr::GetAuctionsMap(uint32 factionTemplateId)
|
||||
{
|
||||
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
return &mNeutralAuctions;
|
||||
|
||||
// team have linked auction houses
|
||||
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
|
||||
if (!u_entry)
|
||||
return &mNeutralAuctions;
|
||||
else if (u_entry->ourMask & FACTION_MASK_ALLIANCE)
|
||||
return &mAllianceAuctions;
|
||||
else if (u_entry->ourMask & FACTION_MASK_HORDE)
|
||||
return &mHordeAuctions;
|
||||
else
|
||||
return &mNeutralAuctions;
|
||||
}
|
||||
|
||||
uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count)
|
||||
{
|
||||
uint32 MSV = pItem->GetTemplate()->SellPrice;
|
||||
|
||||
if (MSV <= 0)
|
||||
return AH_MINIMUM_DEPOSIT;
|
||||
|
||||
float multiplier = CalculatePct(float(entry->depositPercent), 3);
|
||||
uint32 timeHr = (((time / 60) / 60) / 12);
|
||||
uint32 deposit = uint32(((multiplier * MSV * count / 3) * timeHr * 3) * sWorld->getRate(RATE_AUCTION_DEPOSIT));
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_AUCTIONHOUSE, "MSV: %u", MSV);
|
||||
;//sLog->outDebug(LOG_FILTER_AUCTIONHOUSE, "Items: %u", count);
|
||||
;//sLog->outDebug(LOG_FILTER_AUCTIONHOUSE, "Multiplier: %f", multiplier);
|
||||
;//sLog->outDebug(LOG_FILTER_AUCTIONHOUSE, "Deposit: %u", deposit);
|
||||
|
||||
if (deposit < AH_MINIMUM_DEPOSIT)
|
||||
return AH_MINIMUM_DEPOSIT;
|
||||
else
|
||||
return deposit;
|
||||
}
|
||||
|
||||
//does not clear ram
|
||||
void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& trans)
|
||||
{
|
||||
Item* pItem = GetAItem(auction->item_guidlow);
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
|
||||
uint32 bidder_accId = 0;
|
||||
Player* bidder = ObjectAccessor::FindPlayerInOrOutOfWorld(bidder_guid);
|
||||
if (bidder)
|
||||
bidder_accId = bidder->GetSession()->GetAccountId();
|
||||
else
|
||||
bidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(bidder_guid);
|
||||
|
||||
// receiver exist
|
||||
if (bidder || bidder_accId)
|
||||
{
|
||||
// set owner to bidder (to prevent delete item with sender char deleting)
|
||||
// owner in `data` will set at mail receive and item extracting
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER);
|
||||
stmt->setUInt32(0, auction->bidder);
|
||||
stmt->setUInt32(1, pItem->GetGUIDLow());
|
||||
trans->Append(stmt);
|
||||
|
||||
if (bidder)
|
||||
{
|
||||
bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidder_guid, 0, 0, auction->item_template);
|
||||
// FIXME: for offline player need also
|
||||
bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1);
|
||||
}
|
||||
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_WON), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, 0, 0))
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
else
|
||||
sAuctionMgr->RemoveAItem(auction->item_guidlow, true);
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, SQLTransaction& trans)
|
||||
{
|
||||
uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
|
||||
Player* owner = ObjectAccessor::FindPlayerInOrOutOfWorld(owner_guid);
|
||||
uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
|
||||
// owner exist (online or offline)
|
||||
if (owner || owner_accId)
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
|
||||
//call this method to send mail to auction owner, when auction is successful, it does not clear ram
|
||||
void AuctionHouseMgr::SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransaction& trans)
|
||||
{
|
||||
uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
|
||||
Player* owner = ObjectAccessor::FindPlayerInOrOutOfWorld(owner_guid);
|
||||
uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
|
||||
// owner exist
|
||||
if (owner || owner_accId)
|
||||
{
|
||||
uint32 profit = auction->bid + auction->deposit - auction->GetAuctionCut();
|
||||
|
||||
if (owner)
|
||||
{
|
||||
owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS, profit);
|
||||
owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD, auction->bid);
|
||||
owner->GetSession()->SendAuctionOwnerNotification(auction);
|
||||
}
|
||||
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_SUCCESSFUL), AuctionEntry::BuildAuctionMailBody(auction->bidder, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||
.AddMoney(profit)
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
|
||||
if (auction->bid >= 500*GOLD)
|
||||
if (const GlobalPlayerData* gpd = sWorld->GetGlobalPlayerData(auction->bidder))
|
||||
{
|
||||
uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
|
||||
Player* bidder = ObjectAccessor::FindPlayerInOrOutOfWorld(bidder_guid);
|
||||
std::string owner_name = "";
|
||||
uint8 owner_level = 0;
|
||||
if (const GlobalPlayerData* gpd_owner = sWorld->GetGlobalPlayerData(auction->owner))
|
||||
{
|
||||
owner_name = gpd_owner->name;
|
||||
owner_level = gpd_owner->level;
|
||||
}
|
||||
CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<AH> profit: %ug, bidder: %s %u lvl (guid: %u), seller: %s %u lvl (guid: %u), item %u (%u)\", NOW())", gpd->accountId, auction->bidder, gpd->name.c_str(), bidder ? bidder->GetSession()->GetRemoteAddress().c_str() : "", owner_accId, owner_name.c_str(), auction->bid, (profit/GOLD), gpd->name.c_str(), gpd->level, auction->bidder, owner_name.c_str(), owner_level, auction->owner, auction->item_template, auction->itemCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//does not clear ram
|
||||
void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction, SQLTransaction& trans)
|
||||
{
|
||||
//return an item in auction to its owner by mail
|
||||
Item* pItem = GetAItem(auction->item_guidlow);
|
||||
if (!pItem)
|
||||
return;
|
||||
|
||||
uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
|
||||
Player* owner = ObjectAccessor::FindPlayerInOrOutOfWorld(owner_guid);
|
||||
uint32 owner_accId = sObjectMgr->GetPlayerAccountIdByGUID(owner_guid);
|
||||
|
||||
// owner exist
|
||||
if (owner || owner_accId)
|
||||
{
|
||||
if (owner)
|
||||
owner->GetSession()->SendAuctionOwnerNotification(auction);
|
||||
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_EXPIRED), AuctionEntry::BuildAuctionMailBody(0, 0, auction->buyout, auction->deposit, 0))
|
||||
.AddItem(pItem)
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED, 0);
|
||||
}
|
||||
else
|
||||
sAuctionMgr->RemoveAItem(auction->item_guidlow, true);
|
||||
}
|
||||
|
||||
//this function sends mail to old bidder
|
||||
void AuctionHouseMgr::SendAuctionOutbiddedMail(AuctionEntry* auction, uint32 newPrice, Player* newBidder, SQLTransaction& trans)
|
||||
{
|
||||
uint64 oldBidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
|
||||
Player* oldBidder = ObjectAccessor::FindPlayerInOrOutOfWorld(oldBidder_guid);
|
||||
|
||||
uint32 oldBidder_accId = 0;
|
||||
if (!oldBidder)
|
||||
oldBidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(oldBidder_guid);
|
||||
|
||||
// old bidder exist
|
||||
if (oldBidder || oldBidder_accId)
|
||||
{
|
||||
if (oldBidder && newBidder)
|
||||
oldBidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, newBidder->GetGUID(), newPrice, auction->GetAuctionOutBid(), auction->item_template);
|
||||
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_OUTBIDDED), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit, auction->GetAuctionCut()))
|
||||
.AddMoney(auction->bid)
|
||||
.SendMailTo(trans, MailReceiver(oldBidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
}
|
||||
|
||||
//this function sends mail, when auction is cancelled to old bidder
|
||||
void AuctionHouseMgr::SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans)
|
||||
{
|
||||
uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
|
||||
Player* bidder = ObjectAccessor::FindPlayerInOrOutOfWorld(bidder_guid);
|
||||
|
||||
uint32 bidder_accId = 0;
|
||||
if (!bidder)
|
||||
bidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(bidder_guid);
|
||||
|
||||
// bidder exist
|
||||
if (bidder || bidder_accId)
|
||||
MailDraft(auction->BuildAuctionMailSubject(AUCTION_CANCELLED_TO_BIDDER), AuctionEntry::BuildAuctionMailBody(auction->owner, auction->bid, auction->buyout, auction->deposit, 0))
|
||||
.AddMoney(auction->bid)
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->bidder), auction, MAIL_CHECK_MASK_COPIED);
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::LoadAuctionItems()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// need to clear in case we are reloading
|
||||
if (!mAitems.empty())
|
||||
{
|
||||
for (ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
|
||||
delete itr->second;
|
||||
|
||||
mAitems.clear();
|
||||
}
|
||||
|
||||
// data needs to be at first place for Item::LoadFromDB
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTION_ITEMS);
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 auction items. DB table `auctionhouse` or `item_instance` is empty!");
|
||||
sLog->outString();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 item_guid = fields[11].GetUInt32();
|
||||
uint32 item_template = fields[12].GetUInt32();
|
||||
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item_template);
|
||||
if (!proto)
|
||||
{
|
||||
sLog->outError("AuctionHouseMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid, item_template);
|
||||
continue;
|
||||
}
|
||||
|
||||
Item* item = NewItemOrBag(proto);
|
||||
if (!item->LoadFromDB(item_guid, 0, fields, item_template))
|
||||
{
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
AddAItem(item);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u auction items in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::LoadAuctions()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_AUCTIONS);
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 auctions. DB table `auctionhouse` is empty.");
|
||||
sLog->outString();
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
AuctionEntry* aItem = new AuctionEntry();
|
||||
if (!aItem->LoadFromDB(fields))
|
||||
{
|
||||
aItem->DeleteFromDB(trans);
|
||||
delete aItem;
|
||||
continue;
|
||||
}
|
||||
|
||||
GetAuctionsMap(aItem->factionTemplateId)->AddAuction(aItem);
|
||||
count++;
|
||||
} while (result->NextRow());
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
sLog->outString(">> Loaded %u auctions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::AddAItem(Item* it)
|
||||
{
|
||||
ASSERT(it);
|
||||
ASSERT(mAitems.find(it->GetGUIDLow()) == mAitems.end());
|
||||
mAitems[it->GetGUIDLow()] = it;
|
||||
}
|
||||
|
||||
bool AuctionHouseMgr::RemoveAItem(uint32 id, bool deleteFromDB)
|
||||
{
|
||||
ItemMap::iterator i = mAitems.find(id);
|
||||
if (i == mAitems.end())
|
||||
return false;
|
||||
|
||||
if (deleteFromDB)
|
||||
{
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
i->second->FSetState(ITEM_REMOVED);
|
||||
i->second->SaveToDB(trans);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
mAitems.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AuctionHouseMgr::Update()
|
||||
{
|
||||
mHordeAuctions.Update();
|
||||
mAllianceAuctions.Update();
|
||||
mNeutralAuctions.Update();
|
||||
}
|
||||
|
||||
AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTemplateId)
|
||||
{
|
||||
uint32 houseid = 7; // goblin auction house
|
||||
|
||||
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||
{
|
||||
//FIXME: found way for proper auctionhouse selection by another way
|
||||
// AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
|
||||
// but no easy way convert creature faction to player race faction for specific city
|
||||
switch (factionTemplateId)
|
||||
{
|
||||
case 12: houseid = 1; break; // human
|
||||
case 29: houseid = 6; break; // orc, and generic for horde
|
||||
case 55: houseid = 2; break; // dwarf, and generic for alliance
|
||||
case 68: houseid = 4; break; // undead
|
||||
case 80: houseid = 3; break; // n-elf
|
||||
case 104: houseid = 5; break; // trolls
|
||||
case 120: houseid = 7; break; // booty bay, neutral
|
||||
case 474: houseid = 7; break; // gadgetzan, neutral
|
||||
case 855: houseid = 7; break; // everlook, neutral
|
||||
case 1604: houseid = 6; break; // b-elfs,
|
||||
default: // for unknown case
|
||||
{
|
||||
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
|
||||
if (!u_entry)
|
||||
houseid = 7; // goblin auction house
|
||||
else if (u_entry->ourMask & FACTION_MASK_ALLIANCE)
|
||||
houseid = 1; // human auction house
|
||||
else if (u_entry->ourMask & FACTION_MASK_HORDE)
|
||||
houseid = 6; // orc auction house
|
||||
else
|
||||
houseid = 7; // goblin auction house
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sAuctionHouseStore.LookupEntry(houseid);
|
||||
}
|
||||
|
||||
void AuctionHouseObject::AddAuction(AuctionEntry* auction)
|
||||
{
|
||||
ASSERT(auction);
|
||||
|
||||
AuctionsMap[auction->Id] = auction;
|
||||
sScriptMgr->OnAuctionAdd(this, auction);
|
||||
}
|
||||
|
||||
bool AuctionHouseObject::RemoveAuction(AuctionEntry* auction)
|
||||
{
|
||||
bool wasInMap = AuctionsMap.erase(auction->Id) ? true : false;
|
||||
|
||||
sScriptMgr->OnAuctionRemove(this, auction);
|
||||
|
||||
// we need to delete the entry, it is not referenced any more
|
||||
delete auction;
|
||||
auction = NULL;
|
||||
|
||||
return wasInMap;
|
||||
}
|
||||
|
||||
void AuctionHouseObject::Update()
|
||||
{
|
||||
time_t checkTime = sWorld->GetGameTime() + 60;
|
||||
///- Handle expired auctions
|
||||
|
||||
// If storage is empty, no need to update. next == NULL in this case.
|
||||
if (AuctionsMap.empty())
|
||||
return;
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
for (AuctionEntryMap::iterator itr, iter = AuctionsMap.begin(); iter != AuctionsMap.end(); )
|
||||
{
|
||||
itr = iter++;
|
||||
AuctionEntry* auction = (*itr).second;
|
||||
|
||||
if (auction->expire_time > checkTime)
|
||||
continue;
|
||||
|
||||
///- Either cancel the auction if there was no bidder
|
||||
if (auction->bidder == 0)
|
||||
{
|
||||
sAuctionMgr->SendAuctionExpiredMail(auction, trans);
|
||||
sScriptMgr->OnAuctionExpire(this, auction);
|
||||
}
|
||||
///- Or perform the transaction
|
||||
else
|
||||
{
|
||||
//we should send an "item sold" message if the seller is online
|
||||
//we send the item to the winner
|
||||
//we send the money to the seller
|
||||
sAuctionMgr->SendAuctionSuccessfulMail(auction, trans);
|
||||
sAuctionMgr->SendAuctionWonMail(auction, trans);
|
||||
sScriptMgr->OnAuctionSuccessful(this, auction);
|
||||
}
|
||||
|
||||
///- In any case clear the auction
|
||||
auction->DeleteFromDB(trans);
|
||||
|
||||
sAuctionMgr->RemoveAItem(auction->item_guidlow);
|
||||
RemoveAuction(auction);
|
||||
}
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void AuctionHouseObject::BuildListBidderItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount)
|
||||
{
|
||||
for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
|
||||
{
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (Aentry && Aentry->bidder == player->GetGUIDLow())
|
||||
{
|
||||
if (itr->second->BuildAuctionInfo(data))
|
||||
++count;
|
||||
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AuctionHouseObject::BuildListOwnerItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount)
|
||||
{
|
||||
for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
|
||||
{
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
if (Aentry && Aentry->owner == player->GetGUIDLow())
|
||||
{
|
||||
if (Aentry->BuildAuctionInfo(data))
|
||||
++count;
|
||||
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player,
|
||||
std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
|
||||
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
|
||||
uint32& count, uint32& totalcount, uint8 getAll)
|
||||
{
|
||||
uint32 itrcounter = 0;
|
||||
|
||||
// pussywizard: optimization, this is a simplified case
|
||||
if (itemClass == 0xffffffff && itemSubClass == 0xffffffff && inventoryType == 0xffffffff && quality == 0xffffffff && levelmin == 0x00 && levelmax == 0x00 && usable == 0x00 && wsearchedname.empty())
|
||||
{
|
||||
totalcount = Getcount();
|
||||
if (listfrom < totalcount)
|
||||
{
|
||||
AuctionEntryMap::iterator itr = AuctionsMap.begin();
|
||||
std::advance(itr, listfrom);
|
||||
for (; itr != AuctionsMap.end(); ++itr)
|
||||
{
|
||||
itr->second->BuildAuctionInfo(data);
|
||||
if ((++count) >= 50)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t curTime = sWorld->GetGameTime();
|
||||
|
||||
for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
|
||||
{
|
||||
if (AsyncAuctionListingMgr::IsAuctionListingAllowed() == false) // pussywizard: World::Update is waiting for us...
|
||||
if ((itrcounter++) % 100 == 0) // check condition every 100 iterations
|
||||
if (avgDiffTracker.getAverage() >= 30 || getMSTimeDiff(World::GetGameTimeMS(), getMSTime()) >= 10) // pussywizard: stop immediately if diff is high or waiting too long
|
||||
return false;
|
||||
|
||||
AuctionEntry* Aentry = itr->second;
|
||||
// Skip expired auctions
|
||||
if (Aentry->expire_time < curTime)
|
||||
continue;
|
||||
|
||||
Item* item = sAuctionMgr->GetAItem(Aentry->item_guidlow);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
|
||||
if (itemClass != 0xffffffff && proto->Class != itemClass)
|
||||
continue;
|
||||
|
||||
if (itemSubClass != 0xffffffff && proto->SubClass != itemSubClass)
|
||||
continue;
|
||||
|
||||
if (inventoryType != 0xffffffff && proto->InventoryType != inventoryType)
|
||||
{
|
||||
// xinef: exception, robes are counted as chests
|
||||
if (inventoryType != INVTYPE_CHEST || proto->InventoryType != INVTYPE_ROBE)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (quality != 0xffffffff && proto->Quality != quality)
|
||||
continue;
|
||||
|
||||
if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax)))
|
||||
continue;
|
||||
|
||||
if (usable != 0x00)
|
||||
{
|
||||
if (player->CanUseItem(item) != EQUIP_ERR_OK)
|
||||
continue;
|
||||
|
||||
// xinef: check already learded recipes and pets
|
||||
if (proto->Spells[1].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID && player->HasSpell(proto->Spells[1].SpellId))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey)
|
||||
// No need to do any of this if no search term was entered
|
||||
if (!wsearchedname.empty())
|
||||
{
|
||||
std::string name = proto->Name1;
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
// DO NOT use GetItemEnchantMod(proto->RandomProperty) as it may return a result
|
||||
// that matches the search but it may not equal item->GetItemRandomPropertyId()
|
||||
// used in BuildAuctionInfo() which then causes wrong items to be listed
|
||||
int32 propRefID = item->GetItemRandomPropertyId();
|
||||
|
||||
if (propRefID)
|
||||
{
|
||||
// Append the suffix to the name (ie: of the Monkey) if one exists
|
||||
// These are found in ItemRandomSuffix.dbc and ItemRandomProperties.dbc
|
||||
// even though the DBC name seems misleading
|
||||
|
||||
char* const* suffix = NULL;
|
||||
|
||||
if (propRefID < 0)
|
||||
{
|
||||
const ItemRandomSuffixEntry* itemRandEntry = sItemRandomSuffixStore.LookupEntry(-item->GetItemRandomPropertyId());
|
||||
if (itemRandEntry)
|
||||
suffix = itemRandEntry->nameSuffix;
|
||||
}
|
||||
else
|
||||
{
|
||||
const ItemRandomPropertiesEntry* itemRandEntry = sItemRandomPropertiesStore.LookupEntry(item->GetItemRandomPropertyId());
|
||||
if (itemRandEntry)
|
||||
suffix = itemRandEntry->nameSuffix;
|
||||
}
|
||||
|
||||
// dbc local name
|
||||
if (suffix)
|
||||
{
|
||||
// Append the suffix (ie: of the Monkey) to the name using localization
|
||||
// or default enUS if localization is invalid
|
||||
name += ' ';
|
||||
name += suffix[LOCALE_enUS];
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the search (with or without suffix)
|
||||
if (!Utf8FitTo(name, wsearchedname))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the item if no search term or if entered search term was found
|
||||
if (count < 50 && totalcount >= listfrom)
|
||||
{
|
||||
++count;
|
||||
Aentry->BuildAuctionInfo(data);
|
||||
}
|
||||
++totalcount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//this function inserts to WorldPacket auction's data
|
||||
bool AuctionEntry::BuildAuctionInfo(WorldPacket& data) const
|
||||
{
|
||||
Item* item = sAuctionMgr->GetAItem(item_guidlow);
|
||||
if (!item)
|
||||
{
|
||||
sLog->outError("AuctionEntry::BuildAuctionInfo: Auction %u has a non-existent item: %u", Id, item_guidlow);
|
||||
return false;
|
||||
}
|
||||
data << uint32(Id);
|
||||
data << uint32(item->GetEntry());
|
||||
|
||||
for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; ++i)
|
||||
{
|
||||
data << uint32(item->GetEnchantmentId(EnchantmentSlot(i)));
|
||||
data << uint32(item->GetEnchantmentDuration(EnchantmentSlot(i)));
|
||||
data << uint32(item->GetEnchantmentCharges(EnchantmentSlot(i)));
|
||||
}
|
||||
|
||||
data << int32(item->GetItemRandomPropertyId()); // Random item property id
|
||||
data << uint32(item->GetItemSuffixFactor()); // SuffixFactor
|
||||
data << uint32(item->GetCount()); // item->count
|
||||
data << uint32(item->GetSpellCharges()); // item->charge FFFFFFF
|
||||
data << uint32(0); // Unknown
|
||||
data << uint64(owner); // Auction->owner
|
||||
data << uint32(startbid); // Auction->startbid (not sure if useful)
|
||||
data << uint32(bid ? GetAuctionOutBid() : 0);
|
||||
// Minimal outbid
|
||||
data << uint32(buyout); // Auction->buyout
|
||||
data << uint32((expire_time - time(NULL)) * IN_MILLISECONDS); // time left
|
||||
data << uint64(bidder); // auction->bidder current
|
||||
data << uint32(bid); // current bid
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 AuctionEntry::GetAuctionCut() const
|
||||
{
|
||||
int32 cut = int32(CalculatePct(bid, auctionHouseEntry->cutPercent) * sWorld->getRate(RATE_AUCTION_CUT));
|
||||
return std::max(cut, 0);
|
||||
}
|
||||
|
||||
/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
|
||||
uint32 AuctionEntry::GetAuctionOutBid() const
|
||||
{
|
||||
uint32 outbid = CalculatePct(bid, 5);
|
||||
return outbid ? outbid : 1;
|
||||
}
|
||||
|
||||
void AuctionEntry::DeleteFromDB(SQLTransaction& trans) const
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_AUCTION);
|
||||
stmt->setUInt32(0, Id);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
void AuctionEntry::SaveToDB(SQLTransaction& trans) const
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AUCTION);
|
||||
stmt->setUInt32(0, Id);
|
||||
stmt->setUInt32(1, auctioneer);
|
||||
stmt->setUInt32(2, item_guidlow);
|
||||
stmt->setUInt32(3, owner);
|
||||
stmt->setUInt32 (4, buyout);
|
||||
stmt->setUInt32(5, uint32(expire_time));
|
||||
stmt->setUInt32(6, bidder);
|
||||
stmt->setUInt32 (7, bid);
|
||||
stmt->setUInt32 (8, startbid);
|
||||
stmt->setUInt32 (9, deposit);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
bool AuctionEntry::LoadFromDB(Field* fields)
|
||||
{
|
||||
Id = fields[0].GetUInt32();
|
||||
auctioneer = fields[1].GetUInt32();
|
||||
item_guidlow = fields[2].GetUInt32();
|
||||
item_template = fields[3].GetUInt32();
|
||||
itemCount = fields[4].GetUInt32();
|
||||
owner = fields[5].GetUInt32();
|
||||
buyout = fields[6].GetUInt32();
|
||||
expire_time = fields[7].GetUInt32();
|
||||
bidder = fields[8].GetUInt32();
|
||||
bid = fields[9].GetUInt32();
|
||||
startbid = fields[10].GetUInt32();
|
||||
deposit = fields[11].GetUInt32();
|
||||
|
||||
CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(auctioneer);
|
||||
if (!auctioneerData)
|
||||
{
|
||||
sLog->outError("Auction %u has not a existing auctioneer (GUID : %u)", Id, auctioneer);
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
|
||||
if (!auctioneerInfo)
|
||||
{
|
||||
sLog->outError("Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", Id, auctioneer, auctioneerData->id);
|
||||
return false;
|
||||
}
|
||||
|
||||
factionTemplateId = auctioneerInfo->faction;
|
||||
auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(factionTemplateId);
|
||||
if (!auctionHouseEntry)
|
||||
{
|
||||
sLog->outError("Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", Id, auctioneer, auctioneerData->id, factionTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if sold item exists for guid
|
||||
// and item_template in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr::LoadAuctionItems)
|
||||
if (!sAuctionMgr->GetAItem(item_guidlow))
|
||||
{
|
||||
sLog->outError("Auction %u has not a existing item : %u", Id, item_guidlow);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuctionEntry::LoadFromFieldList(Field* fields)
|
||||
{
|
||||
// Loads an AuctionEntry item from a field list. Unlike "LoadFromDB()", this one
|
||||
// does not require the AuctionEntryMap to have been loaded with items. It simply
|
||||
// acts as a wrapper to fill out an AuctionEntry struct from a field list
|
||||
|
||||
Id = fields[0].GetUInt32();
|
||||
auctioneer = fields[1].GetUInt32();
|
||||
item_guidlow = fields[2].GetUInt32();
|
||||
item_template = fields[3].GetUInt32();
|
||||
itemCount = fields[4].GetUInt32();
|
||||
owner = fields[5].GetUInt32();
|
||||
buyout = fields[6].GetUInt32();
|
||||
expire_time = fields[7].GetUInt32();
|
||||
bidder = fields[8].GetUInt32();
|
||||
bid = fields[9].GetUInt32();
|
||||
startbid = fields[10].GetUInt32();
|
||||
deposit = fields[11].GetUInt32();
|
||||
|
||||
CreatureData const* auctioneerData = sObjectMgr->GetCreatureData(auctioneer);
|
||||
if (!auctioneerData)
|
||||
{
|
||||
sLog->outError("AuctionEntry::LoadFromFieldList() - Auction %u has not a existing auctioneer (GUID : %u)", Id, auctioneer);
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureTemplate const* auctioneerInfo = sObjectMgr->GetCreatureTemplate(auctioneerData->id);
|
||||
if (!auctioneerInfo)
|
||||
{
|
||||
sLog->outError("AuctionEntry::LoadFromFieldList() - Auction %u has not a existing auctioneer (GUID : %u Entry: %u)", Id, auctioneer, auctioneerData->id);
|
||||
return false;
|
||||
}
|
||||
|
||||
factionTemplateId = auctioneerInfo->faction;
|
||||
auctionHouseEntry = AuctionHouseMgr::GetAuctionHouseEntry(factionTemplateId);
|
||||
|
||||
if (!auctionHouseEntry)
|
||||
{
|
||||
sLog->outError("AuctionEntry::LoadFromFieldList() - Auction %u has auctioneer (GUID : %u Entry: %u) with wrong faction %u", Id, auctioneer, auctioneerData->id, factionTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string AuctionEntry::BuildAuctionMailSubject(MailAuctionAnswers response) const
|
||||
{
|
||||
std::ostringstream strm;
|
||||
strm << item_template << ":0:" << response << ':' << Id << ':' << itemCount;
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
std::string AuctionEntry::BuildAuctionMailBody(uint32 lowGuid, uint32 bid, uint32 buyout, uint32 deposit, uint32 cut)
|
||||
{
|
||||
std::ostringstream strm;
|
||||
strm.width(16);
|
||||
strm << std::right << std::hex << MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER); // HIGHGUID_PLAYER always present, even for empty guids
|
||||
strm << std::dec << ':' << bid << ':' << buyout;
|
||||
strm << ':' << deposit << ':' << cut;
|
||||
return strm.str();
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _AUCTION_HOUSE_MGR_H
|
||||
#define _AUCTION_HOUSE_MGR_H
|
||||
|
||||
#include <ace/Singleton.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DBCStructure.h"
|
||||
#include "EventProcessor.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
class Item;
|
||||
class Player;
|
||||
|
||||
#define MIN_AUCTION_TIME (12*HOUR)
|
||||
#define MAX_AUCTION_ITEMS 160
|
||||
|
||||
enum AuctionError
|
||||
{
|
||||
ERR_AUCTION_OK = 0,
|
||||
ERR_AUCTION_INVENTORY = 1,
|
||||
ERR_AUCTION_DATABASE_ERROR = 2,
|
||||
ERR_AUCTION_NOT_ENOUGHT_MONEY = 3,
|
||||
ERR_AUCTION_ITEM_NOT_FOUND = 4,
|
||||
ERR_AUCTION_HIGHER_BID = 5,
|
||||
ERR_AUCTION_BID_INCREMENT = 7,
|
||||
ERR_AUCTION_BID_OWN = 10,
|
||||
ERR_AUCTION_RESTRICTED_ACCOUNT = 13
|
||||
};
|
||||
|
||||
enum AuctionAction
|
||||
{
|
||||
AUCTION_SELL_ITEM = 0,
|
||||
AUCTION_CANCEL = 1,
|
||||
AUCTION_PLACE_BID = 2
|
||||
};
|
||||
|
||||
enum MailAuctionAnswers
|
||||
{
|
||||
AUCTION_OUTBIDDED = 0,
|
||||
AUCTION_WON = 1,
|
||||
AUCTION_SUCCESSFUL = 2,
|
||||
AUCTION_EXPIRED = 3,
|
||||
AUCTION_CANCELLED_TO_BIDDER = 4,
|
||||
AUCTION_CANCELED = 5,
|
||||
AUCTION_SALE_PENDING = 6
|
||||
};
|
||||
|
||||
struct AuctionEntry
|
||||
{
|
||||
uint32 Id;
|
||||
uint32 auctioneer; // creature low guid
|
||||
uint32 item_guidlow;
|
||||
uint32 item_template;
|
||||
uint32 itemCount;
|
||||
uint32 owner;
|
||||
uint32 startbid; //maybe useless
|
||||
uint32 bid;
|
||||
uint32 buyout;
|
||||
time_t expire_time;
|
||||
uint32 bidder;
|
||||
uint32 deposit; //deposit can be calculated only when creating auction
|
||||
AuctionHouseEntry const* auctionHouseEntry; // in AuctionHouse.dbc
|
||||
uint32 factionTemplateId;
|
||||
|
||||
// helpers
|
||||
uint32 GetHouseId() const { return auctionHouseEntry->houseId; }
|
||||
uint32 GetHouseFaction() const { return auctionHouseEntry->faction; }
|
||||
uint32 GetAuctionCut() const;
|
||||
uint32 GetAuctionOutBid() const;
|
||||
bool BuildAuctionInfo(WorldPacket & data) const;
|
||||
void DeleteFromDB(SQLTransaction& trans) const;
|
||||
void SaveToDB(SQLTransaction& trans) const;
|
||||
bool LoadFromDB(Field* fields);
|
||||
bool LoadFromFieldList(Field* fields);
|
||||
std::string BuildAuctionMailSubject(MailAuctionAnswers response) const;
|
||||
static std::string BuildAuctionMailBody(uint32 lowGuid, uint32 bid, uint32 buyout, uint32 deposit, uint32 cut);
|
||||
|
||||
};
|
||||
|
||||
//this class is used as auctionhouse instance
|
||||
class AuctionHouseObject
|
||||
{
|
||||
public:
|
||||
// Initialize storage
|
||||
AuctionHouseObject() { next = AuctionsMap.begin(); }
|
||||
~AuctionHouseObject()
|
||||
{
|
||||
for (AuctionEntryMap::iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
typedef std::map<uint32, AuctionEntry*> AuctionEntryMap;
|
||||
|
||||
uint32 Getcount() const { return AuctionsMap.size(); }
|
||||
|
||||
AuctionEntryMap::iterator GetAuctionsBegin() {return AuctionsMap.begin();}
|
||||
AuctionEntryMap::iterator GetAuctionsEnd() {return AuctionsMap.end();}
|
||||
|
||||
AuctionEntry* GetAuction(uint32 id) const
|
||||
{
|
||||
AuctionEntryMap::const_iterator itr = AuctionsMap.find(id);
|
||||
return itr != AuctionsMap.end() ? itr->second : NULL;
|
||||
}
|
||||
|
||||
void AddAuction(AuctionEntry* auction);
|
||||
|
||||
bool RemoveAuction(AuctionEntry* auction);
|
||||
|
||||
void Update();
|
||||
|
||||
void BuildListBidderItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount);
|
||||
void BuildListOwnerItems(WorldPacket& data, Player* player, uint32& count, uint32& totalcount);
|
||||
bool BuildListAuctionItems(WorldPacket& data, Player* player,
|
||||
std::wstring const& searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
|
||||
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
|
||||
uint32& count, uint32& totalcount, uint8 getAll);
|
||||
|
||||
private:
|
||||
AuctionEntryMap AuctionsMap;
|
||||
|
||||
// storage for "next" auction item for next Update()
|
||||
AuctionEntryMap::const_iterator next;
|
||||
};
|
||||
|
||||
class AuctionHouseMgr
|
||||
{
|
||||
friend class ACE_Singleton<AuctionHouseMgr, ACE_Null_Mutex>;
|
||||
|
||||
private:
|
||||
AuctionHouseMgr();
|
||||
~AuctionHouseMgr();
|
||||
|
||||
public:
|
||||
|
||||
typedef UNORDERED_MAP<uint32, Item*> ItemMap;
|
||||
|
||||
AuctionHouseObject* GetAuctionsMap(uint32 factionTemplateId);
|
||||
AuctionHouseObject* GetBidsMap(uint32 factionTemplateId);
|
||||
|
||||
Item* GetAItem(uint32 id)
|
||||
{
|
||||
ItemMap::const_iterator itr = mAitems.find(id);
|
||||
if (itr != mAitems.end())
|
||||
return itr->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//auction messages
|
||||
void SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& trans);
|
||||
void SendAuctionSalePendingMail(AuctionEntry* auction, SQLTransaction& trans);
|
||||
void SendAuctionSuccessfulMail(AuctionEntry* auction, SQLTransaction& trans);
|
||||
void SendAuctionExpiredMail(AuctionEntry* auction, SQLTransaction& trans);
|
||||
void SendAuctionOutbiddedMail(AuctionEntry* auction, uint32 newPrice, Player* newBidder, SQLTransaction& trans);
|
||||
void SendAuctionCancelledToBidderMail(AuctionEntry* auction, SQLTransaction& trans);
|
||||
|
||||
static uint32 GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count);
|
||||
static AuctionHouseEntry const* GetAuctionHouseEntry(uint32 factionTemplateId);
|
||||
|
||||
public:
|
||||
|
||||
//load first auction items, because of check if item exists, when loading
|
||||
void LoadAuctionItems();
|
||||
void LoadAuctions();
|
||||
|
||||
void AddAItem(Item* it);
|
||||
bool RemoveAItem(uint32 id, bool deleteFromDB = false);
|
||||
|
||||
void Update();
|
||||
|
||||
private:
|
||||
|
||||
AuctionHouseObject mHordeAuctions;
|
||||
AuctionHouseObject mAllianceAuctions;
|
||||
AuctionHouseObject mNeutralAuctions;
|
||||
|
||||
ItemMap mAitems;
|
||||
};
|
||||
|
||||
#define sAuctionMgr ACE_Singleton<AuctionHouseMgr, ACE_Null_Mutex>::instance()
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,436 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BATTLEFIELD_H_
|
||||
#define BATTLEFIELD_H_
|
||||
|
||||
#include "Utilities/Util.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "ZoneScript.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "GameObject.h"
|
||||
#include "Battleground.h"
|
||||
#include "ObjectAccessor.h"
|
||||
|
||||
enum BattlefieldTypes
|
||||
{
|
||||
BATTLEFIELD_WG, // Wintergrasp
|
||||
BATTLEFIELD_TB, // Tol Barad (cataclysm)
|
||||
};
|
||||
|
||||
enum BattlefieldIDs
|
||||
{
|
||||
BATTLEFIELD_BATTLEID_WG = 1, // Wintergrasp battle
|
||||
};
|
||||
|
||||
enum BattlefieldObjectiveStates
|
||||
{
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL = 0,
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE,
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE,
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE,
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE,
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE,
|
||||
BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE,
|
||||
};
|
||||
|
||||
enum BattlefieldSounds
|
||||
{
|
||||
BF_HORDE_WINS = 8454,
|
||||
BF_ALLIANCE_WINS = 8455,
|
||||
BF_START = 3439
|
||||
};
|
||||
|
||||
enum BattlefieldTimers
|
||||
{
|
||||
BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL = 1000
|
||||
};
|
||||
|
||||
|
||||
const uint32 BattlefieldFactions[BG_TEAMS_COUNT] =
|
||||
{
|
||||
1732, // Alliance
|
||||
1735 // Horde
|
||||
};
|
||||
|
||||
// some class predefs
|
||||
class Player;
|
||||
class GameObject;
|
||||
class WorldPacket;
|
||||
class Creature;
|
||||
class Unit;
|
||||
|
||||
class Battlefield;
|
||||
class BfGraveyard;
|
||||
|
||||
typedef UNORDERED_SET<uint64> GuidSet;
|
||||
typedef std::vector<BfGraveyard*> GraveyardVect;
|
||||
typedef std::map<uint64, time_t> PlayerTimerMap;
|
||||
|
||||
class BfCapturePoint
|
||||
{
|
||||
public:
|
||||
BfCapturePoint(Battlefield* bf);
|
||||
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {}
|
||||
|
||||
// Send world state update to all players present
|
||||
void SendUpdateWorldState(uint32 field, uint32 value);
|
||||
|
||||
// Send kill notify to players in the controlling faction
|
||||
void SendObjectiveComplete(uint32 id, uint64 guid);
|
||||
|
||||
// Used when player is activated/inactivated in the area
|
||||
virtual bool HandlePlayerEnter(Player* player);
|
||||
virtual GuidSet::iterator HandlePlayerLeave(Player* player);
|
||||
//virtual void HandlePlayerActivityChanged(Player* player);
|
||||
|
||||
// Checks if player is in range of a capture credit marker
|
||||
bool IsInsideObjective(Player* player) const;
|
||||
|
||||
// Returns true if the state of the objective has changed, in this case, the OutdoorPvP must send a world state ui update.
|
||||
virtual bool Update(uint32 diff);
|
||||
virtual void ChangeTeam(TeamId /*oldTeam*/) {}
|
||||
virtual void SendChangePhase();
|
||||
|
||||
bool SetCapturePointData(GameObject* capturePoint);
|
||||
GameObject* GetCapturePointGo() { return ObjectAccessor::GetObjectInWorld(m_capturePoint, (GameObject*)NULL); }
|
||||
GameObject* GetCapturePointGo(WorldObject* obj) { return ObjectAccessor::GetGameObject(*obj, m_capturePoint); }
|
||||
|
||||
TeamId GetTeamId() { return m_team; }
|
||||
protected:
|
||||
bool DelCapturePoint();
|
||||
|
||||
// active Players in the area of the objective, 0 - alliance, 1 - horde
|
||||
GuidSet m_activePlayers[2];
|
||||
|
||||
// Total shift needed to capture the objective
|
||||
float m_maxValue;
|
||||
float m_minValue;
|
||||
|
||||
// Maximum speed of capture
|
||||
float m_maxSpeed;
|
||||
|
||||
// The status of the objective
|
||||
float m_value;
|
||||
TeamId m_team;
|
||||
|
||||
// Objective states
|
||||
BattlefieldObjectiveStates m_OldState;
|
||||
BattlefieldObjectiveStates m_State;
|
||||
|
||||
// Neutral value on capture bar
|
||||
uint32 m_neutralValuePct;
|
||||
|
||||
// Pointer to the Battlefield this objective belongs to
|
||||
Battlefield* m_Bf;
|
||||
|
||||
// Capture point entry
|
||||
uint32 m_capturePointEntry;
|
||||
|
||||
// Gameobject related to that capture point
|
||||
uint64 m_capturePoint;
|
||||
};
|
||||
|
||||
class BfGraveyard
|
||||
{
|
||||
public:
|
||||
BfGraveyard(Battlefield* Bf);
|
||||
|
||||
// Method to changing who controls the graveyard
|
||||
void GiveControlTo(TeamId team);
|
||||
TeamId GetControlTeamId() const { return m_ControlTeam; }
|
||||
|
||||
// Find the nearest graveyard to a player
|
||||
float GetDistance(Player* player);
|
||||
|
||||
// Initialize the graveyard
|
||||
void Initialize(TeamId startcontrol, uint32 gy);
|
||||
|
||||
// Set spirit service for the graveyard
|
||||
void SetSpirit(Creature* spirit, TeamId team);
|
||||
|
||||
// Add a player to the graveyard
|
||||
void AddPlayer(uint64 player_guid);
|
||||
|
||||
// Remove a player from the graveyard
|
||||
void RemovePlayer(uint64 player_guid);
|
||||
|
||||
// Resurrect players
|
||||
void Resurrect();
|
||||
|
||||
// Move players waiting to that graveyard on the nearest one
|
||||
void RelocateDeadPlayers();
|
||||
|
||||
// Check if this graveyard has a spirit guide
|
||||
bool HasNpc(uint64 guid)
|
||||
{
|
||||
if (!m_SpiritGuide[0] && !m_SpiritGuide[1])
|
||||
return false;
|
||||
|
||||
// performance
|
||||
/*if (!ObjectAccessor::FindUnit(m_SpiritGuide[0]) &&
|
||||
!ObjectAccessor::FindUnit(m_SpiritGuide[1]))
|
||||
return false;*/
|
||||
|
||||
return (m_SpiritGuide[0] == guid || m_SpiritGuide[1] == guid);
|
||||
}
|
||||
|
||||
// Check if a player is in this graveyard's resurrect queue
|
||||
bool HasPlayer(uint64 guid) const { return m_ResurrectQueue.find(guid) != m_ResurrectQueue.end(); }
|
||||
|
||||
// Get the graveyard's ID.
|
||||
uint32 GetGraveyardId() const { return m_GraveyardId; }
|
||||
|
||||
protected:
|
||||
TeamId m_ControlTeam;
|
||||
uint32 m_GraveyardId;
|
||||
uint64 m_SpiritGuide[2];
|
||||
GuidSet m_ResurrectQueue;
|
||||
Battlefield* m_Bf;
|
||||
};
|
||||
|
||||
class Battlefield : public ZoneScript
|
||||
{
|
||||
friend class BattlefieldMgr;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
Battlefield();
|
||||
/// Destructor
|
||||
virtual ~Battlefield();
|
||||
|
||||
/// typedef of map witch store capturepoint and the associate gameobject entry
|
||||
typedef std::map<uint32 /*lowguid */, BfCapturePoint*> BfCapturePointMap;
|
||||
|
||||
/// Call this to init the Battlefield
|
||||
virtual bool SetupBattlefield() { return true; }
|
||||
|
||||
/// Update data of a worldstate to all players present in zone
|
||||
void SendUpdateWorldState(uint32 field, uint32 value);
|
||||
|
||||
/**
|
||||
* \brief Called every time for update bf data and time
|
||||
* - Update timer for start/end battle
|
||||
* - Invite player in zone to queue m_StartGroupingTimer minutes before start
|
||||
* - Kick Afk players
|
||||
* \param diff : time ellapsed since last call (in ms)
|
||||
*/
|
||||
virtual bool Update(uint32 diff);
|
||||
|
||||
/// Invite all players in zone to join the queue, called x minutes before battle start in Update()
|
||||
void InvitePlayersInZoneToQueue();
|
||||
/// Invite all players in queue to join battle on battle start
|
||||
void InvitePlayersInQueueToWar();
|
||||
/// Invite all players in zone to join battle on battle start
|
||||
void InvitePlayersInZoneToWar();
|
||||
|
||||
/// Called when a Unit is kill in battlefield zone
|
||||
virtual void HandleKill(Player* /*killer*/, Unit* /*killed*/) {};
|
||||
|
||||
uint32 GetTypeId() { return m_TypeId; }
|
||||
uint32 GetZoneId() { return m_ZoneId; }
|
||||
|
||||
void TeamApplyBuff(TeamId team, uint32 spellId, uint32 spellId2 = 0);
|
||||
|
||||
/// Return true if battle is start, false if battle is not started
|
||||
bool IsWarTime() { return m_isActive; }
|
||||
|
||||
/// Enable or Disable battlefield
|
||||
void ToggleBattlefield(bool enable) { m_IsEnabled = enable; }
|
||||
/// Return if battlefield is enable
|
||||
bool IsEnabled() { return m_IsEnabled; }
|
||||
|
||||
/**
|
||||
* \brief Kick player from battlefield and teleport him to kick-point location
|
||||
* \param guid : guid of player who must be kick
|
||||
*/
|
||||
void KickPlayerFromBattlefield(uint64 guid);
|
||||
|
||||
/// Called when player (player) enter in zone
|
||||
void HandlePlayerEnterZone(Player* player, uint32 zone);
|
||||
/// Called when player (player) leave the zone
|
||||
void HandlePlayerLeaveZone(Player* player, uint32 zone);
|
||||
|
||||
// All-purpose data storage 64 bit
|
||||
virtual uint64 GetData64(uint32 dataId) const { return m_Data64[dataId]; }
|
||||
virtual void SetData64(uint32 dataId, uint64 value) { m_Data64[dataId] = value; }
|
||||
|
||||
// All-purpose data storage 32 bit
|
||||
virtual uint32 GetData(uint32 dataId) const { return m_Data32[dataId]; }
|
||||
virtual void SetData(uint32 dataId, uint32 value) { m_Data32[dataId] = value; }
|
||||
virtual void UpdateData(uint32 index, int32 pad) { m_Data32[index] += pad; }
|
||||
|
||||
// Battlefield - generic methods
|
||||
TeamId GetDefenderTeam() { return m_DefenderTeam; }
|
||||
TeamId GetAttackerTeam() { return TeamId(1 - m_DefenderTeam); }
|
||||
TeamId GetOtherTeam(TeamId team) { return (team == TEAM_HORDE ? TEAM_ALLIANCE : TEAM_HORDE); }
|
||||
void SetDefenderTeam(TeamId team) { m_DefenderTeam = team; }
|
||||
|
||||
// Group methods
|
||||
/**
|
||||
* \brief Find a not full battlefield group, if there is no, create one
|
||||
* \param TeamId : Id of player team for who we search a group (player->GetTeamId())
|
||||
*/
|
||||
Group* GetFreeBfRaid(TeamId TeamId);
|
||||
/// Return battlefield group where player is.
|
||||
Group* GetGroupPlayer(uint64 guid, TeamId TeamId);
|
||||
/// Force player to join a battlefield group
|
||||
bool AddOrSetPlayerToCorrectBfGroup(Player* player);
|
||||
|
||||
// Graveyard methods
|
||||
// Find which graveyard the player must be teleported to to be resurrected by spiritguide
|
||||
WorldSafeLocsEntry const * GetClosestGraveyard(Player* player);
|
||||
|
||||
virtual void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid);
|
||||
void RemovePlayerFromResurrectQueue(uint64 player_guid);
|
||||
void SetGraveyardNumber(uint32 number) { m_GraveyardList.resize(number); }
|
||||
BfGraveyard* GetGraveyardById(uint32 id) const;
|
||||
|
||||
// Misc methods
|
||||
Creature* SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId teamId);
|
||||
Creature* SpawnCreature(uint32 entry, Position pos, TeamId teamId);
|
||||
GameObject* SpawnGameObject(uint32 entry, float x, float y, float z, float o);
|
||||
|
||||
// Script-methods
|
||||
|
||||
/// Called on start
|
||||
virtual void OnBattleStart() {};
|
||||
/// Called at the end of battle
|
||||
virtual void OnBattleEnd(bool /*endByTimer*/) {};
|
||||
/// Called x minutes before battle start when player in zone are invite to join queue
|
||||
virtual void OnStartGrouping() {};
|
||||
/// Called when a player accept to join the battle
|
||||
virtual void OnPlayerJoinWar(Player* /*player*/) {};
|
||||
/// Called when a player leave the battle
|
||||
virtual void OnPlayerLeaveWar(Player* /*player*/) {};
|
||||
/// Called when a player leave battlefield zone
|
||||
virtual void OnPlayerLeaveZone(Player* /*player*/) {};
|
||||
/// Called when a player enter in battlefield zone
|
||||
virtual void OnPlayerEnterZone(Player* /*player*/) {};
|
||||
|
||||
void SendWarningToAllInZone(uint32 entry);
|
||||
void SendWarningToPlayer(Player* player, uint32 entry);
|
||||
|
||||
void PlayerAcceptInviteToQueue(Player* player);
|
||||
void PlayerAcceptInviteToWar(Player* player);
|
||||
uint32 GetBattleId() { return m_BattleId; }
|
||||
void AskToLeaveQueue(Player* player);
|
||||
|
||||
//virtual void DoCompleteOrIncrementAchievement(uint32 /*achievement*/, Player* /*player*/, uint8 /*incrementNumber = 1*/) {};
|
||||
|
||||
/// Send all worldstate data to all player in zone.
|
||||
virtual void SendInitWorldStatesToAll() = 0;
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) = 0;
|
||||
|
||||
/// Return if we can use mount in battlefield
|
||||
bool CanFlyIn() { return !m_isActive; }
|
||||
|
||||
void SendAreaSpiritHealerQueryOpcode(Player* player, const uint64 & guid);
|
||||
|
||||
void StartBattle();
|
||||
void EndBattle(bool endByTimer);
|
||||
|
||||
void HideNpc(Creature* creature);
|
||||
void ShowNpc(Creature* creature, bool aggressive);
|
||||
|
||||
GraveyardVect GetGraveyardVector() { return m_GraveyardList; }
|
||||
|
||||
uint32 GetTimer() { return m_Timer; }
|
||||
void SetTimer(uint32 timer) { m_Timer = timer; }
|
||||
|
||||
void DoPlaySoundToAll(uint32 SoundID);
|
||||
|
||||
void InvitePlayerToQueue(Player* player);
|
||||
void InvitePlayerToWar(Player* player);
|
||||
|
||||
void InitStalker(uint32 entry, float x, float y, float z, float o);
|
||||
|
||||
protected:
|
||||
uint64 StalkerGuid;
|
||||
uint32 m_Timer; // Global timer for event
|
||||
bool m_IsEnabled;
|
||||
bool m_isActive;
|
||||
TeamId m_DefenderTeam;
|
||||
|
||||
// Map of the objectives belonging to this OutdoorPvP
|
||||
BfCapturePointMap m_capturePoints;
|
||||
|
||||
// Players info maps
|
||||
GuidSet m_players[BG_TEAMS_COUNT]; // Players in zone
|
||||
GuidSet m_PlayersInQueue[BG_TEAMS_COUNT]; // Players in the queue
|
||||
GuidSet m_PlayersInWar[BG_TEAMS_COUNT]; // Players in WG combat
|
||||
PlayerTimerMap m_InvitedPlayers[BG_TEAMS_COUNT];
|
||||
PlayerTimerMap m_PlayersWillBeKick[BG_TEAMS_COUNT];
|
||||
|
||||
// Variables that must exist for each battlefield
|
||||
uint32 m_TypeId; // See enum BattlefieldTypes
|
||||
uint32 m_BattleId; // BattleID (for packet)
|
||||
uint32 m_ZoneId; // ZoneID of Wintergrasp = 4197
|
||||
uint32 m_MapId; // MapId where is Battlefield
|
||||
uint32 m_MaxPlayer; // Maximum number of player that participated to Battlefield
|
||||
uint32 m_MinPlayer; // Minimum number of player for Battlefield start
|
||||
uint32 m_MinLevel; // Required level to participate at Battlefield
|
||||
uint32 m_BattleTime; // Length of a battle
|
||||
uint32 m_NoWarBattleTime; // Time between two battles
|
||||
uint32 m_RestartAfterCrash; // Delay to restart Wintergrasp if the server crashed during a running battle.
|
||||
uint32 m_TimeForAcceptInvite;
|
||||
uint32 m_uiKickDontAcceptTimer;
|
||||
WorldLocation KickPosition; // Position where players are teleported if they switch to afk during the battle or if they don't accept invitation
|
||||
|
||||
uint32 m_uiKickAfkPlayersTimer; // Timer for check Afk in war
|
||||
|
||||
// Graveyard variables
|
||||
GraveyardVect m_GraveyardList; // Vector witch contain the different GY of the battle
|
||||
uint32 m_LastResurectTimer; // Timer for resurect player every 30 sec
|
||||
|
||||
uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle
|
||||
bool m_StartGrouping; // bool for know if all players in area has been invited
|
||||
|
||||
GuidSet m_Groups[BG_TEAMS_COUNT]; // Contain different raid group
|
||||
|
||||
std::vector<uint64> m_Data64;
|
||||
std::vector<uint32> m_Data32;
|
||||
|
||||
void KickAfkPlayers();
|
||||
|
||||
// use for switch off all worldstate for client
|
||||
virtual void SendRemoveWorldStates(Player* /*player*/) {}
|
||||
|
||||
// use for send a packet for all player list
|
||||
void BroadcastPacketToZone(WorldPacket& data) const;
|
||||
void BroadcastPacketToQueue(WorldPacket& data) const;
|
||||
void BroadcastPacketToWar(WorldPacket& data) const;
|
||||
|
||||
// CapturePoint system
|
||||
void AddCapturePoint(BfCapturePoint* cp, GameObject* go) { m_capturePoints[go->GetEntry()] = cp; }
|
||||
|
||||
BfCapturePoint* GetCapturePoint(uint32 lowguid) const
|
||||
{
|
||||
Battlefield::BfCapturePointMap::const_iterator itr = m_capturePoints.find(lowguid);
|
||||
if (itr != m_capturePoints.end())
|
||||
return itr->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RegisterZone(uint32 zoneid);
|
||||
bool HasPlayer(Player* player) const;
|
||||
void TeamCastSpell(TeamId team, int32 spellId);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
#include "Battlefield.h"
|
||||
#include "BattlefieldMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
|
||||
//This send to player windows for invite player to join the war
|
||||
//Param1:(BattleId) the BattleId of Bf
|
||||
//Param2:(ZoneId) the zone where the battle is (4197 for wg)
|
||||
//Param3:(time) Time in second that the player have for accept
|
||||
void WorldSession::SendBfInvitePlayerToWar(uint32 BattleId, uint32 ZoneId, uint32 p_time)
|
||||
{
|
||||
//Send packet
|
||||
WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTRY_INVITE, 12);
|
||||
data << uint32(BattleId);
|
||||
data << uint32(ZoneId);
|
||||
data << uint32((time(NULL) + p_time));
|
||||
|
||||
//Sending the packet to player
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//This send invitation to player to join the queue
|
||||
//Param1:(BattleId) the BattleId of Bf
|
||||
void WorldSession::SendBfInvitePlayerToQueue(uint32 BattleId)
|
||||
{
|
||||
WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_INVITE, 5);
|
||||
|
||||
data << uint32(BattleId);
|
||||
data << uint8(1); //warmup ? used ?
|
||||
|
||||
//Sending packet to player
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//This send packet for inform player that he join queue
|
||||
//Param1:(BattleId) the BattleId of Bf
|
||||
//Param2:(ZoneId) the zone where the battle is (4197 for wg)
|
||||
//Param3:(CanQueue) if able to queue
|
||||
//Param4:(Full) on log in is full
|
||||
void WorldSession::SendBfQueueInviteResponse(uint32 BattleId,uint32 ZoneId, bool CanQueue, bool Full)
|
||||
{
|
||||
WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, 11);
|
||||
data << uint32(BattleId);
|
||||
data << uint32(ZoneId);
|
||||
data << uint8((CanQueue ? 1 : 0)); //Accepted //0 you cannot queue wg //1 you are queued
|
||||
data << uint8((Full ? 0 : 1)); //Logging In //0 wg full //1 queue for upcoming
|
||||
data << uint8(1); //Warmup
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//This is call when player accept to join war
|
||||
//Param1:(BattleId) the BattleId of Bf
|
||||
void WorldSession::SendBfEntered(uint32 BattleId)
|
||||
{
|
||||
// m_PlayerInWar[player->GetTeamId()].insert(player->GetGUID());
|
||||
WorldPacket data(SMSG_BATTLEFIELD_MGR_ENTERED, 7);
|
||||
data << uint32(BattleId);
|
||||
data << uint8(1); //unk
|
||||
data << uint8(1); //unk
|
||||
data << uint8(_player->isAFK() ? 1 : 0); //Clear AFK
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::SendBfLeaveMessage(uint32 BattleId, BFLeaveReason reason)
|
||||
{
|
||||
WorldPacket data(SMSG_BATTLEFIELD_MGR_EJECTED, 7);
|
||||
data << uint32(BattleId);
|
||||
data << uint8(reason);//byte Reason
|
||||
data << uint8(2);//byte BattleStatus
|
||||
data << uint8(0);//bool Relocated
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
//Send by client when he click on accept for queue
|
||||
void WorldSession::HandleBfQueueInviteResponse(WorldPacket & recvData)
|
||||
{
|
||||
uint32 BattleId;
|
||||
uint8 Accepted;
|
||||
|
||||
recvData >> BattleId >> Accepted;
|
||||
//sLog->outError("HandleQueueInviteResponse: BattleID:%u Accepted:%u", BattleId, Accepted);
|
||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldByBattleId(BattleId);
|
||||
if (!Bf)
|
||||
return;
|
||||
|
||||
if (Accepted)
|
||||
{
|
||||
Bf->PlayerAcceptInviteToQueue(_player);
|
||||
}
|
||||
}
|
||||
|
||||
//Send by client on clicking in accept or refuse of invitation windows for join game
|
||||
void WorldSession::HandleBfEntryInviteResponse(WorldPacket & recvData)
|
||||
{
|
||||
uint32 BattleId;
|
||||
uint8 Accepted;
|
||||
|
||||
recvData >> BattleId >> Accepted;
|
||||
//sLog->outError("HandleBattlefieldInviteResponse: BattleID:%u Accepted:%u", BattleId, Accepted);
|
||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldByBattleId(BattleId);
|
||||
if (!Bf)
|
||||
return;
|
||||
|
||||
//If player accept invitation
|
||||
if (Accepted)
|
||||
{
|
||||
Bf->PlayerAcceptInviteToWar(_player);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_player->GetZoneId() == Bf->GetZoneId())
|
||||
Bf->KickPlayerFromBattlefield(_player->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleBfExitRequest(WorldPacket & recvData)
|
||||
{
|
||||
uint32 BattleId;
|
||||
|
||||
recvData >> BattleId;
|
||||
//sLog->outError("HandleBfExitRequest: BattleID:%u ", BattleId);
|
||||
Battlefield* Bf = sBattlefieldMgr->GetBattlefieldByBattleId(BattleId);
|
||||
if (!Bf)
|
||||
return;
|
||||
|
||||
Bf->AskToLeaveQueue(_player);
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BattlefieldMgr.h"
|
||||
#include "Zones/BattlefieldWG.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
|
||||
BattlefieldMgr::BattlefieldMgr()
|
||||
{
|
||||
m_UpdateTimer = 0;
|
||||
//sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Instantiating BattlefieldMgr");
|
||||
}
|
||||
|
||||
BattlefieldMgr::~BattlefieldMgr()
|
||||
{
|
||||
//sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Deleting BattlefieldMgr");
|
||||
for (BattlefieldSet::iterator itr = m_BattlefieldSet.begin(); itr != m_BattlefieldSet.end(); ++itr)
|
||||
delete *itr;
|
||||
}
|
||||
|
||||
void BattlefieldMgr::InitBattlefield()
|
||||
{
|
||||
Battlefield* pBf = new BattlefieldWG;
|
||||
// respawn, init variables
|
||||
if (!pBf->SetupBattlefield())
|
||||
{
|
||||
sLog->outString();
|
||||
sLog->outString("Battlefield : Wintergrasp init failed.");
|
||||
delete pBf;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BattlefieldSet.push_back(pBf);
|
||||
sLog->outString();
|
||||
sLog->outString("Battlefield : Wintergrasp successfully initiated.");
|
||||
}
|
||||
|
||||
/* For Cataclysm: Tol Barad
|
||||
pBf = new BattlefieldTB;
|
||||
// respawn, init variables
|
||||
if(!pBf->SetupBattlefield())
|
||||
{
|
||||
;//sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Battlefield : Tol Barad init failed.");
|
||||
delete pBf;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BattlefieldSet.push_back(pBf);
|
||||
;//sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Battlefield : Tol Barad successfully initiated.");
|
||||
} */
|
||||
}
|
||||
|
||||
void BattlefieldMgr::AddZone(uint32 zoneid, Battlefield *handle)
|
||||
{
|
||||
m_BattlefieldMap[zoneid] = handle;
|
||||
}
|
||||
|
||||
void BattlefieldMgr::HandlePlayerEnterZone(Player * player, uint32 zoneid)
|
||||
{
|
||||
BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid);
|
||||
if (itr == m_BattlefieldMap.end())
|
||||
return;
|
||||
|
||||
if (itr->second->HasPlayer(player) || !itr->second->IsEnabled())
|
||||
return;
|
||||
|
||||
itr->second->HandlePlayerEnterZone(player, zoneid);
|
||||
;//sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Player %u entered outdoorpvp id %u", player->GetGUIDLow(), itr->second->GetTypeId());
|
||||
}
|
||||
|
||||
void BattlefieldMgr::HandlePlayerLeaveZone(Player * player, uint32 zoneid)
|
||||
{
|
||||
BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid);
|
||||
if (itr == m_BattlefieldMap.end())
|
||||
return;
|
||||
|
||||
// teleport: remove once in removefromworld, once in updatezone
|
||||
if (!itr->second->HasPlayer(player))
|
||||
return;
|
||||
itr->second->HandlePlayerLeaveZone(player, zoneid);
|
||||
;//sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Player %u left outdoorpvp id %u", player->GetGUIDLow(), itr->second->GetTypeId());
|
||||
}
|
||||
|
||||
Battlefield *BattlefieldMgr::GetBattlefieldToZoneId(uint32 zoneid)
|
||||
{
|
||||
BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid);
|
||||
if (itr == m_BattlefieldMap.end())
|
||||
{
|
||||
// no handle for this zone, return
|
||||
return NULL;
|
||||
}
|
||||
if (!itr->second->IsEnabled())
|
||||
return NULL;
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
Battlefield *BattlefieldMgr::GetBattlefieldByBattleId(uint32 battleid)
|
||||
{
|
||||
for (BattlefieldSet::iterator itr = m_BattlefieldSet.begin(); itr != m_BattlefieldSet.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetBattleId() == battleid)
|
||||
return (*itr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BattlefieldMgr::Update(uint32 diff)
|
||||
{
|
||||
m_UpdateTimer += diff;
|
||||
if (m_UpdateTimer > BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL)
|
||||
{
|
||||
for (BattlefieldSet::iterator itr = m_BattlefieldSet.begin(); itr != m_BattlefieldSet.end(); ++itr)
|
||||
//if ((*itr)->IsEnabled())
|
||||
(*itr)->Update(m_UpdateTimer);
|
||||
m_UpdateTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ZoneScript *BattlefieldMgr::GetZoneScript(uint32 zoneId)
|
||||
{
|
||||
BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneId);
|
||||
if (itr != m_BattlefieldMap.end())
|
||||
return itr->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BATTLEFIELD_MGR_H_
|
||||
#define BATTLEFIELD_MGR_H_
|
||||
|
||||
#include "Battlefield.h"
|
||||
#include "ace/Singleton.h"
|
||||
|
||||
class Player;
|
||||
class GameObject;
|
||||
class Creature;
|
||||
class ZoneScript;
|
||||
struct GossipMenuItems;
|
||||
|
||||
// class to handle player enter / leave / areatrigger / GO use events
|
||||
class BattlefieldMgr
|
||||
{
|
||||
public:
|
||||
// ctor
|
||||
BattlefieldMgr();
|
||||
// dtor
|
||||
~BattlefieldMgr();
|
||||
|
||||
// create battlefield events
|
||||
void InitBattlefield();
|
||||
// called when a player enters an battlefield area
|
||||
void HandlePlayerEnterZone(Player * player, uint32 areaflag);
|
||||
// called when player leaves an battlefield area
|
||||
void HandlePlayerLeaveZone(Player * player, uint32 areaflag);
|
||||
// called when player resurrects
|
||||
void HandlePlayerResurrects(Player * player, uint32 areaflag);
|
||||
// return assigned battlefield
|
||||
Battlefield* GetBattlefieldToZoneId(uint32 zoneid);
|
||||
Battlefield* GetBattlefieldByBattleId(uint32 battleid);
|
||||
|
||||
ZoneScript* GetZoneScript(uint32 zoneId);
|
||||
|
||||
void AddZone(uint32 zoneid, Battlefield * handle);
|
||||
|
||||
void Update(uint32 diff);
|
||||
|
||||
void HandleGossipOption(Player * player, uint64 guid, uint32 gossipid);
|
||||
|
||||
bool CanTalkTo(Player * player, Creature * creature, GossipMenuItems gso);
|
||||
|
||||
void HandleDropFlag(Player * player, uint32 spellId);
|
||||
|
||||
typedef std::vector < Battlefield * >BattlefieldSet;
|
||||
typedef std::map < uint32 /* zoneid */ , Battlefield * >BattlefieldMap;
|
||||
private:
|
||||
// contains all initiated battlefield events
|
||||
// used when initing / cleaning up
|
||||
BattlefieldSet m_BattlefieldSet;
|
||||
// maps the zone ids to an battlefield event
|
||||
// used in player event handling
|
||||
BattlefieldMap m_BattlefieldMap;
|
||||
// update interval
|
||||
uint32 m_UpdateTimer;
|
||||
};
|
||||
|
||||
#define sBattlefieldMgr ACE_Singleton<BattlefieldMgr, ACE_Null_Mutex>::instance()
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,916 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ObjectMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "World.h"
|
||||
#include "Group.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "Player.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include <Config.h>
|
||||
|
||||
ArenaTeam::ArenaTeam()
|
||||
: TeamId(0), Type(0), TeamName(), CaptainGuid(0), BackgroundColor(0), EmblemStyle(0), EmblemColor(0),
|
||||
BorderStyle(0), BorderColor(0)
|
||||
{
|
||||
Stats.WeekGames = 0;
|
||||
Stats.SeasonGames = 0;
|
||||
Stats.Rank = 0;
|
||||
Stats.Rating = sWorld->getIntConfig(CONFIG_ARENA_START_RATING);
|
||||
Stats.WeekWins = 0;
|
||||
Stats.SeasonWins = 0;
|
||||
}
|
||||
|
||||
ArenaTeam::~ArenaTeam()
|
||||
{
|
||||
}
|
||||
|
||||
bool ArenaTeam::Create(uint64 captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor)
|
||||
{
|
||||
// Check if captain is present
|
||||
if (!ObjectAccessor::FindPlayerInOrOutOfWorld(captainGuid))
|
||||
return false;
|
||||
|
||||
// Check if arena team name is already taken
|
||||
if (sArenaTeamMgr->GetArenaTeamByName(TeamName))
|
||||
return false;
|
||||
|
||||
// Generate new arena team id
|
||||
TeamId = sArenaTeamMgr->GenerateArenaTeamId();
|
||||
|
||||
// Assign member variables
|
||||
CaptainGuid = captainGuid;
|
||||
Type = type;
|
||||
TeamName = teamName;
|
||||
BackgroundColor = backgroundColor;
|
||||
EmblemStyle = emblemStyle;
|
||||
EmblemColor = emblemColor;
|
||||
BorderStyle = borderStyle;
|
||||
BorderColor = borderColor;
|
||||
uint32 captainLowGuid = GUID_LOPART(captainGuid);
|
||||
|
||||
// Save arena team to db
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM);
|
||||
stmt->setUInt32(0, TeamId);
|
||||
stmt->setString(1, TeamName);
|
||||
stmt->setUInt32(2, captainLowGuid);
|
||||
stmt->setUInt8(3, Type);
|
||||
stmt->setUInt16(4, Stats.Rating);
|
||||
stmt->setUInt32(5, BackgroundColor);
|
||||
stmt->setUInt8(6, EmblemStyle);
|
||||
stmt->setUInt32(7, EmblemColor);
|
||||
stmt->setUInt8(8, BorderStyle);
|
||||
stmt->setUInt32(9, BorderColor);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
// Add captain as member
|
||||
AddMember(CaptainGuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArenaTeam::AddMember(uint64 playerGuid)
|
||||
{
|
||||
std::string playerName;
|
||||
uint8 playerClass;
|
||||
|
||||
// Check if arena team is full (Can't have more than type * 2 players)
|
||||
if (GetMembersSize() >= GetType() * 2)
|
||||
return false;
|
||||
|
||||
// xinef: Get player name and class from player storage or global data storage
|
||||
Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(playerGuid);
|
||||
if (player)
|
||||
{
|
||||
playerClass = player->getClass();
|
||||
playerName = player->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalPlayerData const* playerData = sWorld->GetGlobalPlayerData(GUID_LOPART(playerGuid));
|
||||
if (!playerData)
|
||||
return false;
|
||||
|
||||
playerName = playerData->name;
|
||||
playerClass = playerData->playerClass;
|
||||
}
|
||||
|
||||
// Check if player is already in a similar arena team
|
||||
if ((player && player->GetArenaTeamId(GetSlot())) || Player::GetArenaTeamIdFromStorage(GUID_LOPART(playerGuid), GetSlot()) != 0)
|
||||
{
|
||||
sLog->outError("Arena: Player %s (guid: %u) already has an arena team of type %u", playerName.c_str(), GUID_LOPART(playerGuid), GetType());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set player's personal rating
|
||||
uint32 personalRating = 0;
|
||||
|
||||
if (sWorld->getIntConfig(CONFIG_ARENA_START_PERSONAL_RATING) > 0)
|
||||
personalRating = sWorld->getIntConfig(CONFIG_ARENA_START_PERSONAL_RATING);
|
||||
else if (GetRating() >= 1000)
|
||||
personalRating = 1000;
|
||||
|
||||
// xinef: zomg! sync query
|
||||
// Try to get player's match maker rating from db and fall back to config setting if not found
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MATCH_MAKER_RATING);
|
||||
stmt->setUInt32(0, GUID_LOPART(playerGuid));
|
||||
stmt->setUInt8(1, GetSlot());
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
uint16 matchMakerRating;
|
||||
uint16 maxMMR;
|
||||
if (result)
|
||||
{
|
||||
matchMakerRating = (*result)[0].GetUInt16();
|
||||
uint16 Max = (*result)[1].GetUInt16();
|
||||
maxMMR = std::max(Max, matchMakerRating);
|
||||
}
|
||||
else
|
||||
{
|
||||
matchMakerRating = sWorld->getIntConfig(CONFIG_ARENA_START_MATCHMAKER_RATING);
|
||||
maxMMR = matchMakerRating;
|
||||
}
|
||||
|
||||
// Remove all player signatures from other petitions
|
||||
// This will prevent player from joining too many arena teams and corrupt arena team data integrity
|
||||
Player::RemovePetitionsAndSigns(playerGuid, GetType());
|
||||
|
||||
// Feed data to the struct
|
||||
ArenaTeamMember newMember;
|
||||
//newMember.Name = playerName;
|
||||
newMember.Guid = playerGuid;
|
||||
newMember.Class = playerClass;
|
||||
newMember.SeasonGames = 0;
|
||||
newMember.WeekGames = 0;
|
||||
newMember.SeasonWins = 0;
|
||||
newMember.WeekWins = 0;
|
||||
newMember.PersonalRating = personalRating;
|
||||
newMember.MatchMakerRating = matchMakerRating;
|
||||
newMember.MaxMMR = maxMMR;
|
||||
|
||||
Members.push_back(newMember);
|
||||
sWorld->UpdateGlobalPlayerArenaTeam(GUID_LOPART(playerGuid), GetSlot(), GetId());
|
||||
|
||||
// Save player's arena team membership to db
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM_MEMBER);
|
||||
stmt->setUInt32(0, TeamId);
|
||||
stmt->setUInt32(1, GUID_LOPART(playerGuid));
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
// Inform player if online
|
||||
if (player)
|
||||
{
|
||||
player->SetInArenaTeam(TeamId, GetSlot(), GetType());
|
||||
player->SetArenaTeamIdInvited(0);
|
||||
|
||||
// Hide promote/remove buttons
|
||||
if (CaptainGuid != playerGuid)
|
||||
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArenaTeam::LoadArenaTeamFromDB(QueryResult result)
|
||||
{
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
TeamId = fields[0].GetUInt32();
|
||||
TeamName = fields[1].GetString();
|
||||
CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
Type = fields[3].GetUInt8();
|
||||
BackgroundColor = fields[4].GetUInt32();
|
||||
EmblemStyle = fields[5].GetUInt8();
|
||||
EmblemColor = fields[6].GetUInt32();
|
||||
BorderStyle = fields[7].GetUInt8();
|
||||
BorderColor = fields[8].GetUInt32();
|
||||
Stats.Rating = fields[9].GetUInt16();
|
||||
Stats.WeekGames = fields[10].GetUInt16();
|
||||
Stats.WeekWins = fields[11].GetUInt16();
|
||||
Stats.SeasonGames = fields[12].GetUInt16();
|
||||
Stats.SeasonWins = fields[13].GetUInt16();
|
||||
Stats.Rank = fields[14].GetUInt32();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArenaTeam::LoadMembersFromDB(QueryResult result)
|
||||
{
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
bool captainPresentInTeam = false;
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
// Prevent crash if db records are broken when all members in result are already processed and current team doesn't have any members
|
||||
if (!fields)
|
||||
break;
|
||||
|
||||
uint32 arenaTeamId = fields[0].GetUInt32();
|
||||
|
||||
// We loaded all members for this arena_team already, break cycle
|
||||
if (arenaTeamId > TeamId)
|
||||
break;
|
||||
|
||||
ArenaTeamMember newMember;
|
||||
newMember.Guid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
newMember.WeekGames = fields[2].GetUInt16();
|
||||
newMember.WeekWins = fields[3].GetUInt16();
|
||||
newMember.SeasonGames = fields[4].GetUInt16();
|
||||
newMember.SeasonWins = fields[5].GetUInt16();
|
||||
//newMember.Name = fields[6].GetString();
|
||||
newMember.Class = fields[7].GetUInt8();
|
||||
newMember.PersonalRating = fields[8].GetUInt16();
|
||||
newMember.MatchMakerRating = fields[9].GetUInt16() > 0 ? fields[9].GetUInt16() : sWorld->getIntConfig(CONFIG_ARENA_START_MATCHMAKER_RATING);;
|
||||
newMember.MaxMMR = std::max(fields[10].GetUInt16(), newMember.MatchMakerRating);
|
||||
|
||||
// Delete member if character information is missing
|
||||
if (fields[6].GetString().empty())
|
||||
{
|
||||
sLog->outErrorDb("ArenaTeam %u has member with empty name - probably player %u doesn't exist, deleting him from memberlist!", arenaTeamId, GUID_LOPART(newMember.Guid));
|
||||
this->DelMember(newMember.Guid, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if team team has a valid captain
|
||||
if (newMember.Guid == GetCaptain())
|
||||
captainPresentInTeam = true;
|
||||
|
||||
// Put the player in the team
|
||||
Members.push_back(newMember);
|
||||
sWorld->UpdateGlobalPlayerArenaTeam(GUID_LOPART(newMember.Guid), GetSlot(), GetId());
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
if (Empty() || !captainPresentInTeam)
|
||||
{
|
||||
// Arena team is empty or captain is not in team, delete from db
|
||||
;//sLog->outDebug(LOG_FILTER_BATTLEGROUND, "ArenaTeam %u does not have any members or its captain is not in team, disbanding it...", TeamId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArenaTeam::SetCaptain(uint64 guid)
|
||||
{
|
||||
// Disable remove/promote buttons
|
||||
Player* oldCaptain = ObjectAccessor::FindPlayerInOrOutOfWorld(GetCaptain());
|
||||
if (oldCaptain)
|
||||
oldCaptain->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 1);
|
||||
|
||||
// Set new captain
|
||||
CaptainGuid = guid;
|
||||
|
||||
// Update database
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_CAPTAIN);
|
||||
stmt->setUInt32(0, GUID_LOPART(guid));
|
||||
stmt->setUInt32(1, GetId());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
// Enable remove/promote buttons
|
||||
if (Player* newCaptain = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
|
||||
{
|
||||
newCaptain->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 0);
|
||||
/*if (oldCaptain)
|
||||
{
|
||||
sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Player: %s [GUID: %u] promoted player: %s [GUID: %u] to leader of arena team [Id: %u] [Type: %u].",
|
||||
oldCaptain->GetName().c_str(), oldCaptain->GetGUIDLow(), newCaptain->GetName().c_str(),
|
||||
newCaptain->GetGUIDLow(), GetId(), GetType());
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::DelMember(uint64 guid, bool cleanDb)
|
||||
{
|
||||
// Remove member from team
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (itr->Guid == guid)
|
||||
{
|
||||
Members.erase(itr);
|
||||
sWorld->UpdateGlobalPlayerArenaTeam(GUID_LOPART(guid), GetSlot(), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
// Inform player and remove arena team info from player data
|
||||
if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
|
||||
{
|
||||
player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
|
||||
// delete all info regarding this team
|
||||
for (uint32 i = 0; i < ARENA_TEAM_END; ++i)
|
||||
player->SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType(i), 0);
|
||||
}
|
||||
|
||||
// Only used for single member deletion, for arena team disband we use a single query for more efficiency
|
||||
if (cleanDb)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARENA_TEAM_MEMBER);
|
||||
stmt->setUInt32(0, GetId());
|
||||
stmt->setUInt32(1, GUID_LOPART(guid));
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::Disband(WorldSession* session)
|
||||
{
|
||||
// Remove all members from arena team
|
||||
while (!Members.empty())
|
||||
DelMember(Members.front().Guid, false);
|
||||
|
||||
// Broadcast update
|
||||
if (session)
|
||||
{
|
||||
BroadcastEvent(ERR_ARENA_TEAM_DISBANDED_S, 0, 2, session->GetPlayerName(), GetName(), "");
|
||||
}
|
||||
|
||||
// Update database
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARENA_TEAM);
|
||||
stmt->setUInt32(0, TeamId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARENA_TEAM_MEMBERS);
|
||||
stmt->setUInt32(0, TeamId);
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
// Remove arena team from ObjectMgr
|
||||
sArenaTeamMgr->RemoveArenaTeam(TeamId);
|
||||
}
|
||||
|
||||
void ArenaTeam::Roster(WorldSession* session)
|
||||
{
|
||||
Player* player = NULL;
|
||||
|
||||
uint8 unk308 = 0;
|
||||
std::string tempName;
|
||||
|
||||
WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
|
||||
data << uint32(GetId()); // team id
|
||||
data << uint8(unk308); // 308 unknown value but affect packet structure
|
||||
data << uint32(GetMembersSize()); // members count
|
||||
data << uint32(GetType()); // arena team type?
|
||||
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
player = ObjectAccessor::FindPlayerInOrOutOfWorld(itr->Guid);
|
||||
|
||||
data << uint64(itr->Guid); // guid
|
||||
data << uint8((player ? 1 : 0)); // online flag
|
||||
tempName = "";
|
||||
sObjectMgr->GetPlayerNameByGUID(itr->Guid, tempName);
|
||||
data << tempName; // member name
|
||||
data << uint32((itr->Guid == GetCaptain() ? 0 : 1));// captain flag 0 captain 1 member
|
||||
data << uint8((player ? player->getLevel() : 0)); // unknown, level?
|
||||
data << uint8(itr->Class); // class
|
||||
data << uint32(itr->WeekGames); // played this week
|
||||
data << uint32(itr->WeekWins); // wins this week
|
||||
data << uint32(itr->SeasonGames); // played this season
|
||||
data << uint32(itr->SeasonWins); // wins this season
|
||||
data << uint32(itr->PersonalRating); // personal rating
|
||||
if (unk308)
|
||||
{
|
||||
data << float(0.0f); // 308 unk
|
||||
data << float(0.0f); // 308 unk
|
||||
}
|
||||
}
|
||||
|
||||
session->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
|
||||
}
|
||||
|
||||
void ArenaTeam::Query(WorldSession* session)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_TEAM_QUERY_RESPONSE, 4*7+GetName().size()+1);
|
||||
data << uint32(GetId()); // team id
|
||||
data << GetName(); // team name
|
||||
data << uint32(GetType()); // arena team type (2=2x2, 3=3x3 or 5=5x5)
|
||||
data << uint32(BackgroundColor); // background color
|
||||
data << uint32(EmblemStyle); // emblem style
|
||||
data << uint32(EmblemColor); // emblem color
|
||||
data << uint32(BorderStyle); // border style
|
||||
data << uint32(BorderColor); // border color
|
||||
session->SendPacket(&data);
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE");
|
||||
}
|
||||
|
||||
void ArenaTeam::SendStats(WorldSession* session)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);
|
||||
data << uint32(GetId()); // team id
|
||||
data << uint32(Stats.Rating); // rating
|
||||
data << uint32(Stats.WeekGames); // games this week
|
||||
data << uint32(Stats.WeekWins); // wins this week
|
||||
data << uint32(Stats.SeasonGames); // played this season
|
||||
data << uint32(Stats.SeasonWins); // wins this season
|
||||
data << uint32(Stats.Rank); // rank
|
||||
session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void ArenaTeam::NotifyStatsChanged()
|
||||
{
|
||||
// This is called after a rated match ended
|
||||
// Updates arena team stats for every member of the team (not only the ones who participated!)
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(itr->Guid))
|
||||
SendStats(player->GetSession());
|
||||
}
|
||||
|
||||
void ArenaTeam::Inspect(WorldSession* session, uint64 guid)
|
||||
{
|
||||
ArenaTeamMember* member = GetMember(guid);
|
||||
if (!member)
|
||||
return;
|
||||
|
||||
WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
|
||||
data << uint64(guid); // player guid
|
||||
data << uint8(GetSlot()); // slot (0...2)
|
||||
data << uint32(GetId()); // arena team id
|
||||
data << uint32(Stats.Rating); // rating
|
||||
data << uint32(Stats.SeasonGames); // season played
|
||||
data << uint32(Stats.SeasonWins); // season wins
|
||||
data << uint32(member->SeasonGames); // played (count of all games, that the inspected member participated...)
|
||||
data << uint32(member->PersonalRating); // personal rating
|
||||
session->SendPacket(&data);
|
||||
}
|
||||
|
||||
void ArenaTeamMember::ModifyPersonalRating(Player* player, int32 mod, uint32 type)
|
||||
{
|
||||
if (int32(PersonalRating) + mod < 0)
|
||||
PersonalRating = 0;
|
||||
else
|
||||
PersonalRating += mod;
|
||||
|
||||
if (player)
|
||||
{
|
||||
player->SetArenaTeamInfoField(ArenaTeam::GetSlotByType(type), ARENA_TEAM_PERSONAL_RATING, PersonalRating);
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING, PersonalRating, type);
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeamMember::ModifyMatchmakerRating(int32 mod, uint32 /*slot*/)
|
||||
{
|
||||
if (mod < 0)
|
||||
{
|
||||
// pussywizard: prevent lowering MMR too much from max achieved MMR
|
||||
int32 maxAllowedDrop = (int32)sWorld->getIntConfig(CONFIG_MAX_ALLOWED_MMR_DROP);
|
||||
mod = std::min<int32>(std::max<int32>(-((int32)MatchMakerRating - (int32)MaxMMR + maxAllowedDrop), mod), 0);
|
||||
}
|
||||
|
||||
if (int32(MatchMakerRating) + mod < 0)
|
||||
MatchMakerRating = 0;
|
||||
else
|
||||
MatchMakerRating += mod;
|
||||
|
||||
if (MatchMakerRating > MaxMMR)
|
||||
MaxMMR = MatchMakerRating;
|
||||
}
|
||||
|
||||
void ArenaTeam::BroadcastPacket(WorldPacket* packet)
|
||||
{
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(itr->Guid))
|
||||
player->GetSession()->SendPacket(packet);
|
||||
}
|
||||
|
||||
void ArenaTeam::BroadcastEvent(ArenaTeamEvents event, uint64 guid, uint8 strCount, std::string const& str1, std::string const& str2, std::string const& str3)
|
||||
{
|
||||
WorldPacket data(SMSG_ARENA_TEAM_EVENT, 1+1+1);
|
||||
data << uint8(event);
|
||||
data << uint8(strCount);
|
||||
switch (strCount)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
data << str1;
|
||||
break;
|
||||
case 2:
|
||||
data << str1 << str2;
|
||||
break;
|
||||
case 3:
|
||||
data << str1 << str2 << str3;
|
||||
break;
|
||||
default:
|
||||
sLog->outError("Unhandled strCount %u in ArenaTeam::BroadcastEvent", strCount);
|
||||
return;
|
||||
}
|
||||
|
||||
if (guid)
|
||||
data << uint64(guid);
|
||||
|
||||
BroadcastPacket(&data);
|
||||
|
||||
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_ARENA_TEAM_EVENT");
|
||||
}
|
||||
|
||||
void ArenaTeam::MassInviteToEvent(WorldSession* session)
|
||||
{
|
||||
WorldPacket data(SMSG_CALENDAR_ARENA_TEAM, (Members.size() - 1) * (4 + 8 + 1));
|
||||
data << uint32(Members.size() - 1);
|
||||
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
if (itr->Guid != session->GetPlayer()->GetGUID())
|
||||
{
|
||||
data.appendPackGUID(itr->Guid);
|
||||
data << uint8(0); // unk
|
||||
}
|
||||
}
|
||||
|
||||
session->SendPacket(&data);
|
||||
}
|
||||
|
||||
uint8 ArenaTeam::GetSlotByType(uint32 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ARENA_TEAM_2v2: return 0;
|
||||
case ARENA_TEAM_3v3: return 1;
|
||||
case ARENA_TEAM_5v5: return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sLog->outError("FATAL: Unknown arena team type %u for some arena team", type);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
bool ArenaTeam::IsMember(uint64 guid) const
|
||||
{
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (itr->Guid == guid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 ArenaTeam::GetPoints(uint32 memberRating)
|
||||
{
|
||||
// Returns how many points would be awarded with this team type with this rating
|
||||
float points;
|
||||
|
||||
uint32 rating = memberRating + 150 < Stats.Rating ? memberRating : Stats.Rating;
|
||||
|
||||
if (rating <= 1500)
|
||||
{
|
||||
if (sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) < 6)
|
||||
points = (float)rating * 0.22f + 14.0f;
|
||||
else
|
||||
points = 344;
|
||||
}
|
||||
else
|
||||
points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating));
|
||||
|
||||
// Type penalties for teams < 5v5
|
||||
if (Type == ARENA_TEAM_2v2)
|
||||
points *= 0.76f;
|
||||
else if (Type == ARENA_TEAM_3v3)
|
||||
points *= 0.88f;
|
||||
|
||||
points *= sWorld->getRate(RATE_ARENA_POINTS);
|
||||
|
||||
return (uint32) points;
|
||||
}
|
||||
|
||||
uint32 ArenaTeam::GetAverageMMR(Group* group) const
|
||||
{
|
||||
if (!group)
|
||||
return 0;
|
||||
|
||||
uint32 matchMakerRating = 0;
|
||||
uint32 playerDivider = 0;
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
// Skip if player is not online
|
||||
if (!ObjectAccessor::FindPlayerInOrOutOfWorld(itr->Guid))
|
||||
continue;
|
||||
|
||||
// Skip if player is not member of group
|
||||
if (!group->IsMember(itr->Guid))
|
||||
continue;
|
||||
|
||||
matchMakerRating += itr->MatchMakerRating;
|
||||
++playerDivider;
|
||||
}
|
||||
|
||||
// x/0 = crash
|
||||
if (playerDivider == 0)
|
||||
playerDivider = 1;
|
||||
|
||||
matchMakerRating /= playerDivider;
|
||||
|
||||
return matchMakerRating;
|
||||
}
|
||||
|
||||
float ArenaTeam::GetChanceAgainst(uint32 ownRating, uint32 opponentRating)
|
||||
{
|
||||
// Returns the chance to win against a team with the given rating, used in the rating adjustment calculation
|
||||
// ELO system
|
||||
return 1.0f / (1.0f + exp(log(10.0f) * (float)((float)opponentRating - (float)ownRating) / 650.0f));
|
||||
}
|
||||
|
||||
int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float& confidence_factor*/)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
float won_mod = (won) ? 1.0f : 0.0f;
|
||||
float mod = won_mod - chance;
|
||||
|
||||
// Work in progress:
|
||||
/*
|
||||
// This is a simulation, as there is not much info on how it really works
|
||||
float confidence_mod = min(1.0f - fabs(mod), 0.5f);
|
||||
|
||||
// Apply confidence factor to the mod:
|
||||
mod *= confidence_factor
|
||||
|
||||
// And only after that update the new confidence factor
|
||||
confidence_factor -= ((confidence_factor - 1.0f) * confidence_mod) / confidence_factor;
|
||||
*/
|
||||
|
||||
// Real rating modification
|
||||
mod *= 24.0f;
|
||||
|
||||
return (int32)ceil(mod);
|
||||
}
|
||||
|
||||
int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float confidence_factor*/)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
float won_mod = (won) ? 1.0f : 0.0f;
|
||||
|
||||
// Calculate the rating modification
|
||||
float mod;
|
||||
|
||||
// TODO: Replace this hack with using the confidence factor (limiting the factor to 2.0f)
|
||||
if (won && ownRating < 1300)
|
||||
{
|
||||
if (ownRating < 1000)
|
||||
mod = 48.0f * (won_mod - chance);
|
||||
else
|
||||
mod = (24.0f + (24.0f * (1300.0f - float(ownRating)) / 300.0f)) * (won_mod - chance);
|
||||
}
|
||||
else
|
||||
mod = 24.0f * (won_mod - chance);
|
||||
|
||||
return (int32)ceil(mod);
|
||||
}
|
||||
|
||||
void ArenaTeam::FinishGame(int32 mod, const Map* bgMap)
|
||||
{
|
||||
// Rating can only drop to 0
|
||||
if (int32(Stats.Rating) + mod < 0)
|
||||
Stats.Rating = 0;
|
||||
else
|
||||
{
|
||||
Stats.Rating += mod;
|
||||
|
||||
// Check if rating related achivements are met
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (Player* member = ObjectAccessor::FindPlayerInOrOutOfWorld(itr->Guid))
|
||||
if (member->FindMap() == bgMap)
|
||||
member->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING, Stats.Rating, Type);
|
||||
}
|
||||
|
||||
// Update number of games played per season or week
|
||||
Stats.WeekGames += 1;
|
||||
Stats.SeasonGames += 1;
|
||||
|
||||
// Update team's rank, start with rank 1 and increase until no team with more rating was found
|
||||
Stats.Rank = 1;
|
||||
ArenaTeamMgr::ArenaTeamContainer::const_iterator i = sArenaTeamMgr->GetArenaTeamMapBegin();
|
||||
for (; i != sArenaTeamMgr->GetArenaTeamMapEnd(); ++i)
|
||||
{
|
||||
if (i->second->GetType() == Type && i->second->GetStats().Rating > Stats.Rating)
|
||||
++Stats.Rank;
|
||||
}
|
||||
}
|
||||
|
||||
int32 ArenaTeam::WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change, const Map* bgMap)
|
||||
{
|
||||
// Called when the team has won
|
||||
// Change in Matchmaker rating
|
||||
int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, true);
|
||||
|
||||
// Change in Team Rating
|
||||
rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, true);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(rating_change, bgMap);
|
||||
|
||||
// Update number of wins per season and week
|
||||
Stats.WeekWins += 1;
|
||||
Stats.SeasonWins += 1;
|
||||
|
||||
// Return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
int32 ArenaTeam::LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change, const Map* bgMap)
|
||||
{
|
||||
// Called when the team has lost
|
||||
// Change in Matchmaker Rating
|
||||
int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, false);
|
||||
|
||||
// Change in Team Rating
|
||||
rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, false);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(rating_change, bgMap);
|
||||
|
||||
// return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
|
||||
{
|
||||
// Called for each participant of a match after losing
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
if (itr->Guid == player->GetGUID())
|
||||
{
|
||||
// Update personal rating
|
||||
int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, false);
|
||||
itr->ModifyPersonalRating(player, mod, GetType());
|
||||
|
||||
// Update matchmaker rating
|
||||
itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
|
||||
|
||||
// Update personal played stats
|
||||
itr->WeekGames +=1;
|
||||
itr->SeasonGames +=1;
|
||||
|
||||
// update the unit fields
|
||||
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_WEEK, itr->WeekGames);
|
||||
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_SEASON, itr->SeasonGames);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
|
||||
{
|
||||
// called for each participant after winning a match
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
if (itr->Guid == player->GetGUID())
|
||||
{
|
||||
// update personal rating
|
||||
int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, true);
|
||||
itr->ModifyPersonalRating(player, mod, GetType());
|
||||
|
||||
// update matchmaker rating (pussywizard: but don't allow it to go over team rating)
|
||||
if (itr->MatchMakerRating < Stats.Rating)
|
||||
{
|
||||
mod = std::min(MatchmakerRatingChange, Stats.Rating - itr->MatchMakerRating);
|
||||
itr->ModifyMatchmakerRating(mod, GetSlot());
|
||||
}
|
||||
|
||||
// update personal stats
|
||||
itr->WeekGames +=1;
|
||||
itr->SeasonGames +=1;
|
||||
itr->SeasonWins += 1;
|
||||
itr->WeekWins += 1;
|
||||
// update unit fields
|
||||
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_WEEK, itr->WeekGames);
|
||||
player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_SEASON, itr->SeasonGames);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::UpdateArenaPointsHelper(std::map<uint32, uint32>& playerPoints)
|
||||
{
|
||||
// Called after a match has ended and the stats are already modified
|
||||
// Helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
|
||||
// 10 played games per week is a minimum
|
||||
if (Stats.WeekGames < 10)
|
||||
return;
|
||||
|
||||
// To get points, a player has to participate in at least 30% of the matches
|
||||
uint32 requiredGames = (uint32)ceil(Stats.WeekGames * 0.3f);
|
||||
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
// The player participated in enough games, update his points
|
||||
uint32 pointsToAdd = 0;
|
||||
if (itr->WeekGames >= requiredGames)
|
||||
pointsToAdd = GetPoints(itr->PersonalRating);
|
||||
|
||||
std::map<uint32, uint32>::iterator plr_itr = playerPoints.find(GUID_LOPART(itr->Guid));
|
||||
if (plr_itr != playerPoints.end())
|
||||
{
|
||||
// Check if there is already more points
|
||||
if (plr_itr->second < pointsToAdd)
|
||||
playerPoints[GUID_LOPART(itr->Guid)] = pointsToAdd;
|
||||
}
|
||||
else
|
||||
playerPoints[GUID_LOPART(itr->Guid)] = pointsToAdd;
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::SaveToDB()
|
||||
{
|
||||
// Save team and member stats to db
|
||||
// Called after a match has ended or when calculating arena_points
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_STATS);
|
||||
stmt->setUInt16(0, Stats.Rating);
|
||||
stmt->setUInt16(1, Stats.WeekGames);
|
||||
stmt->setUInt16(2, Stats.WeekWins);
|
||||
stmt->setUInt16(3, Stats.SeasonGames);
|
||||
stmt->setUInt16(4, Stats.SeasonWins);
|
||||
stmt->setUInt32(5, Stats.Rank);
|
||||
stmt->setUInt32(6, GetId());
|
||||
trans->Append(stmt);
|
||||
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_MEMBER);
|
||||
stmt->setUInt16(0, itr->PersonalRating);
|
||||
stmt->setUInt16(1, itr->WeekGames);
|
||||
stmt->setUInt16(2, itr->WeekWins);
|
||||
stmt->setUInt16(3, itr->SeasonGames);
|
||||
stmt->setUInt16(4, itr->SeasonWins);
|
||||
stmt->setUInt32(5, GetId());
|
||||
stmt->setUInt32(6, GUID_LOPART(itr->Guid));
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHARACTER_ARENA_STATS);
|
||||
stmt->setUInt32(0, GUID_LOPART(itr->Guid));
|
||||
stmt->setUInt8(1, GetSlot());
|
||||
stmt->setUInt16(2, itr->MatchMakerRating);
|
||||
stmt->setUInt16(3, itr->MaxMMR);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void ArenaTeam::FinishWeek()
|
||||
{
|
||||
// Reset team stats
|
||||
Stats.WeekGames = 0;
|
||||
Stats.WeekWins = 0;
|
||||
|
||||
// Reset member stats
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
{
|
||||
itr->WeekGames = 0;
|
||||
itr->WeekWins = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ArenaTeam::IsFighting() const
|
||||
{
|
||||
for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (Player* player = ObjectAccessor::FindPlayer(itr->Guid))
|
||||
if (player->GetMap()->IsBattleArena())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ArenaTeamMember* ArenaTeam::GetMember(const std::string& name)
|
||||
{
|
||||
return GetMember(sObjectMgr->GetPlayerGUIDByName(name));
|
||||
}
|
||||
|
||||
ArenaTeamMember* ArenaTeam::GetMember(uint64 guid)
|
||||
{
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
if (itr->Guid == guid)
|
||||
return &(*itr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_ARENATEAM_H
|
||||
#define AZEROTHCORE_ARENATEAM_H
|
||||
|
||||
#include "QueryResult.h"
|
||||
#include "Map.h"
|
||||
#include <ace/Singleton.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
class WorldSession;
|
||||
class WorldPacket;
|
||||
class Player;
|
||||
class Group;
|
||||
|
||||
enum ArenaTeamCommandTypes
|
||||
{
|
||||
ERR_ARENA_TEAM_CREATE_S = 0x00,
|
||||
ERR_ARENA_TEAM_INVITE_SS = 0x01,
|
||||
ERR_ARENA_TEAM_QUIT_S = 0x03,
|
||||
ERR_ARENA_TEAM_FOUNDER_S = 0x0E
|
||||
};
|
||||
|
||||
enum ArenaTeamCommandErrors
|
||||
{
|
||||
ERR_ARENA_TEAM_INTERNAL = 0x01,
|
||||
ERR_ALREADY_IN_ARENA_TEAM = 0x02,
|
||||
ERR_ALREADY_IN_ARENA_TEAM_S = 0x03,
|
||||
ERR_INVITED_TO_ARENA_TEAM = 0x04,
|
||||
ERR_ALREADY_INVITED_TO_ARENA_TEAM_S = 0x05,
|
||||
ERR_ARENA_TEAM_NAME_INVALID = 0x06,
|
||||
ERR_ARENA_TEAM_NAME_EXISTS_S = 0x07,
|
||||
ERR_ARENA_TEAM_LEADER_LEAVE_S = 0x08,
|
||||
ERR_ARENA_TEAM_PERMISSIONS = 0x08,
|
||||
ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM = 0x09,
|
||||
ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS = 0x0A,
|
||||
ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S = 0x0B,
|
||||
ERR_ARENA_TEAM_NOT_ALLIED = 0x0C,
|
||||
ERR_ARENA_TEAM_IGNORING_YOU_S = 0x13,
|
||||
ERR_ARENA_TEAM_TARGET_TOO_LOW_S = 0x15,
|
||||
ERR_ARENA_TEAM_TARGET_TOO_HIGH_S = 0x16,
|
||||
ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S = 0x17,
|
||||
ERR_ARENA_TEAM_NOT_FOUND = 0x1B,
|
||||
ERR_ARENA_TEAMS_LOCKED = 0x1E
|
||||
};
|
||||
|
||||
enum ArenaTeamEvents
|
||||
{
|
||||
ERR_ARENA_TEAM_JOIN_SS = 3, // player name + arena team name
|
||||
ERR_ARENA_TEAM_LEAVE_SS = 4, // player name + arena team name
|
||||
ERR_ARENA_TEAM_REMOVE_SSS = 5, // player name + arena team name + captain name
|
||||
ERR_ARENA_TEAM_LEADER_IS_SS = 6, // player name + arena team name
|
||||
ERR_ARENA_TEAM_LEADER_CHANGED_SSS = 7, // old captain + new captain + arena team name
|
||||
ERR_ARENA_TEAM_DISBANDED_S = 8 // captain name + arena team name
|
||||
};
|
||||
|
||||
/*
|
||||
need info how to send these ones:
|
||||
ERR_ARENA_TEAM_YOU_JOIN_S - client show it automatically when accept invite
|
||||
ERR_ARENA_TEAM_TARGET_TOO_LOW_S
|
||||
ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S
|
||||
ERR_ARENA_TEAM_LEVEL_TOO_LOW_I
|
||||
*/
|
||||
|
||||
enum ArenaTeamTypes
|
||||
{
|
||||
ARENA_TEAM_2v2 = 2,
|
||||
ARENA_TEAM_3v3 = 3,
|
||||
ARENA_TEAM_5v5 = 5
|
||||
};
|
||||
|
||||
struct ArenaTeamMember
|
||||
{
|
||||
uint64 Guid;
|
||||
//std::string Name;
|
||||
uint8 Class;
|
||||
uint16 WeekGames;
|
||||
uint16 WeekWins;
|
||||
uint16 SeasonGames;
|
||||
uint16 SeasonWins;
|
||||
uint16 PersonalRating;
|
||||
uint16 MatchMakerRating;
|
||||
uint16 MaxMMR;
|
||||
|
||||
void ModifyPersonalRating(Player* player, int32 mod, uint32 type);
|
||||
void ModifyMatchmakerRating(int32 mod, uint32 slot);
|
||||
};
|
||||
|
||||
struct ArenaTeamStats
|
||||
{
|
||||
uint16 Rating;
|
||||
uint16 WeekGames;
|
||||
uint16 WeekWins;
|
||||
uint16 SeasonGames;
|
||||
uint16 SeasonWins;
|
||||
uint32 Rank;
|
||||
};
|
||||
|
||||
#define MAX_ARENA_SLOT 3 // 0..2 slots
|
||||
|
||||
class ArenaTeam
|
||||
{
|
||||
public:
|
||||
ArenaTeam();
|
||||
~ArenaTeam();
|
||||
|
||||
bool Create(uint64 captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor);
|
||||
void Disband(WorldSession* session);
|
||||
|
||||
typedef std::list<ArenaTeamMember> MemberList;
|
||||
|
||||
uint32 GetId() const { return TeamId; }
|
||||
uint32 GetType() const { return Type; }
|
||||
uint8 GetSlot() const { return GetSlotByType(GetType()); }
|
||||
static uint8 GetSlotByType(uint32 type);
|
||||
uint64 GetCaptain() const { return CaptainGuid; }
|
||||
std::string const& GetName() const { return TeamName; }
|
||||
const ArenaTeamStats& GetStats() const { return Stats; }
|
||||
|
||||
uint32 GetRating() const { return Stats.Rating; }
|
||||
uint32 GetAverageMMR(Group* group) const;
|
||||
|
||||
void SetCaptain(uint64 guid);
|
||||
bool AddMember(uint64 playerGuid);
|
||||
|
||||
// Shouldn't be uint64 ed, because than can reference guid from members on Disband
|
||||
// and this method removes given record from list. So invalid reference can happen.
|
||||
void DelMember(uint64 guid, bool cleanDb);
|
||||
|
||||
size_t GetMembersSize() const { return Members.size(); }
|
||||
bool Empty() const { return Members.empty(); }
|
||||
MemberList::iterator m_membersBegin() { return Members.begin(); }
|
||||
MemberList::iterator m_membersEnd() { return Members.end(); }
|
||||
bool IsMember(uint64 guid) const;
|
||||
|
||||
ArenaTeamMember* GetMember(uint64 guid);
|
||||
ArenaTeamMember* GetMember(std::string const& name);
|
||||
|
||||
bool IsFighting() const;
|
||||
|
||||
bool LoadArenaTeamFromDB(QueryResult arenaTeamDataResult);
|
||||
bool LoadMembersFromDB(QueryResult arenaTeamMembersResult);
|
||||
void LoadStatsFromDB(uint32 ArenaTeamId);
|
||||
void SaveToDB();
|
||||
|
||||
void BroadcastPacket(WorldPacket* packet);
|
||||
void BroadcastEvent(ArenaTeamEvents event, uint64 guid, uint8 strCount, std::string const& str1, std::string const& str2, std::string const& str3);
|
||||
void NotifyStatsChanged();
|
||||
|
||||
void MassInviteToEvent(WorldSession* session);
|
||||
|
||||
void Roster(WorldSession* session);
|
||||
void Query(WorldSession* session);
|
||||
void SendStats(WorldSession* session);
|
||||
void Inspect(WorldSession* session, uint64 guid);
|
||||
|
||||
uint32 GetPoints(uint32 MemberRating);
|
||||
int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
|
||||
int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
|
||||
float GetChanceAgainst(uint32 ownRating, uint32 opponentRating);
|
||||
int32 WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change, const Map* bgMap);
|
||||
void MemberWon(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange);
|
||||
int32 LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change, const Map* bgMap);
|
||||
void MemberLost(Player* player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12);
|
||||
|
||||
void UpdateArenaPointsHelper(std::map<uint32, uint32> & PlayerPoints);
|
||||
|
||||
void FinishWeek();
|
||||
void FinishGame(int32 mod, const Map* bgMap);
|
||||
|
||||
protected:
|
||||
|
||||
uint32 TeamId;
|
||||
uint8 Type;
|
||||
std::string TeamName;
|
||||
uint64 CaptainGuid;
|
||||
|
||||
uint32 BackgroundColor; // ARGB format
|
||||
uint8 EmblemStyle; // icon id
|
||||
uint32 EmblemColor; // ARGB format
|
||||
uint8 BorderStyle; // border image id
|
||||
uint32 BorderColor; // ARGB format
|
||||
|
||||
MemberList Members;
|
||||
ArenaTeamStats Stats;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Define.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "World.h"
|
||||
#include "Log.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Language.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
|
||||
ArenaTeamMgr::ArenaTeamMgr()
|
||||
{
|
||||
NextArenaTeamId = 1;
|
||||
LastArenaLogId = 0;
|
||||
}
|
||||
|
||||
ArenaTeamMgr::~ArenaTeamMgr()
|
||||
{
|
||||
for (ArenaTeamContainer::iterator itr = ArenaTeamStore.begin(); itr != ArenaTeamStore.end(); ++itr)
|
||||
delete itr->second;
|
||||
}
|
||||
|
||||
// Arena teams collection
|
||||
ArenaTeam* ArenaTeamMgr::GetArenaTeamById(uint32 arenaTeamId) const
|
||||
{
|
||||
ArenaTeamContainer::const_iterator itr = ArenaTeamStore.find(arenaTeamId);
|
||||
if (itr != ArenaTeamStore.end())
|
||||
return itr->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ArenaTeam* ArenaTeamMgr::GetArenaTeamByName(const std::string& arenaTeamName) const
|
||||
{
|
||||
std::string search = arenaTeamName;
|
||||
std::transform(search.begin(), search.end(), search.begin(), ::toupper);
|
||||
for (ArenaTeamContainer::const_iterator itr = ArenaTeamStore.begin(); itr != ArenaTeamStore.end(); ++itr)
|
||||
{
|
||||
std::string teamName = itr->second->GetName();
|
||||
std::transform(teamName.begin(), teamName.end(), teamName.begin(), ::toupper);
|
||||
if (search == teamName)
|
||||
return itr->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ArenaTeam* ArenaTeamMgr::GetArenaTeamByCaptain(uint64 guid) const
|
||||
{
|
||||
for (ArenaTeamContainer::const_iterator itr = ArenaTeamStore.begin(); itr != ArenaTeamStore.end(); ++itr)
|
||||
if (itr->second->GetCaptain() == guid)
|
||||
return itr->second;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ArenaTeamMgr::AddArenaTeam(ArenaTeam* arenaTeam)
|
||||
{
|
||||
ArenaTeamStore[arenaTeam->GetId()] = arenaTeam;
|
||||
}
|
||||
|
||||
void ArenaTeamMgr::RemoveArenaTeam(uint32 arenaTeamId)
|
||||
{
|
||||
ArenaTeamStore.erase(arenaTeamId);
|
||||
}
|
||||
|
||||
uint32 ArenaTeamMgr::GenerateArenaTeamId()
|
||||
{
|
||||
if (NextArenaTeamId >= 0xFFFFFFFE)
|
||||
{
|
||||
sLog->outError("Arena team ids overflow!! Can't continue, shutting down server. ");
|
||||
World::StopNow(ERROR_EXIT_CODE);
|
||||
}
|
||||
return NextArenaTeamId++;
|
||||
}
|
||||
|
||||
void ArenaTeamMgr::LoadArenaTeams()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// Clean out the trash before loading anything
|
||||
CharacterDatabase.Execute("DELETE FROM arena_team_member WHERE arenaTeamId NOT IN (SELECT arenaTeamId FROM arena_team)"); // One-time query
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
QueryResult result = CharacterDatabase.Query("SELECT arenaTeamId, name, captainGuid, type, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor, "
|
||||
// 9 10 11 12 13 14
|
||||
"rating, weekGames, weekWins, seasonGames, seasonWins, rank FROM arena_team ORDER BY arenaTeamId ASC");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
sLog->outString(">> Loaded 0 arena teams. DB table `arena_team` is empty!");
|
||||
sLog->outString();
|
||||
return;
|
||||
}
|
||||
|
||||
QueryResult result2 = CharacterDatabase.Query(
|
||||
// 0 1 2 3 4 5 6 7 8 9 10
|
||||
"SELECT arenaTeamId, atm.guid, atm.weekGames, atm.weekWins, atm.seasonGames, atm.seasonWins, c.name, class, personalRating, matchMakerRating, maxMMR FROM arena_team_member atm"
|
||||
" INNER JOIN arena_team ate USING (arenaTeamId)"
|
||||
" LEFT JOIN characters AS c ON atm.guid = c.guid"
|
||||
" LEFT JOIN character_arena_stats AS cas ON c.guid = cas.guid AND (cas.slot = 0 AND ate.type = 2 OR cas.slot = 1 AND ate.type = 3 OR cas.slot = 2 AND ate.type = 5)"
|
||||
" ORDER BY atm.arenateamid ASC");
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
ArenaTeam* newArenaTeam = new ArenaTeam;
|
||||
|
||||
if (!newArenaTeam->LoadArenaTeamFromDB(result) || !newArenaTeam->LoadMembersFromDB(result2))
|
||||
{
|
||||
newArenaTeam->Disband(NULL);
|
||||
delete newArenaTeam;
|
||||
continue;
|
||||
}
|
||||
|
||||
AddArenaTeam(newArenaTeam);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
sLog->outString(">> Loaded %u arena teams in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
sLog->outString();
|
||||
}
|
||||
|
||||
void ArenaTeamMgr::DistributeArenaPoints()
|
||||
{
|
||||
// Used to distribute arena points based on last week's stats
|
||||
sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_START);
|
||||
|
||||
sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_START);
|
||||
|
||||
// Temporary structure for storing maximum points to add values for all players
|
||||
std::map<uint32, uint32> PlayerPoints;
|
||||
|
||||
// At first update all points for all team members
|
||||
for (ArenaTeamContainer::iterator teamItr = GetArenaTeamMapBegin(); teamItr != GetArenaTeamMapEnd(); ++teamItr)
|
||||
if (ArenaTeam* at = teamItr->second)
|
||||
at->UpdateArenaPointsHelper(PlayerPoints);
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
PreparedStatement* stmt;
|
||||
|
||||
// Cycle that gives points to all players
|
||||
for (std::map<uint32, uint32>::iterator playerItr = PlayerPoints.begin(); playerItr != PlayerPoints.end(); ++playerItr)
|
||||
{
|
||||
// Add points to player if online
|
||||
if (Player* player = HashMapHolder<Player>::Find(playerItr->first))
|
||||
player->ModifyArenaPoints(playerItr->second, &trans);
|
||||
else // Update database
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ARENA_POINTS);
|
||||
stmt->setUInt32(0, playerItr->second);
|
||||
stmt->setUInt32(1, playerItr->first);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
PlayerPoints.clear();
|
||||
|
||||
sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_ONLINE_END);
|
||||
|
||||
sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_START);
|
||||
for (ArenaTeamContainer::iterator titr = GetArenaTeamMapBegin(); titr != GetArenaTeamMapEnd(); ++titr)
|
||||
{
|
||||
if (ArenaTeam* at = titr->second)
|
||||
{
|
||||
at->FinishWeek();
|
||||
at->SaveToDB();
|
||||
at->NotifyStatsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_TEAM_END);
|
||||
|
||||
sWorld->SendWorldText(LANG_DIST_ARENA_POINTS_END);
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _ARENATEAMMGR_H
|
||||
#define _ARENATEAMMGR_H
|
||||
|
||||
#include "ArenaTeam.h"
|
||||
|
||||
class ArenaTeamMgr
|
||||
{
|
||||
friend class ACE_Singleton<ArenaTeamMgr, ACE_Null_Mutex>;
|
||||
ArenaTeamMgr();
|
||||
~ArenaTeamMgr();
|
||||
|
||||
public:
|
||||
typedef UNORDERED_MAP<uint32, ArenaTeam*> ArenaTeamContainer;
|
||||
|
||||
ArenaTeam* GetArenaTeamById(uint32 arenaTeamId) const;
|
||||
ArenaTeam* GetArenaTeamByName(std::string const& arenaTeamName) const;
|
||||
ArenaTeam* GetArenaTeamByCaptain(uint64 guid) const;
|
||||
|
||||
void LoadArenaTeams();
|
||||
void AddArenaTeam(ArenaTeam* arenaTeam);
|
||||
void RemoveArenaTeam(uint32 Id);
|
||||
|
||||
ArenaTeamContainer::iterator GetArenaTeamMapBegin() { return ArenaTeamStore.begin(); }
|
||||
ArenaTeamContainer::iterator GetArenaTeamMapEnd() { return ArenaTeamStore.end(); }
|
||||
|
||||
void DistributeArenaPoints();
|
||||
|
||||
uint32 GenerateArenaTeamId();
|
||||
void SetNextArenaTeamId(uint32 Id) { NextArenaTeamId = Id; }
|
||||
|
||||
uint32 GetNextArenaLogId() { return ++LastArenaLogId; }
|
||||
void SetLastArenaLogId(uint32 id) { LastArenaLogId = id; }
|
||||
|
||||
protected:
|
||||
uint32 NextArenaTeamId;
|
||||
ArenaTeamContainer ArenaTeamStore;
|
||||
uint32 LastArenaLogId;
|
||||
};
|
||||
|
||||
#define sArenaTeamMgr ACE_Singleton<ArenaTeamMgr, ACE_Null_Mutex>::instance()
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,764 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUND_H
|
||||
#define __BATTLEGROUND_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "DBCEnums.h"
|
||||
#include "GameObject.h"
|
||||
|
||||
class Creature;
|
||||
class GameObject;
|
||||
class Group;
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
class BattlegroundMap;
|
||||
class BattlegroundAV;
|
||||
class BattlegroundWS;
|
||||
class BattlegroundAB;
|
||||
class BattlegroundNA;
|
||||
class BattlegroundBE;
|
||||
class BattlegroundEY;
|
||||
class BattlegroundRL;
|
||||
class BattlegroundSA;
|
||||
class BattlegroundDS;
|
||||
class BattlegroundRV;
|
||||
class BattlegroundIC;
|
||||
|
||||
struct PvPDifficultyEntry;
|
||||
struct WorldSafeLocsEntry;
|
||||
|
||||
enum BattlegroundDesertionType
|
||||
{
|
||||
BG_DESERTION_TYPE_LEAVE_BG = 0, // player leaves the BG
|
||||
BG_DESERTION_TYPE_OFFLINE = 1, // player is kicked from BG because offline
|
||||
BG_DESERTION_TYPE_LEAVE_QUEUE = 2, // player is invited to join and refuses to do it
|
||||
BG_DESERTION_TYPE_NO_ENTER_BUTTON = 3, // player is invited to join and do nothing (time expires)
|
||||
BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out
|
||||
};
|
||||
|
||||
enum BattlegroundSounds
|
||||
{
|
||||
SOUND_HORDE_WINS = 8454,
|
||||
SOUND_ALLIANCE_WINS = 8455,
|
||||
SOUND_BG_START = 3439,
|
||||
SOUND_BG_START_L70ETC = 11803,
|
||||
};
|
||||
|
||||
enum BattlegroundQuests
|
||||
{
|
||||
SPELL_WS_QUEST_REWARD = 43483,
|
||||
SPELL_AB_QUEST_REWARD = 43484,
|
||||
SPELL_AV_QUEST_REWARD = 43475,
|
||||
SPELL_AV_QUEST_KILLED_BOSS = 23658,
|
||||
SPELL_EY_QUEST_REWARD = 43477,
|
||||
SPELL_SA_QUEST_REWARD = 61213,
|
||||
SPELL_AB_QUEST_REWARD_4_BASES = 24061,
|
||||
SPELL_AB_QUEST_REWARD_5_BASES = 24064
|
||||
};
|
||||
|
||||
enum BattlegroundMarks
|
||||
{
|
||||
SPELL_WS_MARK_LOSER = 24950,
|
||||
SPELL_WS_MARK_WINNER = 24951,
|
||||
SPELL_AB_MARK_LOSER = 24952,
|
||||
SPELL_AB_MARK_WINNER = 24953,
|
||||
SPELL_AV_MARK_LOSER = 24954,
|
||||
SPELL_AV_MARK_WINNER = 24955,
|
||||
SPELL_SA_MARK_WINNER = 61160,
|
||||
SPELL_SA_MARK_LOSER = 61159,
|
||||
SPELL_WG_MARK_WINNER = 56902,
|
||||
ITEM_AV_MARK_OF_HONOR = 20560,
|
||||
ITEM_WS_MARK_OF_HONOR = 20558,
|
||||
ITEM_AB_MARK_OF_HONOR = 20559,
|
||||
ITEM_EY_MARK_OF_HONOR = 29024,
|
||||
ITEM_SA_MARK_OF_HONOR = 42425,
|
||||
ITEM_IC_MARK_OF_HONOR = 47395,
|
||||
};
|
||||
|
||||
enum BattlegroundMarksCount
|
||||
{
|
||||
ITEM_WINNER_COUNT = 3,
|
||||
ITEM_LOSER_COUNT = 1
|
||||
};
|
||||
|
||||
enum BattlegroundCreatures
|
||||
{
|
||||
BG_CREATURE_ENTRY_A_SPIRITGUIDE = 13116, // alliance
|
||||
BG_CREATURE_ENTRY_H_SPIRITGUIDE = 13117, // horde
|
||||
};
|
||||
|
||||
enum BattlegroundSpells
|
||||
{
|
||||
SPELL_WAITING_FOR_RESURRECT = 2584, // Waiting to Resurrect
|
||||
SPELL_SPIRIT_HEAL_CHANNEL = 22011, // Spirit Heal Channel
|
||||
SPELL_SPIRIT_HEAL = 22012, // Spirit Heal
|
||||
SPELL_RESURRECTION_VISUAL = 24171, // Resurrection Impact Visual
|
||||
SPELL_ARENA_PREPARATION = 32727, // use this one, 32728 not correct
|
||||
SPELL_ALLIANCE_GOLD_FLAG = 32724,
|
||||
SPELL_ALLIANCE_GREEN_FLAG = 32725,
|
||||
SPELL_HORDE_GOLD_FLAG = 35774,
|
||||
SPELL_HORDE_GREEN_FLAG = 35775,
|
||||
SPELL_PREPARATION = 44521, // Preparation
|
||||
SPELL_SPIRIT_HEAL_MANA = 44535, // Spirit Heal
|
||||
SPELL_RECENTLY_DROPPED_FLAG = 42792, // Recently Dropped Flag
|
||||
SPELL_AURA_PLAYER_INACTIVE = 43681, // Inactive
|
||||
SPELL_HONORABLE_DEFENDER_25Y = 68652, // +50% honor when standing at a capture point that you control, 25yards radius (added in 3.2)
|
||||
SPELL_HONORABLE_DEFENDER_60Y = 66157, // +50% honor when standing at a capture point that you control, 60yards radius (added in 3.2), probably for 40+ player battlegrounds
|
||||
SPELL_THE_LAST_STANDING = 26549, // Arena achievement related
|
||||
};
|
||||
|
||||
enum BattlegroundReputations
|
||||
{
|
||||
BG_REP_AV_HORDE = 729,
|
||||
BG_REP_AV_ALLIANCE = 730,
|
||||
BG_REP_AB_HORDE = 510,
|
||||
BG_REP_AB_ALLIANCE = 509,
|
||||
BG_REP_WS_HORDE = 889,
|
||||
BG_REP_WS_ALLIANCE = 890,
|
||||
};
|
||||
|
||||
enum BattlegroundTimeIntervals
|
||||
{
|
||||
CHECK_PLAYER_POSITION_INVERVAL = 9000, // ms
|
||||
RESURRECTION_INTERVAL = 30000, // ms
|
||||
//REMIND_INTERVAL = 10000, // ms
|
||||
INVITATION_REMIND_TIME = 20000, // ms
|
||||
INVITE_ACCEPT_WAIT_TIME = 60000, // ms
|
||||
TIME_TO_AUTOREMOVE = 120000, // ms
|
||||
MAX_OFFLINE_TIME = 300, // secs
|
||||
RESPAWN_ONE_DAY = 86400, // secs
|
||||
RESPAWN_IMMEDIATELY = 0, // secs
|
||||
BUFF_RESPAWN_TIME = 180, // secs
|
||||
};
|
||||
|
||||
enum BattlegroundStartTimeIntervals
|
||||
{
|
||||
BG_START_DELAY_2M = 120000, // ms (2 minutes)
|
||||
BG_START_DELAY_1M = 60000, // ms (1 minute)
|
||||
BG_START_DELAY_30S = 30000, // ms (30 seconds)
|
||||
BG_START_DELAY_15S = 15000, // ms (15 seconds) Used only in arena
|
||||
BG_START_DELAY_NONE = 0, // ms
|
||||
};
|
||||
|
||||
#define BATTLEGROUND_UPDATE_INTERVAL 1000
|
||||
|
||||
enum BattlegroundBuffObjects
|
||||
{
|
||||
BG_OBJECTID_SPEEDBUFF_ENTRY = 179871,
|
||||
BG_OBJECTID_REGENBUFF_ENTRY = 179904,
|
||||
BG_OBJECTID_BERSERKERBUFF_ENTRY = 179905
|
||||
};
|
||||
|
||||
enum BattlegroundRandomRewards
|
||||
{
|
||||
BG_REWARD_WINNER_HONOR_FIRST = 30,
|
||||
BG_REWARD_WINNER_ARENA_FIRST = 25,
|
||||
BG_REWARD_WINNER_HONOR_LAST = 15,
|
||||
BG_REWARD_WINNER_ARENA_LAST = 0,
|
||||
BG_REWARD_LOSER_HONOR_FIRST = 5,
|
||||
BG_REWARD_LOSER_HONOR_LAST = 5
|
||||
};
|
||||
|
||||
const uint32 Buff_Entries[3] = { BG_OBJECTID_SPEEDBUFF_ENTRY, BG_OBJECTID_REGENBUFF_ENTRY, BG_OBJECTID_BERSERKERBUFF_ENTRY };
|
||||
|
||||
enum BattlegroundStatus
|
||||
{
|
||||
STATUS_NONE = 0, // first status, should mean bg is not instance
|
||||
STATUS_WAIT_QUEUE = 1, // means bg is empty and waiting for queue
|
||||
STATUS_WAIT_JOIN = 2, // this means, that BG has already started and it is waiting for more players
|
||||
STATUS_IN_PROGRESS = 3, // means bg is running
|
||||
STATUS_WAIT_LEAVE = 4 // means some faction has won BG and it is ending
|
||||
};
|
||||
|
||||
enum BattlegroundTeams
|
||||
{
|
||||
BG_TEAMS_COUNT = 2
|
||||
};
|
||||
|
||||
struct BattlegroundObjectInfo
|
||||
{
|
||||
BattlegroundObjectInfo() : object(NULL), timer(0), spellid(0) {}
|
||||
|
||||
GameObject *object;
|
||||
int32 timer;
|
||||
uint32 spellid;
|
||||
};
|
||||
|
||||
enum ScoreType
|
||||
{
|
||||
SCORE_KILLING_BLOWS = 1,
|
||||
SCORE_DEATHS = 2,
|
||||
SCORE_HONORABLE_KILLS = 3,
|
||||
SCORE_BONUS_HONOR = 4,
|
||||
//EY, but in MSG_PVP_LOG_DATA opcode!
|
||||
SCORE_DAMAGE_DONE = 5,
|
||||
SCORE_HEALING_DONE = 6,
|
||||
//WS
|
||||
SCORE_FLAG_CAPTURES = 7,
|
||||
SCORE_FLAG_RETURNS = 8,
|
||||
//AB and IC
|
||||
SCORE_BASES_ASSAULTED = 9,
|
||||
SCORE_BASES_DEFENDED = 10,
|
||||
//AV
|
||||
SCORE_GRAVEYARDS_ASSAULTED = 11,
|
||||
SCORE_GRAVEYARDS_DEFENDED = 12,
|
||||
SCORE_TOWERS_ASSAULTED = 13,
|
||||
SCORE_TOWERS_DEFENDED = 14,
|
||||
SCORE_MINES_CAPTURED = 15,
|
||||
SCORE_LEADERS_KILLED = 16,
|
||||
SCORE_SECONDARY_OBJECTIVES = 17,
|
||||
//SOTA
|
||||
SCORE_DESTROYED_DEMOLISHER = 18,
|
||||
SCORE_DESTROYED_WALL = 19,
|
||||
};
|
||||
|
||||
enum ArenaType
|
||||
{
|
||||
ARENA_TYPE_2v2 = 2,
|
||||
ARENA_TYPE_3v3 = 3,
|
||||
ARENA_TYPE_5v5 = 5
|
||||
};
|
||||
|
||||
enum BattlegroundType
|
||||
{
|
||||
TYPE_BATTLEGROUND = 3,
|
||||
TYPE_ARENA = 4
|
||||
};
|
||||
|
||||
enum BattlegroundStartingEvents
|
||||
{
|
||||
BG_STARTING_EVENT_NONE = 0x00,
|
||||
BG_STARTING_EVENT_1 = 0x01,
|
||||
BG_STARTING_EVENT_2 = 0x02,
|
||||
BG_STARTING_EVENT_3 = 0x04,
|
||||
BG_STARTING_EVENT_4 = 0x08
|
||||
};
|
||||
|
||||
enum BattlegroundStartingEventsIds
|
||||
{
|
||||
BG_STARTING_EVENT_FIRST = 0,
|
||||
BG_STARTING_EVENT_SECOND = 1,
|
||||
BG_STARTING_EVENT_THIRD = 2,
|
||||
BG_STARTING_EVENT_FOURTH = 3
|
||||
};
|
||||
#define BG_STARTING_EVENT_COUNT 4
|
||||
|
||||
struct BattlegroundScore
|
||||
{
|
||||
BattlegroundScore(Player* player) : KillingBlows(0), Deaths(0), HonorableKills(0), BonusHonor(0),
|
||||
DamageDone(0), HealingDone(0), player(player)
|
||||
{ }
|
||||
|
||||
virtual ~BattlegroundScore() { } //virtual destructor is used when deleting score from scores map
|
||||
|
||||
uint32 KillingBlows;
|
||||
uint32 Deaths;
|
||||
uint32 HonorableKills;
|
||||
uint32 BonusHonor;
|
||||
uint32 DamageDone;
|
||||
uint32 HealingDone;
|
||||
Player* player;
|
||||
|
||||
uint32 GetKillingBlows() const { return KillingBlows; }
|
||||
uint32 GetDeaths() const { return Deaths; }
|
||||
uint32 GetHonorableKills() const { return HonorableKills; }
|
||||
uint32 GetBonusHonor() const { return BonusHonor; }
|
||||
uint32 GetDamageDone() const { return DamageDone; }
|
||||
uint32 GetHealingDone() const { return HealingDone; }
|
||||
|
||||
virtual uint32 GetAttr1() const { return 0; }
|
||||
virtual uint32 GetAttr2() const { return 0; }
|
||||
virtual uint32 GetAttr3() const { return 0; }
|
||||
virtual uint32 GetAttr4() const { return 0; }
|
||||
virtual uint32 GetAttr5() const { return 0; }
|
||||
};
|
||||
|
||||
class ArenaLogEntryData
|
||||
{
|
||||
public:
|
||||
ArenaLogEntryData() : Guid(0), ArenaTeamId(0), DamageDone(0), HealingDone(0), KillingBlows(0) {}
|
||||
void Fill(const char* name, uint32 guid, uint32 acc, uint32 arenaTeamId, std::string ip)
|
||||
{
|
||||
Name = std::string(name);
|
||||
Guid = guid;
|
||||
Acc = acc;
|
||||
ArenaTeamId = arenaTeamId;
|
||||
IP = ip;
|
||||
}
|
||||
|
||||
std::string Name;
|
||||
uint32 Guid;
|
||||
uint32 Acc;
|
||||
uint32 ArenaTeamId;
|
||||
std::string IP;
|
||||
uint32 DamageDone;
|
||||
uint32 HealingDone;
|
||||
uint32 KillingBlows;
|
||||
};
|
||||
|
||||
enum BGHonorMode
|
||||
{
|
||||
BG_NORMAL = 0,
|
||||
BG_HOLIDAY,
|
||||
BG_HONOR_MODE_NUM
|
||||
};
|
||||
|
||||
#define BG_AWARD_ARENA_POINTS_MIN_LEVEL 71
|
||||
#define ARENA_TIMELIMIT_POINTS_LOSS -16
|
||||
#define ARENA_READY_MARKER_ENTRY 301337
|
||||
|
||||
/*
|
||||
This class is used to:
|
||||
1. Add player to battleground
|
||||
2. Remove player from battleground
|
||||
3. some certain cases, same for all battlegrounds
|
||||
4. It has properties same for all battlegrounds
|
||||
*/
|
||||
|
||||
enum BattlegroundQueueInvitationType
|
||||
{
|
||||
BG_QUEUE_INVITATION_TYPE_NO_BALANCE = 0, // no balance: N+M vs N players
|
||||
BG_QUEUE_INVITATION_TYPE_BALANCED = 1, // teams balanced: N+1 vs N players
|
||||
BG_QUEUE_INVITATION_TYPE_EVEN = 2 // teams even: N vs N players
|
||||
};
|
||||
|
||||
class Battleground
|
||||
{
|
||||
public:
|
||||
Battleground();
|
||||
virtual ~Battleground();
|
||||
|
||||
void Update(uint32 diff);
|
||||
|
||||
virtual bool SetupBattleground() // must be implemented in BG subclass
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual void Init();
|
||||
virtual void StartingEventCloseDoors() { }
|
||||
virtual void StartingEventOpenDoors() { }
|
||||
virtual void ResetBGSubclass() { } // must be implemented in BG subclass
|
||||
|
||||
virtual void DestroyGate(Player* /*player*/, GameObject* /*go*/) {}
|
||||
|
||||
/* achievement req. */
|
||||
virtual bool AllNodesConrolledByTeam(TeamId /*teamId*/) const { return false; }
|
||||
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry);
|
||||
|
||||
/* Battleground */
|
||||
// Get methods:
|
||||
char const* GetName() const { return m_Name; }
|
||||
BattlegroundTypeId GetBgTypeID() const { return m_RealTypeID; }
|
||||
uint32 GetInstanceID() const { return m_InstanceID; }
|
||||
BattlegroundStatus GetStatus() const { return m_Status; }
|
||||
uint32 GetClientInstanceID() const { return m_ClientInstanceID; }
|
||||
uint32 GetStartTime() const { return m_StartTime; }
|
||||
uint32 GetEndTime() const { return m_EndTime; }
|
||||
uint32 GetLastResurrectTime() const { return m_LastResurrectTime; }
|
||||
|
||||
uint32 GetMinLevel() const { return m_LevelMin; }
|
||||
uint32 GetMaxLevel() const { return m_LevelMax; }
|
||||
|
||||
uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; }
|
||||
uint32 GetMinPlayersPerTeam() const { return m_MinPlayersPerTeam; }
|
||||
|
||||
int32 GetStartDelayTime() const { return m_StartDelayTime; }
|
||||
uint8 GetArenaType() const { return m_ArenaType; }
|
||||
TeamId GetWinner() const { return m_WinnerId; }
|
||||
uint32 GetScriptId() const { return ScriptId; }
|
||||
uint32 GetBonusHonorFromKill(uint32 kills) const;
|
||||
|
||||
// Set methods:
|
||||
void SetName(char const* Name) { m_Name = Name; }
|
||||
void SetBgTypeID(BattlegroundTypeId TypeID) { m_RealTypeID = TypeID; }
|
||||
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
|
||||
void SetStatus(BattlegroundStatus Status) { m_Status = Status; }
|
||||
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
|
||||
void SetStartTime(uint32 Time) { m_StartTime = Time; }
|
||||
void SetEndTime(uint32 Time) { m_EndTime = Time; }
|
||||
void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; }
|
||||
void SetLevelRange(uint32 min, uint32 max) { m_LevelMin = min; m_LevelMax = max; }
|
||||
void SetRated(bool state) { m_IsRated = state; }
|
||||
void SetArenaType(uint8 type) { m_ArenaType = type; }
|
||||
void SetArenaorBGType(bool _isArena) { m_IsArena = _isArena; }
|
||||
void SetWinner(TeamId winner) { m_WinnerId = winner; }
|
||||
void SetScriptId(uint32 scriptId) { ScriptId = scriptId; }
|
||||
|
||||
void ModifyStartDelayTime(int32 diff) { m_StartDelayTime -= diff; }
|
||||
void SetStartDelayTime(int32 Time) { m_StartDelayTime = Time; }
|
||||
|
||||
void SetMaxPlayersPerTeam(uint32 MaxPlayers) { m_MaxPlayersPerTeam = MaxPlayers; }
|
||||
void SetMinPlayersPerTeam(uint32 MinPlayers) { m_MinPlayersPerTeam = MinPlayers; }
|
||||
|
||||
void DecreaseInvitedCount(TeamId teamId) { ASSERT(m_BgInvitedPlayers[teamId] > 0); --m_BgInvitedPlayers[teamId]; }
|
||||
void IncreaseInvitedCount(TeamId teamId) { ++m_BgInvitedPlayers[teamId]; }
|
||||
uint32 GetInvitedCount(TeamId teamId) const { return m_BgInvitedPlayers[teamId]; }
|
||||
|
||||
bool HasFreeSlots() const;
|
||||
uint32 GetFreeSlotsForTeam(TeamId teamId) const;
|
||||
uint32 GetMaxFreeSlots() const;
|
||||
|
||||
typedef std::set<Player*> SpectatorList;
|
||||
typedef std::map<uint64, uint64> ToBeTeleportedMap;
|
||||
void AddSpectator(Player* p) { m_Spectators.insert(p); }
|
||||
void RemoveSpectator(Player* p) { m_Spectators.erase(p); }
|
||||
bool HaveSpectators() { return !m_Spectators.empty(); }
|
||||
const SpectatorList& GetSpectators() const { return m_Spectators; }
|
||||
void AddToBeTeleported(uint64 spectator, uint64 participant) { m_ToBeTeleported[spectator] = participant; }
|
||||
void RemoveToBeTeleported(uint64 spectator) { ToBeTeleportedMap::iterator itr = m_ToBeTeleported.find(spectator); if (itr != m_ToBeTeleported.end()) m_ToBeTeleported.erase(itr); }
|
||||
void SpectatorsSendPacket(WorldPacket& data);
|
||||
|
||||
bool isArena() const { return m_IsArena; }
|
||||
bool isBattleground() const { return !m_IsArena; }
|
||||
bool isRated() const { return m_IsRated; }
|
||||
|
||||
typedef std::map<uint64, Player*> BattlegroundPlayerMap;
|
||||
BattlegroundPlayerMap const& GetPlayers() const { return m_Players; }
|
||||
uint32 GetPlayersSize() const { return m_Players.size(); }
|
||||
|
||||
void ReadyMarkerClicked(Player* p); // pussywizard
|
||||
std::set<uint32> readyMarkerClickedSet; // pussywizard
|
||||
|
||||
typedef std::map<uint64, BattlegroundScore*> BattlegroundScoreMap;
|
||||
typedef std::map<uint64, ArenaLogEntryData> ArenaLogEntryDataMap;// pussywizard
|
||||
ArenaLogEntryDataMap ArenaLogEntries; // pussywizard
|
||||
BattlegroundScoreMap::const_iterator GetPlayerScoresBegin() const { return PlayerScores.begin(); }
|
||||
BattlegroundScoreMap::const_iterator GetPlayerScoresEnd() const { return PlayerScores.end(); }
|
||||
uint32 GetPlayerScoresSize() const { return PlayerScores.size(); }
|
||||
|
||||
uint32 GetReviveQueueSize() const { return m_ReviveQueue.size(); }
|
||||
|
||||
void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid);
|
||||
void RemovePlayerFromResurrectQueue(Player* player);
|
||||
|
||||
/// Relocate all players in ReviveQueue to the closest graveyard
|
||||
void RelocateDeadPlayers(uint64 queueIndex);
|
||||
|
||||
void StartBattleground();
|
||||
|
||||
GameObject* GetBGObject(uint32 type);
|
||||
Creature* GetBGCreature(uint32 type);
|
||||
|
||||
// Location
|
||||
void SetMapId(uint32 MapID) { m_MapId = MapID; }
|
||||
uint32 GetMapId() const { return m_MapId; }
|
||||
|
||||
// Map pointers
|
||||
void SetBgMap(BattlegroundMap* map) { m_Map = map; }
|
||||
BattlegroundMap* GetBgMap() const { ASSERT(m_Map); return m_Map; }
|
||||
BattlegroundMap* FindBgMap() const { return m_Map; }
|
||||
|
||||
void SetTeamStartLoc(TeamId teamId, float X, float Y, float Z, float O);
|
||||
void GetTeamStartLoc(TeamId teamId, float &X, float &Y, float &Z, float &O) const
|
||||
{
|
||||
X = m_TeamStartLocX[teamId];
|
||||
Y = m_TeamStartLocY[teamId];
|
||||
Z = m_TeamStartLocZ[teamId];
|
||||
O = m_TeamStartLocO[teamId];
|
||||
}
|
||||
|
||||
void SetStartMaxDist(float startMaxDist) { m_StartMaxDist = startMaxDist; }
|
||||
float GetStartMaxDist() const { return m_StartMaxDist; }
|
||||
|
||||
// Packet Transfer
|
||||
// method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!)
|
||||
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {}
|
||||
void SendPacketToTeam(TeamId teamId, WorldPacket* packet, Player* sender = NULL, bool self = true);
|
||||
void SendPacketToAll(WorldPacket* packet);
|
||||
void YellToAll(Creature* creature, const char* text, uint32 language);
|
||||
|
||||
template<class Do>
|
||||
void BroadcastWorker(Do& _do);
|
||||
|
||||
void PlaySoundToAll(uint32 soundId);
|
||||
void CastSpellOnTeam(uint32 spellId, TeamId teamId);
|
||||
void RemoveAuraOnTeam(uint32 spellId, TeamId teamId);
|
||||
void RewardHonorToTeam(uint32 honor, TeamId teamId);
|
||||
void RewardReputationToTeam(uint32 factionId, uint32 reputation, TeamId teamId);
|
||||
uint32 GetRealRepFactionForPlayer(uint32 factionId, Player* player);
|
||||
|
||||
void UpdateWorldState(uint32 Field, uint32 Value);
|
||||
void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player* player);
|
||||
void EndBattleground(TeamId winnerTeamId);
|
||||
void BlockMovement(Player* player);
|
||||
|
||||
void SendWarningToAll(int32 entry, ...);
|
||||
void SendMessageToAll(int32 entry, ChatMsg type, Player const* source = NULL);
|
||||
void PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...);
|
||||
|
||||
// specialized version with 2 string id args
|
||||
void SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 strId1 = 0, int32 strId2 = 0);
|
||||
|
||||
// Raid Group
|
||||
Group* GetBgRaid(TeamId teamId) const { return m_BgRaids[teamId]; }
|
||||
void SetBgRaid(TeamId teamId, Group* bg_raid);
|
||||
|
||||
virtual void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
|
||||
|
||||
uint32 GetPlayersCountByTeam(TeamId teamId) const { return m_PlayersCount[teamId]; }
|
||||
uint32 GetAlivePlayersCountByTeam(TeamId teamId) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases
|
||||
void UpdatePlayersCountByTeam(TeamId teamId, bool remove)
|
||||
{
|
||||
if (remove)
|
||||
--m_PlayersCount[teamId];
|
||||
else
|
||||
++m_PlayersCount[teamId];
|
||||
}
|
||||
|
||||
// used for rated arena battles
|
||||
void SetArenaTeamIdForTeam(TeamId teamId, uint32 ArenaTeamId) { m_ArenaTeamIds[teamId] = ArenaTeamId; }
|
||||
uint32 GetArenaTeamIdForTeam(TeamId teamId) const { return m_ArenaTeamIds[teamId]; }
|
||||
void SetArenaTeamRatingChangeForTeam(TeamId teamId, int32 RatingChange) { m_ArenaTeamRatingChanges[teamId] = RatingChange; }
|
||||
int32 GetArenaTeamRatingChangeForTeam(TeamId teamId) const { return m_ArenaTeamRatingChanges[teamId]; }
|
||||
void SetArenaMatchmakerRating(TeamId teamId, uint32 MMR) { m_ArenaTeamMMR[teamId] = MMR; }
|
||||
uint32 GetArenaMatchmakerRating(TeamId teamId) const { return m_ArenaTeamMMR[teamId]; }
|
||||
void CheckArenaAfterTimerConditions();
|
||||
void CheckArenaWinConditions();
|
||||
virtual void UpdateArenaWorldState();
|
||||
|
||||
// Triggers handle
|
||||
// must be implemented in BG subclass
|
||||
virtual void HandleAreaTrigger(Player* /*player*/, uint32 /*trigger*/) {}
|
||||
// must be implemented in BG subclass if need AND call base class generic code
|
||||
virtual void HandleKillPlayer(Player* player, Player* killer);
|
||||
virtual void HandleKillUnit(Creature* /*unit*/, Player* /*killer*/);
|
||||
|
||||
// Battleground events
|
||||
virtual void EventPlayerDroppedFlag(Player* /*player*/) {}
|
||||
virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*gameObject*/) {}
|
||||
virtual void EventPlayerDamagedGO(Player* /*player*/, GameObject* /*go*/, uint32 /*eventType*/) {}
|
||||
virtual void EventPlayerUsedGO(Player* /*player*/, GameObject* /*go*/){}
|
||||
|
||||
// this function can be used by spell to interact with the BG map
|
||||
virtual void DoAction(uint32 /*action*/, uint64 /*var*/) {}
|
||||
|
||||
virtual void HandlePlayerResurrect(Player* /*player*/) {}
|
||||
|
||||
// Death related
|
||||
virtual WorldSafeLocsEntry const* GetClosestGraveyard(Player* player);
|
||||
|
||||
virtual void AddPlayer(Player* player); // must be implemented in BG subclass
|
||||
|
||||
void AddOrSetPlayerToCorrectBgGroup(Player* player, TeamId teamId);
|
||||
|
||||
void RemovePlayerAtLeave(Player* player);
|
||||
// can be extended in in BG subclass
|
||||
|
||||
void HandleTriggerBuff(GameObject* gameObject);
|
||||
void SetHoliday(bool is_holiday);
|
||||
|
||||
// TODO: make this protected:
|
||||
typedef std::vector<uint64> BGObjects;
|
||||
typedef std::vector<uint64> BGCreatures;
|
||||
BGObjects BgObjects;
|
||||
BGCreatures BgCreatures;
|
||||
void SpawnBGObject(uint32 type, uint32 respawntime);
|
||||
bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime = 0, GOState goState = GO_STATE_READY);
|
||||
Creature* AddCreature(uint32 entry, uint32 type, float x, float y, float z, float o, uint32 respawntime = 0, MotionTransport* transport = NULL);
|
||||
bool DelCreature(uint32 type);
|
||||
bool DelObject(uint32 type);
|
||||
bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, TeamId teamId);
|
||||
int32 GetObjectType(uint64 guid);
|
||||
|
||||
void DoorOpen(uint32 type);
|
||||
void DoorClose(uint32 type);
|
||||
//to be removed
|
||||
const char* GetTrinityString(int32 entry);
|
||||
|
||||
virtual bool HandlePlayerUnderMap(Player* /*player*/) { return false; }
|
||||
|
||||
// since arenas can be AvA or Hvh, we have to get the "temporary" team of a player
|
||||
static TeamId GetOtherTeamId(TeamId teamId);
|
||||
bool IsPlayerInBattleground(uint64 guid) const;
|
||||
|
||||
bool ToBeDeleted() const { return m_SetDeleteThis; }
|
||||
//void SetDeleteThis() { m_SetDeleteThis = true; }
|
||||
|
||||
void RewardXPAtKill(Player* killer, Player* victim);
|
||||
|
||||
virtual uint64 GetFlagPickerGUID(TeamId /*teamId*/ = TEAM_NEUTRAL) const { return 0; }
|
||||
virtual void SetDroppedFlagGUID(uint64 /*guid*/, TeamId /*teamId*/ = TEAM_NEUTRAL) {}
|
||||
uint32 GetTeamScore(TeamId teamId) const;
|
||||
|
||||
virtual TeamId GetPrematureWinner();
|
||||
|
||||
// because BattleGrounds with different types and same level range has different m_BracketId
|
||||
uint8 GetUniqueBracketId() const;
|
||||
|
||||
BattlegroundAV* ToBattlegroundAV() { if (GetBgTypeID() == BATTLEGROUND_AV) return reinterpret_cast<BattlegroundAV*>(this); else return NULL; }
|
||||
BattlegroundAV const* ToBattlegroundAV() const { if (GetBgTypeID() == BATTLEGROUND_AV) return reinterpret_cast<const BattlegroundAV*>(this); else return NULL; }
|
||||
|
||||
BattlegroundWS* ToBattlegroundWS() { if (GetBgTypeID() == BATTLEGROUND_WS) return reinterpret_cast<BattlegroundWS*>(this); else return NULL; }
|
||||
BattlegroundWS const* ToBattlegroundWS() const { if (GetBgTypeID() == BATTLEGROUND_WS) return reinterpret_cast<const BattlegroundWS*>(this); else return NULL; }
|
||||
|
||||
BattlegroundAB* ToBattlegroundAB() { if (GetBgTypeID() == BATTLEGROUND_AB) return reinterpret_cast<BattlegroundAB*>(this); else return NULL; }
|
||||
BattlegroundAB const* ToBattlegroundAB() const { if (GetBgTypeID() == BATTLEGROUND_AB) return reinterpret_cast<const BattlegroundAB*>(this); else return NULL; }
|
||||
|
||||
BattlegroundNA* ToBattlegroundNA() { if (GetBgTypeID() == BATTLEGROUND_NA) return reinterpret_cast<BattlegroundNA*>(this); else return NULL; }
|
||||
BattlegroundNA const* ToBattlegroundNA() const { if (GetBgTypeID() == BATTLEGROUND_NA) return reinterpret_cast<const BattlegroundNA*>(this); else return NULL; }
|
||||
|
||||
BattlegroundBE* ToBattlegroundBE() { if (GetBgTypeID() == BATTLEGROUND_BE) return reinterpret_cast<BattlegroundBE*>(this); else return NULL; }
|
||||
BattlegroundBE const* ToBattlegroundBE() const { if (GetBgTypeID() == BATTLEGROUND_BE) return reinterpret_cast<const BattlegroundBE*>(this); else return NULL; }
|
||||
|
||||
BattlegroundEY* ToBattlegroundEY() { if (GetBgTypeID() == BATTLEGROUND_EY) return reinterpret_cast<BattlegroundEY*>(this); else return NULL; }
|
||||
BattlegroundEY const* ToBattlegroundEY() const { if (GetBgTypeID() == BATTLEGROUND_EY) return reinterpret_cast<const BattlegroundEY*>(this); else return NULL; }
|
||||
|
||||
BattlegroundRL* ToBattlegroundRL() { if (GetBgTypeID() == BATTLEGROUND_RL) return reinterpret_cast<BattlegroundRL*>(this); else return NULL; }
|
||||
BattlegroundRL const* ToBattlegroundRL() const { if (GetBgTypeID() == BATTLEGROUND_RL) return reinterpret_cast<const BattlegroundRL*>(this); else return NULL; }
|
||||
|
||||
BattlegroundSA* ToBattlegroundSA() { if (GetBgTypeID() == BATTLEGROUND_SA) return reinterpret_cast<BattlegroundSA*>(this); else return NULL; }
|
||||
BattlegroundSA const* ToBattlegroundSA() const { if (GetBgTypeID() == BATTLEGROUND_SA) return reinterpret_cast<const BattlegroundSA*>(this); else return NULL; }
|
||||
|
||||
BattlegroundDS* ToBattlegroundDS() { if (GetBgTypeID() == BATTLEGROUND_DS) return reinterpret_cast<BattlegroundDS*>(this); else return NULL; }
|
||||
BattlegroundDS const* ToBattlegroundDS() const { if (GetBgTypeID() == BATTLEGROUND_DS) return reinterpret_cast<const BattlegroundDS*>(this); else return NULL; }
|
||||
|
||||
BattlegroundRV* ToBattlegroundRV() { if (GetBgTypeID() == BATTLEGROUND_RV) return reinterpret_cast<BattlegroundRV*>(this); else return NULL; }
|
||||
BattlegroundRV const* ToBattlegroundRV() const { if (GetBgTypeID() == BATTLEGROUND_RV) return reinterpret_cast<const BattlegroundRV*>(this); else return NULL; }
|
||||
|
||||
BattlegroundIC* ToBattlegroundIC() { if (GetBgTypeID() == BATTLEGROUND_IC) return reinterpret_cast<BattlegroundIC*>(this); else return NULL; }
|
||||
BattlegroundIC const* ToBattlegroundIC() const { if (GetBgTypeID() == BATTLEGROUND_IC) return reinterpret_cast<const BattlegroundIC*>(this); else return NULL; }
|
||||
|
||||
protected:
|
||||
// this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends Battleground
|
||||
void EndNow();
|
||||
void PlayerAddedToBGCheckIfBGIsRunning(Player* player);
|
||||
|
||||
void _ProcessResurrect(uint32 diff);
|
||||
void _ProcessProgress(uint32 diff);
|
||||
void _ProcessLeave(uint32 diff);
|
||||
void _ProcessJoin(uint32 diff);
|
||||
void _CheckSafePositions(uint32 diff);
|
||||
|
||||
// Scorekeeping
|
||||
BattlegroundScoreMap PlayerScores; // Player scores
|
||||
// must be implemented in BG subclass
|
||||
virtual void RemovePlayer(Player* /*player*/) {}
|
||||
|
||||
// Player lists, those need to be accessible by inherited classes
|
||||
BattlegroundPlayerMap m_Players;
|
||||
// Spirit Guide guid + Player list GUIDS
|
||||
std::map<uint64, std::vector<uint64> > m_ReviveQueue;
|
||||
|
||||
// these are important variables used for starting messages
|
||||
uint8 m_Events;
|
||||
BattlegroundStartTimeIntervals StartDelayTimes[BG_STARTING_EVENT_COUNT];
|
||||
// this must be filled in constructors!
|
||||
uint32 StartMessageIds[BG_STARTING_EVENT_COUNT];
|
||||
|
||||
bool m_BuffChange;
|
||||
|
||||
BGHonorMode m_HonorMode;
|
||||
int32 m_TeamScores[BG_TEAMS_COUNT];
|
||||
|
||||
// pussywizard:
|
||||
uint32 m_UpdateTimer;
|
||||
private:
|
||||
// Battleground
|
||||
BattlegroundTypeId m_RealTypeID;
|
||||
uint32 m_InstanceID; // Battleground Instance's GUID!
|
||||
BattlegroundStatus m_Status;
|
||||
uint32 m_ClientInstanceID; // the instance-id which is sent to the client and without any other internal use
|
||||
uint32 m_StartTime;
|
||||
uint32 m_ResetStatTimer;
|
||||
uint32 m_ValidStartPositionTimer;
|
||||
int32 m_EndTime; // it is set to 120000 when bg is ending and it decreases itself
|
||||
uint32 m_LastResurrectTime;
|
||||
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
|
||||
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
|
||||
bool m_IsArena;
|
||||
TeamId m_WinnerId;
|
||||
int32 m_StartDelayTime;
|
||||
bool m_IsRated; // is this battle rated?
|
||||
bool m_PrematureCountDown;
|
||||
uint32 m_PrematureCountDownTimer;
|
||||
char const* m_Name;
|
||||
|
||||
/* Pre- and post-update hooks */
|
||||
|
||||
/**
|
||||
* @brief Pre-update hook.
|
||||
*
|
||||
* Will be called before battleground update is started. Depending on
|
||||
* the result of this call actual update body may be skipped.
|
||||
*
|
||||
* @param diff a time difference between two worldserver update loops in
|
||||
* milliseconds.
|
||||
*
|
||||
* @return @c true if update must be performed, @c false otherwise.
|
||||
*
|
||||
* @see Update(), PostUpdateImpl().
|
||||
*/
|
||||
virtual bool PreUpdateImpl(uint32 /* diff */) { return true; }
|
||||
|
||||
/**
|
||||
* @brief Post-update hook.
|
||||
*
|
||||
* Will be called after battleground update has passed. May be used to
|
||||
* implement custom update effects in subclasses.
|
||||
*
|
||||
* @param diff a time difference between two worldserver update loops in
|
||||
* milliseconds.
|
||||
*
|
||||
* @see Update(), PreUpdateImpl().
|
||||
*/
|
||||
virtual void PostUpdateImpl(uint32 /* diff */) { }
|
||||
|
||||
// Player lists
|
||||
std::vector<uint64> m_ResurrectQueue; // Player GUID
|
||||
std::deque<uint64> m_OfflineQueue; // Player GUID
|
||||
|
||||
// Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction
|
||||
// Invited counters will be changed only when removing already invited player from queue, removing player from battleground and inviting player to BG
|
||||
// Invited players counters
|
||||
uint32 m_BgInvitedPlayers[BG_TEAMS_COUNT];
|
||||
|
||||
// Raid Group
|
||||
Group* m_BgRaids[BG_TEAMS_COUNT]; // 0 - alliance, 1 - horde
|
||||
|
||||
SpectatorList m_Spectators;
|
||||
ToBeTeleportedMap m_ToBeTeleported;
|
||||
|
||||
// Players count by team
|
||||
uint32 m_PlayersCount[BG_TEAMS_COUNT];
|
||||
|
||||
// Arena team ids by team
|
||||
uint32 m_ArenaTeamIds[BG_TEAMS_COUNT];
|
||||
|
||||
int32 m_ArenaTeamRatingChanges[BG_TEAMS_COUNT];
|
||||
uint32 m_ArenaTeamMMR[BG_TEAMS_COUNT];
|
||||
|
||||
// Limits
|
||||
uint32 m_LevelMin;
|
||||
uint32 m_LevelMax;
|
||||
uint32 m_MaxPlayersPerTeam;
|
||||
uint32 m_MinPlayersPerTeam;
|
||||
|
||||
// Start location
|
||||
uint32 m_MapId;
|
||||
BattlegroundMap* m_Map;
|
||||
float m_TeamStartLocX[BG_TEAMS_COUNT];
|
||||
float m_TeamStartLocY[BG_TEAMS_COUNT];
|
||||
float m_TeamStartLocZ[BG_TEAMS_COUNT];
|
||||
float m_TeamStartLocO[BG_TEAMS_COUNT];
|
||||
float m_StartMaxDist;
|
||||
uint32 ScriptId;
|
||||
};
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUNDMGR_H
|
||||
#define __BATTLEGROUNDMGR_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DBCEnums.h"
|
||||
#include "Battleground.h"
|
||||
#include "BattlegroundQueue.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include <ace/Singleton.h>
|
||||
|
||||
typedef std::map<uint32, Battleground*> BattlegroundContainer;
|
||||
typedef UNORDERED_MAP<uint32, BattlegroundTypeId> BattleMastersMap;
|
||||
|
||||
#define WS_ARENA_DISTRIBUTION_TIME 20001 // Custom worldstate
|
||||
|
||||
struct CreateBattlegroundData
|
||||
{
|
||||
BattlegroundTypeId bgTypeId;
|
||||
bool IsArena;
|
||||
uint32 MinPlayersPerTeam;
|
||||
uint32 MaxPlayersPerTeam;
|
||||
uint32 LevelMin;
|
||||
uint32 LevelMax;
|
||||
char* BattlegroundName;
|
||||
uint32 MapID;
|
||||
float Team1StartLocX;
|
||||
float Team1StartLocY;
|
||||
float Team1StartLocZ;
|
||||
float Team1StartLocO;
|
||||
float Team2StartLocX;
|
||||
float Team2StartLocY;
|
||||
float Team2StartLocZ;
|
||||
float Team2StartLocO;
|
||||
float StartMaxDist;
|
||||
uint32 scriptId;
|
||||
};
|
||||
|
||||
struct GroupQueueInfo;
|
||||
|
||||
// pussywizard
|
||||
class RandomBattlegroundSystem
|
||||
{
|
||||
public:
|
||||
RandomBattlegroundSystem();
|
||||
void Update(uint32 diff);
|
||||
BattlegroundTypeId GetCurrentRandomBg() const { return m_CurrentRandomBg; }
|
||||
void BattlegroundCreated(BattlegroundTypeId bgTypeId);
|
||||
private:
|
||||
BattlegroundTypeId m_CurrentRandomBg;
|
||||
uint32 m_SwitchTimer;
|
||||
std::vector<BattlegroundTypeId> m_BgOrder;
|
||||
};
|
||||
|
||||
class BattlegroundMgr
|
||||
{
|
||||
friend class ACE_Singleton<BattlegroundMgr, ACE_Null_Mutex>;
|
||||
|
||||
private:
|
||||
BattlegroundMgr();
|
||||
~BattlegroundMgr();
|
||||
|
||||
public:
|
||||
void Update(uint32 diff);
|
||||
|
||||
/* Packet Building */
|
||||
void BuildPlayerJoinedBattlegroundPacket(WorldPacket* data, Player* player);
|
||||
void BuildPlayerLeftBattlegroundPacket(WorldPacket* data, uint64 guid);
|
||||
void BuildBattlegroundListPacket(WorldPacket* data, uint64 guid, Player* player, BattlegroundTypeId bgTypeId, uint8 fromWhere);
|
||||
void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result);
|
||||
void BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value);
|
||||
void BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg);
|
||||
void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, TeamId teamId, bool isRated = false, BattlegroundTypeId forceBgTypeId = BATTLEGROUND_TYPE_NONE);
|
||||
void BuildPlaySoundPacket(WorldPacket* data, uint32 soundid);
|
||||
void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, uint64 guid);
|
||||
|
||||
/* Battlegrounds */
|
||||
Battleground* GetBattleground(uint32 InstanceID);
|
||||
Battleground* GetBattlegroundTemplate(BattlegroundTypeId bgTypeId);
|
||||
Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, uint32 minLevel, uint32 maxLevel, uint8 arenaType, bool isRated);
|
||||
|
||||
void AddBattleground(Battleground* bg);
|
||||
void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId);
|
||||
|
||||
void CreateInitialBattlegrounds();
|
||||
void DeleteAllBattlegrounds();
|
||||
|
||||
void SendToBattleground(Player* player, uint32 InstanceID, BattlegroundTypeId bgTypeId);
|
||||
|
||||
/* Battleground queues */
|
||||
BattlegroundQueue& GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId) { return m_BattlegroundQueues[bgQueueTypeId]; }
|
||||
void ScheduleArenaQueueUpdate(uint32 arenaRatedTeamId, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundBracketId bracket_id);
|
||||
uint32 GetPrematureFinishTime() const;
|
||||
|
||||
static void InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TeamId teamId);
|
||||
|
||||
void ToggleArenaTesting();
|
||||
void ToggleTesting();
|
||||
|
||||
void SetHolidayWeekends(uint32 mask);
|
||||
|
||||
bool isArenaTesting() const { return m_ArenaTesting; }
|
||||
bool isTesting() const { return m_Testing; }
|
||||
|
||||
static BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, uint8 arenaType);
|
||||
static BattlegroundTypeId BGTemplateId(BattlegroundQueueTypeId bgQueueTypeId);
|
||||
static bool IsArenaType(BattlegroundTypeId bgTypeId);
|
||||
static uint8 BGArenaType(BattlegroundQueueTypeId bgQueueTypeId);
|
||||
|
||||
static HolidayIds BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId);
|
||||
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday);
|
||||
static bool IsBGWeekend(BattlegroundTypeId bgTypeId);
|
||||
|
||||
PvPDifficultyEntry randomBgDifficultyEntry;
|
||||
|
||||
uint32 GetRatingDiscardTimer() const;
|
||||
void InitAutomaticArenaPointDistribution();
|
||||
void LoadBattleMastersEntry();
|
||||
void CheckBattleMasters();
|
||||
BattlegroundTypeId GetBattleMasterBG(uint32 entry) const
|
||||
{
|
||||
BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
|
||||
if (itr != mBattleMastersMap.end())
|
||||
return itr->second;
|
||||
return BATTLEGROUND_TYPE_NONE;
|
||||
}
|
||||
|
||||
const BattlegroundContainer& GetBattlegroundList() { return m_Battlegrounds; } // pussywizard
|
||||
RandomBattlegroundSystem RandomSystem; // pussywizard
|
||||
|
||||
private:
|
||||
bool CreateBattleground(CreateBattlegroundData& data);
|
||||
uint32 GetNextClientVisibleInstanceId();
|
||||
|
||||
typedef std::map<BattlegroundTypeId, Battleground*> BattlegroundTemplateContainer;
|
||||
BattlegroundTemplateContainer m_BattlegroundTemplates;
|
||||
BattlegroundContainer m_Battlegrounds;
|
||||
|
||||
BattlegroundQueue m_BattlegroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES];
|
||||
|
||||
std::vector<uint64> m_ArenaQueueUpdateScheduler;
|
||||
uint32 m_lastClientVisibleInstanceId;
|
||||
uint32 m_NextPeriodicQueueUpdateTime;
|
||||
time_t m_NextAutoDistributionTime;
|
||||
bool m_ArenaTesting;
|
||||
bool m_Testing;
|
||||
BattleMastersMap mBattleMastersMap;
|
||||
};
|
||||
|
||||
#define sBattlegroundMgr ACE_Singleton<BattlegroundMgr, ACE_Null_Mutex>::instance()
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUNDQUEUE_H
|
||||
#define __BATTLEGROUNDQUEUE_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "DBCEnums.h"
|
||||
#include "Battleground.h"
|
||||
#include "EventProcessor.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10
|
||||
|
||||
struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!)
|
||||
{
|
||||
std::set<uint64> Players; // player guid set
|
||||
TeamId teamId; // Player team (TEAM_ALLIANCE/TEAM_HORDE)
|
||||
BattlegroundTypeId BgTypeId; // battleground type id
|
||||
bool IsRated; // rated
|
||||
uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG
|
||||
uint32 ArenaTeamId; // team id if rated match
|
||||
uint32 JoinTime; // time when group was added
|
||||
uint32 RemoveInviteTime; // time when we will remove invite for players in group
|
||||
uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG
|
||||
uint32 ArenaTeamRating; // if rated match, inited to the rating of the team
|
||||
uint32 ArenaMatchmakerRating; // if rated match, inited to the rating of the team
|
||||
uint32 OpponentsTeamRating; // for rated arena matches
|
||||
uint32 OpponentsMatchmakerRating; // for rated arena matches
|
||||
|
||||
// pussywizard: for internal use
|
||||
uint8 _bracketId;
|
||||
uint8 _groupType;
|
||||
};
|
||||
|
||||
enum BattlegroundQueueGroupTypes
|
||||
{
|
||||
BG_QUEUE_PREMADE_ALLIANCE = 0,
|
||||
BG_QUEUE_PREMADE_HORDE = 1,
|
||||
BG_QUEUE_NORMAL_ALLIANCE = 2,
|
||||
BG_QUEUE_NORMAL_HORDE = 3
|
||||
};
|
||||
#define BG_QUEUE_GROUP_TYPES_COUNT 4
|
||||
|
||||
class Battleground;
|
||||
class BattlegroundQueue
|
||||
{
|
||||
public:
|
||||
BattlegroundQueue();
|
||||
~BattlegroundQueue();
|
||||
|
||||
void BattlegroundQueueUpdate(BattlegroundBracketId bracket_id, uint8 actionMask, bool isRated, uint32 arenaRatedTeamId);
|
||||
void UpdateEvents(uint32 diff);
|
||||
|
||||
void FillPlayersToBG(const int32 aliFree, const int32 hordeFree, BattlegroundBracketId bracket_id);
|
||||
void FillPlayersToBGWithSpecific(const int32 aliFree, const int32 hordeFree, BattlegroundBracketId thisBracketId, BattlegroundQueue* specificQueue, BattlegroundBracketId specificBracketId);
|
||||
bool CheckPremadeMatch(BattlegroundBracketId bracket_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
|
||||
bool CheckNormalMatch(Battleground* bgTemplate, BattlegroundBracketId bracket_id, uint32 minPlayers, uint32 maxPlayers);
|
||||
bool CheckSkirmishForSameFaction(BattlegroundBracketId bracket_id, uint32 minPlayersPerTeam);
|
||||
GroupQueueInfo* AddGroup(Player* leader, Group* group, PvPDifficultyEntry const* bracketEntry, bool isRated, bool isPremade, uint32 ArenaRating, uint32 MatchmakerRating, uint32 ArenaTeamId);
|
||||
void RemovePlayer(uint64 guid, bool sentToBg, uint32 playerQueueSlot);
|
||||
bool IsPlayerInvitedToRatedArena(uint64 pl_guid);
|
||||
bool IsPlayerInvited(uint64 pl_guid, const uint32 bgInstanceGuid, const uint32 removeTime);
|
||||
bool GetPlayerGroupInfoData(uint64 guid, GroupQueueInfo* ginfo);
|
||||
void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo);
|
||||
uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo) const;
|
||||
|
||||
void SetBgTypeIdAndArenaType(BattlegroundTypeId b, uint8 a) { m_bgTypeId = b; m_arenaType = ArenaType(a); } // pussywizard
|
||||
void AddEvent(BasicEvent* Event, uint64 e_time);
|
||||
|
||||
typedef std::map<uint64, GroupQueueInfo*> QueuedPlayersMap;
|
||||
QueuedPlayersMap m_QueuedPlayers;
|
||||
|
||||
//do NOT use deque because deque.erase() invalidates ALL iterators
|
||||
typedef std::list<GroupQueueInfo*> GroupsQueueType;
|
||||
|
||||
/*
|
||||
This two dimensional array is used to store All queued groups
|
||||
First dimension specifies the bgTypeId
|
||||
Second dimension specifies the player's group types -
|
||||
BG_QUEUE_PREMADE_ALLIANCE is used for premade alliance groups and alliance rated arena teams
|
||||
BG_QUEUE_PREMADE_HORDE is used for premade horde groups and horde rated arena teams
|
||||
BG_QUEUE_NORMAL_ALLIANCE is used for normal (or small) alliance groups or non-rated arena matches
|
||||
BG_QUEUE_NORMAL_HORDE is used for normal (or small) horde groups or non-rated arena matches
|
||||
*/
|
||||
GroupsQueueType m_QueuedGroups[MAX_BATTLEGROUND_BRACKETS][BG_QUEUE_GROUP_TYPES_COUNT];
|
||||
|
||||
// class to select and invite groups to bg
|
||||
class SelectionPool
|
||||
{
|
||||
public:
|
||||
SelectionPool(): PlayerCount(0) {};
|
||||
void Init();
|
||||
bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount);
|
||||
bool KickGroup(const uint32 size);
|
||||
uint32 GetPlayerCount() const {return PlayerCount;}
|
||||
public:
|
||||
GroupsQueueType SelectedGroups;
|
||||
private:
|
||||
uint32 PlayerCount;
|
||||
};
|
||||
|
||||
//one selection pool for horde, other one for alliance
|
||||
SelectionPool m_SelectionPools[BG_TEAMS_COUNT];
|
||||
private:
|
||||
|
||||
BattlegroundTypeId m_bgTypeId;
|
||||
ArenaType m_arenaType;
|
||||
uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME];
|
||||
uint32 m_WaitTimeLastIndex[BG_TEAMS_COUNT][MAX_BATTLEGROUND_BRACKETS];
|
||||
|
||||
// Event handler
|
||||
EventProcessor m_events;
|
||||
};
|
||||
|
||||
/*
|
||||
This class is used to invite player to BG again, when minute lasts from his first invitation
|
||||
it is capable to solve all possibilities
|
||||
*/
|
||||
class BGQueueInviteEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
BGQueueInviteEvent(uint64 pl_guid, uint32 BgInstanceGUID, BattlegroundTypeId BgTypeId, uint8 arenaType, uint32 removeTime) :
|
||||
m_PlayerGuid(pl_guid), m_BgInstanceGUID(BgInstanceGUID), m_BgTypeId(BgTypeId), m_ArenaType(arenaType), m_RemoveTime(removeTime)
|
||||
{ }
|
||||
virtual ~BGQueueInviteEvent() { }
|
||||
|
||||
virtual bool Execute(uint64 e_time, uint32 p_time);
|
||||
virtual void Abort(uint64 e_time);
|
||||
private:
|
||||
uint64 m_PlayerGuid;
|
||||
uint32 m_BgInstanceGUID;
|
||||
BattlegroundTypeId m_BgTypeId;
|
||||
uint8 m_ArenaType;
|
||||
uint32 m_RemoveTime;
|
||||
};
|
||||
|
||||
/*
|
||||
This class is used to remove player from BG queue after 1 minute 20 seconds from first invitation
|
||||
We must store removeInvite time in case player left queue and joined and is invited again
|
||||
We must store bgQueueTypeId, because battleground can be deleted already, when player entered it
|
||||
*/
|
||||
class BGQueueRemoveEvent : public BasicEvent
|
||||
{
|
||||
public:
|
||||
BGQueueRemoveEvent(uint64 pl_guid, uint32 bgInstanceGUID, BattlegroundQueueTypeId bgQueueTypeId, uint32 removeTime)
|
||||
: m_PlayerGuid(pl_guid), m_BgInstanceGUID(bgInstanceGUID), m_RemoveTime(removeTime), m_BgQueueTypeId(bgQueueTypeId)
|
||||
{}
|
||||
|
||||
virtual ~BGQueueRemoveEvent() {}
|
||||
|
||||
virtual bool Execute(uint64 e_time, uint32 p_time);
|
||||
virtual void Abort(uint64 e_time);
|
||||
private:
|
||||
uint64 m_PlayerGuid;
|
||||
uint32 m_BgInstanceGUID;
|
||||
uint32 m_RemoveTime;
|
||||
BattlegroundQueueTypeId m_BgQueueTypeId;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,492 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "BattlegroundAB.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "Language.h"
|
||||
#include "Object.h"
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BattlegroundAB::BattlegroundAB()
|
||||
{
|
||||
m_BuffChange = true;
|
||||
BgObjects.resize(BG_AB_OBJECT_MAX);
|
||||
BgCreatures.resize(BG_AB_ALL_NODES_COUNT + BG_AB_DYNAMIC_NODES_COUNT); // xinef: +BG_AB_DYNAMIC_NODES_COUNT buff triggers
|
||||
|
||||
_controlledPoints[TEAM_ALLIANCE] = 0;
|
||||
_controlledPoints[TEAM_HORDE] = 0;
|
||||
_teamScores500Disadvantage[TEAM_ALLIANCE] = false;
|
||||
_teamScores500Disadvantage[TEAM_HORDE] = false;
|
||||
_honorTics = 0;
|
||||
_reputationTics = 0;
|
||||
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN;
|
||||
}
|
||||
|
||||
BattlegroundAB::~BattlegroundAB()
|
||||
{
|
||||
}
|
||||
|
||||
void BattlegroundAB::PostUpdateImpl(uint32 diff)
|
||||
{
|
||||
if (GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
_bgEvents.Update(diff);
|
||||
while (uint32 eventId =_bgEvents.ExecuteEvent())
|
||||
switch (eventId)
|
||||
{
|
||||
case BG_AB_EVENT_UPDATE_BANNER_STABLE:
|
||||
case BG_AB_EVENT_UPDATE_BANNER_FARM:
|
||||
case BG_AB_EVENT_UPDATE_BANNER_BLACKSMITH:
|
||||
case BG_AB_EVENT_UPDATE_BANNER_LUMBERMILL:
|
||||
case BG_AB_EVENT_UPDATE_BANNER_GOLDMINE:
|
||||
CreateBanner(eventId - BG_AB_EVENT_UPDATE_BANNER_STABLE, false);
|
||||
break;
|
||||
case BG_AB_EVENT_CAPTURE_STABLE:
|
||||
case BG_AB_EVENT_CAPTURE_FARM:
|
||||
case BG_AB_EVENT_CAPTURE_BLACKSMITH:
|
||||
case BG_AB_EVENT_CAPTURE_LUMBERMILL:
|
||||
case BG_AB_EVENT_CAPTURE_GOLDMINE:
|
||||
{
|
||||
uint8 node = eventId - BG_AB_EVENT_CAPTURE_STABLE;
|
||||
TeamId teamId = _capturePointInfo[node]._state == BG_AB_NODE_STATE_ALLY_CONTESTED ? TEAM_ALLIANCE : TEAM_HORDE;
|
||||
DeleteBanner(node);
|
||||
_capturePointInfo[node]._ownerTeamId = teamId;
|
||||
_capturePointInfo[node]._state = teamId == TEAM_ALLIANCE ? BG_AB_NODE_STATE_ALLY_OCCUPIED : BG_AB_NODE_STATE_HORDE_OCCUPIED;
|
||||
_capturePointInfo[node]._captured = true;
|
||||
|
||||
CreateBanner(node, false);
|
||||
NodeOccupied(node);
|
||||
SendNodeUpdate(node);
|
||||
|
||||
SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN, teamId == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE, NULL, teamId == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE, LANG_BG_AB_NODE_STABLES + node);
|
||||
PlaySoundToAll(teamId == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_CAPTURED_ALLIANCE : BG_AB_SOUND_NODE_CAPTURED_HORDE);
|
||||
break;
|
||||
}
|
||||
case BG_AB_EVENT_ALLIANCE_TICK:
|
||||
case BG_AB_EVENT_HORDE_TICK:
|
||||
{
|
||||
TeamId teamId = TeamId(eventId - BG_AB_EVENT_ALLIANCE_TICK);
|
||||
uint8 controlledPoints = _controlledPoints[teamId];
|
||||
if (controlledPoints == 0)
|
||||
{
|
||||
_bgEvents.ScheduleEvent(eventId, 3000);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8 honorRewards = uint8(m_TeamScores[teamId] / _honorTics);
|
||||
uint8 reputationRewards = uint8(m_TeamScores[teamId] / _reputationTics);
|
||||
uint8 information = uint8(m_TeamScores[teamId] / BG_AB_WARNING_NEAR_VICTORY_SCORE);
|
||||
m_TeamScores[teamId] += BG_AB_TickPoints[controlledPoints];
|
||||
if (m_TeamScores[teamId] > BG_AB_MAX_TEAM_SCORE)
|
||||
m_TeamScores[teamId] = BG_AB_MAX_TEAM_SCORE;
|
||||
|
||||
if (honorRewards < uint8(m_TeamScores[teamId] / _honorTics))
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), teamId);
|
||||
if (reputationRewards < uint8(m_TeamScores[teamId] / _reputationTics))
|
||||
RewardReputationToTeam(teamId == TEAM_ALLIANCE ? 509 : 510, 10, teamId);
|
||||
if (information < uint8(m_TeamScores[teamId] / BG_AB_WARNING_NEAR_VICTORY_SCORE))
|
||||
{
|
||||
SendMessageToAll(teamId == TEAM_ALLIANCE ? LANG_BG_AB_A_NEAR_VICTORY : LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL);
|
||||
PlaySoundToAll(BG_AB_SOUND_NEAR_VICTORY);
|
||||
}
|
||||
|
||||
UpdateWorldState(teamId == TEAM_ALLIANCE ? BG_AB_OP_RESOURCES_ALLY : BG_AB_OP_RESOURCES_HORDE, m_TeamScores[teamId]);
|
||||
if (m_TeamScores[teamId] > m_TeamScores[GetOtherTeamId(teamId)] + 500)
|
||||
_teamScores500Disadvantage[GetOtherTeamId(teamId)] = true;
|
||||
if (m_TeamScores[teamId] >= BG_AB_MAX_TEAM_SCORE)
|
||||
EndBattleground(teamId);
|
||||
|
||||
_bgEvents.ScheduleEvent(eventId, BG_AB_TickIntervals[controlledPoints]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundAB::StartingEventCloseDoors()
|
||||
{
|
||||
|
||||
for (uint32 obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * BG_AB_OBJECTS_PER_NODE; ++obj)
|
||||
SpawnBGObject(obj, RESPAWN_ONE_DAY);
|
||||
for (uint32 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i)
|
||||
SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY);
|
||||
|
||||
// Starting doors
|
||||
SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY);
|
||||
DoorClose(BG_AB_OBJECT_GATE_A);
|
||||
DoorClose(BG_AB_OBJECT_GATE_H);
|
||||
}
|
||||
|
||||
void BattlegroundAB::StartingEventOpenDoors()
|
||||
{
|
||||
for (uint32 banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; banner += BG_AB_OBJECTS_PER_NODE, ++i)
|
||||
SpawnBGObject(banner, RESPAWN_IMMEDIATELY);
|
||||
|
||||
for (uint32 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + urand(0, 2) + i * 3, RESPAWN_IMMEDIATELY);
|
||||
|
||||
DoorOpen(BG_AB_OBJECT_GATE_A);
|
||||
DoorOpen(BG_AB_OBJECT_GATE_H);
|
||||
StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, BG_AB_EVENT_START_BATTLE);
|
||||
_bgEvents.ScheduleEvent(BG_AB_EVENT_ALLIANCE_TICK, 3000);
|
||||
_bgEvents.ScheduleEvent(BG_AB_EVENT_HORDE_TICK, 3000);
|
||||
}
|
||||
|
||||
void BattlegroundAB::AddPlayer(Player* player)
|
||||
{
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundABScore(player);
|
||||
}
|
||||
|
||||
void BattlegroundAB::RemovePlayer(Player* player)
|
||||
{
|
||||
player->SetPhaseMask(1, false);
|
||||
}
|
||||
|
||||
void BattlegroundAB::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 3948: // Arathi Basin Alliance Exit.
|
||||
if (player->GetTeamId() != TEAM_ALLIANCE)
|
||||
player->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
|
||||
else
|
||||
player->LeaveBattleground();
|
||||
break;
|
||||
case 3949: // Arathi Basin Horde Exit.
|
||||
if (player->GetTeamId() != TEAM_HORDE)
|
||||
player->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
|
||||
else
|
||||
player->LeaveBattleground();
|
||||
break;
|
||||
case 3866: // Stables
|
||||
case 3869: // Gold Mine
|
||||
case 3867: // Farm
|
||||
case 3868: // Lumber Mill
|
||||
case 3870: // Black Smith
|
||||
case 4020: // Unk1
|
||||
case 4021: // Unk2
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundAB::CreateBanner(uint8 node, bool delay)
|
||||
{
|
||||
// Just put it into the queue
|
||||
if (delay)
|
||||
{
|
||||
_bgEvents.RescheduleEvent(BG_AB_EVENT_UPDATE_BANNER_STABLE+node, BG_AB_BANNER_UPDATE_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnBGObject(node*BG_AB_OBJECTS_PER_NODE + _capturePointInfo[node]._state, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(node*BG_AB_OBJECTS_PER_NODE + BG_AB_OBJECT_AURA_ALLY + _capturePointInfo[node]._ownerTeamId, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
void BattlegroundAB::DeleteBanner(uint8 node)
|
||||
{
|
||||
SpawnBGObject(node*BG_AB_OBJECTS_PER_NODE + _capturePointInfo[node]._state, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(node*BG_AB_OBJECTS_PER_NODE + BG_AB_OBJECT_AURA_ALLY + _capturePointInfo[node]._ownerTeamId, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
void BattlegroundAB::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
for (uint8 node = 0; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
|
||||
{
|
||||
if (_capturePointInfo[node]._state == BG_AB_NODE_STATE_NEUTRAL)
|
||||
data << uint32(_capturePointInfo[node]._iconNone) << uint32(1);
|
||||
|
||||
for (uint8 i = BG_AB_NODE_STATE_ALLY_OCCUPIED; i <= BG_AB_NODE_STATE_HORDE_CONTESTED; ++i)
|
||||
data << uint32(_capturePointInfo[node]._iconCapture + i-1) << uint32(_capturePointInfo[node]._state == i);
|
||||
}
|
||||
|
||||
data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(_controlledPoints[TEAM_ALLIANCE]);
|
||||
data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(_controlledPoints[TEAM_HORDE]);
|
||||
data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE);
|
||||
data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_NEAR_VICTORY_SCORE);
|
||||
data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[TEAM_ALLIANCE]);
|
||||
data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[TEAM_HORDE]);
|
||||
data << uint32(0x745) << uint32(0x2); // 37 1861 unk
|
||||
}
|
||||
|
||||
void BattlegroundAB::SendNodeUpdate(uint8 node)
|
||||
{
|
||||
UpdateWorldState(_capturePointInfo[node]._iconNone, 0);
|
||||
for (uint8 i = BG_AB_NODE_STATE_ALLY_OCCUPIED; i <= BG_AB_NODE_STATE_HORDE_CONTESTED; ++i)
|
||||
UpdateWorldState(_capturePointInfo[node]._iconCapture + i-1, _capturePointInfo[node]._state == i);
|
||||
|
||||
UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, _controlledPoints[TEAM_ALLIANCE]);
|
||||
UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, _controlledPoints[TEAM_HORDE]);
|
||||
}
|
||||
|
||||
void BattlegroundAB::NodeOccupied(uint8 node)
|
||||
{
|
||||
ApplyPhaseMask();
|
||||
AddSpiritGuide(node, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], _capturePointInfo[node]._ownerTeamId);
|
||||
|
||||
++_controlledPoints[_capturePointInfo[node]._ownerTeamId];
|
||||
if (_controlledPoints[_capturePointInfo[node]._ownerTeamId] >= 5)
|
||||
CastSpellOnTeam(SPELL_AB_QUEST_REWARD_5_BASES, _capturePointInfo[node]._ownerTeamId);
|
||||
if (_controlledPoints[_capturePointInfo[node]._ownerTeamId] >= 4)
|
||||
CastSpellOnTeam(SPELL_AB_QUEST_REWARD_4_BASES, _capturePointInfo[node]._ownerTeamId);
|
||||
|
||||
Creature* trigger = GetBgMap()->GetCreature(BgCreatures[BG_AB_ALL_NODES_COUNT + node]);
|
||||
if (!trigger)
|
||||
trigger = AddCreature(WORLD_TRIGGER, BG_AB_ALL_NODES_COUNT + node, BG_AB_NodePositions[node][0], BG_AB_NodePositions[node][1], BG_AB_NodePositions[node][2], BG_AB_NodePositions[node][3]);
|
||||
|
||||
if (trigger)
|
||||
{
|
||||
trigger->setFaction(_capturePointInfo[node]._ownerTeamId == TEAM_ALLIANCE ? 84 : 83);
|
||||
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, false);
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundAB::NodeDeoccupied(uint8 node)
|
||||
{
|
||||
--_controlledPoints[_capturePointInfo[node]._ownerTeamId];
|
||||
|
||||
_capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL;
|
||||
RelocateDeadPlayers(BgCreatures[node]);
|
||||
|
||||
DelCreature(node); // Delete spirit healer
|
||||
DelCreature(BG_AB_ALL_NODES_COUNT + node); // Delete aura trigger
|
||||
}
|
||||
|
||||
void BattlegroundAB::EventPlayerClickedOnFlag(Player* player, GameObject* gameObject)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS || !player->IsWithinDistInMap(gameObject, 10.0f))
|
||||
return;
|
||||
|
||||
uint8 node = BG_AB_NODE_STABLES;
|
||||
for (; node < BG_AB_DYNAMIC_NODES_COUNT; ++node)
|
||||
if (player->GetDistance2d(BG_AB_NodePositions[node][0], BG_AB_NodePositions[node][1]) < 10.0f)
|
||||
break;
|
||||
|
||||
if (node == BG_AB_DYNAMIC_NODES_COUNT || _capturePointInfo[node]._ownerTeamId == player->GetTeamId() ||
|
||||
(_capturePointInfo[node]._state == BG_AB_NODE_STATE_ALLY_CONTESTED && player->GetTeamId() == TEAM_ALLIANCE) ||
|
||||
(_capturePointInfo[node]._state == BG_AB_NODE_STATE_HORDE_CONTESTED && player->GetTeamId() == TEAM_HORDE))
|
||||
return;
|
||||
|
||||
player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
|
||||
uint32 sound = 0;
|
||||
uint32 message = 0;
|
||||
uint32 message2 = 0;
|
||||
DeleteBanner(node);
|
||||
CreateBanner(node, true);
|
||||
|
||||
if (_capturePointInfo[node]._state == BG_AB_NODE_STATE_NEUTRAL)
|
||||
{
|
||||
player->KilledMonsterCredit(BG_AB_QUEST_CREDIT_BASE + node, 0);
|
||||
UpdatePlayerScore(player, SCORE_BASES_ASSAULTED, 1);
|
||||
_capturePointInfo[node]._state = BG_AB_NODE_STATE_ALLY_CONTESTED + player->GetTeamId();
|
||||
_capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL;
|
||||
_bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME);
|
||||
sound = BG_AB_SOUND_NODE_CLAIMED;
|
||||
message = LANG_BG_AB_NODE_CLAIMED;
|
||||
message2 = player->GetTeamId() == TEAM_ALLIANCE ? LANG_BG_AB_ALLY : LANG_BG_AB_HORDE;
|
||||
}
|
||||
else if (_capturePointInfo[node]._state == BG_AB_NODE_STATE_ALLY_CONTESTED || _capturePointInfo[node]._state == BG_AB_NODE_STATE_HORDE_CONTESTED)
|
||||
{
|
||||
if (!_capturePointInfo[node]._captured)
|
||||
{
|
||||
player->KilledMonsterCredit(BG_AB_QUEST_CREDIT_BASE + node, 0);
|
||||
UpdatePlayerScore(player, SCORE_BASES_ASSAULTED, 1);
|
||||
_capturePointInfo[node]._state = BG_AB_NODE_STATE_ALLY_CONTESTED + player->GetTeamId();
|
||||
_capturePointInfo[node]._ownerTeamId = TEAM_NEUTRAL;
|
||||
_bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME);
|
||||
message = LANG_BG_AB_NODE_ASSAULTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePlayerScore(player, SCORE_BASES_DEFENDED, 1);
|
||||
_capturePointInfo[node]._state = BG_AB_NODE_STATE_ALLY_OCCUPIED + player->GetTeamId();
|
||||
_capturePointInfo[node]._ownerTeamId = player->GetTeamId();
|
||||
_bgEvents.CancelEvent(BG_AB_EVENT_CAPTURE_STABLE + node);
|
||||
NodeOccupied(node); // after setting team owner
|
||||
message = LANG_BG_AB_NODE_DEFENDED;
|
||||
}
|
||||
sound = player->GetTeamId() == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->KilledMonsterCredit(BG_AB_QUEST_CREDIT_BASE + node, 0);
|
||||
UpdatePlayerScore(player, SCORE_BASES_ASSAULTED, 1);
|
||||
NodeDeoccupied(node); // before setting team owner to neutral
|
||||
|
||||
_capturePointInfo[node]._state = BG_AB_NODE_STATE_ALLY_CONTESTED + player->GetTeamId();
|
||||
|
||||
ApplyPhaseMask();
|
||||
_bgEvents.RescheduleEvent(BG_AB_EVENT_CAPTURE_STABLE + node, BG_AB_FLAG_CAPTURING_TIME);
|
||||
message = LANG_BG_AB_NODE_ASSAULTED;
|
||||
sound = player->GetTeamId() == TEAM_ALLIANCE ? BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE : BG_AB_SOUND_NODE_ASSAULTED_HORDE;
|
||||
}
|
||||
|
||||
SendNodeUpdate(node);
|
||||
PlaySoundToAll(sound);
|
||||
SendMessage2ToAll(message, player->GetTeamId() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE, player, LANG_BG_AB_NODE_STABLES + node, message2);
|
||||
}
|
||||
|
||||
TeamId BattlegroundAB::GetPrematureWinner()
|
||||
{
|
||||
if (_controlledPoints[TEAM_ALLIANCE] > _controlledPoints[TEAM_HORDE])
|
||||
return TEAM_ALLIANCE;
|
||||
return _controlledPoints[TEAM_HORDE] > _controlledPoints[TEAM_ALLIANCE] ? TEAM_HORDE : Battleground::GetPrematureWinner();
|
||||
}
|
||||
|
||||
bool BattlegroundAB::SetupBattleground()
|
||||
{
|
||||
for (uint32 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_NODE_BANNER_0 + i, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_BANNER_ALLY + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_BANNER_A, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_BANNER_HORDE + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_BANNER_H, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_BANNER_CONT_A + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_BANNER_CONT_A, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_BANNER_CONT_H + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_BANNER_CONT_H, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_AURA_ALLY + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_AURA_A, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_AURA_HORDE + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_AURA_H, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_AURA_CONTESTED + BG_AB_OBJECTS_PER_NODE*i, BG_AB_OBJECTID_AURA_C, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
AddObject(BG_AB_OBJECT_GATE_A, BG_AB_OBJECTID_GATE_A, BG_AB_DoorPositions[0][0], BG_AB_DoorPositions[0][1], BG_AB_DoorPositions[0][2], BG_AB_DoorPositions[0][3], BG_AB_DoorPositions[0][4], BG_AB_DoorPositions[0][5], BG_AB_DoorPositions[0][6], BG_AB_DoorPositions[0][7], RESPAWN_IMMEDIATELY);
|
||||
AddObject(BG_AB_OBJECT_GATE_H, BG_AB_OBJECTID_GATE_H, BG_AB_DoorPositions[1][0], BG_AB_DoorPositions[1][1], BG_AB_DoorPositions[1][2], BG_AB_DoorPositions[1][3], BG_AB_DoorPositions[1][4], BG_AB_DoorPositions[1][5], BG_AB_DoorPositions[1][6], BG_AB_DoorPositions[1][7], RESPAWN_IMMEDIATELY);
|
||||
|
||||
for (uint32 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
{
|
||||
AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i, Buff_Entries[0], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 1, Buff_Entries[1], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
AddObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + 3 * i + 2, Buff_Entries[2], BG_AB_BuffPositions[i][0], BG_AB_BuffPositions[i][1], BG_AB_BuffPositions[i][2], BG_AB_BuffPositions[i][3], 0, 0, sin(BG_AB_BuffPositions[i][3]/2), cos(BG_AB_BuffPositions[i][3]/2), RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
AddSpiritGuide(BG_AB_SPIRIT_ALIANCE, BG_AB_SpiritGuidePos[BG_AB_SPIRIT_ALIANCE][0], BG_AB_SpiritGuidePos[BG_AB_SPIRIT_ALIANCE][1], BG_AB_SpiritGuidePos[BG_AB_SPIRIT_ALIANCE][2], BG_AB_SpiritGuidePos[BG_AB_SPIRIT_ALIANCE][3], TEAM_ALLIANCE);
|
||||
AddSpiritGuide(BG_AB_SPIRIT_HORDE, BG_AB_SpiritGuidePos[BG_AB_SPIRIT_HORDE][0], BG_AB_SpiritGuidePos[BG_AB_SPIRIT_HORDE][1], BG_AB_SpiritGuidePos[BG_AB_SPIRIT_HORDE][2], BG_AB_SpiritGuidePos[BG_AB_SPIRIT_HORDE][3], TEAM_HORDE);
|
||||
|
||||
for (uint32 i = BG_AB_OBJECT_BANNER_NEUTRAL; i < BG_AB_OBJECT_MAX; ++i)
|
||||
if (BgObjects[i] == 0)
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundAB: Failed to spawn some object Battleground not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32 i = BG_AB_SPIRIT_ALIANCE; i <= BG_AB_SPIRIT_HORDE; ++i)
|
||||
if (BgCreatures[i] == 0)
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundAB: Failed to spawn spirit guides Battleground not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundAB::Init()
|
||||
{
|
||||
//call parent's class reset
|
||||
Battleground::Init();
|
||||
|
||||
_bgEvents.Reset();
|
||||
|
||||
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID()) ? BG_AB_HONOR_TICK_WEEKEND : BG_AB_HONOR_TICK_NORMAL;
|
||||
_reputationTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID()) ? BG_AB_REP_TICK_WEEKEND : BG_AB_REP_TICK_NORMAL;
|
||||
|
||||
_capturePointInfo[BG_AB_NODE_STABLES]._iconNone = BG_AB_OP_STABLE_ICON;
|
||||
_capturePointInfo[BG_AB_NODE_FARM]._iconNone = BG_AB_OP_FARM_ICON;
|
||||
_capturePointInfo[BG_AB_NODE_BLACKSMITH]._iconNone = BG_AB_OP_BLACKSMITH_ICON;
|
||||
_capturePointInfo[BG_AB_NODE_LUMBER_MILL]._iconNone = BG_AB_OP_LUMBERMILL_ICON;
|
||||
_capturePointInfo[BG_AB_NODE_GOLD_MINE]._iconNone = BG_AB_OP_GOLDMINE_ICON;
|
||||
_capturePointInfo[BG_AB_NODE_STABLES]._iconCapture = BG_AB_OP_STABLE_STATE_ALIENCE;
|
||||
_capturePointInfo[BG_AB_NODE_FARM]._iconCapture = BG_AB_OP_FARM_STATE_ALIENCE;
|
||||
_capturePointInfo[BG_AB_NODE_BLACKSMITH]._iconCapture = BG_AB_OP_BLACKSMITH_STATE_ALIENCE;
|
||||
_capturePointInfo[BG_AB_NODE_LUMBER_MILL]._iconCapture = BG_AB_OP_LUMBERMILL_STATE_ALIENCE;
|
||||
_capturePointInfo[BG_AB_NODE_GOLD_MINE]._iconCapture = BG_AB_OP_GOLDMINE_STATE_ALIENCE;
|
||||
}
|
||||
|
||||
void BattlegroundAB::EndBattleground(TeamId winnerTeamId)
|
||||
{
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), winnerTeamId);
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), TEAM_HORDE);
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), TEAM_ALLIANCE);
|
||||
Battleground::EndBattleground(winnerTeamId);
|
||||
_bgEvents.Reset();
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const* BattlegroundAB::GetClosestGraveyard(Player* player)
|
||||
{
|
||||
WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[BG_AB_SPIRIT_ALIANCE + player->GetTeamId()]);
|
||||
WorldSafeLocsEntry const* nearestEntry = entry;
|
||||
|
||||
float pX = player->GetPositionX();
|
||||
float pY = player->GetPositionY();
|
||||
float dist = (entry->x - pX)*(entry->x - pX)+(entry->y - pY)*(entry->y - pY);
|
||||
float minDist = dist;
|
||||
|
||||
for (uint8 i = BG_AB_NODE_STABLES; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
if (_capturePointInfo[i]._ownerTeamId == player->GetTeamId())
|
||||
{
|
||||
entry = sWorldSafeLocsStore.LookupEntry(BG_AB_GraveyardIds[i]);
|
||||
dist = (entry->x - pX)*(entry->x - pX) + (entry->y - pY)*(entry->y - pY);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
nearestEntry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return nearestEntry;
|
||||
}
|
||||
|
||||
void BattlegroundAB::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
|
||||
{
|
||||
BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID());
|
||||
if (itr == PlayerScores.end())
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SCORE_BASES_ASSAULTED:
|
||||
((BattlegroundABScore*)itr->second)->BasesAssaulted += value;
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_AB_OBJECTIVE_ASSAULT_BASE);
|
||||
break;
|
||||
case SCORE_BASES_DEFENDED:
|
||||
((BattlegroundABScore*)itr->second)->BasesDefended += value;
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_AB_OBJECTIVE_DEFEND_BASE);
|
||||
break;
|
||||
default:
|
||||
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool BattlegroundAB::AllNodesConrolledByTeam(TeamId teamId) const
|
||||
{
|
||||
return _controlledPoints[teamId] == BG_AB_DYNAMIC_NODES_COUNT;
|
||||
}
|
||||
|
||||
void BattlegroundAB::ApplyPhaseMask()
|
||||
{
|
||||
uint32 phaseMask = 1;
|
||||
for (uint32 i = BG_AB_NODE_STABLES; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
|
||||
if (_capturePointInfo[i]._ownerTeamId != TEAM_NEUTRAL)
|
||||
phaseMask |= 1 << (i*2+1 + _capturePointInfo[i]._ownerTeamId);
|
||||
|
||||
const BattlegroundPlayerMap& bgPlayerMap = GetPlayers();
|
||||
for (BattlegroundPlayerMap::const_iterator itr = bgPlayerMap.begin(); itr != bgPlayerMap.end(); ++itr)
|
||||
{
|
||||
itr->second->SetPhaseMask(phaseMask, false);
|
||||
itr->second->UpdateObjectVisibility(true, false);
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUNDAB_H
|
||||
#define __BATTLEGROUNDAB_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BG_AB_Events
|
||||
{
|
||||
BG_AB_EVENT_UPDATE_BANNER_STABLE = 1,
|
||||
BG_AB_EVENT_UPDATE_BANNER_FARM = 2,
|
||||
BG_AB_EVENT_UPDATE_BANNER_BLACKSMITH = 3,
|
||||
BG_AB_EVENT_UPDATE_BANNER_LUMBERMILL = 4,
|
||||
BG_AB_EVENT_UPDATE_BANNER_GOLDMINE = 5,
|
||||
|
||||
BG_AB_EVENT_CAPTURE_STABLE = 6,
|
||||
BG_AB_EVENT_CAPTURE_FARM = 7,
|
||||
BG_AB_EVENT_CAPTURE_BLACKSMITH = 8,
|
||||
BG_AB_EVENT_CAPTURE_LUMBERMILL = 9,
|
||||
BG_AB_EVENT_CAPTURE_GOLDMINE = 10,
|
||||
|
||||
BG_AB_EVENT_ALLIANCE_TICK = 11,
|
||||
BG_AB_EVENT_HORDE_TICK = 12
|
||||
};
|
||||
|
||||
enum BG_AB_WorldStates
|
||||
{
|
||||
BG_AB_OP_OCCUPIED_BASES_HORDE = 1778,
|
||||
BG_AB_OP_OCCUPIED_BASES_ALLY = 1779,
|
||||
BG_AB_OP_RESOURCES_ALLY = 1776,
|
||||
BG_AB_OP_RESOURCES_HORDE = 1777,
|
||||
BG_AB_OP_RESOURCES_MAX = 1780,
|
||||
BG_AB_OP_RESOURCES_WARNING = 1955,
|
||||
|
||||
BG_AB_OP_STABLE_ICON = 1842, //Stable map icon (NONE)
|
||||
BG_AB_OP_STABLE_STATE_ALIENCE = 1767, //Stable map state (ALIENCE)
|
||||
BG_AB_OP_STABLE_STATE_HORDE = 1768, //Stable map state (HORDE)
|
||||
BG_AB_OP_STABLE_STATE_CON_ALI = 1769, //Stable map state (CON ALIENCE)
|
||||
BG_AB_OP_STABLE_STATE_CON_HOR = 1770, //Stable map state (CON HORDE)
|
||||
|
||||
BG_AB_OP_FARM_ICON = 1845, //Farm map icon (NONE)
|
||||
BG_AB_OP_FARM_STATE_ALIENCE = 1772, //Farm state (ALIENCE)
|
||||
BG_AB_OP_FARM_STATE_HORDE = 1773, //Farm state (HORDE)
|
||||
BG_AB_OP_FARM_STATE_CON_ALI = 1774, //Farm state (CON ALIENCE)
|
||||
BG_AB_OP_FARM_STATE_CON_HOR = 1775, //Farm state (CON HORDE)
|
||||
|
||||
BG_AB_OP_BLACKSMITH_ICON = 1846, //Blacksmith map icon (NONE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_ALIENCE = 1782, //Blacksmith map state (ALIENCE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_HORDE = 1783, //Blacksmith map state (HORDE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_CON_ALI = 1784, //Blacksmith map state (CON ALIENCE)
|
||||
BG_AB_OP_BLACKSMITH_STATE_CON_HOR = 1785, //Blacksmith map state (CON HORDE)
|
||||
|
||||
BG_AB_OP_LUMBERMILL_ICON = 1844, //Lumber Mill map icon (NONE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_ALIENCE = 1792, //Lumber Mill map state (ALIENCE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_HORDE = 1793, //Lumber Mill map state (HORDE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_CON_ALI = 1794, //Lumber Mill map state (CON ALIENCE)
|
||||
BG_AB_OP_LUMBERMILL_STATE_CON_HOR = 1795, //Lumber Mill map state (CON HORDE)
|
||||
|
||||
BG_AB_OP_GOLDMINE_ICON = 1843, //Gold Mine map icon (NONE)
|
||||
BG_AB_OP_GOLDMINE_STATE_ALIENCE = 1787, //Gold Mine map state (ALIENCE)
|
||||
BG_AB_OP_GOLDMINE_STATE_HORDE = 1788, //Gold Mine map state (HORDE)
|
||||
BG_AB_OP_GOLDMINE_STATE_CON_ALI = 1789, //Gold Mine map state (CON ALIENCE
|
||||
BG_AB_OP_GOLDMINE_STATE_CON_HOR = 1790, //Gold Mine map state (CON HORDE)
|
||||
};
|
||||
|
||||
enum BG_AB_ObjectIds
|
||||
{
|
||||
BG_AB_OBJECTID_NODE_BANNER_0 = 180087, // Stables banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_1 = 180088, // Blacksmith banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_2 = 180089, // Farm banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_3 = 180090, // Lumber mill banner
|
||||
BG_AB_OBJECTID_NODE_BANNER_4 = 180091, // Gold mine banner
|
||||
|
||||
BG_AB_OBJECTID_BANNER_A = 180058,
|
||||
BG_AB_OBJECTID_BANNER_CONT_A = 180059,
|
||||
BG_AB_OBJECTID_BANNER_H = 180060,
|
||||
BG_AB_OBJECTID_BANNER_CONT_H = 180061,
|
||||
|
||||
BG_AB_OBJECTID_AURA_A = 180100,
|
||||
BG_AB_OBJECTID_AURA_H = 180101,
|
||||
BG_AB_OBJECTID_AURA_C = 180102,
|
||||
|
||||
BG_AB_OBJECTID_GATE_A = 180255,
|
||||
BG_AB_OBJECTID_GATE_H = 180256
|
||||
};
|
||||
|
||||
enum BG_AB_ObjectType
|
||||
{
|
||||
BG_AB_OBJECT_BANNER_NEUTRAL = 0,
|
||||
BG_AB_OBJECT_BANNER_ALLY = 1,
|
||||
BG_AB_OBJECT_BANNER_HORDE = 2,
|
||||
BG_AB_OBJECT_BANNER_CONT_A = 3,
|
||||
BG_AB_OBJECT_BANNER_CONT_H = 4,
|
||||
BG_AB_OBJECT_AURA_ALLY = 5,
|
||||
BG_AB_OBJECT_AURA_HORDE = 6,
|
||||
BG_AB_OBJECT_AURA_CONTESTED = 7,
|
||||
BG_AB_OBJECTS_PER_NODE = 8,
|
||||
|
||||
BG_AB_OBJECT_GATE_A = 40,
|
||||
BG_AB_OBJECT_GATE_H = 41,
|
||||
|
||||
BG_AB_OBJECT_SPEEDBUFF_STABLES = 42,
|
||||
BG_AB_OBJECT_REGENBUFF_STABLES = 43,
|
||||
BG_AB_OBJECT_BERSERKBUFF_STABLES = 44,
|
||||
BG_AB_OBJECT_SPEEDBUFF_BLACKSMITH = 45,
|
||||
BG_AB_OBJECT_REGENBUFF_BLACKSMITH = 46,
|
||||
BG_AB_OBJECT_BERSERKBUFF_BLACKSMITH = 47,
|
||||
BG_AB_OBJECT_SPEEDBUFF_FARM = 48,
|
||||
BG_AB_OBJECT_REGENBUFF_FARM = 49,
|
||||
BG_AB_OBJECT_BERSERKBUFF_FARM = 50,
|
||||
BG_AB_OBJECT_SPEEDBUFF_LUMBER_MILL = 51,
|
||||
BG_AB_OBJECT_REGENBUFF_LUMBER_MILL = 52,
|
||||
BG_AB_OBJECT_BERSERKBUFF_LUMBER_MILL = 53,
|
||||
BG_AB_OBJECT_SPEEDBUFF_GOLD_MINE = 54,
|
||||
BG_AB_OBJECT_REGENBUFF_GOLD_MINE = 55,
|
||||
BG_AB_OBJECT_BERSERKBUFF_GOLD_MINE = 56,
|
||||
BG_AB_OBJECT_MAX = 57,
|
||||
};
|
||||
|
||||
enum BG_AB_BattlegroundNodes
|
||||
{
|
||||
BG_AB_NODE_STABLES = 0,
|
||||
BG_AB_NODE_BLACKSMITH = 1,
|
||||
BG_AB_NODE_FARM = 2,
|
||||
BG_AB_NODE_LUMBER_MILL = 3,
|
||||
BG_AB_NODE_GOLD_MINE = 4,
|
||||
BG_AB_DYNAMIC_NODES_COUNT = 5, // dynamic nodes that can be captured
|
||||
|
||||
BG_AB_SPIRIT_ALIANCE = 5,
|
||||
BG_AB_SPIRIT_HORDE = 6,
|
||||
BG_AB_ALL_NODES_COUNT = 7, // all nodes (dynamic and static)
|
||||
};
|
||||
|
||||
enum BG_AB_NodeStatus
|
||||
{
|
||||
BG_AB_NODE_STATE_NEUTRAL = 0,
|
||||
BG_AB_NODE_STATE_ALLY_OCCUPIED = 1,
|
||||
BG_AB_NODE_STATE_HORDE_OCCUPIED = 2,
|
||||
BG_AB_NODE_STATE_ALLY_CONTESTED = 3,
|
||||
BG_AB_NODE_STATE_HORDE_CONTESTED = 4
|
||||
};
|
||||
|
||||
enum BG_AB_Sounds
|
||||
{
|
||||
BG_AB_SOUND_NODE_CLAIMED = 8192,
|
||||
BG_AB_SOUND_NODE_CAPTURED_ALLIANCE = 8173,
|
||||
BG_AB_SOUND_NODE_CAPTURED_HORDE = 8213,
|
||||
BG_AB_SOUND_NODE_ASSAULTED_ALLIANCE = 8212,
|
||||
BG_AB_SOUND_NODE_ASSAULTED_HORDE = 8174,
|
||||
BG_AB_SOUND_NEAR_VICTORY = 8456
|
||||
};
|
||||
|
||||
enum BG_AB_Misc
|
||||
{
|
||||
BG_AB_OBJECTIVE_ASSAULT_BASE = 122,
|
||||
BG_AB_OBJECTIVE_DEFEND_BASE = 123,
|
||||
BG_AB_EVENT_START_BATTLE = 9158, // Achievement: Let's Get This Done
|
||||
BG_AB_QUEST_CREDIT_BASE = 15001,
|
||||
|
||||
BG_AB_HONOR_TICK_NORMAL = 260,
|
||||
BG_AB_HONOR_TICK_WEEKEND = 160,
|
||||
BG_AB_REP_TICK_NORMAL = 160,
|
||||
BG_AB_REP_TICK_WEEKEND = 120,
|
||||
|
||||
BG_AB_WARNING_NEAR_VICTORY_SCORE = 1400,
|
||||
BG_AB_MAX_TEAM_SCORE = 1600,
|
||||
|
||||
BG_AB_FLAG_CAPTURING_TIME = 60000,
|
||||
BG_AB_BANNER_UPDATE_TIME = 2000
|
||||
};
|
||||
|
||||
const uint32 BG_AB_TickIntervals[BG_AB_DYNAMIC_NODES_COUNT+1] = {0, 12000, 9000, 6000, 3000, 1000};
|
||||
const uint32 BG_AB_TickPoints[BG_AB_DYNAMIC_NODES_COUNT+1] = {0, 10, 10, 10, 10, 30};
|
||||
const uint32 BG_AB_GraveyardIds[BG_AB_ALL_NODES_COUNT] = {895, 894, 893, 897, 896, 898, 899};
|
||||
|
||||
const float BG_AB_BuffPositions[BG_AB_DYNAMIC_NODES_COUNT][4] =
|
||||
{
|
||||
{1185.71f, 1185.24f, -56.36f, 2.56f}, // stables
|
||||
{990.75f, 1008.18f, -42.60f, 2.43f}, // blacksmith
|
||||
{817.66f, 843.34f, -56.54f, 3.01f}, // farm
|
||||
{807.46f, 1189.16f, 11.92f, 5.44f}, // lumber mill
|
||||
{1146.62f, 816.94f, -98.49f, 6.14f} // gold mine
|
||||
};
|
||||
|
||||
const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] =
|
||||
{
|
||||
{1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables
|
||||
{977.0156f, 1046.616f, -44.80923f, -2.600541f}, // blacksmith
|
||||
{806.1821f, 874.2723f, -55.99371f, -2.303835f}, // farm
|
||||
{856.1419f, 1148.902f, 11.18469f, -2.303835f}, // lumber mill
|
||||
{1146.923f, 848.1782f, -110.917f, -0.7330382f} // gold mine
|
||||
};
|
||||
|
||||
const float BG_AB_DoorPositions[2][8] =
|
||||
{
|
||||
{1284.597f, 1281.167f, -15.97792f, 0.7068594f, 0.012957f, -0.060288f, 0.344959f, 0.93659f},
|
||||
{708.0903f, 708.4479f, -17.8342f, -2.391099f, 0.050291f, 0.015127f, 0.929217f, -0.365784f}
|
||||
};
|
||||
|
||||
const float BG_AB_SpiritGuidePos[BG_AB_ALL_NODES_COUNT][4] =
|
||||
{
|
||||
{1200.03f, 1171.09f, -56.47f, 5.15f}, // stables
|
||||
{1017.43f, 960.61f, -42.95f, 4.88f}, // blacksmith
|
||||
{833.00f, 793.00f, -57.25f, 5.27f}, // farm
|
||||
{775.17f, 1206.40f, 15.79f, 1.90f}, // lumber mill
|
||||
{1207.48f, 787.00f, -83.36f, 5.51f}, // gold mine
|
||||
{1354.05f, 1275.48f, -11.30f, 4.77f}, // alliance starting base
|
||||
{714.61f, 646.15f, -10.87f, 4.34f} // horde starting base
|
||||
};
|
||||
|
||||
struct BattlegroundABScore : public BattlegroundScore
|
||||
{
|
||||
BattlegroundABScore(Player* player) : BattlegroundScore(player), BasesAssaulted(0), BasesDefended(0) { }
|
||||
~BattlegroundABScore() { }
|
||||
uint32 BasesAssaulted;
|
||||
uint32 BasesDefended;
|
||||
|
||||
uint32 GetAttr1() const final override { return BasesAssaulted; }
|
||||
uint32 GetAttr2() const final override { return BasesDefended; }
|
||||
};
|
||||
|
||||
class BattlegroundAB : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundAB();
|
||||
~BattlegroundAB();
|
||||
|
||||
void AddPlayer(Player* player);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
void RemovePlayer(Player* player);
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
bool SetupBattleground();
|
||||
void Init();
|
||||
void EndBattleground(TeamId winnerTeamId);
|
||||
WorldSafeLocsEntry const* GetClosestGraveyard(Player* player);
|
||||
|
||||
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
|
||||
void FillInitialWorldStates(WorldPacket& data);
|
||||
void EventPlayerClickedOnFlag(Player* source, GameObject* gameObject);
|
||||
|
||||
bool AllNodesConrolledByTeam(TeamId teamId) const;
|
||||
bool IsTeamScores500Disadvantage(TeamId teamId) const { return _teamScores500Disadvantage[teamId]; }
|
||||
|
||||
TeamId GetPrematureWinner();
|
||||
private:
|
||||
void PostUpdateImpl(uint32 diff);
|
||||
|
||||
void DeleteBanner(uint8 node);
|
||||
void CreateBanner(uint8 node, bool delay);
|
||||
void SendNodeUpdate(uint8 node);
|
||||
void NodeOccupied(uint8 node);
|
||||
void NodeDeoccupied(uint8 node);
|
||||
void ApplyPhaseMask();
|
||||
|
||||
struct CapturePointInfo
|
||||
{
|
||||
CapturePointInfo() : _ownerTeamId(TEAM_NEUTRAL), _iconNone(0), _iconCapture(0), _state(BG_AB_NODE_STATE_NEUTRAL), _captured(false)
|
||||
{
|
||||
}
|
||||
|
||||
uint8 _state;
|
||||
uint32 _iconNone;
|
||||
uint32 _iconCapture;
|
||||
TeamId _ownerTeamId;
|
||||
bool _captured;
|
||||
};
|
||||
|
||||
CapturePointInfo _capturePointInfo[BG_AB_DYNAMIC_NODES_COUNT];
|
||||
EventMap _bgEvents;
|
||||
uint32 _honorTics;
|
||||
uint32 _reputationTics;
|
||||
uint8 _controlledPoints[BG_TEAMS_COUNT];
|
||||
bool _teamScores500Disadvantage[BG_TEAMS_COUNT];
|
||||
};
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BattlegroundBE.h"
|
||||
#include "Language.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BattlegroundBE::BattlegroundBE()
|
||||
{
|
||||
BgObjects.resize(BG_BE_OBJECT_MAX);
|
||||
|
||||
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
|
||||
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
|
||||
//we must set messageIds
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
|
||||
}
|
||||
|
||||
BattlegroundBE::~BattlegroundBE()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattlegroundBE::StartingEventCloseDoors()
|
||||
{
|
||||
for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; ++i)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
|
||||
for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i)
|
||||
SpawnBGObject(i, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
void BattlegroundBE::StartingEventOpenDoors()
|
||||
{
|
||||
for (uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
void BattlegroundBE::AddPlayer(Player* player)
|
||||
{
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundBE::RemovePlayer(Player* /*player*/)
|
||||
{
|
||||
if (GetStatus() == STATUS_WAIT_LEAVE)
|
||||
return;
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
void BattlegroundBE::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (!killer)
|
||||
{
|
||||
sLog->outError("Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Battleground::HandleKillPlayer(player, killer);
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
bool BattlegroundBE::HandlePlayerUnderMap(Player* player)
|
||||
{
|
||||
player->NearTeleportTo(6238.930176f, 262.963470f, 0.889519f, player->GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundBE::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
// this is wrong way to implement these things. On official it done by gameobject spell cast.
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4538: // buff trigger?
|
||||
//buff_guid = BgObjects[BG_BE_OBJECT_BUFF_1];
|
||||
break;
|
||||
case 4539: // buff trigger?
|
||||
//buff_guid = BgObjects[BG_BE_OBJECT_BUFF_2];
|
||||
break;
|
||||
// OUTSIDE OF ARENA, TELEPORT!
|
||||
case 4919:
|
||||
player->NearTeleportTo(6220.90f, 318.94f, 5.1f, 5.3f);
|
||||
break;
|
||||
case 4921:
|
||||
player->NearTeleportTo(6250.27f, 208.50f, 4.77f, 1.9f);
|
||||
break;
|
||||
case 4922:
|
||||
player->NearTeleportTo(6214.4f, 227.12f, 4.28f, 0.8f);
|
||||
break;
|
||||
case 4923:
|
||||
player->NearTeleportTo(6180.98f, 265.28f, 4.27f, 6.06f);
|
||||
break;
|
||||
case 4924:
|
||||
player->NearTeleportTo(6269.0f, 295.06f, 4.46f, 3.98f);
|
||||
break;
|
||||
case 4944: // under arena -20
|
||||
case 5039: // under arena -40
|
||||
case 5040: // under arena -60
|
||||
player->NearTeleportTo(6238.930176f, 262.963470f, 0.889519f, player->GetOrientation());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundBE::FillInitialWorldStates(WorldPacket &data)
|
||||
{
|
||||
data << uint32(0x9f3) << uint32(1); // 9
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundBE::Init()
|
||||
{
|
||||
//call parent's class reset
|
||||
Battleground::Init();
|
||||
}
|
||||
|
||||
bool BattlegroundBE::SetupBattleground()
|
||||
{
|
||||
// gates
|
||||
if (!AddObject(BG_BE_OBJECT_DOOR_1, BG_BE_OBJECT_TYPE_DOOR_1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_BE_OBJECT_DOOR_2, BG_BE_OBJECT_TYPE_DOOR_2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_BE_OBJECT_DOOR_3, BG_BE_OBJECT_TYPE_DOOR_3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_BE_OBJECT_DOOR_4, BG_BE_OBJECT_TYPE_DOOR_4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, RESPAWN_IMMEDIATELY)
|
||||
// buffs
|
||||
|| !AddObject(BG_BE_OBJECT_BUFF_1, BG_BE_OBJECT_TYPE_BUFF_1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|
||||
|| !AddObject(BG_BE_OBJECT_BUFF_2, BG_BE_OBJECT_TYPE_BUFF_2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120)
|
||||
// Arena Ready Marker
|
||||
|| !AddObject(BG_BE_OBJECT_READY_MARKER_1, ARENA_READY_MARKER_ENTRY, 6189.47f, 235.54f, 5.52f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300)
|
||||
|| !AddObject(BG_BE_OBJECT_READY_MARKER_2, ARENA_READY_MARKER_ENTRY, 6287.19f, 288.25f, 5.33f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundBE: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundBE::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
|
||||
{
|
||||
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUNDBE_H
|
||||
#define __BATTLEGROUNDBE_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BattlegroundBEObjectTypes
|
||||
{
|
||||
BG_BE_OBJECT_DOOR_1 = 0,
|
||||
BG_BE_OBJECT_DOOR_2 = 1,
|
||||
BG_BE_OBJECT_DOOR_3 = 2,
|
||||
BG_BE_OBJECT_DOOR_4 = 3,
|
||||
BG_BE_OBJECT_BUFF_1 = 4,
|
||||
BG_BE_OBJECT_BUFF_2 = 5,
|
||||
BG_BE_OBJECT_READY_MARKER_1 = 6,
|
||||
BG_BE_OBJECT_READY_MARKER_2 = 7,
|
||||
BG_BE_OBJECT_MAX = 8
|
||||
};
|
||||
|
||||
enum BattlegroundBEObjects
|
||||
{
|
||||
BG_BE_OBJECT_TYPE_DOOR_1 = 183971,
|
||||
BG_BE_OBJECT_TYPE_DOOR_2 = 183973,
|
||||
BG_BE_OBJECT_TYPE_DOOR_3 = 183970,
|
||||
BG_BE_OBJECT_TYPE_DOOR_4 = 183972,
|
||||
BG_BE_OBJECT_TYPE_BUFF_1 = 184663,
|
||||
BG_BE_OBJECT_TYPE_BUFF_2 = 184664
|
||||
};
|
||||
|
||||
class BattlegroundBE : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundBE();
|
||||
~BattlegroundBE();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void AddPlayer(Player* player);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
|
||||
void RemovePlayer(Player* player);
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
bool SetupBattleground();
|
||||
void Init();
|
||||
void FillInitialWorldStates(WorldPacket &d);
|
||||
void HandleKillPlayer(Player* player, Player* killer);
|
||||
bool HandlePlayerUnderMap(Player* player);
|
||||
|
||||
/* Scorekeeping */
|
||||
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
|
||||
};
|
||||
#endif
|
||||
@@ -1,267 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BattlegroundDS.h"
|
||||
#include "Creature.h"
|
||||
#include "GameObject.h"
|
||||
#include "Language.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BattlegroundDS::BattlegroundDS()
|
||||
{
|
||||
BgObjects.resize(BG_DS_OBJECT_MAX);
|
||||
BgCreatures.resize(BG_DS_NPC_MAX);
|
||||
|
||||
_waterfallTimer = 0;
|
||||
_waterfallStatus = 0;
|
||||
_waterfallKnockbackTimer = 0;
|
||||
_pipeKnockBackTimer = 0;
|
||||
_pipeKnockBackCount = 0;
|
||||
|
||||
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
|
||||
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
|
||||
//we must set messageIds
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
|
||||
}
|
||||
|
||||
BattlegroundDS::~BattlegroundDS()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattlegroundDS::PostUpdateImpl(uint32 diff)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (getPipeKnockBackCount() < BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
|
||||
{
|
||||
if (getPipeKnockBackTimer() < diff)
|
||||
{
|
||||
for (uint32 i = BG_DS_NPC_PIPE_KNOCKBACK_1; i <= BG_DS_NPC_PIPE_KNOCKBACK_2; ++i)
|
||||
if (Creature* waterSpout = GetBgMap()->GetCreature(BgCreatures[i]))
|
||||
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_FLUSH, true);
|
||||
|
||||
setPipeKnockBackCount(getPipeKnockBackCount() + 1);
|
||||
setPipeKnockBackTimer(BG_DS_PIPE_KNOCKBACK_DELAY);
|
||||
}
|
||||
else
|
||||
setPipeKnockBackTimer(getPipeKnockBackTimer() - diff);
|
||||
}
|
||||
|
||||
if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_ON) // Repeat knockback while the waterfall still active
|
||||
{
|
||||
if (getWaterFallKnockbackTimer() < diff)
|
||||
{
|
||||
if (Creature* waterSpout = GetBgMap()->GetCreature(BgCreatures[BG_DS_NPC_WATERFALL_KNOCKBACK]))
|
||||
waterSpout->CastSpell(waterSpout, BG_DS_SPELL_WATER_SPOUT, true);
|
||||
|
||||
setWaterFallKnockbackTimer(BG_DS_WATERFALL_KNOCKBACK_TIMER);
|
||||
}
|
||||
else
|
||||
setWaterFallKnockbackTimer(getWaterFallKnockbackTimer() - diff);
|
||||
}
|
||||
|
||||
if (getWaterFallTimer() < diff)
|
||||
{
|
||||
if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_OFF) // Add the water
|
||||
{
|
||||
DoorClose(BG_DS_OBJECT_WATER_2);
|
||||
setWaterFallTimer(BG_DS_WATERFALL_WARNING_DURATION);
|
||||
setWaterFallStatus(BG_DS_WATERFALL_STATUS_WARNING);
|
||||
}
|
||||
else if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_WARNING) // Active collision and perform knockback
|
||||
{
|
||||
if (GameObject* gob = GetBgMap()->GetGameObject(BgObjects[BG_DS_OBJECT_WATER_1]))
|
||||
gob->SetGoState(GO_STATE_READY);
|
||||
|
||||
setWaterFallTimer(BG_DS_WATERFALL_DURATION);
|
||||
setWaterFallStatus(BG_DS_WATERFALL_STATUS_ON);
|
||||
setWaterFallKnockbackTimer(BG_DS_WATERFALL_KNOCKBACK_TIMER);
|
||||
}
|
||||
else //if (getWaterFallStatus() == BG_DS_WATERFALL_STATUS_ON) // Remove collision and water
|
||||
{
|
||||
// turn off collision
|
||||
if (GameObject* gob = GetBgMap()->GetGameObject(BgObjects[BG_DS_OBJECT_WATER_1]))
|
||||
gob->SetGoState(GO_STATE_ACTIVE);
|
||||
|
||||
DoorOpen(BG_DS_OBJECT_WATER_2);
|
||||
setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX));
|
||||
setWaterFallStatus(BG_DS_WATERFALL_STATUS_OFF);
|
||||
}
|
||||
}
|
||||
else
|
||||
setWaterFallTimer(getWaterFallTimer() - diff);
|
||||
}
|
||||
|
||||
void BattlegroundDS::StartingEventCloseDoors()
|
||||
{
|
||||
for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
void BattlegroundDS::StartingEventOpenDoors()
|
||||
{
|
||||
for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
|
||||
setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX));
|
||||
setWaterFallStatus(BG_DS_WATERFALL_STATUS_OFF);
|
||||
|
||||
setPipeKnockBackTimer(BG_DS_PIPE_KNOCKBACK_FIRST_DELAY);
|
||||
setPipeKnockBackCount(0);
|
||||
|
||||
SpawnBGObject(BG_DS_OBJECT_WATER_2, RESPAWN_IMMEDIATELY);
|
||||
DoorOpen(BG_DS_OBJECT_WATER_2);
|
||||
|
||||
// Turn off collision
|
||||
if (GameObject* gob = GetBgMap()->GetGameObject(BgObjects[BG_DS_OBJECT_WATER_1]))
|
||||
gob->SetGoState(GO_STATE_ACTIVE);
|
||||
|
||||
// Remove effects of Demonic Circle Summon
|
||||
for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
|
||||
if (itr->second->HasAura(48018))
|
||||
itr->second->RemoveAurasDueToSpell(48018);
|
||||
}
|
||||
|
||||
void BattlegroundDS::AddPlayer(Player* player)
|
||||
{
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundDS::RemovePlayer(Player* /*player*/)
|
||||
{
|
||||
if (GetStatus() == STATUS_WAIT_LEAVE)
|
||||
return;
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
void BattlegroundDS::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (!killer)
|
||||
{
|
||||
sLog->outError("BattlegroundDS: Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Battleground::HandleKillPlayer(player, killer);
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
void BattlegroundDS::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 5347:
|
||||
case 5348:
|
||||
// Remove effects of Demonic Circle Summon
|
||||
if (player->HasAura(48018))
|
||||
player->RemoveAurasDueToSpell(48018);
|
||||
|
||||
// Someone has get back into the pipes and the knockback has already been performed,
|
||||
// so we reset the knockback count for kicking the player again into the arena.
|
||||
if (getPipeKnockBackCount() >= BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT)
|
||||
setPipeKnockBackCount(0);
|
||||
break;
|
||||
// OUTSIDE OF ARENA, TELEPORT!
|
||||
case 5328:
|
||||
player->NearTeleportTo(1290.44f, 744.96f, 3.16f, 1.6f);
|
||||
break;
|
||||
case 5329:
|
||||
player->NearTeleportTo(1292.6f, 837.07f, 3.161f, 4.7f);
|
||||
break;
|
||||
case 5330:
|
||||
player->NearTeleportTo(1250.68f, 790.86f, 3.16f, 0.0f);
|
||||
break;
|
||||
case 5331:
|
||||
player->NearTeleportTo(1332.50f, 790.9f, 3.16f, 3.14f);
|
||||
break;
|
||||
case 5326: // -10
|
||||
case 5343: // -40
|
||||
case 5344: // -60
|
||||
player->NearTeleportTo(1330.0f, 800.0f, 3.16f, player->GetOrientation());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool BattlegroundDS::HandlePlayerUnderMap(Player* player)
|
||||
{
|
||||
player->NearTeleportTo(1299.046f, 784.825f, 9.338f, 2.422f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundDS::FillInitialWorldStates(WorldPacket &data)
|
||||
{
|
||||
data << uint32(3610) << uint32(1); // 9 show
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundDS::Init()
|
||||
{
|
||||
//call parent's class reset
|
||||
Battleground::Init();
|
||||
}
|
||||
|
||||
bool BattlegroundDS::SetupBattleground()
|
||||
{
|
||||
// gates
|
||||
if (!AddObject(BG_DS_OBJECT_DOOR_1, BG_DS_OBJECT_TYPE_DOOR_1, 1350.95f, 817.2f, 20.8096f, 3.15f, 0, 0, 0.99627f, 0.0862864f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_DS_OBJECT_DOOR_2, BG_DS_OBJECT_TYPE_DOOR_2, 1232.65f, 764.913f, 20.0729f, 6.3f, 0, 0, 0.0310211f, -0.999519f, RESPAWN_IMMEDIATELY)
|
||||
// water
|
||||
|| !AddObject(BG_DS_OBJECT_WATER_1, BG_DS_OBJECT_TYPE_WATER_1, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120)
|
||||
|| !AddObject(BG_DS_OBJECT_WATER_2, BG_DS_OBJECT_TYPE_WATER_2, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120)
|
||||
// buffs
|
||||
|| !AddObject(BG_DS_OBJECT_BUFF_1, BG_DS_OBJECT_TYPE_BUFF_1, 1291.7f, 813.424f, 7.11472f, 4.64562f, 0, 0, 0.730314f, -0.683111f, 120)
|
||||
|| !AddObject(BG_DS_OBJECT_BUFF_2, BG_DS_OBJECT_TYPE_BUFF_2, 1291.7f, 768.911f, 7.11472f, 1.55194f, 0, 0, 0.700409f, 0.713742f, 120)
|
||||
// knockback creatures
|
||||
|| !AddCreature(BG_DS_NPC_TYPE_WATER_SPOUT, BG_DS_NPC_WATERFALL_KNOCKBACK, 1291.76f, 791.02f, 7.115f, 3.054326f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddCreature(BG_DS_NPC_TYPE_WATER_SPOUT, BG_DS_NPC_PIPE_KNOCKBACK_1, 1369.977f, 817.2882f, 16.08718f, 3.106686f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddCreature(BG_DS_NPC_TYPE_WATER_SPOUT, BG_DS_NPC_PIPE_KNOCKBACK_2, 1212.833f, 765.3871f, 16.09484f, 0.0f, RESPAWN_IMMEDIATELY)
|
||||
// Arena Ready Marker
|
||||
|| !AddObject(BG_DS_OBJECT_READY_MARKER_1, ARENA_READY_MARKER_ENTRY, 1229.44f, 759.35f, 17.89f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300)
|
||||
|| !AddObject(BG_DS_OBJECT_READY_MARKER_2, ARENA_READY_MARKER_ENTRY, 1352.90f, 822.77f, 17.96f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundDS: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUNDDS_H
|
||||
#define __BATTLEGROUNDDS_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BattlegroundDSObjectTypes
|
||||
{
|
||||
BG_DS_OBJECT_DOOR_1 = 0,
|
||||
BG_DS_OBJECT_DOOR_2 = 1,
|
||||
BG_DS_OBJECT_WATER_1 = 2, // Collision
|
||||
BG_DS_OBJECT_WATER_2 = 3,
|
||||
BG_DS_OBJECT_BUFF_1 = 4,
|
||||
BG_DS_OBJECT_BUFF_2 = 5,
|
||||
BG_DS_OBJECT_READY_MARKER_1 = 6,
|
||||
BG_DS_OBJECT_READY_MARKER_2 = 7,
|
||||
BG_DS_OBJECT_MAX = 8
|
||||
};
|
||||
|
||||
enum BattlegroundDSObjects
|
||||
{
|
||||
BG_DS_OBJECT_TYPE_DOOR_1 = 192642,
|
||||
BG_DS_OBJECT_TYPE_DOOR_2 = 192643,
|
||||
BG_DS_OBJECT_TYPE_WATER_1 = 194395, // Collision
|
||||
BG_DS_OBJECT_TYPE_WATER_2 = 191877,
|
||||
BG_DS_OBJECT_TYPE_BUFF_1 = 184663,
|
||||
BG_DS_OBJECT_TYPE_BUFF_2 = 184664
|
||||
};
|
||||
|
||||
enum BattlegroundDSCreatureTypes
|
||||
{
|
||||
BG_DS_NPC_WATERFALL_KNOCKBACK = 0,
|
||||
BG_DS_NPC_PIPE_KNOCKBACK_1 = 1,
|
||||
BG_DS_NPC_PIPE_KNOCKBACK_2 = 2,
|
||||
BG_DS_NPC_MAX = 3
|
||||
};
|
||||
|
||||
enum BattlegroundDSCreatures
|
||||
{
|
||||
BG_DS_NPC_TYPE_WATER_SPOUT = 28567,
|
||||
};
|
||||
|
||||
enum BattlegroundDSSpells
|
||||
{
|
||||
BG_DS_SPELL_FLUSH = 57405, // Visual and target selector for the starting knockback from the pipe
|
||||
BG_DS_SPELL_FLUSH_KNOCKBACK = 61698, // Knockback effect for previous spell (triggered, not need to be casted)
|
||||
BG_DS_SPELL_WATER_SPOUT = 58873, // Knockback effect of the central waterfall
|
||||
};
|
||||
|
||||
enum BattlegroundDSData
|
||||
{ // These values are NOT blizzlike... need the correct data!
|
||||
BG_DS_WATERFALL_TIMER_MIN = 30000,
|
||||
BG_DS_WATERFALL_TIMER_MAX = 60000,
|
||||
BG_DS_WATERFALL_WARNING_DURATION = 5000,
|
||||
BG_DS_WATERFALL_DURATION = 30000,
|
||||
BG_DS_WATERFALL_KNOCKBACK_TIMER = 1500,
|
||||
|
||||
BG_DS_PIPE_KNOCKBACK_FIRST_DELAY = 5000,
|
||||
BG_DS_PIPE_KNOCKBACK_DELAY = 3000,
|
||||
BG_DS_PIPE_KNOCKBACK_TOTAL_COUNT = 2,
|
||||
|
||||
BG_DS_WATERFALL_STATUS_WARNING = 1, // Water starting to fall, but no LoS Blocking nor movement blocking
|
||||
BG_DS_WATERFALL_STATUS_ON = 2, // LoS and Movement blocking active
|
||||
BG_DS_WATERFALL_STATUS_OFF = 3,
|
||||
};
|
||||
|
||||
class BattlegroundDS : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundDS();
|
||||
~BattlegroundDS();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void AddPlayer(Player* player);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
|
||||
void RemovePlayer(Player* player);
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
bool SetupBattleground();
|
||||
void Init();
|
||||
void FillInitialWorldStates(WorldPacket &d);
|
||||
void HandleKillPlayer(Player* player, Player* killer);
|
||||
bool HandlePlayerUnderMap(Player* player);
|
||||
private:
|
||||
uint32 _waterfallTimer;
|
||||
uint8 _waterfallStatus;
|
||||
uint32 _waterfallKnockbackTimer;
|
||||
uint32 _pipeKnockBackTimer;
|
||||
uint8 _pipeKnockBackCount;
|
||||
|
||||
void PostUpdateImpl(uint32 diff);
|
||||
protected:
|
||||
uint32 getWaterFallStatus() { return _waterfallStatus; };
|
||||
void setWaterFallStatus(uint8 status) { _waterfallStatus = status; };
|
||||
uint32 getWaterFallTimer() { return _waterfallTimer; };
|
||||
void setWaterFallTimer(uint32 timer) { _waterfallTimer = timer; };
|
||||
uint32 getWaterFallKnockbackTimer() { return _waterfallKnockbackTimer; };
|
||||
void setWaterFallKnockbackTimer(uint32 timer) { _waterfallKnockbackTimer = timer; };
|
||||
uint8 getPipeKnockBackCount() { return _pipeKnockBackCount; };
|
||||
void setPipeKnockBackCount(uint8 count) { _pipeKnockBackCount = count; };
|
||||
uint32 getPipeKnockBackTimer() { return _pipeKnockBackTimer; };
|
||||
void setPipeKnockBackTimer(uint32 timer) { _pipeKnockBackTimer = timer; };
|
||||
};
|
||||
#endif
|
||||
@@ -1,610 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#include "BattlegroundEY.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "Creature.h"
|
||||
#include "Language.h"
|
||||
#include "Object.h"
|
||||
#include "Player.h"
|
||||
#include "Util.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BattlegroundEY::BattlegroundEY()
|
||||
{
|
||||
m_BuffChange = true;
|
||||
BgObjects.resize(BG_EY_OBJECT_MAX);
|
||||
BgCreatures.resize(BG_EY_CREATURES_MAX);
|
||||
|
||||
_capturePointInfo[POINT_FEL_REAVER]._areaTrigger = AT_FEL_REAVER_BUFF;
|
||||
_capturePointInfo[POINT_BLOOD_ELF]._areaTrigger = AT_BLOOD_ELF_BUFF;
|
||||
_capturePointInfo[POINT_DRAENEI_RUINS]._areaTrigger = AT_DRAENEI_RUINS_BUFF;
|
||||
_capturePointInfo[POINT_MAGE_TOWER]._areaTrigger = AT_MAGE_TOWER_BUFF;
|
||||
_honorTics = 0;
|
||||
_ownedPointsCount[TEAM_ALLIANCE] = 0;
|
||||
_ownedPointsCount[TEAM_HORDE] = 0;
|
||||
_flagKeeperGUID = 0;
|
||||
_droppedFlagGUID = 0;
|
||||
_flagState = BG_EY_FLAG_STATE_ON_BASE;
|
||||
_flagCapturedObject = 0;
|
||||
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN;
|
||||
}
|
||||
|
||||
BattlegroundEY::~BattlegroundEY()
|
||||
{
|
||||
}
|
||||
|
||||
void BattlegroundEY::PostUpdateImpl(uint32 diff)
|
||||
{
|
||||
if (GetStatus() == STATUS_IN_PROGRESS)
|
||||
{
|
||||
_bgEvents.Update(diff);
|
||||
while (uint32 eventId = _bgEvents.ExecuteEvent())
|
||||
switch (eventId)
|
||||
{
|
||||
case BG_EY_EVENT_ADD_POINTS:
|
||||
if (_ownedPointsCount[TEAM_ALLIANCE] > 0)
|
||||
AddPoints(TEAM_ALLIANCE, BG_EY_TickPoints[_ownedPointsCount[TEAM_ALLIANCE] - 1]);
|
||||
if (_ownedPointsCount[TEAM_HORDE] > 0)
|
||||
AddPoints(TEAM_HORDE, BG_EY_TickPoints[_ownedPointsCount[TEAM_HORDE] - 1]);
|
||||
_bgEvents.ScheduleEvent(BG_EY_EVENT_ADD_POINTS, BG_EY_FPOINTS_TICK_TIME - (World::GetGameTimeMS() % BG_EY_FPOINTS_TICK_TIME));
|
||||
break;
|
||||
case BG_EY_EVENT_FLAG_ON_GROUND:
|
||||
RespawnFlagAfterDrop();
|
||||
break;
|
||||
case BG_EY_EVENT_RESPAWN_FLAG:
|
||||
RespawnFlag();
|
||||
break;
|
||||
case BG_EY_EVENT_CHECK_CPOINTS:
|
||||
UpdatePointsState();
|
||||
_bgEvents.ScheduleEvent(BG_EY_EVENT_CHECK_CPOINTS, BG_EY_FPOINTS_CHECK_TIME - (World::GetGameTimeMS() % BG_EY_FPOINTS_CHECK_TIME));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundEY::StartingEventCloseDoors()
|
||||
{
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY);
|
||||
|
||||
for (uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER; i < BG_EY_OBJECT_MAX; ++i)
|
||||
SpawnBGObject(i, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
void BattlegroundEY::StartingEventOpenDoors()
|
||||
{
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY);
|
||||
|
||||
for (uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
|
||||
for (uint32 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + i*3 + urand(0, 2), RESPAWN_IMMEDIATELY);
|
||||
|
||||
// Achievement: Flurry
|
||||
StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, BG_EY_EVENT_START_BATTLE);
|
||||
_bgEvents.ScheduleEvent(BG_EY_EVENT_ADD_POINTS, 0);
|
||||
_bgEvents.ScheduleEvent(BG_EY_EVENT_CHECK_CPOINTS, 0);
|
||||
}
|
||||
|
||||
void BattlegroundEY::AddPoints(TeamId teamId, uint32 points)
|
||||
{
|
||||
uint8 honorRewards = uint8(m_TeamScores[teamId] / _honorTics);
|
||||
m_TeamScores[teamId] += points;
|
||||
|
||||
for (; honorRewards < uint8(m_TeamScores[teamId] / _honorTics); ++honorRewards)
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), teamId);
|
||||
|
||||
UpdateWorldState(teamId == TEAM_ALLIANCE ? EY_ALLIANCE_RESOURCES : EY_HORDE_RESOURCES, std::min<uint32>(m_TeamScores[teamId], BG_EY_MAX_TEAM_SCORE));
|
||||
if (m_TeamScores[teamId] >= BG_EY_MAX_TEAM_SCORE)
|
||||
EndBattleground(teamId);
|
||||
}
|
||||
|
||||
void BattlegroundEY::UpdatePointsState()
|
||||
{
|
||||
std::vector<GameObject*> pointsVec;
|
||||
for (uint8 point = 0; point < EY_POINTS_MAX; ++point)
|
||||
{
|
||||
pointsVec.push_back(GetBGObject(BG_EY_OBJECT_TOWER_CAP_FEL_REAVER + point));
|
||||
_capturePointInfo[point]._playersCount[TEAM_ALLIANCE] = 0;
|
||||
_capturePointInfo[point]._playersCount[TEAM_HORDE] = 0;
|
||||
}
|
||||
|
||||
const BattlegroundPlayerMap& bgPlayerMap = GetPlayers();
|
||||
for (BattlegroundPlayerMap::const_iterator itr = bgPlayerMap.begin(); itr != bgPlayerMap.end(); ++itr)
|
||||
{
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW, itr->second);
|
||||
for (uint8 point = 0; point < EY_POINTS_MAX; ++point)
|
||||
if (GameObject* pointObject = pointsVec[point])
|
||||
if (itr->second->CanCaptureTowerPoint() && itr->second->IsWithinDistInMap(pointObject, BG_EY_POINT_RADIUS))
|
||||
{
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW, itr->second);
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY, itr->second);
|
||||
UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, _capturePointInfo[point]._barStatus, itr->second);
|
||||
++_capturePointInfo[point]._playersCount[itr->second->GetTeamId()];
|
||||
|
||||
// Xinef: ugly hax... area trigger is no longer called by client...
|
||||
if (pointObject->GetEntry() == BG_OBJECT_FR_TOWER_CAP_EY_ENTRY && itr->second->GetDistance2d(2043.96f, 1729.68f) < 3.0f)
|
||||
HandleAreaTrigger(itr->second, AT_FEL_REAVER_POINT);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 point = 0; point < EY_POINTS_MAX; ++point)
|
||||
{
|
||||
_capturePointInfo[point]._barStatus += std::max<int8>(std::min<int8>(_capturePointInfo[point]._playersCount[TEAM_ALLIANCE] - _capturePointInfo[point]._playersCount[TEAM_HORDE], BG_EY_POINT_MAX_CAPTURERS_COUNT), -BG_EY_POINT_MAX_CAPTURERS_COUNT);
|
||||
_capturePointInfo[point]._barStatus = std::max<int8>(std::min<int8>(_capturePointInfo[point]._barStatus, BG_EY_PROGRESS_BAR_ALI_CONTROLLED), BG_EY_PROGRESS_BAR_HORDE_CONTROLLED);
|
||||
|
||||
TeamId pointOwnerTeamId = TEAM_NEUTRAL;
|
||||
if (_capturePointInfo[point]._barStatus <= BG_EY_PROGRESS_BAR_NEUTRAL_LOW)
|
||||
pointOwnerTeamId = TEAM_HORDE;
|
||||
else if (_capturePointInfo[point]._barStatus >= BG_EY_PROGRESS_BAR_NEUTRAL_HIGH)
|
||||
pointOwnerTeamId = TEAM_ALLIANCE;
|
||||
|
||||
if (pointOwnerTeamId != _capturePointInfo[point]._ownerTeamId)
|
||||
{
|
||||
if (_capturePointInfo[point].IsUncontrolled())
|
||||
EventTeamCapturedPoint(pointOwnerTeamId, point);
|
||||
|
||||
if (pointOwnerTeamId == TEAM_NEUTRAL && _capturePointInfo[point].IsUnderControl())
|
||||
EventTeamLostPoint(pointOwnerTeamId, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundEY::EndBattleground(TeamId winnerTeamId)
|
||||
{
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), winnerTeamId);
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), TEAM_ALLIANCE);
|
||||
RewardHonorToTeam(GetBonusHonorFromKill(1), TEAM_HORDE);
|
||||
Battleground::EndBattleground(winnerTeamId);
|
||||
}
|
||||
|
||||
void BattlegroundEY::UpdatePointsCount()
|
||||
{
|
||||
UpdateWorldState(EY_ALLIANCE_BASE, _ownedPointsCount[TEAM_ALLIANCE]);
|
||||
UpdateWorldState(EY_HORDE_BASE, _ownedPointsCount[TEAM_HORDE]);
|
||||
}
|
||||
|
||||
void BattlegroundEY::UpdatePointsIcons(uint32 point)
|
||||
{
|
||||
if (_capturePointInfo[point].IsUnderControl())
|
||||
{
|
||||
UpdateWorldState(m_PointsIconStruct[point].WorldStateControlIndex, 0);
|
||||
UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceControlledIndex, _capturePointInfo[point].IsUnderControl(TEAM_ALLIANCE));
|
||||
UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeControlledIndex, _capturePointInfo[point].IsUnderControl(TEAM_HORDE));
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateWorldState(m_PointsIconStruct[point].WorldStateAllianceControlledIndex, 0);
|
||||
UpdateWorldState(m_PointsIconStruct[point].WorldStateHordeControlledIndex, 0);
|
||||
UpdateWorldState(m_PointsIconStruct[point].WorldStateControlIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundEY::AddPlayer(Player* player)
|
||||
{
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundEYScore(player);
|
||||
}
|
||||
|
||||
void BattlegroundEY::RemovePlayer(Player* player)
|
||||
{
|
||||
if (GetFlagPickerGUID() == player->GetGUID())
|
||||
EventPlayerDroppedFlag(player);
|
||||
}
|
||||
|
||||
void BattlegroundEY::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS || !player->IsAlive())
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case AT_BLOOD_ELF_POINT:
|
||||
if (_capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(player->GetTeamId()))
|
||||
if (_flagState == BG_EY_FLAG_STATE_ON_PLAYER && GetFlagPickerGUID() == player->GetGUID())
|
||||
EventPlayerCapturedFlag(player, BG_EY_OBJECT_FLAG_BLOOD_ELF);
|
||||
break;
|
||||
case AT_FEL_REAVER_POINT:
|
||||
if (_capturePointInfo[POINT_FEL_REAVER].IsUnderControl(player->GetTeamId()))
|
||||
if (_flagState == BG_EY_FLAG_STATE_ON_PLAYER && GetFlagPickerGUID() == player->GetGUID())
|
||||
EventPlayerCapturedFlag(player, BG_EY_OBJECT_FLAG_FEL_REAVER);
|
||||
break;
|
||||
case AT_MAGE_TOWER_POINT:
|
||||
if (_capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(player->GetTeamId()))
|
||||
if (_flagState == BG_EY_FLAG_STATE_ON_PLAYER && GetFlagPickerGUID() == player->GetGUID())
|
||||
EventPlayerCapturedFlag(player, BG_EY_OBJECT_FLAG_MAGE_TOWER);
|
||||
break;
|
||||
case AT_DRAENEI_RUINS_POINT:
|
||||
if (_capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(player->GetTeamId()))
|
||||
if (_flagState == BG_EY_FLAG_STATE_ON_PLAYER && GetFlagPickerGUID() == player->GetGUID())
|
||||
EventPlayerCapturedFlag(player, BG_EY_OBJECT_FLAG_DRAENEI_RUINS);
|
||||
break;
|
||||
case 4512:
|
||||
case 4515:
|
||||
case 4517:
|
||||
case 4519:
|
||||
case 4530:
|
||||
case 4531:
|
||||
case 5866:
|
||||
case AT_BLOOD_ELF_BUFF:
|
||||
case AT_FEL_REAVER_BUFF:
|
||||
case AT_MAGE_TOWER_BUFF:
|
||||
case AT_DRAENEI_RUINS_BUFF:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool BattlegroundEY::SetupBattleground()
|
||||
{
|
||||
// doors
|
||||
AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY);
|
||||
AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY);
|
||||
// banners (alliance)
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_FEL_REAVER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_FEL_REAVER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_A_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_A_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_A_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY);
|
||||
// banners (horde)
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_FEL_REAVER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_FEL_REAVER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_H_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_H_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_H_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY);
|
||||
// banners (natural)
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2057.46f, 1735.07f, 1187.91f, -0.925024f, 0, 0, 0.446198f, -0.894934f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_FEL_REAVER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2032.25f, 1729.53f, 1190.33f, 1.8675f, 0, 0, 0.803857f, 0.594823f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_FEL_REAVER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2092.35f, 1775.46f, 1187.08f, -0.401426f, 0, 0, 0.199368f, -0.979925f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2047.19f, 1349.19f, 1189.0f, -1.62316f, 0, 0, 0.725374f, -0.688354f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2074.32f, 1385.78f, 1194.72f, 0.488692f, 0, 0, 0.241922f, 0.970296f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2025.13f, 1386.12f, 1192.74f, 2.3911f, 0, 0, 0.930418f, 0.366501f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2276.8f, 1400.41f, 1196.33f, 2.44346f, 0, 0, 0.939693f, 0.34202f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2305.78f, 1404.56f, 1199.38f, 1.74533f, 0, 0, 0.766044f, 0.642788f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2245.4f, 1366.41f, 1195.28f, 2.21657f, 0, 0, 0.894934f, 0.446198f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_OBJECT_N_BANNER_EY_ENTRY, 2270.84f, 1784.08f, 1186.76f, 2.42601f, 0, 0, 0.936672f, 0.350207f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT, BG_OBJECT_N_BANNER_EY_ENTRY, 2269.13f, 1737.7f, 1186.66f, 0.994838f, 0, 0, 0.477159f, 0.878817f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT, BG_OBJECT_N_BANNER_EY_ENTRY, 2300.86f, 1741.25f, 1187.7f, -0.785398f, 0, 0, 0.382683f, -0.92388f, RESPAWN_ONE_DAY);
|
||||
// flags
|
||||
AddObject(BG_EY_OBJECT_FLAG_NETHERSTORM, BG_OBJECT_FLAG2_EY_ENTRY, 2174.782227f, 1569.054688f, 1160.361938f, -1.448624f, 0, 0, 0.662620f, -0.748956f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_FLAG_FEL_REAVER, BG_OBJECT_FLAG1_EY_ENTRY, 2044.28f, 1729.68f, 1189.96f, -0.017453f, 0, 0, 0.008727f, -0.999962f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_FLAG_BLOOD_ELF, BG_OBJECT_FLAG1_EY_ENTRY, 2048.83f, 1393.65f, 1194.49f, 0.20944f, 0, 0, 0.104528f, 0.994522f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_FLAG_DRAENEI_RUINS, BG_OBJECT_FLAG1_EY_ENTRY, 2286.56f, 1402.36f, 1197.11f, 3.72381f, 0, 0, 0.957926f, -0.287016f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_FLAG_MAGE_TOWER, BG_OBJECT_FLAG1_EY_ENTRY, 2284.48f, 1731.23f, 1189.99f, 2.89725f, 0, 0, 0.992546f, 0.121869f, RESPAWN_ONE_DAY);
|
||||
// tower cap
|
||||
AddObject(BG_EY_OBJECT_TOWER_CAP_FEL_REAVER, BG_OBJECT_FR_TOWER_CAP_EY_ENTRY, 2024.600708f, 1742.819580f, 1195.157715f, 2.443461f, 0, 0, 0.939693f, 0.342020f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF, BG_OBJECT_BE_TOWER_CAP_EY_ENTRY, 2050.493164f, 1372.235962f, 1194.563477f, 1.710423f, 0, 0, 0.754710f, 0.656059f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS, BG_OBJECT_DR_TOWER_CAP_EY_ENTRY, 2301.010498f, 1386.931641f, 1197.183472f, 1.570796f, 0, 0, 0.707107f, 0.707107f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER, BG_OBJECT_HU_TOWER_CAP_EY_ENTRY, 2282.121582f, 1760.006958f, 1189.707153f, 1.919862f, 0, 0, 0.819152f, 0.573576f, RESPAWN_ONE_DAY);
|
||||
|
||||
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
{
|
||||
AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(_capturePointInfo[i]._areaTrigger);
|
||||
AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + i * 3 + 0, Buff_Entries[0], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY);
|
||||
AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY);
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const* sg = NULL;
|
||||
sg = sWorldSafeLocsStore.LookupEntry(BG_EY_GRAVEYARD_MAIN_ALLIANCE);
|
||||
AddSpiritGuide(BG_EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, TEAM_ALLIANCE);
|
||||
|
||||
sg = sWorldSafeLocsStore.LookupEntry(BG_EY_GRAVEYARD_MAIN_HORDE);
|
||||
AddSpiritGuide(BG_EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, TEAM_HORDE);
|
||||
|
||||
for (uint32 i = BG_EY_OBJECT_DOOR_A; i < BG_EY_OBJECT_MAX; ++i)
|
||||
if (BgObjects[i] == 0)
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundEY: Failed to spawn some object Battleground not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32 i = BG_EY_SPIRIT_MAIN_ALLIANCE; i <= BG_EY_SPIRIT_MAIN_HORDE; ++i)
|
||||
if (BgCreatures[i] == 0)
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundEY: Failed to spawn spirit guides Battleground not created!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundEY::Init()
|
||||
{
|
||||
//call parent's class reset
|
||||
Battleground::Init();
|
||||
|
||||
_bgEvents.Reset();
|
||||
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID()) ? BG_EY_HONOR_TICK_WEEKEND : BG_EY_HONOR_TICK_NORMAL;
|
||||
_ownedPointsCount[TEAM_ALLIANCE] = 0;
|
||||
_ownedPointsCount[TEAM_HORDE] = 0;
|
||||
_flagKeeperGUID = 0;
|
||||
_droppedFlagGUID = 0;
|
||||
_flagState = BG_EY_FLAG_STATE_ON_BASE;
|
||||
_flagCapturedObject = 0;
|
||||
}
|
||||
|
||||
void BattlegroundEY::RespawnFlag()
|
||||
{
|
||||
if (_flagState != BG_EY_FLAG_STATE_ON_BASE)
|
||||
return;
|
||||
|
||||
if (_flagCapturedObject > 0)
|
||||
SpawnBGObject(_flagCapturedObject, RESPAWN_ONE_DAY);
|
||||
|
||||
_flagCapturedObject = 0;
|
||||
SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_IMMEDIATELY);
|
||||
|
||||
SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL);
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_RESET);
|
||||
UpdateWorldState(NETHERSTORM_FLAG, 1);
|
||||
}
|
||||
|
||||
void BattlegroundEY::RespawnFlagAfterDrop()
|
||||
{
|
||||
if (_flagState != BG_EY_FLAG_STATE_ON_GROUND)
|
||||
return;
|
||||
|
||||
_flagState = BG_EY_FLAG_STATE_ON_BASE;
|
||||
RespawnFlag();
|
||||
if (GameObject* flag = ObjectAccessor::GetObjectInMap(GetDroppedFlagGUID(), FindBgMap(), (GameObject*)NULL))
|
||||
flag->Delete();
|
||||
SetDroppedFlagGUID(0);
|
||||
}
|
||||
|
||||
void BattlegroundEY::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
Battleground::HandleKillPlayer(player, killer);
|
||||
EventPlayerDroppedFlag(player);
|
||||
}
|
||||
|
||||
void BattlegroundEY::EventPlayerDroppedFlag(Player* player)
|
||||
{
|
||||
if (GetFlagPickerGUID() != player->GetGUID())
|
||||
return;
|
||||
|
||||
SetFlagPicker(0);
|
||||
player->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
_flagState = BG_EY_FLAG_STATE_ON_GROUND;
|
||||
_bgEvents.RescheduleEvent(BG_EY_EVENT_FLAG_ON_GROUND, BG_EY_FLAG_ON_GROUND_TIME);
|
||||
|
||||
player->CastSpell(player, SPELL_RECENTLY_DROPPED_FLAG, true);
|
||||
player->CastSpell(player, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true);
|
||||
|
||||
SendMessageToAll(LANG_BG_EY_DROPPED_FLAG, player->GetTeamId() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE);
|
||||
}
|
||||
|
||||
void BattlegroundEY::EventPlayerClickedOnFlag(Player* player, GameObject* gameObject)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS || GetFlagPickerGUID() || !player->IsWithinDistInMap(gameObject, 10.0f))
|
||||
return;
|
||||
|
||||
_flagState = BG_EY_FLAG_STATE_ON_PLAYER;
|
||||
SpawnBGObject(BG_EY_OBJECT_FLAG_NETHERSTORM, RESPAWN_ONE_DAY);
|
||||
SetFlagPicker(player->GetGUID());
|
||||
SetDroppedFlagGUID(0);
|
||||
|
||||
player->CastSpell(player, BG_EY_NETHERSTORM_FLAG_SPELL, true);
|
||||
player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
|
||||
PSendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG, player->GetTeamId() == TEAM_ALLIANCE ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE, NULL, player->GetName().c_str());
|
||||
PlaySoundToAll(player->GetTeamId() == TEAM_ALLIANCE ? BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE : BG_EY_SOUND_FLAG_PICKED_UP_HORDE);
|
||||
UpdateWorldState(NETHERSTORM_FLAG, 0);
|
||||
}
|
||||
|
||||
void BattlegroundEY::EventTeamLostPoint(TeamId teamId, uint32 point)
|
||||
{
|
||||
TeamId oldTeamId = _capturePointInfo[point]._ownerTeamId;
|
||||
if (oldTeamId == TEAM_ALLIANCE)
|
||||
{
|
||||
_ownedPointsCount[TEAM_ALLIANCE]--;
|
||||
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY);
|
||||
SendMessageToAll(m_LosingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ownedPointsCount[TEAM_HORDE]--;
|
||||
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_LosingPointTypes[point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY);
|
||||
SendMessageToAll(m_LosingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE);
|
||||
}
|
||||
|
||||
SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType + 1, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_LosingPointTypes[point].SpawnNeutralObjectType + 2, RESPAWN_IMMEDIATELY);
|
||||
|
||||
_capturePointInfo[point]._ownerTeamId = TEAM_NEUTRAL;
|
||||
|
||||
UpdatePointsIcons(point);
|
||||
UpdatePointsCount();
|
||||
DelCreature(BG_EY_TRIGGER_FEL_REAVER + point);
|
||||
}
|
||||
|
||||
void BattlegroundEY::EventTeamCapturedPoint(TeamId teamId, uint32 point)
|
||||
{
|
||||
SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType + 1, RESPAWN_ONE_DAY);
|
||||
SpawnBGObject(m_CapturingPointTypes[point].DespawnNeutralObjectType + 2, RESPAWN_ONE_DAY);
|
||||
|
||||
if (teamId == TEAM_ALLIANCE)
|
||||
{
|
||||
_ownedPointsCount[TEAM_ALLIANCE]++;
|
||||
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY);
|
||||
SendMessageToAll(m_CapturingPointTypes[point].MessageIdAlliance, CHAT_MSG_BG_SYSTEM_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ownedPointsCount[TEAM_HORDE]++;
|
||||
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY);
|
||||
SpawnBGObject(m_CapturingPointTypes[point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY);
|
||||
SendMessageToAll(m_CapturingPointTypes[point].MessageIdHorde, CHAT_MSG_BG_SYSTEM_HORDE);
|
||||
}
|
||||
|
||||
_capturePointInfo[point]._ownerTeamId = teamId;
|
||||
if (BgCreatures[point])
|
||||
DelCreature(point);
|
||||
|
||||
WorldSafeLocsEntry const* sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[point].GraveYardId);
|
||||
AddSpiritGuide(point, sg->x, sg->y, sg->z, 3.124139f, teamId);
|
||||
|
||||
UpdatePointsIcons(point);
|
||||
UpdatePointsCount();
|
||||
|
||||
// Xinef: done this way to avoid errors in console
|
||||
Creature* trigger = GetBgMap()->GetCreature(BgCreatures[BG_EY_TRIGGER_FEL_REAVER + point]);
|
||||
if (!trigger)
|
||||
trigger = AddCreature(WORLD_TRIGGER, BG_EY_TRIGGER_FEL_REAVER + point, BG_EY_TriggerPositions[point][0], BG_EY_TriggerPositions[point][1], BG_EY_TriggerPositions[point][2], BG_EY_TriggerPositions[point][3]);
|
||||
|
||||
if (trigger)
|
||||
{
|
||||
trigger->setFaction(teamId == TEAM_ALLIANCE ? 84 : 83);
|
||||
trigger->CastSpell(trigger, SPELL_HONORABLE_DEFENDER_25Y, true);
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundEY::EventPlayerCapturedFlag(Player* player, uint32 BgObjectType)
|
||||
{
|
||||
SetFlagPicker(0);
|
||||
_flagState = BG_EY_FLAG_STATE_ON_BASE;
|
||||
player->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL);
|
||||
player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT);
|
||||
|
||||
SpawnBGObject(BgObjectType, RESPAWN_IMMEDIATELY);
|
||||
_bgEvents.RescheduleEvent(BG_EY_EVENT_RESPAWN_FLAG, BG_EY_FLAG_RESPAWN_TIME);
|
||||
_flagCapturedObject = BgObjectType;
|
||||
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE)
|
||||
{
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE);
|
||||
SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE);
|
||||
SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, player);
|
||||
}
|
||||
|
||||
UpdatePlayerScore(player, SCORE_FLAG_CAPTURES, 1);
|
||||
if (_ownedPointsCount[player->GetTeamId()] > 0)
|
||||
AddPoints(player->GetTeamId(), BG_EY_FlagPoints[_ownedPointsCount[player->GetTeamId()] - 1]);
|
||||
}
|
||||
|
||||
void BattlegroundEY::UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor)
|
||||
{
|
||||
if (type == SCORE_FLAG_CAPTURES)
|
||||
{
|
||||
BattlegroundScoreMap::iterator itr = PlayerScores.find(player->GetGUID());
|
||||
if (itr != PlayerScores.end())
|
||||
((BattlegroundEYScore*)itr->second)->FlagCaptures += value;
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, BG_EY_OBJECTIVE_CAPTURE_FLAG);
|
||||
return;
|
||||
}
|
||||
|
||||
Battleground::UpdatePlayerScore(player, type, value, doAddHonor);
|
||||
}
|
||||
|
||||
void BattlegroundEY::FillInitialWorldStates(WorldPacket& data)
|
||||
{
|
||||
data << uint32(EY_HORDE_BASE) << uint32(_ownedPointsCount[TEAM_HORDE]);
|
||||
data << uint32(EY_ALLIANCE_BASE) << uint32(_ownedPointsCount[TEAM_ALLIANCE]);
|
||||
data << uint32(DRAENEI_RUINS_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(DRAENEI_RUINS_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_DRAENEI_RUINS].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(DRAENEI_RUINS_UNCONTROL) << uint32(_capturePointInfo[POINT_DRAENEI_RUINS].IsUncontrolled());
|
||||
data << uint32(MAGE_TOWER_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(MAGE_TOWER_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_MAGE_TOWER].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(MAGE_TOWER_UNCONTROL) << uint32(_capturePointInfo[POINT_MAGE_TOWER].IsUncontrolled());
|
||||
data << uint32(FEL_REAVER_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_FEL_REAVER].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(FEL_REAVER_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_FEL_REAVER].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(FEL_REAVER_UNCONTROL) << uint32(_capturePointInfo[POINT_FEL_REAVER].IsUncontrolled());
|
||||
data << uint32(BLOOD_ELF_HORDE_CONTROL) << uint32(_capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(TEAM_HORDE));
|
||||
data << uint32(BLOOD_ELF_ALLIANCE_CONTROL) << uint32(_capturePointInfo[POINT_BLOOD_ELF].IsUnderControl(TEAM_ALLIANCE));
|
||||
data << uint32(BLOOD_ELF_UNCONTROL) << uint32(_capturePointInfo[POINT_BLOOD_ELF].IsUncontrolled());
|
||||
data << uint32(NETHERSTORM_FLAG) << uint32(_flagState == BG_EY_FLAG_STATE_ON_BASE);
|
||||
data << uint32(NETHERSTORM_FLAG_STATE_HORDE) << uint32(1);
|
||||
data << uint32(NETHERSTORM_FLAG_STATE_ALLIANCE) << uint32(1);
|
||||
data << uint32(EY_HORDE_RESOURCES) << uint32(GetTeamScore(TEAM_HORDE));
|
||||
data << uint32(EY_ALLIANCE_RESOURCES) << uint32(GetTeamScore(TEAM_ALLIANCE));
|
||||
data << uint32(PROGRESS_BAR_SHOW) << uint32(0);
|
||||
data << uint32(PROGRESS_BAR_PERCENT_GREY) << uint32(0);
|
||||
data << uint32(PROGRESS_BAR_STATUS) << uint32(0);
|
||||
}
|
||||
|
||||
WorldSafeLocsEntry const* BattlegroundEY::GetClosestGraveyard(Player* player)
|
||||
{
|
||||
WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(BG_EY_GRAVEYARD_MAIN_ALLIANCE + player->GetTeamId());
|
||||
WorldSafeLocsEntry const* nearestEntry = entry;
|
||||
|
||||
float pX = player->GetPositionX();
|
||||
float pY = player->GetPositionY();
|
||||
float pZ = player->GetPositionZ();
|
||||
float dist = (entry->x - pX)*(entry->x - pX) + (entry->y - pY)*(entry->y - pY) + (entry->z - pZ)*(entry->z - pZ);
|
||||
float minDist = dist;
|
||||
|
||||
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
if (_capturePointInfo[i].IsUnderControl(player->GetTeamId()))
|
||||
{
|
||||
entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId);
|
||||
dist = (entry->x - pX)*(entry->x - pX) + (entry->y - pY)*(entry->y - pY) + (entry->z - pZ)*(entry->z - pZ);
|
||||
if (dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
nearestEntry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
return nearestEntry;
|
||||
}
|
||||
|
||||
bool BattlegroundEY::AllNodesConrolledByTeam(TeamId teamId) const
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
|
||||
if (_capturePointInfo[i].IsUnderControl(teamId))
|
||||
++count;
|
||||
|
||||
return count == EY_POINTS_MAX;
|
||||
}
|
||||
|
||||
TeamId BattlegroundEY::GetPrematureWinner()
|
||||
{
|
||||
if (GetTeamScore(TEAM_ALLIANCE) > GetTeamScore(TEAM_HORDE))
|
||||
return TEAM_ALLIANCE;
|
||||
|
||||
return GetTeamScore(TEAM_HORDE) > GetTeamScore(TEAM_ALLIANCE) ? TEAM_HORDE : Battleground::GetPrematureWinner();
|
||||
}
|
||||
@@ -1,399 +0,0 @@
|
||||
/*
|
||||
REWRITTEN BY XINEF
|
||||
*/
|
||||
|
||||
#ifndef __BATTLEGROUNDEY_H
|
||||
#define __BATTLEGROUNDEY_H
|
||||
|
||||
#include "Language.h"
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BG_EY_Events
|
||||
{
|
||||
BG_EY_EVENT_ADD_POINTS = 1,
|
||||
BG_EY_EVENT_FLAG_ON_GROUND = 2,
|
||||
BG_EY_EVENT_RESPAWN_FLAG = 3,
|
||||
BG_EY_EVENT_CHECK_CPOINTS = 4
|
||||
};
|
||||
|
||||
enum BG_EY_Timers
|
||||
{
|
||||
BG_EY_FLAG_RESPAWN_TIME = 20*IN_MILLISECONDS,
|
||||
BG_EY_FLAG_ON_GROUND_TIME = 10*IN_MILLISECONDS,
|
||||
BG_EY_FPOINTS_CHECK_TIME = 2*IN_MILLISECONDS,
|
||||
BG_EY_FPOINTS_TICK_TIME = 1*IN_MILLISECONDS
|
||||
};
|
||||
|
||||
enum BG_EY_WorldStates
|
||||
{
|
||||
EY_ALLIANCE_RESOURCES = 2749,
|
||||
EY_HORDE_RESOURCES = 2750,
|
||||
EY_ALLIANCE_BASE = 2752,
|
||||
EY_HORDE_BASE = 2753,
|
||||
DRAENEI_RUINS_HORDE_CONTROL = 2733,
|
||||
DRAENEI_RUINS_ALLIANCE_CONTROL = 2732,
|
||||
DRAENEI_RUINS_UNCONTROL = 2731,
|
||||
MAGE_TOWER_ALLIANCE_CONTROL = 2730,
|
||||
MAGE_TOWER_HORDE_CONTROL = 2729,
|
||||
MAGE_TOWER_UNCONTROL = 2728,
|
||||
FEL_REAVER_HORDE_CONTROL = 2727,
|
||||
FEL_REAVER_ALLIANCE_CONTROL = 2726,
|
||||
FEL_REAVER_UNCONTROL = 2725,
|
||||
BLOOD_ELF_HORDE_CONTROL = 2724,
|
||||
BLOOD_ELF_ALLIANCE_CONTROL = 2723,
|
||||
BLOOD_ELF_UNCONTROL = 2722,
|
||||
PROGRESS_BAR_PERCENT_GREY = 2720, //100 = empty (only grey), 0 = blue|red (no grey)
|
||||
PROGRESS_BAR_STATUS = 2719, //50 init!, 48 ... hordak bere .. 33 .. 0 = full 100% hordacky, 100 = full alliance
|
||||
PROGRESS_BAR_SHOW = 2718, //1 init, 0 druhy send - bez messagu, 1 = controlled aliance
|
||||
NETHERSTORM_FLAG = 2757,
|
||||
//set to 2 when flag is picked up, and to 1 if it is dropped
|
||||
NETHERSTORM_FLAG_STATE_ALLIANCE = 2769,
|
||||
NETHERSTORM_FLAG_STATE_HORDE = 2770
|
||||
};
|
||||
|
||||
enum BG_EY_ProgressBarConsts
|
||||
{
|
||||
BG_EY_POINT_MAX_CAPTURERS_COUNT = 5,
|
||||
BG_EY_POINT_RADIUS = 50,
|
||||
BG_EY_PROGRESS_BAR_DONT_SHOW = 0,
|
||||
BG_EY_PROGRESS_BAR_SHOW = 1,
|
||||
BG_EY_PROGRESS_BAR_PERCENT_GREY = 40,
|
||||
BG_EY_PROGRESS_BAR_STATE_MIDDLE = 50,
|
||||
BG_EY_PROGRESS_BAR_HORDE_CONTROLLED = 0,
|
||||
BG_EY_PROGRESS_BAR_NEUTRAL_LOW = 30,
|
||||
BG_EY_PROGRESS_BAR_NEUTRAL_HIGH = 70,
|
||||
BG_EY_PROGRESS_BAR_ALI_CONTROLLED = 100
|
||||
};
|
||||
|
||||
enum BG_EY_Sounds
|
||||
{
|
||||
BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE = 8212,
|
||||
BG_EY_SOUND_FLAG_CAPTURED_HORDE = 8213,
|
||||
BG_EY_SOUND_FLAG_PICKED_UP_HORDE = 8174,
|
||||
BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE = 8173,
|
||||
BG_EY_SOUND_FLAG_RESET = 8192
|
||||
};
|
||||
|
||||
enum BG_EY_Spells
|
||||
{
|
||||
BG_EY_NETHERSTORM_FLAG_SPELL = 34976,
|
||||
BG_EY_PLAYER_DROPPED_FLAG_SPELL = 34991
|
||||
};
|
||||
|
||||
enum BG_EY_ObjectEntry
|
||||
{
|
||||
BG_OBJECT_A_DOOR_EY_ENTRY = 184719, //Alliance door
|
||||
BG_OBJECT_H_DOOR_EY_ENTRY = 184720, //Horde door
|
||||
BG_OBJECT_FLAG1_EY_ENTRY = 184493, //Netherstorm flag (generic)
|
||||
BG_OBJECT_FLAG2_EY_ENTRY = 184141, //Netherstorm flag (flagstand)
|
||||
BG_OBJECT_FLAG3_EY_ENTRY = 184142, //Netherstorm flag (flagdrop)
|
||||
BG_OBJECT_A_BANNER_EY_ENTRY = 184381, //Visual Banner (Alliance)
|
||||
BG_OBJECT_H_BANNER_EY_ENTRY = 184380, //Visual Banner (Horde)
|
||||
BG_OBJECT_N_BANNER_EY_ENTRY = 184382, //Visual Banner (Neutral)
|
||||
BG_OBJECT_BE_TOWER_CAP_EY_ENTRY = 184080, //BE Tower Cap Pt
|
||||
BG_OBJECT_FR_TOWER_CAP_EY_ENTRY = 184081, //Fel Reaver Cap Pt
|
||||
BG_OBJECT_HU_TOWER_CAP_EY_ENTRY = 184082, //Human Tower Cap Pt
|
||||
BG_OBJECT_DR_TOWER_CAP_EY_ENTRY = 184083 //Draenei Tower Cap Pt
|
||||
};
|
||||
|
||||
enum BG_EY_AreaTriggers
|
||||
{
|
||||
AT_BLOOD_ELF_POINT = 4476,
|
||||
AT_FEL_REAVER_POINT = 4514,
|
||||
AT_MAGE_TOWER_POINT = 4516,
|
||||
AT_DRAENEI_RUINS_POINT = 4518,
|
||||
AT_BLOOD_ELF_BUFF = 4568,
|
||||
AT_FEL_REAVER_BUFF = 4569,
|
||||
AT_MAGE_TOWER_BUFF = 4570,
|
||||
AT_DRAENEI_RUINS_BUFF = 4571
|
||||
};
|
||||
|
||||
enum BG_EY_Graveyards
|
||||
{
|
||||
BG_EY_GRAVEYARD_MAIN_ALLIANCE = 1103,
|
||||
BG_EY_GRAVEYARD_MAIN_HORDE = 1104,
|
||||
BG_EY_GRAVEYARD_FEL_REAVER = 1105,
|
||||
BG_EY_GRAVEYARD_BLOOD_ELF = 1106,
|
||||
BG_EY_GRAVEYARD_DRAENEI_RUINS = 1107,
|
||||
BG_EY_GRAVEYARD_MAGE_TOWER = 1108
|
||||
};
|
||||
|
||||
enum BG_EY_Points
|
||||
{
|
||||
POINT_FEL_REAVER = 0,
|
||||
POINT_BLOOD_ELF = 1,
|
||||
POINT_DRAENEI_RUINS = 2,
|
||||
POINT_MAGE_TOWER = 3,
|
||||
EY_POINTS_MAX = 4
|
||||
};
|
||||
|
||||
enum BG_EY_CreatureTypes
|
||||
{
|
||||
BG_EY_SPIRIT_FEL_REAVER = 0,
|
||||
BG_EY_SPIRIT_BLOOD_ELF = 1,
|
||||
BG_EY_SPIRIT_DRAENEI_RUINS = 2,
|
||||
BG_EY_SPIRIT_MAGE_TOWER = 3,
|
||||
BG_EY_SPIRIT_MAIN_ALLIANCE = 4,
|
||||
BG_EY_SPIRIT_MAIN_HORDE = 5,
|
||||
|
||||
BG_EY_TRIGGER_FEL_REAVER = 6,
|
||||
BG_EY_TRIGGER_BLOOD_ELF = 7,
|
||||
BG_EY_TRIGGER_DRAENEI_RUINS = 8,
|
||||
BG_EY_TRIGGER_MAGE_TOWER = 9,
|
||||
|
||||
BG_EY_CREATURES_MAX = 10
|
||||
};
|
||||
|
||||
enum BG_EY_ObjectTypes
|
||||
{
|
||||
BG_EY_OBJECT_DOOR_A = 0,
|
||||
BG_EY_OBJECT_DOOR_H = 1,
|
||||
BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER = 2,
|
||||
BG_EY_OBJECT_A_BANNER_FEL_REAVER_LEFT = 3,
|
||||
BG_EY_OBJECT_A_BANNER_FEL_REAVER_RIGHT = 4,
|
||||
BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER = 5,
|
||||
BG_EY_OBJECT_A_BANNER_BLOOD_ELF_LEFT = 6,
|
||||
BG_EY_OBJECT_A_BANNER_BLOOD_ELF_RIGHT = 7,
|
||||
BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER = 8,
|
||||
BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_LEFT = 9,
|
||||
BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_RIGHT = 10,
|
||||
BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER = 11,
|
||||
BG_EY_OBJECT_A_BANNER_MAGE_TOWER_LEFT = 12,
|
||||
BG_EY_OBJECT_A_BANNER_MAGE_TOWER_RIGHT = 13,
|
||||
BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER = 14,
|
||||
BG_EY_OBJECT_H_BANNER_FEL_REAVER_LEFT = 15,
|
||||
BG_EY_OBJECT_H_BANNER_FEL_REAVER_RIGHT = 16,
|
||||
BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER = 17,
|
||||
BG_EY_OBJECT_H_BANNER_BLOOD_ELF_LEFT = 18,
|
||||
BG_EY_OBJECT_H_BANNER_BLOOD_ELF_RIGHT = 19,
|
||||
BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER = 20,
|
||||
BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_LEFT = 21,
|
||||
BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_RIGHT = 22,
|
||||
BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER = 23,
|
||||
BG_EY_OBJECT_H_BANNER_MAGE_TOWER_LEFT = 24,
|
||||
BG_EY_OBJECT_H_BANNER_MAGE_TOWER_RIGHT = 25,
|
||||
BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER = 26,
|
||||
BG_EY_OBJECT_N_BANNER_FEL_REAVER_LEFT = 27,
|
||||
BG_EY_OBJECT_N_BANNER_FEL_REAVER_RIGHT = 28,
|
||||
BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER = 29,
|
||||
BG_EY_OBJECT_N_BANNER_BLOOD_ELF_LEFT = 30,
|
||||
BG_EY_OBJECT_N_BANNER_BLOOD_ELF_RIGHT = 31,
|
||||
BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER = 32,
|
||||
BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_LEFT = 33,
|
||||
BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_RIGHT = 34,
|
||||
BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER = 35,
|
||||
BG_EY_OBJECT_N_BANNER_MAGE_TOWER_LEFT = 36,
|
||||
BG_EY_OBJECT_N_BANNER_MAGE_TOWER_RIGHT = 37,
|
||||
BG_EY_OBJECT_TOWER_CAP_FEL_REAVER = 38,
|
||||
BG_EY_OBJECT_TOWER_CAP_BLOOD_ELF = 39,
|
||||
BG_EY_OBJECT_TOWER_CAP_DRAENEI_RUINS = 40,
|
||||
BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER = 41,
|
||||
BG_EY_OBJECT_FLAG_NETHERSTORM = 42,
|
||||
BG_EY_OBJECT_FLAG_FEL_REAVER = 43,
|
||||
BG_EY_OBJECT_FLAG_BLOOD_ELF = 44,
|
||||
BG_EY_OBJECT_FLAG_DRAENEI_RUINS = 45,
|
||||
BG_EY_OBJECT_FLAG_MAGE_TOWER = 46,
|
||||
//buffs
|
||||
BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER = 47,
|
||||
BG_EY_OBJECT_REGENBUFF_FEL_REAVER = 48,
|
||||
BG_EY_OBJECT_BERSERKBUFF_FEL_REAVER = 49,
|
||||
BG_EY_OBJECT_SPEEDBUFF_BLOOD_ELF = 50,
|
||||
BG_EY_OBJECT_REGENBUFF_BLOOD_ELF = 51,
|
||||
BG_EY_OBJECT_BERSERKBUFF_BLOOD_ELF = 52,
|
||||
BG_EY_OBJECT_SPEEDBUFF_DRAENEI_RUINS = 53,
|
||||
BG_EY_OBJECT_REGENBUFF_DRAENEI_RUINS = 54,
|
||||
BG_EY_OBJECT_BERSERKBUFF_DRAENEI_RUINS = 55,
|
||||
BG_EY_OBJECT_SPEEDBUFF_MAGE_TOWER = 56,
|
||||
BG_EY_OBJECT_REGENBUFF_MAGE_TOWER = 57,
|
||||
BG_EY_OBJECT_BERSERKBUFF_MAGE_TOWER = 58,
|
||||
BG_EY_OBJECT_MAX = 59
|
||||
};
|
||||
|
||||
enum BG_EY_Score
|
||||
{
|
||||
BG_EY_WARNING_NEAR_VICTORY_SCORE = 1400,
|
||||
BG_EY_MAX_TEAM_SCORE = 1600,
|
||||
|
||||
BG_EY_HONOR_TICK_WEEKEND = 160,
|
||||
BG_EY_HONOR_TICK_NORMAL = 260,
|
||||
|
||||
BG_EY_EVENT_START_BATTLE = 13180, // Achievement: Flurry
|
||||
BG_EY_OBJECTIVE_CAPTURE_FLAG = 183
|
||||
};
|
||||
|
||||
enum BG_EY_FlagState
|
||||
{
|
||||
BG_EY_FLAG_STATE_ON_BASE = 1,
|
||||
BG_EY_FLAG_STATE_ON_PLAYER = 2,
|
||||
BG_EY_FLAG_STATE_ON_GROUND = 3
|
||||
};
|
||||
|
||||
struct BattlegroundEYPointIconsStruct
|
||||
{
|
||||
BattlegroundEYPointIconsStruct(uint32 _WorldStateControlIndex, uint32 _WorldStateAllianceControlledIndex, uint32 _WorldStateHordeControlledIndex)
|
||||
: WorldStateControlIndex(_WorldStateControlIndex), WorldStateAllianceControlledIndex(_WorldStateAllianceControlledIndex), WorldStateHordeControlledIndex(_WorldStateHordeControlledIndex) {}
|
||||
uint32 WorldStateControlIndex;
|
||||
uint32 WorldStateAllianceControlledIndex;
|
||||
uint32 WorldStateHordeControlledIndex;
|
||||
};
|
||||
|
||||
const float BG_EY_TriggerPositions[EY_POINTS_MAX][4] =
|
||||
{
|
||||
{2044.28f, 1729.68f, 1189.96f, 0.017453f}, // FEL_REAVER center
|
||||
{2048.83f, 1393.65f, 1194.49f, 0.20944f}, // BLOOD_ELF center
|
||||
{2286.56f, 1402.36f, 1197.11f, 3.72381f}, // DRAENEI_RUINS center
|
||||
{2284.48f, 1731.23f, 1189.99f, 2.89725f} // MAGE_TOWER center
|
||||
};
|
||||
|
||||
struct BattlegroundEYLosingPointStruct
|
||||
{
|
||||
BattlegroundEYLosingPointStruct(uint32 _SpawnNeutralObjectType, uint32 _DespawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _DespawnObjectTypeHorde, uint32 _MessageIdHorde)
|
||||
: SpawnNeutralObjectType(_SpawnNeutralObjectType),
|
||||
DespawnObjectTypeAlliance(_DespawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance),
|
||||
DespawnObjectTypeHorde(_DespawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde)
|
||||
{}
|
||||
|
||||
uint32 SpawnNeutralObjectType;
|
||||
uint32 DespawnObjectTypeAlliance;
|
||||
uint32 MessageIdAlliance;
|
||||
uint32 DespawnObjectTypeHorde;
|
||||
uint32 MessageIdHorde;
|
||||
};
|
||||
|
||||
struct BattlegroundEYCapturingPointStruct
|
||||
{
|
||||
BattlegroundEYCapturingPointStruct(uint32 _DespawnNeutralObjectType, uint32 _SpawnObjectTypeAlliance, uint32 _MessageIdAlliance, uint32 _SpawnObjectTypeHorde, uint32 _MessageIdHorde, uint32 _GraveYardId)
|
||||
: DespawnNeutralObjectType(_DespawnNeutralObjectType),
|
||||
SpawnObjectTypeAlliance(_SpawnObjectTypeAlliance), MessageIdAlliance(_MessageIdAlliance),
|
||||
SpawnObjectTypeHorde(_SpawnObjectTypeHorde), MessageIdHorde(_MessageIdHorde),
|
||||
GraveYardId(_GraveYardId)
|
||||
{}
|
||||
|
||||
uint32 DespawnNeutralObjectType;
|
||||
uint32 SpawnObjectTypeAlliance;
|
||||
uint32 MessageIdAlliance;
|
||||
uint32 SpawnObjectTypeHorde;
|
||||
uint32 MessageIdHorde;
|
||||
uint32 GraveYardId;
|
||||
};
|
||||
|
||||
const uint32 BG_EY_TickPoints[EY_POINTS_MAX] = {1, 2, 5, 10};
|
||||
const uint32 BG_EY_FlagPoints[EY_POINTS_MAX] = {75, 85, 100, 500};
|
||||
|
||||
//constant arrays:
|
||||
const BattlegroundEYPointIconsStruct m_PointsIconStruct[EY_POINTS_MAX] =
|
||||
{
|
||||
BattlegroundEYPointIconsStruct(FEL_REAVER_UNCONTROL, FEL_REAVER_ALLIANCE_CONTROL, FEL_REAVER_HORDE_CONTROL),
|
||||
BattlegroundEYPointIconsStruct(BLOOD_ELF_UNCONTROL, BLOOD_ELF_ALLIANCE_CONTROL, BLOOD_ELF_HORDE_CONTROL),
|
||||
BattlegroundEYPointIconsStruct(DRAENEI_RUINS_UNCONTROL, DRAENEI_RUINS_ALLIANCE_CONTROL, DRAENEI_RUINS_HORDE_CONTROL),
|
||||
BattlegroundEYPointIconsStruct(MAGE_TOWER_UNCONTROL, MAGE_TOWER_ALLIANCE_CONTROL, MAGE_TOWER_HORDE_CONTROL)
|
||||
};
|
||||
|
||||
const BattlegroundEYLosingPointStruct m_LosingPointTypes[EY_POINTS_MAX] =
|
||||
{
|
||||
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_LOST_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_LOST_H_F_RUINS),
|
||||
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_LOST_H_B_TOWER),
|
||||
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_LOST_H_D_RUINS),
|
||||
BattlegroundEYLosingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_LOST_H_M_TOWER)
|
||||
};
|
||||
|
||||
const BattlegroundEYCapturingPointStruct m_CapturingPointTypes[EY_POINTS_MAX] =
|
||||
{
|
||||
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_FEL_REAVER_CENTER, BG_EY_OBJECT_A_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_TAKEN_A_F_RUINS, BG_EY_OBJECT_H_BANNER_FEL_REAVER_CENTER, LANG_BG_EY_HAS_TAKEN_H_F_RUINS, BG_EY_GRAVEYARD_FEL_REAVER),
|
||||
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_BLOOD_ELF_CENTER, BG_EY_OBJECT_A_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_A_B_TOWER, BG_EY_OBJECT_H_BANNER_BLOOD_ELF_CENTER, LANG_BG_EY_HAS_TAKEN_H_B_TOWER, BG_EY_GRAVEYARD_BLOOD_ELF),
|
||||
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_DRAENEI_RUINS_CENTER, BG_EY_OBJECT_A_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_A_D_RUINS, BG_EY_OBJECT_H_BANNER_DRAENEI_RUINS_CENTER, LANG_BG_EY_HAS_TAKEN_H_D_RUINS, BG_EY_GRAVEYARD_DRAENEI_RUINS),
|
||||
BattlegroundEYCapturingPointStruct(BG_EY_OBJECT_N_BANNER_MAGE_TOWER_CENTER, BG_EY_OBJECT_A_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_A_M_TOWER, BG_EY_OBJECT_H_BANNER_MAGE_TOWER_CENTER, LANG_BG_EY_HAS_TAKEN_H_M_TOWER, BG_EY_GRAVEYARD_MAGE_TOWER)
|
||||
};
|
||||
|
||||
struct BattlegroundEYScore : public BattlegroundScore
|
||||
{
|
||||
BattlegroundEYScore(Player* player) : BattlegroundScore(player), FlagCaptures(0) { }
|
||||
~BattlegroundEYScore() { }
|
||||
uint32 FlagCaptures;
|
||||
|
||||
uint32 GetAttr1() const final override { return FlagCaptures; }
|
||||
};
|
||||
|
||||
class BattlegroundEY : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundEY();
|
||||
~BattlegroundEY();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void AddPlayer(Player* player);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
|
||||
/* BG Flags */
|
||||
uint64 GetFlagPickerGUID(TeamId /*teamId*/ = TEAM_NEUTRAL) const { return _flagKeeperGUID; }
|
||||
void SetFlagPicker(uint64 guid) { _flagKeeperGUID = guid; }
|
||||
uint8 GetFlagState() const { return _flagState; }
|
||||
void RespawnFlag();
|
||||
void RespawnFlagAfterDrop();
|
||||
|
||||
void RemovePlayer(Player* player);
|
||||
void HandleBuffUse(uint64 buff_guid);
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
void HandleKillPlayer(Player* player, Player* killer);
|
||||
WorldSafeLocsEntry const* GetClosestGraveyard(Player* player);
|
||||
bool SetupBattleground();
|
||||
void Init();
|
||||
void EndBattleground(TeamId winnerTeamId);
|
||||
void UpdatePlayerScore(Player* player, uint32 type, uint32 value, bool doAddHonor = true);
|
||||
void FillInitialWorldStates(WorldPacket& data);
|
||||
void SetDroppedFlagGUID(uint64 guid, TeamId /*teamId*/ = TEAM_NEUTRAL) { _droppedFlagGUID = guid; }
|
||||
uint64 GetDroppedFlagGUID() const { return _droppedFlagGUID; }
|
||||
|
||||
/* Battleground Events */
|
||||
void EventPlayerClickedOnFlag(Player* player, GameObject* gameObject);
|
||||
void EventPlayerDroppedFlag(Player* player);
|
||||
|
||||
/* achievement req. */
|
||||
bool AllNodesConrolledByTeam(TeamId teamId) const;
|
||||
TeamId GetPrematureWinner();
|
||||
|
||||
private:
|
||||
void PostUpdateImpl(uint32 diff);
|
||||
|
||||
void EventPlayerCapturedFlag(Player* Source, uint32 BgObjectType);
|
||||
void EventTeamLostPoint(TeamId teamId, uint32 point);
|
||||
void EventTeamCapturedPoint(TeamId teamId, uint32 point);
|
||||
void UpdatePointsCount();
|
||||
void UpdatePointsIcons(uint32 point);
|
||||
|
||||
/* Point status updating procedures */
|
||||
void UpdatePointsState();
|
||||
|
||||
/* Scorekeeping */
|
||||
void AddPoints(TeamId teamId, uint32 points);
|
||||
|
||||
struct CapturePointInfo
|
||||
{
|
||||
CapturePointInfo() : _ownerTeamId(TEAM_NEUTRAL), _barStatus(BG_EY_PROGRESS_BAR_STATE_MIDDLE), _areaTrigger(0)
|
||||
{
|
||||
_playersCount[TEAM_ALLIANCE] = 0;
|
||||
_playersCount[TEAM_HORDE] = 0;
|
||||
}
|
||||
|
||||
TeamId _ownerTeamId;
|
||||
uint32 _areaTrigger;
|
||||
int8 _barStatus;
|
||||
int8 _playersCount[BG_TEAMS_COUNT];
|
||||
|
||||
bool IsUnderControl(TeamId teamId) const { return _ownerTeamId == teamId; }
|
||||
bool IsUnderControl() const { return _ownerTeamId != TEAM_NEUTRAL; }
|
||||
bool IsUncontrolled() const { return _ownerTeamId == TEAM_NEUTRAL; }
|
||||
};
|
||||
|
||||
CapturePointInfo _capturePointInfo[EY_POINTS_MAX];
|
||||
EventMap _bgEvents;
|
||||
uint32 _honorTics;
|
||||
uint8 _ownedPointsCount[BG_TEAMS_COUNT];
|
||||
uint64 _flagKeeperGUID;
|
||||
uint64 _droppedFlagGUID;
|
||||
uint8 _flagState;
|
||||
uint32 _flagCapturedObject;
|
||||
};
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BattlegroundNA.h"
|
||||
#include "Language.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BattlegroundNA::BattlegroundNA()
|
||||
{
|
||||
BgObjects.resize(BG_NA_OBJECT_MAX);
|
||||
|
||||
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
|
||||
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
|
||||
//we must set messageIds
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
|
||||
}
|
||||
|
||||
BattlegroundNA::~BattlegroundNA()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattlegroundNA::StartingEventCloseDoors()
|
||||
{
|
||||
for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; ++i)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
void BattlegroundNA::StartingEventOpenDoors()
|
||||
{
|
||||
for (uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
void BattlegroundNA::AddPlayer(Player* player)
|
||||
{
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundNA::RemovePlayer(Player* /*player*/)
|
||||
{
|
||||
if (GetStatus() == STATUS_WAIT_LEAVE)
|
||||
return;
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
void BattlegroundNA::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (!killer)
|
||||
{
|
||||
sLog->outError("BattlegroundNA: Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Battleground::HandleKillPlayer(player, killer);
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
bool BattlegroundNA::HandlePlayerUnderMap(Player* player)
|
||||
{
|
||||
player->NearTeleportTo(4055.504395f, 2919.660645f, 13.611241f, player->GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundNA::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4536: // buff trigger?
|
||||
case 4537: // buff trigger?
|
||||
break;
|
||||
// OUTSIDE OF ARENA, TELEPORT!
|
||||
case 4917:
|
||||
case 5006:
|
||||
case 5008:
|
||||
player->NearTeleportTo(4054.15f, 2923.7f, 13.4f, player->GetOrientation());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundNA::FillInitialWorldStates(WorldPacket &data)
|
||||
{
|
||||
data << uint32(0xa11) << uint32(1); // 9
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundNA::Init()
|
||||
{
|
||||
//call parent's class reset
|
||||
Battleground::Init();
|
||||
}
|
||||
|
||||
bool BattlegroundNA::SetupBattleground()
|
||||
{
|
||||
// gates
|
||||
if (!AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, RESPAWN_IMMEDIATELY)
|
||||
// buffs
|
||||
|| !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941f, 2895.250000f, 13.052700f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|
||||
|| !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078f, 2946.350098f, 13.051300f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120)
|
||||
// Arena Ready Marker
|
||||
|| !AddObject(BG_NA_OBJECT_READY_MARKER_1, ARENA_READY_MARKER_ENTRY, 4090.46f, 2875.43f, 12.16f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300)
|
||||
|| !AddObject(BG_NA_OBJECT_READY_MARKER_2, ARENA_READY_MARKER_ENTRY, 4022.82f, 2966.61f, 12.17f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundNA: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BATTLEGROUNDNA_H
|
||||
#define __BATTLEGROUNDNA_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BattlegroundNAObjectTypes
|
||||
{
|
||||
BG_NA_OBJECT_DOOR_1 = 0,
|
||||
BG_NA_OBJECT_DOOR_2 = 1,
|
||||
BG_NA_OBJECT_DOOR_3 = 2,
|
||||
BG_NA_OBJECT_DOOR_4 = 3,
|
||||
BG_NA_OBJECT_BUFF_1 = 4,
|
||||
BG_NA_OBJECT_BUFF_2 = 5,
|
||||
BG_NA_OBJECT_READY_MARKER_1 = 6,
|
||||
BG_NA_OBJECT_READY_MARKER_2 = 7,
|
||||
BG_NA_OBJECT_MAX = 8
|
||||
};
|
||||
|
||||
enum BattlegroundNAObjects
|
||||
{
|
||||
BG_NA_OBJECT_TYPE_DOOR_1 = 183978,
|
||||
BG_NA_OBJECT_TYPE_DOOR_2 = 183980,
|
||||
BG_NA_OBJECT_TYPE_DOOR_3 = 183977,
|
||||
BG_NA_OBJECT_TYPE_DOOR_4 = 183979,
|
||||
BG_NA_OBJECT_TYPE_BUFF_1 = 184663,
|
||||
BG_NA_OBJECT_TYPE_BUFF_2 = 184664
|
||||
};
|
||||
|
||||
class BattlegroundNA : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundNA();
|
||||
~BattlegroundNA();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void AddPlayer(Player* player);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
|
||||
void RemovePlayer(Player* player);
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
bool SetupBattleground();
|
||||
void Init();
|
||||
void FillInitialWorldStates(WorldPacket &d);
|
||||
void HandleKillPlayer(Player* player, Player* killer);
|
||||
bool HandlePlayerUnderMap(Player* player);
|
||||
};
|
||||
#endif
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BattlegroundRL.h"
|
||||
#include "Language.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
BattlegroundRL::BattlegroundRL()
|
||||
{
|
||||
BgObjects.resize(BG_RL_OBJECT_MAX);
|
||||
|
||||
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
|
||||
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
|
||||
//we must set messageIds
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
|
||||
}
|
||||
|
||||
BattlegroundRL::~BattlegroundRL()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BattlegroundRL::StartingEventCloseDoors()
|
||||
{
|
||||
for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
|
||||
SpawnBGObject(i, RESPAWN_IMMEDIATELY);
|
||||
}
|
||||
|
||||
void BattlegroundRL::StartingEventOpenDoors()
|
||||
{
|
||||
for (uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
void BattlegroundRL::AddPlayer(Player* player)
|
||||
{
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundRL::RemovePlayer(Player* /*player*/)
|
||||
{
|
||||
if (GetStatus() == STATUS_WAIT_LEAVE)
|
||||
return;
|
||||
|
||||
UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
void BattlegroundRL::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (!killer)
|
||||
{
|
||||
sLog->outError("Killer player not found");
|
||||
return;
|
||||
}
|
||||
|
||||
Battleground::HandleKillPlayer(player, killer);
|
||||
|
||||
Battleground::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
bool BattlegroundRL::HandlePlayerUnderMap(Player* player)
|
||||
{
|
||||
player->NearTeleportTo(1285.810547f, 1667.896851f, 39.957642f, player->GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundRL::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4696: // buff trigger?
|
||||
case 4697: // buff trigger?
|
||||
break;
|
||||
// OUTSIDE OF ARENA, TELEPORT!
|
||||
case 4927:
|
||||
case 4928:
|
||||
player->NearTeleportTo(1230.77f, 1662.42f, 34.56f, 0.0f);
|
||||
break;
|
||||
case 4929:
|
||||
case 4930:
|
||||
player->NearTeleportTo(1341.16f, 1673.52f, 34.43f, 3.5f);
|
||||
break;
|
||||
case 4931:
|
||||
player->NearTeleportTo(1294.74f, 1584.5f, 31.62f, 1.66f);
|
||||
break;
|
||||
case 4932:
|
||||
player->NearTeleportTo(1277.5f, 1751.07f, 31.61f, 4.7f);
|
||||
break;
|
||||
case 4933:
|
||||
player->NearTeleportTo(1269.14f, 1713.85f, 34.46f, 5.23f);
|
||||
break;
|
||||
case 4934:
|
||||
player->NearTeleportTo(1298.14f, 1713.8f, 33.58f, 4.55f);
|
||||
break;
|
||||
case 4935:
|
||||
player->NearTeleportTo(1306.32f, 1620.75f, 34.25f, 1.97f);
|
||||
break;
|
||||
case 4936:
|
||||
player->NearTeleportTo(1277.97f, 1615.51f, 34.56f, 1.15f);
|
||||
break;
|
||||
case 4941: // under arena +10
|
||||
case 5041: // under arena -10
|
||||
case 5042: // under arena -30
|
||||
player->NearTeleportTo(1285.810547f, 1667.896851f, 39.957642f, player->GetOrientation());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundRL::FillInitialWorldStates(WorldPacket &data)
|
||||
{
|
||||
data << uint32(0xbba) << uint32(1); // 9
|
||||
Battleground::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundRL::Init()
|
||||
{
|
||||
//call parent's reset
|
||||
Battleground::Init();
|
||||
}
|
||||
|
||||
bool BattlegroundRL::SetupBattleground()
|
||||
{
|
||||
// gates
|
||||
if (!AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f, RESPAWN_IMMEDIATELY)
|
||||
// buffs
|
||||
|| !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971f, 1632.719971f, 36.730400f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120)
|
||||
|| !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049f, 1699.170044f, 34.872601f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120)
|
||||
// Arena Ready Marker
|
||||
|| !AddObject(BG_RL_OBJECT_READY_MARKER_1, ARENA_READY_MARKER_ENTRY, 1298.61f, 1598.59f, 31.62f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300)
|
||||
|| !AddObject(BG_RL_OBJECT_READY_MARKER_2, ARENA_READY_MARKER_ENTRY, 1273.71f, 1734.05f, 31.61f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300))
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundRL: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BATTLEGROUNDRL_H
|
||||
#define __BATTLEGROUNDRL_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BattlegroundRLObjectTypes
|
||||
{
|
||||
BG_RL_OBJECT_DOOR_1 = 0,
|
||||
BG_RL_OBJECT_DOOR_2 = 1,
|
||||
BG_RL_OBJECT_BUFF_1 = 2,
|
||||
BG_RL_OBJECT_BUFF_2 = 3,
|
||||
BG_RL_OBJECT_READY_MARKER_1 = 4,
|
||||
BG_RL_OBJECT_READY_MARKER_2 = 5,
|
||||
BG_RL_OBJECT_MAX = 6
|
||||
};
|
||||
|
||||
enum BattlegroundRLObjects
|
||||
{
|
||||
BG_RL_OBJECT_TYPE_DOOR_1 = 185918,
|
||||
BG_RL_OBJECT_TYPE_DOOR_2 = 185917,
|
||||
BG_RL_OBJECT_TYPE_BUFF_1 = 184663,
|
||||
BG_RL_OBJECT_TYPE_BUFF_2 = 184664
|
||||
};
|
||||
|
||||
class BattlegroundRL : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundRL();
|
||||
~BattlegroundRL();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void AddPlayer(Player* player);
|
||||
void Init();
|
||||
void FillInitialWorldStates(WorldPacket &d);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
|
||||
void RemovePlayer(Player* player);
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
bool SetupBattleground();
|
||||
void HandleKillPlayer(Player* player, Player* killer);
|
||||
bool HandlePlayerUnderMap(Player* player);
|
||||
};
|
||||
#endif
|
||||
@@ -1,351 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Battleground.h"
|
||||
#include "BattlegroundRV.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Language.h"
|
||||
#include "Player.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "GameObject.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Pet.h"
|
||||
|
||||
BattlegroundRV::BattlegroundRV()
|
||||
{
|
||||
BgObjects.resize(BG_RV_OBJECT_MAX);
|
||||
|
||||
StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M;
|
||||
StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S;
|
||||
StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
|
||||
StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE;
|
||||
StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS;
|
||||
StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN;
|
||||
|
||||
CheckPlayersTimer = 0;
|
||||
}
|
||||
|
||||
BattlegroundRV::~BattlegroundRV() { }
|
||||
|
||||
void BattlegroundRV::TeleportUnitToNewZ(Unit* unit, float newZ, bool casting)
|
||||
{
|
||||
if (!unit->IsAlive())
|
||||
return;
|
||||
unit->NearTeleportTo(unit->GetPositionX(), unit->GetPositionY(), newZ, unit->GetOrientation(), casting);
|
||||
unit->m_positionZ = newZ;
|
||||
}
|
||||
|
||||
void BattlegroundRV::CheckPositionForUnit(Unit* unit)
|
||||
{
|
||||
// get height at current pos, if something is wrong (below or high above) - teleport
|
||||
if (!unit->IsFalling() && unit->IsAlive())
|
||||
{
|
||||
float groundZ_vmap = unit->GetMap()->GetHeight(unit->GetPositionX(), unit->GetPositionY(), 37.0f, true, 50.0f);
|
||||
float groundZ_dyntree = unit->GetMap()->GetDynamicMapTree().getHeight(unit->GetPositionX(), unit->GetPositionY(), 37.0f, 50.0f, unit->GetPhaseMask());
|
||||
if (groundZ_vmap > 28.0f && groundZ_vmap < 29.0f || groundZ_dyntree > 28.0f && groundZ_dyntree < 37.0f)
|
||||
{
|
||||
float groundZ = std::max<float>(groundZ_vmap, groundZ_dyntree);
|
||||
if (unit->GetPositionZ() < groundZ - 0.2f || unit->GetPositionZ() > groundZ + 3.5f)
|
||||
TeleportUnitToNewZ(unit, groundZ+1.0f, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundRV::PostUpdateImpl(uint32 diff)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (getTimer() < diff)
|
||||
{
|
||||
switch (getState())
|
||||
{
|
||||
case BG_RV_STATE_OPEN_FENCES:
|
||||
for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i)
|
||||
DoorOpen(i);
|
||||
setTimer(BG_RV_CLOSE_FIRE_TIMER);
|
||||
setState(BG_RV_STATE_CLOSE_FIRE);
|
||||
|
||||
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||
if (Player* player = itr->second)
|
||||
{
|
||||
// Demonic Circle Summon
|
||||
if (GameObject* gObj = player->GetGameObject(48018))
|
||||
{
|
||||
gObj->Relocate(gObj->GetPositionX(), gObj->GetPositionY(), 28.28f);
|
||||
gObj->UpdateObjectVisibility(true);
|
||||
}
|
||||
|
||||
if (player->GetPositionZ() < 27.0f)
|
||||
TeleportUnitToNewZ(player, 28.28f, true);
|
||||
|
||||
for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
|
||||
if (player->m_SummonSlot[i])
|
||||
if (Creature* totem = GetBgMap()->GetCreature(player->m_SummonSlot[i]))
|
||||
if (totem->GetPositionZ() < 28.0f)
|
||||
TeleportUnitToNewZ(totem, 28.28f, true);
|
||||
|
||||
for (Unit::ControlSet::const_iterator itr = player->m_Controlled.begin(); itr != player->m_Controlled.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetPositionZ() < 28.0f)
|
||||
TeleportUnitToNewZ((*itr), 28.28f, true);
|
||||
|
||||
// Xinef: override stay position
|
||||
if (CharmInfo* charmInfo = (*itr)->GetCharmInfo())
|
||||
if (charmInfo->IsAtStay())
|
||||
{
|
||||
(*itr)->StopMovingOnCurrentPos();
|
||||
charmInfo->SaveStayPosition(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fix ground on elevators (so aoe spells can be casted there)
|
||||
{
|
||||
uint32 objects[2] = {BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_ELEVATOR_2};
|
||||
for (uint8 i=0; i<2; ++i)
|
||||
if (GameObject* go = GetBGObject(objects[i]))
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_TRANSPORT);
|
||||
}
|
||||
break;
|
||||
case BG_RV_STATE_CLOSE_FIRE:
|
||||
for (uint8 i = BG_RV_OBJECT_FIRE_1; i <= BG_RV_OBJECT_FIREDOOR_2; ++i)
|
||||
DoorClose(i);
|
||||
// Fire got closed after five seconds, leaves twenty seconds before toggling pillars
|
||||
setTimer(BG_RV_FIRE_TO_PILLAR_TIMER);
|
||||
setState(BG_RV_STATE_SWITCH_PILLARS);
|
||||
break;
|
||||
case BG_RV_STATE_SWITCH_PILLARS:
|
||||
UpdatePillars();
|
||||
setTimer(BG_RV_PILLAR_SWITCH_TIMER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
setTimer(getTimer() - diff);
|
||||
|
||||
if (getState() == BG_RV_STATE_OPEN_FENCES)
|
||||
return;
|
||||
|
||||
if (CheckPlayersTimer <= diff)
|
||||
{
|
||||
CheckPlayersTimer = 0;
|
||||
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||
CheckPositionForUnit(itr->second);
|
||||
|
||||
// maybe for pets and m_Controlled also, but not really necessary
|
||||
}
|
||||
else
|
||||
CheckPlayersTimer -= diff;
|
||||
}
|
||||
|
||||
void BattlegroundRV::StartingEventCloseDoors()
|
||||
{
|
||||
}
|
||||
|
||||
void BattlegroundRV::StartingEventOpenDoors()
|
||||
{
|
||||
for (BattlegroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||
itr->second->SetPhaseMask(1, true);
|
||||
|
||||
// Buff respawn
|
||||
SpawnBGObject(BG_RV_OBJECT_BUFF_1, 90);
|
||||
SpawnBGObject(BG_RV_OBJECT_BUFF_2, 90);
|
||||
|
||||
// Elevators
|
||||
DoorOpen(BG_RV_OBJECT_ELEVATOR_1);
|
||||
DoorOpen(BG_RV_OBJECT_ELEVATOR_2);
|
||||
|
||||
setState(BG_RV_STATE_OPEN_FENCES);
|
||||
setTimer(BG_RV_FIRST_TIMER);
|
||||
}
|
||||
|
||||
void BattlegroundRV::AddPlayer(Player* player)
|
||||
{
|
||||
if (GetStatus() == STATUS_WAIT_JOIN && player->GetBgTeamId() == TEAM_HORDE)
|
||||
player->SetPhaseMask(2, true);
|
||||
|
||||
Battleground::AddPlayer(player);
|
||||
PlayerScores[player->GetGUID()] = new BattlegroundScore(player);
|
||||
BattlegroundRV::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundRV::RemovePlayer(Player* player)
|
||||
{
|
||||
if (GetStatus() == STATUS_WAIT_LEAVE)
|
||||
return;
|
||||
|
||||
if (GetStatus() == STATUS_WAIT_JOIN)
|
||||
player->SetPhaseMask(1, true);
|
||||
|
||||
BattlegroundRV::UpdateArenaWorldState();
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
void BattlegroundRV::HandleKillPlayer(Player* player, Player* killer)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS)
|
||||
return;
|
||||
|
||||
if (!killer)
|
||||
return;
|
||||
|
||||
Battleground::HandleKillPlayer(player, killer);
|
||||
BattlegroundRV::UpdateArenaWorldState();
|
||||
|
||||
CheckArenaWinConditions();
|
||||
}
|
||||
|
||||
bool BattlegroundRV::HandlePlayerUnderMap(Player* player)
|
||||
{
|
||||
player->NearTeleportTo(763.5f, -284, 28.276f, 2.422f);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundRV::HandleAreaTrigger(Player* player, uint32 trigger)
|
||||
{
|
||||
if (GetStatus() != STATUS_IN_PROGRESS || getState() == BG_RV_STATE_OPEN_FENCES /*during elevator rising it's possible to jump and cause areatrigger*/)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
// fire was removed in 3.2.0
|
||||
case 5473:
|
||||
case 5474:
|
||||
break;
|
||||
// OUTSIDE OF ARENA, TELEPORT!
|
||||
case 5224:
|
||||
player->NearTeleportTo(765.0f, -294.0f, 28.3f, player->GetOrientation());
|
||||
break;
|
||||
case 5226:
|
||||
player->NearTeleportTo(765.0f, -272.0f, 28.3f, player->GetOrientation());
|
||||
break;
|
||||
case 5447:
|
||||
player->NearTeleportTo(763.5f, -284, 28.276f, 2.422f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BattlegroundRV::FillInitialWorldStates(WorldPacket &data)
|
||||
{
|
||||
data << uint32(BG_RV_WORLD_STATE) << uint32(1);
|
||||
BattlegroundRV::UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
void BattlegroundRV::UpdateArenaWorldState()
|
||||
{
|
||||
UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(TEAM_ALLIANCE));
|
||||
UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(TEAM_HORDE));
|
||||
}
|
||||
|
||||
void BattlegroundRV::Init()
|
||||
{
|
||||
//call parent's class reset
|
||||
Battleground::Init();
|
||||
}
|
||||
|
||||
bool BattlegroundRV::SetupBattleground()
|
||||
{
|
||||
// elevators
|
||||
if (!AddObject(BG_RV_OBJECT_ELEVATOR_1, BG_RV_OBJECT_TYPE_ELEVATOR_1, 763.536377f, -294.535767f, 0.505383f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_ELEVATOR_2, BG_RV_OBJECT_TYPE_ELEVATOR_2, 763.506348f, -273.873352f, 0.505383f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
// buffs
|
||||
|| !AddObject(BG_RV_OBJECT_BUFF_1, BG_RV_OBJECT_TYPE_BUFF_1, 735.551819f, -284.794678f, 28.276682f, 0.034906f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_BUFF_2, BG_RV_OBJECT_TYPE_BUFF_2, 791.224487f, -284.794464f, 28.276682f, 2.600535f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
// fire
|
||||
|| !AddObject(BG_RV_OBJECT_FIRE_1, BG_RV_OBJECT_TYPE_FIRE_1, 743.543457f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_FIRE_2, BG_RV_OBJECT_TYPE_FIRE_2, 782.971802f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_FIREDOOR_1, BG_RV_OBJECT_TYPE_FIREDOOR_1, 743.711060f, -284.099609f, 27.542587f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_FIREDOOR_2, BG_RV_OBJECT_TYPE_FIREDOOR_2, 783.221252f, -284.133362f, 27.535686f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
// Gear
|
||||
|| !AddObject(BG_RV_OBJECT_GEAR_1, BG_RV_OBJECT_TYPE_GEAR_1, 763.664551f, -261.872986f, 26.686588f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_GEAR_2, BG_RV_OBJECT_TYPE_GEAR_2, 763.578979f, -306.146149f, 26.665222f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
// Pulley
|
||||
|| !AddObject(BG_RV_OBJECT_PULLEY_1, BG_RV_OBJECT_TYPE_PULLEY_1, 700.722290f, -283.990662f, 39.517582f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_PULLEY_2, BG_RV_OBJECT_TYPE_PULLEY_2, 826.303833f, -283.996429f, 39.517582f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
// Pilars
|
||||
|| !AddObject(BG_RV_OBJECT_PILAR_1, BG_RV_OBJECT_TYPE_PILAR_1, 763.632385f, -306.162384f, 25.909504f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_PILAR_2, BG_RV_OBJECT_TYPE_PILAR_2, 723.644287f, -284.493256f, 24.648525f, 3.141593f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_PILAR_3, BG_RV_OBJECT_TYPE_PILAR_3, 763.611145f, -261.856750f, 25.909504f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|| !AddObject(BG_RV_OBJECT_PILAR_4, BG_RV_OBJECT_TYPE_PILAR_4, 802.211609f, -284.493256f, 24.648525f, 0.000000f, 0, 0, 0, RESPAWN_IMMEDIATELY)
|
||||
|
||||
// Arena Ready Marker
|
||||
|| !AddObject(BG_RV_OBJECT_READY_MARKER_1, ARENA_READY_MARKER_ENTRY, 769.93f, -301.04f, 2.80f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300)
|
||||
|| !AddObject(BG_RV_OBJECT_READY_MARKER_2, ARENA_READY_MARKER_ENTRY, 757.02f, -267.30f, 2.80f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 300)
|
||||
)
|
||||
{
|
||||
sLog->outErrorDb("BatteGroundRV: Failed to spawn some object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8 i=0; i<BG_RV_OBJECT_MAX; ++i)
|
||||
if (GameObject* go = GetBGObject(i))
|
||||
go->SetPhaseMask(3, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BattlegroundRV::UpdatePillars()
|
||||
{
|
||||
GameObject* test = GetBgMap()->GetGameObject(BgObjects[BG_RV_OBJECT_PILAR_1]);
|
||||
if (!test)
|
||||
return;
|
||||
|
||||
if (test->GetGoState() == GO_STATE_READY)
|
||||
{
|
||||
for (uint8 i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_GEAR_2; ++i)
|
||||
if (GameObject* go = GetBgMap()->GetGameObject(BgObjects[i]))
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
for (uint8 i = BG_RV_OBJECT_PILAR_2; i <= BG_RV_OBJECT_PULLEY_2; ++i)
|
||||
if (GameObject* go = GetBgMap()->GetGameObject(BgObjects[i]))
|
||||
go->SetGoState(GO_STATE_READY);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 i = BG_RV_OBJECT_PILAR_1; i <= BG_RV_OBJECT_GEAR_2; ++i)
|
||||
if (GameObject* go = GetBgMap()->GetGameObject(BgObjects[i]))
|
||||
go->SetGoState(GO_STATE_READY);
|
||||
for (uint8 i = BG_RV_OBJECT_PILAR_2; i <= BG_RV_OBJECT_PULLEY_2; ++i)
|
||||
if (GameObject* go = GetBgMap()->GetGameObject(BgObjects[i]))
|
||||
go->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 BattlegroundRV::GetPillarIdForPos(Position* p)
|
||||
{
|
||||
float range = 1.75f;
|
||||
if (p->GetExactDist2d(763.632385f, -306.162384f) < range)
|
||||
return BG_RV_OBJECT_PILAR_1;
|
||||
if (p->GetExactDist2d(723.644287f, -284.493256f) < 2.0f*range)
|
||||
return BG_RV_OBJECT_PILAR_2;
|
||||
if (p->GetExactDist2d(763.611145f, -261.856750f) < range)
|
||||
return BG_RV_OBJECT_PILAR_3;
|
||||
if (p->GetExactDist2d(802.211609f, -284.493256f) < 2.0f*range)
|
||||
return BG_RV_OBJECT_PILAR_4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
GameObject* BattlegroundRV::GetPillarAtPosition(Position* p)
|
||||
{
|
||||
uint32 pillar = GetPillarIdForPos(p);
|
||||
if (!pillar)
|
||||
return NULL;
|
||||
return GetBgMap()->GetGameObject(BgObjects[pillar]);
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (C)
|
||||
* Copyright (C)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __BATTLEGROUNDRV_H
|
||||
#define __BATTLEGROUNDRV_H
|
||||
|
||||
#include "Battleground.h"
|
||||
|
||||
enum BattlegroundRVObjectTypes
|
||||
{
|
||||
BG_RV_OBJECT_BUFF_1,
|
||||
BG_RV_OBJECT_BUFF_2,
|
||||
BG_RV_OBJECT_FIRE_1,
|
||||
BG_RV_OBJECT_FIRE_2,
|
||||
BG_RV_OBJECT_FIREDOOR_1,
|
||||
BG_RV_OBJECT_FIREDOOR_2,
|
||||
|
||||
BG_RV_OBJECT_PILAR_1,
|
||||
BG_RV_OBJECT_PILAR_3,
|
||||
BG_RV_OBJECT_GEAR_1,
|
||||
BG_RV_OBJECT_GEAR_2,
|
||||
|
||||
BG_RV_OBJECT_PILAR_2,
|
||||
BG_RV_OBJECT_PILAR_4,
|
||||
BG_RV_OBJECT_PULLEY_1,
|
||||
BG_RV_OBJECT_PULLEY_2,
|
||||
|
||||
BG_RV_OBJECT_ELEVATOR_1,
|
||||
BG_RV_OBJECT_ELEVATOR_2,
|
||||
|
||||
BG_RV_OBJECT_READY_MARKER_1,
|
||||
BG_RV_OBJECT_READY_MARKER_2,
|
||||
|
||||
BG_RV_OBJECT_MAX,
|
||||
};
|
||||
|
||||
enum BattlegroundRVObjects
|
||||
{
|
||||
BG_RV_OBJECT_TYPE_BUFF_1 = 184663,
|
||||
BG_RV_OBJECT_TYPE_BUFF_2 = 184664,
|
||||
BG_RV_OBJECT_TYPE_FIRE_1 = 192704,
|
||||
BG_RV_OBJECT_TYPE_FIRE_2 = 192705,
|
||||
|
||||
BG_RV_OBJECT_TYPE_FIREDOOR_2 = 192387,
|
||||
BG_RV_OBJECT_TYPE_FIREDOOR_1 = 192388,
|
||||
BG_RV_OBJECT_TYPE_PULLEY_1 = 192389,
|
||||
BG_RV_OBJECT_TYPE_PULLEY_2 = 192390,
|
||||
BG_RV_OBJECT_TYPE_GEAR_1 = 192393,
|
||||
BG_RV_OBJECT_TYPE_GEAR_2 = 192394,
|
||||
|
||||
BG_RV_OBJECT_TYPE_ELEVATOR_1 = 194582,
|
||||
BG_RV_OBJECT_TYPE_ELEVATOR_2 = 194586,
|
||||
|
||||
BG_RV_OBJECT_TYPE_PILAR_1 = 194583, // axe
|
||||
BG_RV_OBJECT_TYPE_PILAR_2 = 194584, // arena
|
||||
BG_RV_OBJECT_TYPE_PILAR_3 = 194585, // lightning
|
||||
BG_RV_OBJECT_TYPE_PILAR_4 = 194587, // ivory
|
||||
};
|
||||
|
||||
enum BattlegroundRVData
|
||||
{
|
||||
BG_RV_STATE_OPEN_FENCES,
|
||||
BG_RV_STATE_SWITCH_PILLARS,
|
||||
BG_RV_STATE_CLOSE_FIRE,
|
||||
|
||||
BG_RV_PILLAR_SWITCH_TIMER = 25000,
|
||||
BG_RV_FIRE_TO_PILLAR_TIMER = 20000,
|
||||
BG_RV_CLOSE_FIRE_TIMER = 5000,
|
||||
BG_RV_FIRST_TIMER = 20500, // elevators rise in 20133ms
|
||||
BG_RV_WORLD_STATE_A = 0xe11,
|
||||
BG_RV_WORLD_STATE_H = 0xe10,
|
||||
BG_RV_WORLD_STATE = 0xe1a,
|
||||
};
|
||||
|
||||
class BattlegroundRV : public Battleground
|
||||
{
|
||||
public:
|
||||
BattlegroundRV();
|
||||
~BattlegroundRV();
|
||||
|
||||
/* inherited from BattlegroundClass */
|
||||
void AddPlayer(Player* player);
|
||||
void RemovePlayer(Player* player);
|
||||
void StartingEventCloseDoors();
|
||||
void StartingEventOpenDoors();
|
||||
void Init();
|
||||
void FillInitialWorldStates(WorldPacket &d);
|
||||
void UpdateArenaWorldState();
|
||||
void HandleAreaTrigger(Player* player, uint32 trigger);
|
||||
bool SetupBattleground();
|
||||
void HandleKillPlayer(Player* player, Player* killer);
|
||||
bool HandlePlayerUnderMap(Player* player);
|
||||
|
||||
GameObject* GetPillarAtPosition(Position* p);
|
||||
|
||||
private:
|
||||
uint32 Timer;
|
||||
uint32 State;
|
||||
uint16 CheckPlayersTimer;
|
||||
|
||||
void PostUpdateImpl(uint32 diff);
|
||||
|
||||
protected:
|
||||
uint32 getTimer() { return Timer; }
|
||||
void setTimer(uint32 timer) { Timer = timer; }
|
||||
uint32 getState() { return State; };
|
||||
void setState(uint32 state) { State = state; }
|
||||
|
||||
void TeleportUnitToNewZ(Unit* unit, float newZ, bool casting);
|
||||
void CheckPositionForUnit(Unit* unit);
|
||||
void UpdatePillars();
|
||||
uint32 GetPillarIdForPos(Position* p);
|
||||
};
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user