diff options
Diffstat (limited to 'src')
233 files changed, 10361 insertions, 3931 deletions
diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp index 20d1193b8e2..86590bfa3f5 100644 --- a/src/server/bnetserver/Main.cpp +++ b/src/server/bnetserver/Main.cpp @@ -51,25 +51,52 @@ using namespace boost::program_options; # define _TRINITY_BNET_CONFIG "bnetserver.conf" #endif +#if PLATFORM == PLATFORM_WINDOWS +#include "ServiceWin32.h" +char serviceName[] = "bnetserver"; +char serviceLongName[] = "TrinityCore bnet service"; +char serviceDescription[] = "TrinityCore Battle.net emulator authentication service"; +/* +* -1 - not in service mode +* 0 - stopped +* 1 - running +* 2 - paused +*/ +int m_ServiceStatus = -1; + +static boost::asio::deadline_timer* _serviceStatusWatchTimer; +void ServiceStatusWatcher(boost::system::error_code const& error); +#endif + bool StartDB(); void StopDB(); void SignalHandler(const boost::system::error_code& error, int signalNumber); void KeepDatabaseAliveHandler(const boost::system::error_code& error); -variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile); +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService); -std::unique_ptr<boost::asio::io_service> _ioService; -std::unique_ptr<boost::asio::deadline_timer> _dbPingTimer; -uint32 _dbPingInterval; +static boost::asio::io_service* _ioService; +static boost::asio::deadline_timer* _dbPingTimer; +static uint32 _dbPingInterval; LoginDatabaseWorkerPool LoginDatabase; int main(int argc, char** argv) { std::string configFile = _TRINITY_BNET_CONFIG; - auto vm = GetConsoleArguments(argc, argv, configFile); + std::string configService; + auto vm = GetConsoleArguments(argc, argv, configFile, configService); // exit if help is enabled if (vm.count("help")) return 0; +#if PLATFORM == PLATFORM_WINDOWS + if (configService.compare("install") == 0) + return WinServiceInstall() ? 0 : 1; + else if (configService.compare("uninstall") == 0) + return WinServiceUninstall() ? 0 : 1; + else if (configService.compare("run") == 0) + return WinServiceRun() ? 0 : 1; +#endif + std::string configError; if (!sConfigMgr->LoadInitial(configFile, configError)) { @@ -109,7 +136,7 @@ int main(int argc, char** argv) sIpcContext->Initialize(); - _ioService.reset(new boost::asio::io_service()); + _ioService = new boost::asio::io_service(); // Get the list of realms for the server sRealmList->Initialize(*_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10), worldListenPort); @@ -120,6 +147,7 @@ int main(int argc, char** argv) { TC_LOG_ERROR("server.bnetserver", "Specified battle.net port (%d) out of allowed range (1-65535)", bnport); StopDB(); + delete _ioService; return 1; } @@ -139,13 +167,22 @@ int main(int argc, char** argv) // Enabled a timed callback for handling the database keep alive ping _dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30); - _dbPingTimer.reset(new boost::asio::deadline_timer(*_ioService)); + _dbPingTimer = new boost::asio::deadline_timer(*_ioService); _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval)); _dbPingTimer->async_wait(KeepDatabaseAliveHandler); sComponentMgr->Load(); sModuleMgr->Load(); +#if PLATFORM == PLATFORM_WINDOWS + if (m_ServiceStatus != -1) + { + _serviceStatusWatchTimer = new boost::asio::deadline_timer(*_ioService); + _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1)); + _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher); + } +#endif + // Start the io service worker loop _ioService->run(); @@ -162,9 +199,10 @@ int main(int argc, char** argv) TC_LOG_INFO("server.bnetserver", "Halting process..."); - signals.clear(); + signals.cancel(); - _ioService.reset(); + delete _dbPingTimer; + delete _ioService; return 0; } @@ -211,24 +249,55 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error) } } -variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile) +#if PLATFORM == PLATFORM_WINDOWS +void ServiceStatusWatcher(boost::system::error_code const& error) +{ + if (!error) + { + if (m_ServiceStatus == 0) + { + _ioService->stop(); + delete _serviceStatusWatchTimer; + } + else + { + _serviceStatusWatchTimer->expires_from_now(boost::posix_time::seconds(1)); + _serviceStatusWatchTimer->async_wait(ServiceStatusWatcher); + } + } +} +#endif + +variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService) { + (void)configService; + options_description all("Allowed options"); all.add_options() ("help,h", "print usage message") ("config,c", value<std::string>(&configFile)->default_value(_TRINITY_BNET_CONFIG), "use <arg> as configuration file") ; +#if PLATFORM == PLATFORM_WINDOWS + options_description win("Windows platform specific options"); + win.add_options() + ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]") + ; + + all.add(win); +#endif variables_map variablesMap; try { store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap); notify(variablesMap); } - catch (std::exception& e) { + catch (std::exception& e) + { std::cerr << e.what() << "\n"; } - if (variablesMap.count("help")) { + if (variablesMap.count("help")) + { std::cout << all << "\n"; } diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp index bb752fd9b49..e0b1ed3b161 100644 --- a/src/server/collision/Management/MMapManager.cpp +++ b/src/server/collision/Management/MMapManager.cpp @@ -24,6 +24,9 @@ namespace MMAP { + static char const* const MAP_FILE_NAME_FORMAT = "%smmaps/%04i.mmap"; + static char const* const TILE_FILE_NAME_FORMAT = "%smmaps/%04i%02i%02i.mmtile"; + // ######################## MMapManager ######################## MMapManager::~MMapManager() { @@ -41,15 +44,11 @@ namespace MMAP return true; // load and init dtNavMesh - read parameters from file - uint32 pathLen = uint32(sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap") + 1); - char *fileName = new char[pathLen]; - snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i.mmap").c_str(), mapId); - - FILE* file = fopen(fileName, "rb"); + std::string fileName = Trinity::StringFormat(MAP_FILE_NAME_FORMAT, sWorld->GetDataPath().c_str(), mapId); + FILE* file = fopen(fileName.c_str(), "rb"); if (!file) { - TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName); - delete [] fileName; + TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName.c_str()); return false; } @@ -58,8 +57,7 @@ namespace MMAP fclose(file); if (count != 1) { - TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName); - delete [] fileName; + TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName.c_str()); return false; } @@ -68,14 +66,11 @@ namespace MMAP if (dtStatusFailed(mesh->init(¶ms))) { dtFreeNavMesh(mesh); - TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName); - delete [] fileName; + TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %04u from file %s", mapId, fileName.c_str()); return false; } - delete [] fileName; - - TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId); + TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %04i.mmap", mapId); // store inside our map list MMapData* mmap_data = new MMapData(mesh, mapId); @@ -104,33 +99,27 @@ namespace MMAP if (mmap->loadedTileRefs.find(packedGridPos) != mmap->loadedTileRefs.end()) return false; - // load this tile :: mmaps/MMMXXYY.mmtile - uint32 pathLen = uint32(sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1); - char *fileName = new char[pathLen]; - - snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y); - - FILE* file = fopen(fileName, "rb"); + // load this tile :: mmaps/MMMMXXYY.mmtile + std::string fileName = Trinity::StringFormat(TILE_FILE_NAME_FORMAT, sWorld->GetDataPath().c_str(), mapId, x, y); + FILE* file = fopen(fileName.c_str(), "rb"); if (!file) { - TC_LOG_DEBUG("maps", "MMAP:loadMap: Could not open mmtile file '%s'", fileName); - delete [] fileName; + TC_LOG_DEBUG("maps", "MMAP:loadMap: Could not open mmtile file '%s'", fileName.c_str()); return false; } - delete [] fileName; // read header MmapTileHeader fileHeader; if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC) { - TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y); + TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap %04u%02i%02i.mmtile", mapId, x, y); fclose(file); return false; } if (fileHeader.mmapVersion != MMAP_VERSION) { - TC_LOG_ERROR("maps", "MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i", + TC_LOG_ERROR("maps", "MMAP:loadMap: %04u%02i%02i.mmtile was built with generator v%i, expected v%i", mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION); fclose(file); return false; @@ -142,7 +131,7 @@ namespace MMAP size_t result = fread(data, fileHeader.size, 1, file); if (!result) { - TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y); + TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header or data in mmap %04u%02i%02i.mmtile", mapId, x, y); fclose(file); return false; } @@ -157,14 +146,14 @@ namespace MMAP { mmap->loadedTileRefs.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef)); ++loadedTiles; - TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y); + TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %04i[%02i, %02i] into %04i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y); LoadPhaseTiles(mapId, x, y); return true; } - TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y); + TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load %04u%02i%02i.mmtile into navmesh", mapId, x, y); dtFree(data); return false; } @@ -172,37 +161,33 @@ namespace MMAP PhasedTile* MMapManager::LoadTile(uint32 mapId, int32 x, int32 y) { // load this tile :: mmaps/MMMXXYY.mmtile - uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1; - char *fileName = new char[pathLen]; - - snprintf(fileName, pathLen, (sWorld->GetDataPath() + "mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y); - - FILE* file = fopen(fileName, "rb"); + std::string fileName = Trinity::StringFormat(TILE_FILE_NAME_FORMAT, sWorld->GetDataPath().c_str(), mapId, x, y); + FILE* file = fopen(fileName.c_str(), "rb"); if (!file) { // Not all tiles have phased versions, don't flood this msg //TC_LOG_DEBUG("phase", "MMAP:LoadTile: Could not open mmtile file '%s'", fileName); - delete[] fileName; return NULL; } - delete[] fileName; PhasedTile* pTile = new PhasedTile(); // read header if (fread(&pTile->fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || pTile->fileHeader.mmapMagic != MMAP_MAGIC) { - TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y); + TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header in mmap %04u%02i%02i.mmtile", mapId, x, y); fclose(file); - return NULL; + delete pTile; + return nullptr; } if (pTile->fileHeader.mmapVersion != MMAP_VERSION) { - TC_LOG_ERROR("phase", "MMAP:LoadTile: %03u%02i%02i.mmtile was built with generator v%i, expected v%i", + TC_LOG_ERROR("phase", "MMAP:LoadTile: %04u%02i%02i.mmtile was built with generator v%i, expected v%i", mapId, x, y, pTile->fileHeader.mmapVersion, MMAP_VERSION); fclose(file); - return NULL; + delete pTile; + return nullptr; } pTile->data = (unsigned char*)dtAlloc(pTile->fileHeader.size, DT_ALLOC_PERM); @@ -211,9 +196,10 @@ namespace MMAP size_t result = fread(pTile->data, pTile->fileHeader.size, 1, file); if (!result) { - TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y); + TC_LOG_ERROR("phase", "MMAP:LoadTile: Bad header or data in mmap %04u%02i%02i.mmtile", mapId, x, y); fclose(file); - return NULL; + delete pTile; + return nullptr; } fclose(file); @@ -237,7 +223,7 @@ namespace MMAP // only a few tiles have terrain swaps, do not write error for them if (data) { - TC_LOG_DEBUG("phase", "MMAP:LoadPhaseTiles: Loaded phased %03u%02i%02i.mmtile for root phase map %u", map->ID, x, y, mapId); + TC_LOG_DEBUG("phase", "MMAP:LoadPhaseTiles: Loaded phased %04u%02i%02i.mmtile for root phase map %u", map->ID, x, y, mapId); _phaseTiles[map->ID][packedGridPos] = data; } } @@ -256,7 +242,7 @@ namespace MMAP if (_phaseTiles[mapId][packedGridPos]) { - TC_LOG_DEBUG("phase", "MMAP:UnloadPhaseTile: Unloaded phased %03u%02i%02i.mmtile for root phase map %u", mapId, x, y, rootMapId); + TC_LOG_DEBUG("phase", "MMAP:UnloadPhaseTile: Unloaded phased %04u%02i%02i.mmtile for root phase map %u", mapId, x, y, rootMapId); delete _phaseTiles[mapId][packedGridPos]->data; delete _phaseTiles[mapId][packedGridPos]; _phaseTiles[mapId].erase(packedGridPos); @@ -269,7 +255,7 @@ namespace MMAP if (loadedMMaps.find(mapId) == loadedMMaps.end()) { // file may not exist, therefore not loaded - TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y); + TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %04u%02i%02i.mmtile", mapId, x, y); return false; } @@ -280,7 +266,7 @@ namespace MMAP if (mmap->loadedTileRefs.find(packedGridPos) == mmap->loadedTileRefs.end()) { // file may not exist, therefore not loaded - TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y); + TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %04u%02i%02i.mmtile", mapId, x, y); return false; } @@ -292,14 +278,14 @@ namespace MMAP // this is technically a memory leak // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used // we cannot recover from this error - assert out - TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); + TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %04u%02i%02i.mmtile from navmesh", mapId, x, y); ASSERT(false); } else { mmap->loadedTileRefs.erase(packedGridPos); --loadedTiles; - TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId); + TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %04i", mapId, x, y, mapId); UnloadPhaseTile(mapId, x, y); return true; @@ -313,7 +299,7 @@ namespace MMAP if (loadedMMaps.find(mapId) == loadedMMaps.end()) { // file may not exist, therefore not loaded - TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId); + TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %04u", mapId); return false; } @@ -324,18 +310,18 @@ namespace MMAP uint32 x = (i->first >> 16); uint32 y = (i->first & 0x0000FFFF); if (dtStatusFailed(mmap->navMesh->removeTile(i->second, NULL, NULL))) - TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); + TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %04u%02i%02i.mmtile from navmesh", mapId, x, y); else { UnloadPhaseTile(mapId, x, y); --loadedTiles; - TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId); + TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %04i[%02i, %02i] from %04i", mapId, x, y, mapId); } } delete mmap; loadedMMaps.erase(mapId); - TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId); + TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %04i.mmap", mapId); return true; } @@ -346,14 +332,14 @@ namespace MMAP if (loadedMMaps.find(mapId) == loadedMMaps.end()) { // file may not exist, therefore not loaded - TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId); + TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %04u", mapId); return false; } MMapData* mmap = loadedMMaps[mapId]; if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) { - TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId); + TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %04u instanceId %u", mapId, instanceId); return false; } @@ -361,7 +347,7 @@ namespace MMAP dtFreeNavMeshQuery(query); mmap->navMeshQueries.erase(instanceId); - TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId); + TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId %04u instanceId %u", mapId, instanceId); return true; } @@ -388,11 +374,11 @@ namespace MMAP if (dtStatusFailed(query->init(mmap->GetNavMesh(swaps), 1024))) { dtFreeNavMeshQuery(query); - TC_LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); + TC_LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %04u instanceId %u", mapId, instanceId); return NULL; } - TC_LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); + TC_LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %04u instanceId %u", mapId, instanceId); mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query)); } @@ -426,25 +412,25 @@ namespace MMAP if (loadedPhasedTiles[swap].find(packedXY) == loadedPhasedTiles[swap].end()) { - TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: mmtile %03u[%02i, %02i] unload skipped, due to not loaded", swap, x, y); + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: mmtile %04u[%02i, %02i] unload skipped, due to not loaded", swap, x, y); return; } dtMeshHeader* header = (dtMeshHeader*)ptile->data; // remove old tile if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], NULL, NULL))) - TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not unload phased %03u%02i%02i.mmtile from navmesh", swap, x, y); + TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not unload phased %04u%02i%02i.mmtile from navmesh", swap, x, y); else { - TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Unloaded phased %03u%02i%02i.mmtile from navmesh", swap, x, y); + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Unloaded phased %04u%02i%02i.mmtile from navmesh", swap, x, y); // restore base tile if (dtStatusSucceed(navMesh->addTile(_baseTiles[packedXY]->data, _baseTiles[packedXY]->dataSize, 0, 0, &loadedTileRefs[packedXY]))) { - TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Loaded base mmtile %03u[%02i, %02i] into %03i[%02i, %02i]", _mapId, x, y, _mapId, header->x, header->y); + TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Loaded base mmtile %04u[%02i, %02i] into %04i[%02i, %02i]", _mapId, x, y, _mapId, header->x, header->y); } else - TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not load base %03u%02i%02i.mmtile to navmesh", _mapId, x, y); + TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not load base %04u%02i%02i.mmtile to navmesh", _mapId, x, y); } loadedPhasedTiles[swap].erase(packedXY); @@ -464,12 +450,12 @@ namespace MMAP if (loadedTileRefs.find(packedXY) == loadedTileRefs.end()) { - TC_LOG_DEBUG("phase", "MMapData::AddSwap: phased mmtile %03u[%02i, %02i] load skipped, due to not loaded base tile on map %u", swap, x, y, _mapId); + TC_LOG_DEBUG("phase", "MMapData::AddSwap: phased mmtile %04u[%02i, %02i] load skipped, due to not loaded base tile on map %u", swap, x, y, _mapId); return; } if (loadedPhasedTiles[swap].find(packedXY) != loadedPhasedTiles[swap].end()) { - TC_LOG_DEBUG("phase", "MMapData::AddSwap: WARNING! phased mmtile %03u[%02i, %02i] load skipped, due to already loaded on map %u", swap, x, y, _mapId); + TC_LOG_DEBUG("phase", "MMapData::AddSwap: WARNING! phased mmtile %04u[%02i, %02i] load skipped, due to already loaded on map %u", swap, x, y, _mapId); return; } @@ -480,25 +466,25 @@ namespace MMAP if (!oldTile) { - TC_LOG_DEBUG("phase", "MMapData::AddSwap: phased mmtile %03u[%02i, %02i] load skipped, due to not loaded base tile ref on map %u", swap, x, y, _mapId); + TC_LOG_DEBUG("phase", "MMapData::AddSwap: phased mmtile %04u[%02i, %02i] load skipped, due to not loaded base tile ref on map %u", swap, x, y, _mapId); return; } - uint32 old_x = oldTile->header->x; - uint32 old_y = oldTile->header->y; - // header xy is based on the swap map's tile set, wich doesn't have all the same tiles as root map, so copy the xy from the orignal header - memcpy(ptile->data + 8, (char*)&old_x, 4); - memcpy(ptile->data + 12, (char*)&old_y, 4); + header->x = oldTile->header->x; + header->y = oldTile->header->y; // the removed tile's data PhasedTile* pt = new PhasedTile(); // remove old tile if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], &pt->data, &pt->dataSize))) - TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not unload %03u%02i%02i.mmtile from navmesh", _mapId, x, y); + { + TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not unload %04u%02i%02i.mmtile from navmesh", _mapId, x, y); + delete pt; + } else { - TC_LOG_DEBUG("phase", "MMapData::AddSwap: Unloaded %03u%02i%02i.mmtile from navmesh", _mapId, x, y); + TC_LOG_DEBUG("phase", "MMapData::AddSwap: Unloaded %04u%02i%02i.mmtile from navmesh", _mapId, x, y); // store the removed data first time, this is the origonal, non-phased tile if (_baseTiles.find(packedXY) == _baseTiles.end()) @@ -510,43 +496,38 @@ namespace MMAP // add new swapped tile if (dtStatusSucceed(navMesh->addTile(ptile->data, ptile->fileHeader.size, 0, 0, &loadedTileRefs[packedXY]))) { - TC_LOG_DEBUG("phase", "MMapData::AddSwap: Loaded phased mmtile %03u[%02i, %02i] into %03i[%02i, %02i]", swap, x, y, _mapId, header->x, header->y); + TC_LOG_DEBUG("phase", "MMapData::AddSwap: Loaded phased mmtile %04u[%02i, %02i] into %04i[%02i, %02i]", swap, x, y, _mapId, header->x, header->y); } else - TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not load %03u%02i%02i.mmtile to navmesh", swap, x, y); + TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not load %04u%02i%02i.mmtile to navmesh", swap, x, y); } } dtNavMesh* MMapData::GetNavMesh(TerrainSet swaps) { - for (uint32 swap : _activeSwaps) + std::set<uint32> activeSwaps = _activeSwaps; // _activeSwaps is modified inside RemoveSwap + for (uint32 swap : activeSwaps) { - if (swaps.find(swap) == swaps.end()) // swap not active + if (!swaps.count(swap)) // swap not active { PhaseTileContainer ptc = MMAP::MMapFactory::createOrGetMMapManager()->GetPhaseTileContainer(swap); for (PhaseTileContainer::const_iterator itr = ptc.begin(); itr != ptc.end(); ++itr) - { RemoveSwap(itr->second, swap, itr->first); // remove swap - } } } - if (!swaps.empty()) + // for each of the calling unit's terrain swaps + for (uint32 swap : swaps) { - // for each of the calling unit's terrain swaps - for (uint32 swap : swaps) + if (!_activeSwaps.count(swap)) // swap not active { // for each of the terrain swap's xy tiles PhaseTileContainer ptc = MMAP::MMapFactory::createOrGetMMapManager()->GetPhaseTileContainer(swap); for (PhaseTileContainer::const_iterator itr = ptc.begin(); itr != ptc.end(); ++itr) - { - if (_activeSwaps.find(swap) == _activeSwaps.end()) // swap not active - { - AddSwap(itr->second, swap, itr->first); // add swap - } - } + AddSwap(itr->second, swap, itr->first); // add swap } } + return navMesh; } } diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp index f9fcff96ad2..0c3ff1a9bfa 100644 --- a/src/server/collision/Management/VMapManager2.cpp +++ b/src/server/collision/Management/VMapManager2.cpp @@ -66,7 +66,7 @@ namespace VMAP std::string VMapManager2::getMapFileName(unsigned int mapId) { std::stringstream fname; - fname.width(3); + fname.width(4); fname << std::setfill('0') << mapId << std::string(MAP_FILENAME_EXTENSION2); return fname.str(); diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp index b493ec18f5f..862f3e1cefe 100644 --- a/src/server/collision/Maps/MapTree.cpp +++ b/src/server/collision/Maps/MapTree.cpp @@ -90,7 +90,7 @@ namespace VMAP { std::stringstream tilefilename; tilefilename.fill('0'); - tilefilename << std::setw(3) << mapID << '_'; + tilefilename << std::setw(4) << mapID << '_'; //tilefilename << std::setw(2) << tileX << '_' << std::setw(2) << tileY << ".vmtile"; tilefilename << std::setw(2) << tileY << '_' << std::setw(2) << tileX << ".vmtile"; return tilefilename.str(); diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp index 172c556b9a7..ce39dc02da8 100644 --- a/src/server/collision/Maps/TileAssembler.cpp +++ b/src/server/collision/Maps/TileAssembler.cpp @@ -24,7 +24,6 @@ #include <set> #include <iomanip> #include <sstream> -#include <iomanip> using G3D::Vector3; using G3D::AABox; @@ -116,7 +115,7 @@ namespace VMAP // write map tree file std::stringstream mapfilename; - mapfilename << iDestDir << '/' << std::setfill('0') << std::setw(3) << map_iter->first << ".vmtree"; + mapfilename << iDestDir << '/' << std::setfill('0') << std::setw(4) << map_iter->first << ".vmtree"; FILE* mapfile = fopen(mapfilename.str().c_str(), "wb"); if (!mapfile) { @@ -157,7 +156,7 @@ namespace VMAP uint32 nSpawns = tileEntries.count(tile->first); std::stringstream tilefilename; tilefilename.fill('0'); - tilefilename << iDestDir << '/' << std::setw(3) << map_iter->first << '_'; + tilefilename << iDestDir << '/' << std::setw(4) << map_iter->first << '_'; uint32 x, y; StaticMapTree::unpackTileID(tile->first, x, y); tilefilename << std::setw(2) << x << '_' << std::setw(2) << y << ".vmtile"; diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp index 6140c266b18..607460a2784 100644 --- a/src/server/collision/Models/GameObjectModel.cpp +++ b/src/server/collision/Models/GameObjectModel.cpp @@ -188,12 +188,12 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto return hit; } -bool GameObjectModel::Relocate(const GameObject& go) +bool GameObjectModel::UpdatePosition() { if (!iModel) return false; - ModelList::const_iterator it = model_list.find(go.GetDisplayId()); + ModelList::const_iterator it = model_list.find(owner->GetDisplayId()); if (it == model_list.end()) return false; @@ -205,9 +205,9 @@ bool GameObjectModel::Relocate(const GameObject& go) return false; } - iPos = Vector3(go.GetPositionX(), go.GetPositionY(), go.GetPositionZ()); + iPos = Vector3(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ()); - G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(go.GetOrientation(), 0, 0); + G3D::Matrix3 iRotation = G3D::Matrix3::fromEulerAnglesZYX(owner->GetOrientation(), 0, 0); iInvRot = iRotation.inverse(); // transform bounding box: mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale); @@ -221,7 +221,7 @@ bool GameObjectModel::Relocate(const GameObject& go) for (int i = 0; i < 8; ++i) { Vector3 pos(iBound.corner(i)); - go.SummonCreature(1, pos.x, pos.y, pos.z, 0, TEMPSUMMON_MANUAL_DESPAWN); + owner->SummonCreature(1, pos.x, pos.y, pos.z, 0, TEMPSUMMON_MANUAL_DESPAWN); } #endif diff --git a/src/server/collision/Models/GameObjectModel.h b/src/server/collision/Models/GameObjectModel.h index 232ebbee5e9..43d299d6d8f 100644 --- a/src/server/collision/Models/GameObjectModel.h +++ b/src/server/collision/Models/GameObjectModel.h @@ -68,7 +68,7 @@ public: static GameObjectModel* Create(const GameObject& go); - bool Relocate(GameObject const& go); + bool UpdatePosition(); }; #endif // _GAMEOBJECT_MODEL_H diff --git a/src/server/collision/VMapDefinitions.h b/src/server/collision/VMapDefinitions.h index 8d18372d2b1..7234256f069 100644 --- a/src/server/collision/VMapDefinitions.h +++ b/src/server/collision/VMapDefinitions.h @@ -25,8 +25,8 @@ namespace VMAP { - const char VMAP_MAGIC[] = "VMAP_4.2"; - const char RAW_VMAP_MAGIC[] = "VMAP042"; // used in extracted vmap files with raw data + const char VMAP_MAGIC[] = "VMAP_4.3"; + const char RAW_VMAP_MAGIC[] = "VMAP043"; // used in extracted vmap files with raw data const char GAMEOBJECT_MODELS[] = "GameObjectModels.dtree"; // defined in TileAssembler.cpp currently... diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 91eb00f17c5..3ea18f272ae 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -128,7 +128,7 @@ class UnitAI virtual void InitializeAI() { if (!me->isDead()) Reset(); } - virtual void Reset() { }; + virtual void Reset() { } // Called when unit is charmed virtual void OnCharmed(bool apply) = 0; diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index f835206aba5..8a37186d0af 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -53,7 +53,7 @@ namespace FactorySelector 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)) + else if (creature->HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); else if (creature->IsGuard()) ai_factory = ai_registry.GetRegistryItem("GuardAI"); diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index bc26fc42df8..66164730219 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -478,7 +478,7 @@ void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false } //disable npcflags - me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + me->SetUInt64Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC)) { HasImmuneToNPCFlags = true; diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 720847b2f20..ab91b0b5b27 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -313,7 +313,7 @@ void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, const Qu TC_LOG_DEBUG("scripts", "FollowerAI start with WAYPOINT_MOTION_TYPE, set to MoveIdle."); } - me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + me->SetUInt64Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); AddFollowState(STATE_FOLLOW_INPROGRESS); diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index f3520820f30..f50bf1fe0e1 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1355,7 +1355,31 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_SET_COUNTER: { - StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset); + if (ObjectList* targets = GetTargets(e, unit)) + { + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + { + if (IsCreature(*itr)) + { + if (SmartAI* ai = CAST_AI(SmartAI, (*itr)->ToCreature()->AI())) + ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset); + else + TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping"); + } + else if (IsGameObject(*itr)) + { + if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, (*itr)->ToGameObject()->AI())) + ai->GetScript()->StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset); + else + TC_LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping"); + } + } + + delete targets; + } + else + StoreCounter(e.action.setCounter.counterId, e.action.setCounter.value, e.action.setCounter.reset); + break; } case SMART_ACTION_WP_START: @@ -1681,7 +1705,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsCreature(*itr)) - (*itr)->ToUnit()->SetUInt32Value(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + (*itr)->ToUnit()->SetUInt64Value(UNIT_NPC_FLAGS, e.action.unitFlag.flag); delete targets; break; @@ -1694,7 +1718,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsCreature(*itr)) - (*itr)->ToUnit()->SetFlag(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + (*itr)->ToUnit()->SetFlag64(UNIT_NPC_FLAGS, e.action.unitFlag.flag); delete targets; break; @@ -1707,7 +1731,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) if (IsCreature(*itr)) - (*itr)->ToUnit()->RemoveFlag(UNIT_NPC_FLAGS, e.action.unitFlag.flag); + (*itr)->ToUnit()->RemoveFlag64(UNIT_NPC_FLAGS, e.action.unitFlag.flag); delete targets; break; diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 0233d1aa7d0..c5cc5aedb43 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -177,33 +177,25 @@ class SmartScript GameObject* FindGameObjectNear(WorldObject* searchObject, ObjectGuid::LowType guid) const { - GameObject* gameObject = NULL; + auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid); + if (bounds.first == bounds.second) + return nullptr; - 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->GetGridActivationRange()); - - return gameObject; + return bounds.first->second; } Creature* FindCreatureNear(WorldObject* searchObject, ObjectGuid::LowType guid) const { - Creature* creature = NULL; - CellCoord p(Trinity::ComputeCellCoord(searchObject->GetPositionX(), searchObject->GetPositionY())); - Cell cell(p); + auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid); + if (bounds.first == bounds.second) + return nullptr; - 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->GetGridActivationRange()); + auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair) + { + return pair.second->IsAlive(); + }); - return creature; + return creatureItr != bounds.second ? creatureItr->second : bounds.first->second; } ObjectListMap* mTargetStorage; diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 2a499db8fdb..6d56774e447 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -61,7 +61,7 @@ enum RBACPermissions // 9 - reuse RBAC_PERM_USE_CHARACTER_TEMPLATES = 10, RBAC_PERM_LOG_GM_TRADE = 11, - // 12 - reuse + // 12 - reuse RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES = 13, RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK = 14, RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK = 15, @@ -738,6 +738,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_TICKET_RESET_BUG = 831, RBAC_PERM_COMMAND_TICKET_RESET_COMPLAINT = 832, RBAC_PERM_COMMAND_TICKET_RESET_SUGGESTION = 833, + RBAC_PERM_COMMAND_GO_QUEST = 834, // custom permissions 1000+ RBAC_PERM_MAX @@ -846,6 +847,7 @@ class RBACData * @return Success or failure (with reason) to grant the permission * * Example Usage: + * @code * // previously defined "RBACData* rbac" with proper initialization * uint32 permissionId = 2; * if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST) @@ -869,6 +871,7 @@ class RBACData * @return Success or failure (with reason) to deny the permission * * Example Usage: + * @code * // previously defined "RBACData* rbac" with proper initialization * uint32 permissionId = 2; * if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS) @@ -893,6 +896,7 @@ class RBACData * @return Success or failure (with reason) to remove the permission * * Example Usage: + * @code * // previously defined "RBACData* rbac" with proper initialization * uint32 permissionId = 2; * if (rbac->RevokeRole(permissionId) == RBAC_OK) @@ -983,9 +987,6 @@ class RBACData * * Given a list of permissions, gets all the inherited permissions * @param permissions The list of permissions to expand - * - * @return new list of permissions containing original permissions and - * all other pemissions that are linked to the original ones */ void ExpandPermissions(RBACPermissionContainer& permissions); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index cfe93b0cde3..9c347879768 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -28,6 +28,7 @@ #include "DBCEnums.h" #include "DisableMgr.h" #include "GameEventMgr.h" +#include "Garrison.h" #include "GridNotifiersImpl.h" #include "Group.h" #include "Guild.h" @@ -1161,6 +1162,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: SetCriteriaProgress(achievementCriteria, 1, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: @@ -1269,6 +1271,39 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: + case ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR: + case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: + case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: + case ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: + case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON: + case ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS: break; // Not implemented yet :( } @@ -1413,6 +1448,7 @@ bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteria const* achieveme case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: return progress->counter >= (requiredAmount * 75); @@ -2492,6 +2528,44 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(ModifierTreeNode const* if (!unit || unit->GetHealthPct() >= reqValue) return false; break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY: // 145 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->PacketInfo.Quality != reqValue) + return false; + + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL: // 146 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->PacketInfo.FollowerLevel < reqValue) + return false; + + break; + } + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL: // 184 + { + if (!referencePlayer) + return false; + Garrison* garrison = referencePlayer->GetGarrison(); + if (!garrison) + return false; + Garrison::Follower const* follower = garrison->GetFollower(miscValue1); + if (!follower || follower->GetItemLevel() < reqValue) + return false; + break; + } default: break; } @@ -2729,6 +2803,74 @@ char const* AchievementGlobalMgr::GetCriteriaTypeString(AchievementCriteriaTypes return "GUILD_CHALLENGE_TYPE"; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE: return "GUILD_CHALLENGE"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED: + return "LFR_DUNGEONS_COMPLETED"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES: + return "LFR_LEAVES"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER: + return "LFR_VOTE_KICKS_INITIATED_BY_PLAYER"; + case ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER: + return "LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER"; + case ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR: + return "BE_KICKED_FROM_LFR"; + case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: + return "COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: + return "COMPLETE_SCENARIO_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: + return "COMPLETE_SCENARIO"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: + return "OWN_BATTLE_PET"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: + return "OWN_BATTLE_PET_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: + return "CAPTURE_BATTLE_PET"; + case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: + return "WIN_PET_BATTLE"; + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: + return "LEVEL_BATTLE_PET"; + case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT: + return "CAPTURE_BATTLE_PET_CREDIT"; + case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT: + return "LEVEL_BATTLE_PET_CREDIT"; + case ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA: + return "ENTER_AREA"; + case ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA: + return "LEAVE_AREA"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER: + return "COMPLETE_DUNGEON_ENCOUNTER"; + case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + return "PLACE_GARRISON_BUILDING"; + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING: + return "UPGRADE_GARRISON_BUILDING"; + case ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING: + return "CONSTRUCT_GARRISON_BUILDING"; + case ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON: + return "UPGRADE_GARRISON"; + case ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION: + return "START_GARRISON_MISSION"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT: + return "COMPLETE_GARRISON_MISSION_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION: + return "COMPLETE_GARRISON_MISSION"; + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT: + return "RECRUIT_GARRISON_FOLLOWER_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT: + return "LEARN_GARRISON_BLUEPRINT_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT: + return "COMPLETE_GARRISON_SHIPMENT"; + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL: + return "RAISE_GARRISON_FOLLOWER_ITEM_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL: + return "RAISE_GARRISON_FOLLOWER_LEVEL"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY: + return "OWN_TOY"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT: + return "OWN_TOY_COUNT"; + case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + return "RECRUIT_GARRISON_FOLLOWER"; + case ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS: + return "OWN_HEIRLOOMS"; } return "MISSING_TYPE"; } diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 2b34d308763..76b2d849a73 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -320,7 +320,7 @@ bool AuctionBotSeller::Initialize() continue; } - if (prototype->GetFlags() & ITEM_FLAG_UNLOCKED) + if (prototype->GetFlags() & ITEM_FIELD_FLAG_UNLOCKED) { // skip any not locked lootable items (mostly quest specific or reward cases) if (!prototype->GetLockID()) diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index c6c46c48f50..f37526ae71b 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -71,7 +71,7 @@ namespace Trinity void do_helper(WorldPacket& data, char const* text) { WorldPackets::Chat::Chat packet; - packet.Initalize(_msgtype, LANG_UNIVERSAL, _source, _source, text); + packet.Initialize(_msgtype, LANG_UNIVERSAL, _source, _source, text); packet.Write(); data = packet.Move(); } @@ -98,7 +98,7 @@ namespace Trinity snprintf(str, 2048, text, arg1str, arg2str); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgtype, LANG_UNIVERSAL, _source, _source, str); + packet.Initialize(_msgtype, LANG_UNIVERSAL, _source, _source, str); packet.Write(); data = packet.Move(); } diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 1bb636078e2..a227dc1a07b 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -471,8 +471,8 @@ void BattlegroundMgr::LoadBattlegroundTemplates() _battlegroundMapTemplates.clear(); _battlegroundTemplates.clear(); - // 0 1 2 3 4 5 6 7 8 9 10 11 - QueryResult result = WorldDatabase.Query("SELECT id, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, AllianceStartO, HordeStartLoc, HordeStartO, StartMaxDist, Weight, ScriptName FROM battleground_template"); + // 0 1 2 3 4 5 6 7 8 9 + QueryResult result = WorldDatabase.Query("SELECT ID, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, HordeStartLoc, StartMaxDist, Weight, ScriptName FROM battleground_template"); if (!result) { TC_LOG_ERROR("server.loading", ">> Loaded 0 battlegrounds. DB table `battleground_template` is empty."); @@ -504,22 +504,22 @@ void BattlegroundMgr::LoadBattlegroundTemplates() bgTemplate.MaxPlayersPerTeam = fields[2].GetUInt16(); bgTemplate.MinLevel = fields[3].GetUInt8(); bgTemplate.MaxLevel = fields[4].GetUInt8(); - float dist = fields[9].GetFloat(); + float dist = fields[7].GetFloat(); bgTemplate.MaxStartDistSq = dist * dist; - bgTemplate.Weight = fields[10].GetUInt8(); - bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[11].GetCString()); + bgTemplate.Weight = fields[8].GetUInt8(); + bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[9].GetCString()); bgTemplate.BattlemasterEntry = bl; if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam) { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u)", + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for ID %u has bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u)", bgTemplate.Id, bgTemplate.MinPlayersPerTeam, bgTemplate.MaxPlayersPerTeam); continue; } if (bgTemplate.MinLevel == 0 || bgTemplate.MaxLevel == 0 || bgTemplate.MinLevel > bgTemplate.MaxLevel) { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has bad values for MinLevel (%u) and MaxLevel (%u)", + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for ID %u has bad values for MinLevel (%u) and MaxLevel (%u)", bgTemplate.Id, bgTemplate.MinLevel, bgTemplate.MaxLevel); continue; } @@ -529,22 +529,22 @@ void BattlegroundMgr::LoadBattlegroundTemplates() uint32 startId = fields[5].GetUInt32(); if (WorldSafeLocsEntry const* start = sWorldSafeLocsStore.LookupEntry(startId)) { - bgTemplate.StartLocation[TEAM_ALLIANCE].Relocate(start->Loc.X, start->Loc.Y, start->Loc.Z, fields[6].GetFloat()); + bgTemplate.StartLocation[TEAM_ALLIANCE].Relocate(start->Loc.X, start->Loc.Y, start->Loc.Z, (start->Facing * M_PI) / 180); } else { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId); + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for ID %u a non-existant WorldSafeLoc (ID: %u) in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId); continue; } - startId = fields[7].GetUInt32(); + startId = fields[6].GetUInt32(); if (WorldSafeLocsEntry const* start = sWorldSafeLocsStore.LookupEntry(startId)) { - bgTemplate.StartLocation[TEAM_HORDE].Relocate(start->Loc.X, start->Loc.Y, start->Loc.Z, fields[8].GetFloat()); + bgTemplate.StartLocation[TEAM_HORDE].Relocate(start->Loc.X, start->Loc.Y, start->Loc.Z, (start->Facing * M_PI) / 180); } else { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId); + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for ID %u has a non-existant WorldSafeLoc (ID: %u) in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId); continue; } } diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h index 9a65019a390..eb225250a56 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.h +++ b/src/server/game/Battlegrounds/BattlegroundQueue.h @@ -106,7 +106,7 @@ class BattlegroundQueue class SelectionPool { public: - SelectionPool(): PlayerCount(0) { }; + SelectionPool(): PlayerCount(0) { } void Init(); bool AddGroup(GroupQueueInfo* ginfo, uint32 desiredCount); bool KickGroup(uint32 size); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h index 3694c62d663..8b6f16d1ff9 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBFG.h @@ -42,7 +42,7 @@ class BattlegroundBFGScore final : public BattlegroundScore } } - void BuildObjectivesBlock(std::vector<int32>& stats) + void BuildObjectivesBlock(std::vector<int32>& stats) override { stats.push_back(BasesAssaulted); stats.push_back(BasesDefended); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundTP.h b/src/server/game/Battlegrounds/Zones/BattlegroundTP.h index b11485d6025..1dfd3801864 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundTP.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundTP.h @@ -42,7 +42,7 @@ class BattlegroundTPScore final : public BattlegroundScore } } - void BuildObjectivesBlock(std::vector<int32>& stats) + void BuildObjectivesBlock(std::vector<int32>& stats) override { stats.push_back(FlagCaptures); stats.push_back(FlagReturns); diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index caa75c24121..9c3646c39ca 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -24,6 +24,7 @@ file(GLOB_RECURSE sources_DataStores DataStores/*.cpp DataStores/*.h) file(GLOB_RECURSE sources_DungeonFinding DungeonFinding/*.cpp DungeonFinding/*.h) file(GLOB_RECURSE sources_Entities Entities/*.cpp Entities/*.h) file(GLOB_RECURSE sources_Events Events/*.cpp Events/*.h) +file(GLOB_RECURSE sources_Garrison Garrison/*.cpp Garrison/*.h) file(GLOB_RECURSE sources_Globals Globals/*.cpp Globals/*.h) file(GLOB_RECURSE sources_Grids Grids/*.cpp Grids/*.h) file(GLOB_RECURSE sources_Groups Groups/*.cpp Groups/*.h) @@ -75,6 +76,7 @@ set(game_STAT_SRCS ${sources_DungeonFinding} ${sources_Entities} ${sources_Events} + ${sources_Garrison} ${sources_Globals} ${sources_Grids} ${sources_Groups} @@ -172,6 +174,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Vehicle ${CMAKE_CURRENT_SOURCE_DIR}/Entities/Transport ${CMAKE_CURRENT_SOURCE_DIR}/Events + ${CMAKE_CURRENT_SOURCE_DIR}/Garrison ${CMAKE_CURRENT_SOURCE_DIR}/Globals ${CMAKE_CURRENT_SOURCE_DIR}/Grids/Cells ${CMAKE_CURRENT_SOURCE_DIR}/Grids/Notifiers @@ -217,8 +220,8 @@ include_directories( GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) add_library(game STATIC - ${game_STAT_SRCS} ${game_STAT_PCH_SRC} + ${game_STAT_SRCS} ) add_dependencies(game revision.h) diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 04b6eb1b5b1..97fa489d388 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -626,10 +626,10 @@ void Channel::Say(ObjectGuid const& guid, std::string const& what, uint32 lang) WorldPackets::Chat::Chat packet; if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) - packet.Initalize(CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _name); + packet.Initialize(CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, _name); else { - packet.Initalize(CHAT_MSG_CHANNEL, Language(lang), nullptr, nullptr, what, 0, _name); + packet.Initialize(CHAT_MSG_CHANNEL, Language(lang), nullptr, nullptr, what, 0, _name); packet.SenderGUID = guid; packet.TargetGUID = guid; } @@ -990,32 +990,42 @@ void Channel::MakeVoiceOff(WorldPackets::Channel::ChannelNotify& data, ObjectGui void Channel::JoinNotify(Player const* player) { ObjectGuid const& guid = player->GetGUID(); - WorldPacket data(IsConstant() ? SMSG_USERLIST_ADD : SMSG_USERLIST_UPDATE, 8 + 1 + 1 + 4 + GetName().size()); - data << guid; - data << uint8(GetPlayerFlags(guid)); - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); if (IsConstant()) - SendToAllButOne(&data, guid); + { + WorldPackets::Channel::UserlistAdd userlistAdd; + userlistAdd.AddedUserGUID = guid; + userlistAdd._ChannelFlags = GetFlags(); + userlistAdd.UserFlags = GetPlayerFlags(guid); + userlistAdd.ChannelID = GetChannelId(); + userlistAdd.ChannelName = GetName(); + SendToAllButOne(userlistAdd.Write(), guid); + } else - SendToAll(&data); + { + WorldPackets::Channel::UserlistUpdate userlistUpdate; + userlistUpdate.UpdatedUserGUID = guid; + userlistUpdate._ChannelFlags = GetFlags(); + userlistUpdate.UserFlags = GetPlayerFlags(guid); + userlistUpdate.ChannelID = GetChannelId(); + userlistUpdate.ChannelName = GetName(); + SendToAll(userlistUpdate.Write()); + } } void Channel::LeaveNotify(Player const* player) { ObjectGuid const& guid = player->GetGUID(); - WorldPacket data(SMSG_USERLIST_REMOVE, 8 + 1 + 4 + GetName().size()); - data << guid; - data << uint8(GetFlags()); - data << uint32(GetNumPlayers()); - data << GetName(); + WorldPackets::Channel::UserlistRemove userlistRemove; + userlistRemove.RemovedUserGUID = guid; + userlistRemove._ChannelFlags = GetFlags(); + userlistRemove.ChannelID = GetChannelId(); + userlistRemove.ChannelName = GetName(); if (IsConstant()) - SendToAllButOne(&data, guid); + SendToAllButOne(userlistRemove.Write(), guid); else - SendToAll(&data); + SendToAll(userlistRemove.Write()); } void Channel::SetModerator(ObjectGuid const& guid, bool set) diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 2cfe0797bce..23cd4e4cada 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -72,7 +72,9 @@ enum ChatNotify CHAT_NOT_IN_AREA_NOTICE = 0x20, //+ "[%s] You are not in the correct area for this channel."; -- The user is trying to send a chat to a zone specific channel, and they're not physically in that zone. CHAT_NOT_IN_LFG_NOTICE = 0x21, //+ "[%s] You must be queued in looking for group before joining this channel."; -- The user must be in the looking for group system to join LFG chat channels. CHAT_VOICE_ON_NOTICE = 0x22, //+ "[%s] Channel voice enabled by %s."; - CHAT_VOICE_OFF_NOTICE = 0x23 //+ "[%s] Channel voice disabled by %s."; + CHAT_VOICE_OFF_NOTICE = 0x23, //+ "[%s] Channel voice disabled by %s."; + CHAT_TRIAL_RESTRICTED = 0x24, + CHAT_NOT_ALLOWED_IN_CHANNEL = 0x25 }; enum ChannelFlags @@ -206,7 +208,7 @@ class Channel void DeVoice(Player const* player); void JoinNotify(Player const* player); void LeaveNotify(Player const* player); - void SetOwnership(bool ownership) { _ownership = ownership; }; + void SetOwnership(bool ownership) { _ownership = ownership; } static void CleanOldChannelsInDB(); private: diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 837ff0be60f..52c52726b73 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -201,7 +201,7 @@ void ChatHandler::SendSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); m_session->SendPacket(packet.Write()); } @@ -219,7 +219,7 @@ void ChatHandler::SendGlobalSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalMessage(packet.Write()); } @@ -237,7 +237,7 @@ void ChatHandler::SendGlobalGMSysMessage(const char *str) while (char* line = LineFromMessage(pos)) { - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); sWorld->SendGlobalGMMessage(packet.Write()); } @@ -321,9 +321,9 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, st std::string zoneName = "Unknown"; if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) { - areaName = area->ZoneName; + areaName = area->AreaName_lang; if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID)) - zoneName = zone->ZoneName; + zoneName = zone->AreaName_lang; } sLog->outCommand(m_session->GetAccountId(), "Command: %s [Player: %s (%s) (Account: %u) X: %f Y: %f Z: %f Map: %u (%s) Area: %u (%s) Zone: %s Selected: %s (%s)]", @@ -796,15 +796,11 @@ GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(ObjectGuid::Lo if (!obj && sObjectMgr->GetGOData(lowguid)) // guid is DB guid of object { - // search near player then - CellCoord p(Trinity::ComputeCellCoord(pl->GetPositionX(), pl->GetPositionY())); - Cell cell(p); + auto bounds = pl->GetMap()->GetGameObjectBySpawnIdStore().equal_range(lowguid); + if (bounds.first == bounds.second) + return nullptr; - Trinity::GameObjectWithDbGUIDCheck go_check(*pl, lowguid); - Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(pl, obj, go_check); - - TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker); - cell.Visit(p, object_checker, *pl->GetMap(), *pl, pl->GetGridActivationRange()); + return bounds.first->second; } return obj; diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index bed2cc793f4..01c65315d35 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -28,6 +28,18 @@ DB2Storage<AreaGroupMemberEntry> sAreaGroupMemberStore("AreaGroupMemb DB2Storage<BroadcastTextEntry> sBroadcastTextStore("BroadcastText.db2", BroadcastTextFormat, HOTFIX_SEL_BROADCAST_TEXT); DB2Storage<CurrencyTypesEntry> sCurrencyTypesStore("CurrencyTypes.db2", CurrencyTypesFormat, HOTFIX_SEL_CURRENCY_TYPES); DB2Storage<CurvePointEntry> sCurvePointStore("CurvePoint.db2", CurvePointFormat, HOTFIX_SEL_CURVE_POINT); +DB2Storage<GameObjectsEntry> sGameObjectsStore("GameObjects.db2", GameObjectsFormat, HOTFIX_SEL_GAMEOBJECTS); +DB2Storage<GarrAbilityEntry> sGarrAbilityStore("GarrAbility.db2", GarrAbilityFormat, HOTFIX_SEL_GARR_ABILITY); +DB2Storage<GarrBuildingEntry> sGarrBuildingStore("GarrBuilding.db2", GarrBuildingFormat, HOTFIX_SEL_GARR_BUILDING); +DB2Storage<GarrBuildingPlotInstEntry> sGarrBuildingPlotInstStore("GarrBuildingPlotInst.db2", GarrBuildingPlotInstFormat, HOTFIX_SEL_GARR_BUILDING_PLOT_INST); +DB2Storage<GarrClassSpecEntry> sGarrClassSpecStore("GarrClassSpec.db2", GarrClassSpecFormat, HOTFIX_SEL_GARR_CLASS_SPEC); +DB2Storage<GarrFollowerEntry> sGarrFollowerStore("GarrFollower.db2", GarrFollowerFormat, HOTFIX_SEL_GARR_FOLLOWER); +DB2Storage<GarrFollowerXAbilityEntry> sGarrFollowerXAbilityStore("GarrFollowerXAbility.db2", GarrFollowerXAbilityFormat, HOTFIX_SEL_GARR_FOLLOWER_X_ABILITY); +DB2Storage<GarrPlotBuildingEntry> sGarrPlotBuildingStore("GarrPlotBuilding.db2", GarrPlotBuildingFormat, HOTFIX_SEL_GARR_PLOT_BUILDING); +DB2Storage<GarrPlotEntry> sGarrPlotStore("GarrPlot.db2", GarrPlotFormat, HOTFIX_SEL_GARR_PLOT); +DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore("GarrPlotInstance.db2", GarrPlotInstanceFormat, HOTFIX_SEL_GARR_PLOT_INSTANCE); +DB2Storage<GarrSiteLevelEntry> sGarrSiteLevelStore("GarrSiteLevel.db2", GarrSiteLevelFormat, HOTFIX_SEL_GARR_SITE_LEVEL); +DB2Storage<GarrSiteLevelPlotInstEntry> sGarrSiteLevelPlotInstStore("GarrSiteLevelPlotInst.db2", GarrSiteLevelPlotInstFormat, HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST); DB2Storage<HolidaysEntry> sHolidaysStore("Holidays.db2", HolidaysEntryFormat, HOTFIX_SEL_HOLIDAYS); DB2Storage<ItemAppearanceEntry> sItemAppearanceStore("ItemAppearance.db2", ItemAppearanceFormat, HOTFIX_SEL_ITEM_APPEARANCE); DB2Storage<ItemBonusEntry> sItemBonusStore("ItemBonus.db2", ItemBonusFormat, HOTFIX_SEL_ITEM_BONUS); @@ -50,8 +62,8 @@ DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore("Spel DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore("SpellClassOptions.db2", SpellClassOptionsFormat, HOTFIX_SEL_SPELL_CLASS_OPTIONS); DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore("SpellLearnSpell.db2", SpellLearnSpellFormat, HOTFIX_SEL_SPELL_LEARN_SPELL); DB2Storage<SpellMiscEntry> sSpellMiscStore("SpellMisc.db2", SpellMiscFormat, HOTFIX_SEL_SPELL_MISC); -DB2Storage<SpellPowerEntry> sSpellPowerStore("SpellPower.db2", SpellPowerFormat, HOTFIX_SEL_SPELL_POWER); DB2Storage<SpellPowerDifficultyEntry> sSpellPowerDifficultyStore("SpellPowerDifficulty.db2", SpellPowerDifficultyFormat, HOTFIX_SEL_SPELL_POWER_DIFFICULTY); +DB2Storage<SpellPowerEntry> sSpellPowerStore("SpellPower.db2", SpellPowerFormat, HOTFIX_SEL_SPELL_POWER); DB2Storage<SpellReagentsEntry> sSpellReagentsStore("SpellReagents.db2", SpellReagentsFormat, HOTFIX_SEL_SPELL_REAGENTS); DB2Storage<SpellRuneCostEntry> sSpellRuneCostStore("SpellRuneCost.db2", SpellRuneCostFormat, HOTFIX_SEL_SPELL_RUNE_COST); DB2Storage<SpellTotemsEntry> sSpellTotemsStore("SpellTotems.db2", SpellTotemsFormat, HOTFIX_SEL_SPELL_TOTEMS); @@ -125,41 +137,57 @@ void DB2Manager::LoadStores(std::string const& dataPath) DB2StoreProblemList bad_db2_files; uint32 availableDb2Locales = 0xFF; - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sAreaGroupStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sAreaGroupMemberStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sBroadcastTextStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sCurrencyTypesStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sCurvePointStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sHolidaysStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemAppearanceStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemBonusStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemBonusTreeNodeStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemCurrencyCostStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemEffectStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemExtendedCostStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemModifiedAppearanceStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemSparseStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sItemXBonusTreeStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sKeyChainStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sMountStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sOverrideSpellDataStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sPhaseXPhaseGroupStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sQuestPackageItemStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSoundEntriesStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellAuraRestrictionsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellCastingRequirementsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellClassOptionsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellLearnSpellStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellMiscStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellPowerStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellPowerDifficultyStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellReagentsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellRuneCostStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sSpellTotemsStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sTaxiNodesStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sTaxiPathNodeStore, db2Path); - LoadDB2(availableDb2Locales, bad_db2_files, _stores, &sTaxiPathStore, db2Path); +#define LOAD_DB2(store) LoadDB2(availableDb2Locales, bad_db2_files, _stores, &store, db2Path) + + LOAD_DB2(sAreaGroupMemberStore); + LOAD_DB2(sAreaGroupStore); + LOAD_DB2(sBroadcastTextStore); + LOAD_DB2(sCurrencyTypesStore); + LOAD_DB2(sCurvePointStore); + LOAD_DB2(sGameObjectsStore); + LOAD_DB2(sGarrAbilityStore); + LOAD_DB2(sGarrBuildingStore); + LOAD_DB2(sGarrBuildingPlotInstStore); + LOAD_DB2(sGarrClassSpecStore); + LOAD_DB2(sGarrFollowerStore); + LOAD_DB2(sGarrFollowerXAbilityStore); + LOAD_DB2(sGarrPlotBuildingStore); + LOAD_DB2(sGarrPlotInstanceStore); + LOAD_DB2(sGarrPlotStore); + LOAD_DB2(sGarrSiteLevelPlotInstStore); + LOAD_DB2(sGarrSiteLevelStore); + LOAD_DB2(sHolidaysStore); + LOAD_DB2(sItemAppearanceStore); + LOAD_DB2(sItemBonusStore); + LOAD_DB2(sItemBonusTreeNodeStore); + LOAD_DB2(sItemCurrencyCostStore); + LOAD_DB2(sItemEffectStore); + LOAD_DB2(sItemExtendedCostStore); + LOAD_DB2(sItemModifiedAppearanceStore); + LOAD_DB2(sItemSparseStore); + LOAD_DB2(sItemStore); + LOAD_DB2(sItemXBonusTreeStore); + LOAD_DB2(sKeyChainStore); + LOAD_DB2(sMountStore); + LOAD_DB2(sOverrideSpellDataStore); + LOAD_DB2(sPhaseXPhaseGroupStore); + LOAD_DB2(sQuestPackageItemStore); + LOAD_DB2(sSoundEntriesStore); + LOAD_DB2(sSpellAuraRestrictionsStore); + LOAD_DB2(sSpellCastingRequirementsStore); + LOAD_DB2(sSpellClassOptionsStore); + LOAD_DB2(sSpellLearnSpellStore); + LOAD_DB2(sSpellMiscStore); + LOAD_DB2(sSpellPowerDifficultyStore); + LOAD_DB2(sSpellPowerStore); + LOAD_DB2(sSpellReagentsStore); + LOAD_DB2(sSpellRuneCostStore); + LOAD_DB2(sSpellTotemsStore); + LOAD_DB2(sTaxiNodesStore); + LOAD_DB2(sTaxiPathNodeStore); + LOAD_DB2(sTaxiPathStore); + +#undef LOAD_DB2 for (AreaGroupMemberEntry const* areaGroupMember : sAreaGroupMemberStore) _areaGroupMembers[areaGroupMember->AreaGroupID].push_back(areaGroupMember->AreaID); @@ -493,6 +521,11 @@ MountEntry const* DB2Manager::GetMount(uint32 spellId) const return nullptr; } +MountEntry const* DB2Manager::GetMountById(uint32 id) const +{ + return sMountStore.LookupEntry(id); +} + std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItems(uint32 questPackageID) const { auto itr = _questPackages.find(questPackageID); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index ece71c7413e..a79b3d1c1fa 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -23,8 +23,20 @@ #include "SharedDefines.h" extern DB2Storage<BroadcastTextEntry> sBroadcastTextStore; -extern DB2Storage<HolidaysEntry> sHolidaysStore; extern DB2Storage<CurrencyTypesEntry> sCurrencyTypesStore; +extern DB2Storage<GameObjectsEntry> sGameObjectsStore; +extern DB2Storage<GarrAbilityEntry> sGarrAbilityStore; +extern DB2Storage<GarrBuildingEntry> sGarrBuildingStore; +extern DB2Storage<GarrBuildingPlotInstEntry> sGarrBuildingPlotInstStore; +extern DB2Storage<GarrClassSpecEntry> sGarrClassSpecStore; +extern DB2Storage<GarrFollowerEntry> sGarrFollowerStore; +extern DB2Storage<GarrFollowerXAbilityEntry> sGarrFollowerXAbilityStore; +extern DB2Storage<GarrPlotBuildingEntry> sGarrPlotBuildingStore; +extern DB2Storage<GarrPlotEntry> sGarrPlotStore; +extern DB2Storage<GarrPlotInstanceEntry> sGarrPlotInstanceStore; +extern DB2Storage<GarrSiteLevelEntry> sGarrSiteLevelStore; +extern DB2Storage<GarrSiteLevelPlotInstEntry> sGarrSiteLevelPlotInstStore; +extern DB2Storage<HolidaysEntry> sHolidaysStore; extern DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore; extern DB2Storage<ItemEffectEntry> sItemEffectStore; extern DB2Storage<ItemEntry> sItemStore; @@ -98,6 +110,7 @@ public: std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const; uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const; MountEntry const* GetMount(uint32 spellId) const; + MountEntry const* GetMountById(uint32 id) const; std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const; std::set<uint32> GetPhasesForGroup(uint32 group) const; std::vector<SpellPowerEntry const*> GetSpellPowers(uint32 spellId, Difficulty difficulty = DIFFICULTY_NONE, bool* hasDifficultyPowers = nullptr) const; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 912ae5d60d5..80c79a94b96 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -81,6 +81,166 @@ struct CurvePointEntry float Y; // 4 }; +struct GameObjectsEntry +{ + uint32 ID; // 0 + uint32 MapID; // 1 + uint32 DisplayID; // 2 + DBCPosition3D Position; // 3-5 + float RotationX; // 6 + float RotationY; // 7 + float RotationZ; // 8 + float RotationW; // 9 + float Size; // 10 + uint32 PhaseUseFlags; // 11 + uint32 PhaseID; // 12 + uint32 PhaseGroupID; // 13 + uint32 Type; // 14 + uint32 Data[8]; // 15-22 + LocalizedString* Name; // 23 +}; + +struct GarrAbilityEntry +{ + uint32 ID; // 0 + uint32 Flags; // 1 + LocalizedString* Name; // 2 + LocalizedString* Description; // 3 + uint32 IconFileDataID; // 4 + uint32 OtherFactionGarrAbilityID; // 5 + uint32 GarrAbilityCategoryID; // 6 +}; + +struct GarrBuildingEntry +{ + uint32 ID; // 0 + uint32 HordeGameObjectID; // 1 + uint32 AllianceGameObjectID; // 2 + uint32 Unknown; // 3 + uint32 Type; // 4 + uint32 Level; // 5 + LocalizedString* NameAlliance; // 6 + LocalizedString* NameHorde; // 7 + LocalizedString* Description; // 8 + LocalizedString* Tooltip; // 9 + uint32 BuildDuration; // 10 + uint32 CostCurrencyID; // 11 + int32 CostCurrencyAmount; // 12 + uint32 HordeTexPrefixKitID; // 13 + uint32 AllianceTexPrefixKitID; // 14 + uint32 IconFileDataID; // 15 + uint32 BonusAmount; // 16 + uint32 Flags; // 17 + uint32 AllianceActivationScenePackageID; // 18 + uint32 HordeActivationScenePackageID; // 19 + uint32 MaxShipments; // 20 + uint32 FollowerRequiredGarrAbilityID; // 21 + uint32 FollowerGarrAbilityEffectID; // 22 + int32 CostMoney; // 23 +}; + +struct GarrBuildingPlotInstEntry +{ + uint32 ID; // 0 + uint32 GarrBuildingID; // 1 + uint32 UiTextureAtlasMemberID; // 2 + uint32 GarrSiteLevelPlotInstID; // 3 + DBCPosition2D LandmarkOffset; // 4-5 +}; + +struct GarrClassSpecEntry +{ + uint32 ID; // 0 + LocalizedString* NameMale; // 1 + LocalizedString* NameFemale; // 2 + LocalizedString* NameGenderless; // 3 + uint32 ClassAtlasID; // 4 UiTextureAtlasMember.db2 ref + uint32 GarrFollItemSetID; // 5 +}; + +struct GarrFollowerEntry +{ + uint32 ID; // 0 + uint32 HordeCreatureID; // 1 + uint32 AllianceCreatureID; // 2 + uint32 HordeUiAnimRaceInfoID; // 3 + uint32 AllianceUiAnimRaceInfoID; // 4 + uint32 Quality; // 5 + uint32 HordeGarrClassSpecID; // 6 + uint32 AllianceGarrClassSpecID; // 7 + uint32 HordeGarrFollItemSetID; // 8 + uint32 AllianceGarrFollItemSetID; // 9 + uint32 Level; // 10 + uint32 ItemLevelWeapon; // 11 + uint32 ItemLevelArmor; // 12 + uint32 Unknown1; // 13 + uint32 Flags; // 14 + LocalizedString* HordeSourceText; // 15 + LocalizedString* AllianceSourceText; // 16 + int32 Unknown2; // 17 + int32 Unknown3; // 18 + uint32 HordePortraitIconID; // 19 + uint32 AlliancePortraitIconID; // 20 +}; + +struct GarrFollowerXAbilityEntry +{ + uint32 ID; // 0 + uint32 GarrFollowerID; // 1 + uint32 GarrAbilityID; // 2 + uint32 FactionIndex; // 3 +}; + +struct GarrPlotEntry +{ + uint32 ID; // 0 + uint32 GarrPlotUICategoryID; // 1 + uint32 PlotType; // 2 + uint32 Flags; // 3 + LocalizedString* Name; // 4 + uint32 MinCount; // 5 + uint32 MaxCount; // 6 + uint32 AllianceConstructionGameObjectID; // 7 + uint32 HordeConstructionGameObjectID; // 8 +}; + +struct GarrPlotBuildingEntry +{ + uint32 ID; // 0 + uint32 GarrPlotID; // 1 + uint32 GarrBuildingID; // 2 +}; + +struct GarrPlotInstanceEntry +{ + uint32 ID; // 0 + uint32 GarrPlotID; // 1 + LocalizedString* Name; // 2 +}; + +struct GarrSiteLevelEntry +{ + uint32 ID; // 0 + uint32 Level; // 1 + uint32 MapID; // 2 + uint32 SiteID; // 3 + uint32 UITextureKitID; // 4 + DBCPosition2D TownHall; // 5-6 + uint32 MovieID; // 7 + uint32 Level2; // 8 + uint32 UpgradeResourceCost; // 9 + uint32 UpgradeMoneyCost; // 10 +}; + +struct GarrSiteLevelPlotInstEntry +{ + uint32 ID; // 0 + uint32 GarrSiteLevelID; // 1 + uint32 GarrPlotInstanceID; // 2 + DBCPosition2D Landmark; // 3-4 + uint32 Unknown; // 5 +}; + struct HolidaysEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index f59c7b56f56..7c915b37326 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -23,6 +23,18 @@ char const AreaGroupMemberFormat[] = "nii"; char const BroadcastTextFormat[] = "nissiiiiiiiii"; char const CurrencyTypesFormat[] = "nisssiiiiiis"; char const CurvePointFormat[] = "niiff"; +char const GameObjectsFormat[] = "niiffffffffiiiiiiiiiiiis"; +char const GarrAbilityFormat[] = "nissiii"; +char const GarrBuildingFormat[] = "niiiiissssiiiiiiiiiiiiii"; +char const GarrBuildingPlotInstFormat[] = "niiiff"; +char const GarrClassSpecFormat[] = "nsssii"; +char const GarrFollowerFormat[] = "niiiiiiiiiiiiiissiiii"; +char const GarrFollowerXAbilityFormat[] = "niii"; +char const GarrPlotBuildingFormat[] = "nii"; +char const GarrPlotFormat[] = "niiisiiii"; +char const GarrPlotInstanceFormat[] = "nis"; +char const GarrSiteLevelFormat[] = "niiiiffiiii"; +char const GarrSiteLevelPlotInstFormat[] = "niiffi"; char const HolidaysEntryFormat[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiisiii"; char const ItemFormat[] = "niiiiiiii"; char const ItemAppearanceFormat[] = "nii"; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index cc310fbdeb5..719e539a9c4 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -21,6 +21,8 @@ #include "Define.h" +#pragma pack(push, 1) + struct DBCPosition2D { float X; @@ -34,6 +36,8 @@ struct DBCPosition3D float Z; }; +#pragma pack(pop) + enum LevelLimit { // Client expected level limitation, like as used in DBC item max levels for "until max player level" @@ -155,6 +159,12 @@ enum AchievementCriteriaAdditionalCondition ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY = 145, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL = 146, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_RARE_MISSION = 147, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_BUILDING_LEVEL = 149, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_MISSION_TYPE = 167, // NYI + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_ILVL = 184, }; enum AchievementCriteriaFlags @@ -184,121 +194,169 @@ enum AchievementCriteriaTimedTypes enum AchievementCriteriaTypes { - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0, - ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS = 3, // struct { uint32 itemCount; } - ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5, - ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10, // you have to complete a daily quest x times in a row - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11, - ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12, - ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15, - ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16, - ACHIEVEMENT_CRITERIA_TYPE_DEATH = 17, - ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19, - ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20, - ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER = 23, - ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24, - ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27, - ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29, - ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31, - ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32, - ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL = 35, - ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36, - ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40, - ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42, - ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43, - ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44, - ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, - ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, - ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc - ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, - ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52, - ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53, - ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54, - ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55, - ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die - ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57, - ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, - ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61, - ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67, - ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68, - ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, - ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, - ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, + ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0, + ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS = 3, // struct { uint32 itemCount; } + ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5, + ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY = 10, // you have to complete a daily quest x times in a row + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE = 11, + ACHIEVEMENT_CRITERIA_TYPE_CURRENCY = 12, + ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15, + ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16, + ACHIEVEMENT_CRITERIA_TYPE_DEATH = 17, + ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19, + ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20, + ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER = 23, + ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24, + ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27, + ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28, + ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29, + ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE = 30, + ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31, + ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32, + ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33, + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34, + ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL = 35, + ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36, + ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING = 39, + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40, + ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42, + ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43, + ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44, + ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, + ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, + ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, + ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc + ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, + ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52, + ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53, + ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54, + ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55, + ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die + ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57, + ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, + ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS = 61, + ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD = 62, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING = 63, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER = 65, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL = 66, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67, + ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68, + ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, + ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, + ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, /// @todo 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) - ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN = 74, - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, - ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, - ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE = 78, - ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS = 80, - ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION = 82, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID = 83, - ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS = 84, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87, - ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88, - ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS = 89, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM = 90, - ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, - ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST = 104, - ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105, - ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106, - ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107, - ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, - ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing - ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112, - ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, - ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114, - ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS = 115, - ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS = 119, - ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS = 124, - ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125, - ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD = 126, - ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL = 127, - ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS = 128, - ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS = 129, - ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND = 130, - ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING = 132, - ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD = 133, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD = 134, - ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD = 135, - ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD = 136, - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE = 138, //struct { Flag flag; uint32 count; } 1: Guild Dungeon, 2:Guild Challenge, 3:Guild battlefield - ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139 //struct { uint32 count; } Guild Challenge -}; - -#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 188 + ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN = 74, + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, + ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, + ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, + ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE = 78, + ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS = 80, + ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION = 82, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID = 83, + ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS = 84, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD = 85, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED = 86, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION = 87, + ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION = 88, + ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS = 89, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM = 90, + ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM = 91, + ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED = 93, + ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED = 94, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT = 101, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED = 102, + ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED = 103, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST = 104, + ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED = 105, + ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED = 106, + ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107, + ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, + ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109, + ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing + ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112, + ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, + ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114, + ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS = 115, + ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS = 119, + ACHIEVEMENT_CRITERIA_TYPE_SPENT_GOLD_GUILD_REPAIRS = 124, + ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125, + ACHIEVEMENT_CRITERIA_TYPE_CRAFT_ITEMS_GUILD = 126, + ACHIEVEMENT_CRITERIA_TYPE_CATCH_FROM_POOL = 127, + ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_BANK_SLOTS = 128, + ACHIEVEMENT_CRITERIA_TYPE_EARN_GUILD_ACHIEVEMENT_POINTS = 129, + ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_BATTLEGROUND = 130, + ACHIEVEMENT_CRITERIA_TYPE_REACH_BG_RATING = 132, + ACHIEVEMENT_CRITERIA_TYPE_BUY_GUILD_TABARD = 133, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD = 134, + ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD = 135, + ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD = 136, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE = 138, //struct { Flag flag; uint32 count; } 1: Guild Dungeon, 2:Guild Challenge, 3:Guild battlefield + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE = 139, //struct { uint32 count; } Guild Challenge + // 140 unk + // 141 unk + // 142 unk + // 143 unk + // 144 unk + ACHIEVEMENT_CRITERIA_TYPE_LFR_DUNGEONS_COMPLETED = 145, + ACHIEVEMENT_CRITERIA_TYPE_LFR_LEAVES = 146, + ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_INITIATED_BY_PLAYER = 147, + ACHIEVEMENT_CRITERIA_TYPE_LFR_VOTE_KICKS_NOT_INIT_BY_PLAYER = 148, + ACHIEVEMENT_CRITERIA_TYPE_BE_KICKED_FROM_LFR = 149, + ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK = 150, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT = 151, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO = 152, + // ACHIEVEMENT_CRITERIA_TYPE_REACH_SOMETHING_LIKE_AREATRIGGER = 153, + // 154 + ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET = 155, + ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT = 156, + ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET = 157, + ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE = 158, + // 159 + ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET = 160, + ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET_CREDIT = 161, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET_CREDIT = 162, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA = 163, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA = 164, // triggers a quest credit + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165, + ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING = 167, + ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON_BUILDING = 168, + ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169, + ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON = 170, + ACHIEVEMENT_CRITERIA_TYPE_START_GARRISON_MISSION = 171, + // 172 + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION_COUNT = 173, + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174, + ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER_COUNT = 175, + // 176 + // 177 + ACHIEVEMENT_CRITERIA_TYPE_LEARN_GARRISON_BLUEPRINT_COUNT = 178, + // 179 + // 180 + // 181 + ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182, + ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_ITEM_LEVEL = 183, + ACHIEVEMENT_CRITERIA_TYPE_RAISE_GARRISON_FOLLOWER_LEVEL = 184, + ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY = 185, + ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY_COUNT = 186, + ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER = 187, + ACHIEVEMENT_CRITERIA_TYPE_OWN_HEIRLOOMS = 189 +}; + +#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL 190 enum AchievementCriteriaTreeOperator { @@ -427,6 +485,7 @@ enum MapFlags MAP_FLAG_CAN_TOGGLE_DIFFICULTY = 0x0100, MAP_FLAG_FLEX_LOCKING = 0x8000, // All difficulties share completed encounters lock, not bound to a single instance id // heroic difficulty flag overrides it and uses instance id bind + MAP_FLAG_GARRISON = 0x4000000 }; enum AbilytyLearnType diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index e1f0c595b5f..fcc6a23ddf3 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -60,6 +60,7 @@ static AreaFlagByMapID sAreaFlagByMapID; // for instances wit static WMOAreaInfoByTripple sWMOAreaInfoByTripple; DBCStorage <AchievementEntry> sAchievementStore(Achievementfmt); +DBCStorage <AnimKitEntry> sAnimKitStore(AnimKitfmt); DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt); DBCStorage <ArmorLocationEntry> sArmorLocationStore(ArmorLocationfmt); DBCStorage <AuctionHouseEntry> sAuctionHouseStore(AuctionHouseEntryfmt); @@ -131,6 +132,9 @@ GameTable <GtSpellScalingEntry> sGtSpellScalingStore(GtSpellScalingfmt) GameTable <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore(GtOCTBaseHPByClassfmt); GameTable <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore(GtOCTBaseMPByClassfmt); DBCStorage <GuildPerkSpellsEntry> sGuildPerkSpellsStore(GuildPerkSpellsfmt); +DBCStorage <GuildColorBackgroundEntry> sGuildColorBackgroundStore(GuildColorBackgroundfmt); +DBCStorage <GuildColorBorderEntry> sGuildColorBorderStore(GuildColorBorderfmt); +DBCStorage <GuildColorEmblemEntry> sGuildColorEmblemStore(GuildColorEmblemfmt); DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore(ImportPriceArmorfmt); DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore(ImportPriceQualityfmt); @@ -369,6 +373,7 @@ void LoadDBCStores(const std::string& dataPath) } LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc"/*, &CustomAchievementfmt, &CustomAchievementIndex*/);//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sAnimKitStore, dbcPath, "AnimKit.dbc");//19865 LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTriggerStore, dbcPath, "AreaTrigger.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sAuctionHouseStore, dbcPath, "AuctionHouse.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sArmorLocationStore, dbcPath, "ArmorLocation.dbc");//19116 @@ -462,6 +467,9 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphPropertiesStore, dbcPath, "GlyphProperties.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sGlyphSlotStore, dbcPath, "GlyphSlot.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sGuildPerkSpellsStore, dbcPath, "GuildPerkSpells.dbc");//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sGuildColorBackgroundStore, dbcPath, "GuildColorBackground.dbc");//19865 + LoadDBC(availableDbcLocales, bad_dbc_files, sGuildColorBorderStore, dbcPath, "GuildColorBorder.dbc"); //19865 + LoadDBC(availableDbcLocales, bad_dbc_files, sGuildColorEmblemStore, dbcPath, "GuildColorEmblem.dbc");//19865 LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceArmorStore, dbcPath, "ImportPriceArmor.dbc"); // 19116 LoadDBC(availableDbcLocales, bad_dbc_files, sImportPriceQualityStore, dbcPath, "ImportPriceQuality.dbc"); // 19116 @@ -881,9 +889,9 @@ void Map2ZoneCoordinates(float& x, float& y, uint32 zone) std::swap(x, y); // client have map coords swapped } -MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID) +MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapId, Difficulty* difficulty /*= nullptr*/) { - auto itr = sMapDifficultyMap.find(mapID); + auto itr = sMapDifficultyMap.find(mapId); if (itr == sMapDifficultyMap.end()) return nullptr; @@ -892,14 +900,22 @@ MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID) for (auto& p : itr->second) { - DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(p.first); - if (!difficulty) + DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(p.first); + if (!difficultyEntry) continue; - if (difficulty->Flags & DIFFICULTY_FLAG_DEFAULT) + if (difficultyEntry->Flags & DIFFICULTY_FLAG_DEFAULT) + { + if (difficulty) + *difficulty = Difficulty(p.first); + return p.second; + } } + if (difficulty) + *difficulty = Difficulty(itr->second.begin()->first); + return itr->second.begin()->second; } @@ -920,7 +936,7 @@ MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficult { DifficultyEntry const* diffEntry = sDifficultyStore.LookupEntry(difficulty); if (!diffEntry) - return GetDefaultMapDifficulty(mapId); + return GetDefaultMapDifficulty(mapId, &difficulty); uint32 tmpDiff = difficulty; MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); @@ -929,7 +945,7 @@ MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficult tmpDiff = diffEntry->FallbackDifficultyID; diffEntry = sDifficultyStore.LookupEntry(tmpDiff); if (!diffEntry) - return GetDefaultMapDifficulty(mapId); + return GetDefaultMapDifficulty(mapId, &difficulty); // pull new data mapDiff = GetMapDifficultyData(mapId, Difficulty(tmpDiff)); // we are 10 normal or 25 normal diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 72c0c35f1cb..03eda581f28 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -66,7 +66,7 @@ void Zone2MapCoordinates(float &x, float &y, uint32 zone); void Map2ZoneCoordinates(float &x, float &y, uint32 zone); typedef std::unordered_map<uint32, std::unordered_map<uint32, MapDifficultyEntry const*>> MapDifficultyMap; -MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapID); +MapDifficultyEntry const* GetDefaultMapDifficulty(uint32 mapId, Difficulty* difficulty = nullptr); MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); MapDifficultyEntry const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty); @@ -123,6 +123,7 @@ private: }; extern DBCStorage <AchievementEntry> sAchievementStore; +extern DBCStorage <AnimKitEntry> sAnimKitStore; extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore; extern DBCStorage <ArmorLocationEntry> sArmorLocationStore; @@ -184,6 +185,9 @@ extern GameTable <GtSpellScalingEntry> sGtSpellScalingStore; extern GameTable <GtOCTBaseHPByClassEntry> sGtOCTBaseHPByClassStore; extern GameTable <GtOCTBaseMPByClassEntry> sGtOCTBaseMPByClassStore; extern DBCStorage <GuildPerkSpellsEntry> sGuildPerkSpellsStore; +extern DBCStorage <GuildColorBackgroundEntry> sGuildColorBackgroundStore; +extern DBCStorage <GuildColorBorderEntry> sGuildColorBorderStore; +extern DBCStorage <GuildColorEmblemEntry> sGuildColorEmblemStore; extern DBCStorage <ImportPriceArmorEntry> sImportPriceArmorStore; extern DBCStorage <ImportPriceQualityEntry> sImportPriceQualityStore; extern DBCStorage <ImportPriceShieldEntry> sImportPriceShieldStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 178ab097d81..aac3cbd2193 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -50,12 +50,12 @@ struct AchievementEntry uint32 CriteriaTree; // 14 }; -struct AchievementCategoryEntry +struct AnimKitEntry { uint32 ID; // 0 - uint32 Parent; // 1 -1 for main category - //char* Name_lang; // 2 - //uint32 UIOrder; // 3 + //uint32 OneShotDuration; // 1 + //uint32 OneShotStopAnimKitID; // 2 + //uint32 LowDefAnimKitID; // 3 }; // Temporary define until max depth is found somewhere (adt?) @@ -72,10 +72,10 @@ struct AreaTableEntry //uint32 SoundProviderPrefUnderwater; // 7, //uint32 AmbienceID; // 8, //uint32 ZoneMusic; // 9, - char* ZoneName; // 10 + //char* ZoneName; // 10 - Internal name //uint32 IntroSound; // 11 uint32 ExplorationLevel; // 12 - //char* AreaName_lang // 13 + char* AreaName_lang; // 13 - In-game name uint32 FactionGroupMask; // 14 uint32 LiquidTypeID[4]; // 15-18 //float AmbientMultiplier; // 19 @@ -494,12 +494,15 @@ struct CriteriaEntry uint32 ObjectiveId; // ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA = 31 + // ACHIEVEMENT_CRITERIA_TYPE_ENTER_AREA = 163 + // ACHIEVEMENT_CRITERIA_TYPE_LEAVE_AREA = 164 uint32 AreaID; // ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36 // ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41 // ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42 // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57 + // ACHIEVEMENT_CRITERIA_TYPE_OWN_TOY = 185 uint32 ItemID; // ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38 @@ -544,6 +547,21 @@ struct CriteriaEntry // ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109 uint32 LootType; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DUNGEON_ENCOUNTER = 165 + uint32 DungeonEncounterID; + + // ACHIEVEMENT_CRITERIA_TYPE_CONSTRUCT_GARRISON_BUILDING = 169 + uint32 GarrBuildingID; + + // ACHIEVEMENT_CRITERIA_TYPE_UPGRADE_GARRISON = 170 + uint32 GarrisonLevel; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_MISSION = 174 + uint32 GarrMissionID; + + // ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GARRISON_SHIPMENT = 182 + uint32 CharShipmentContainerID; } Asset; // 2 uint32 StartEvent; // 3 uint32 StartAsset; // 4 @@ -935,6 +953,33 @@ struct GuildPerkSpellsEntry uint32 SpellID; // 2 }; +// GuildColorBackground.dbc +struct GuildColorBackgroundEntry +{ + uint32 ID; + //uint8 Red; + //uint8 Green; + //uint8 Blue; +}; + +// GuildColorBorder.dbc +struct GuildColorBorderEntry +{ + uint32 ID; + //uint8 Red; + //uint8 Green; + //uint8 Blue; +}; + +// GuildColorEmblem.dbc +struct GuildColorEmblemEntry +{ + uint32 ID; + //uint8 Red; + //uint8 Green; + //uint8 Blue; +}; + // ImportPriceArmor.dbc struct ImportPriceArmorEntry { @@ -1235,13 +1280,13 @@ struct MapEntry uint32 RaidOffset; // 17 uint32 MaxPlayers; // 18 int32 ParentMapID; // 19 related to phasing - //uint32 CosmeticParentMapID // 20 + int32 CosmeticParentMapID; // 20 //uint32 TimeOffset // 21 // Helpers uint32 Expansion() const { return ExpansionID; } - bool IsDungeon() const { return InstanceType == MAP_INSTANCE || InstanceType == MAP_RAID; } + bool IsDungeon() const { return (InstanceType == MAP_INSTANCE || InstanceType == MAP_RAID) && !IsGarrison(); } bool IsNonRaidDungeon() const { return InstanceType == MAP_INSTANCE; } bool Instanceable() const { return InstanceType == MAP_INSTANCE || InstanceType == MAP_RAID || InstanceType == MAP_BATTLEGROUND || InstanceType == MAP_ARENA; } bool IsRaid() const { return InstanceType == MAP_RAID; } @@ -1266,6 +1311,7 @@ struct MapEntry } bool IsDynamicDifficultyMap() const { return (Flags & MAP_FLAG_CAN_TOGGLE_DIFFICULTY) != 0; } + bool IsGarrison() const { return (Flags & MAP_FLAG_GARRISON) != 0; } }; struct MapDifficultyEntry diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 8c067dabb27..c7aa00286e1 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -25,7 +25,8 @@ char const Achievementfmt[] = "niixsxiixixxiii"; const std::string CustomAchievementfmt = "pppaaaapapaapp"; const std::string CustomAchievementIndex = "ID"; -char const AreaTableEntryfmt[] = "iiiniixxxxsxixiiiiixxxxxxxxxx"; +char const AnimKitfmt[] = "nxxx"; +char const AreaTableEntryfmt[] = "iiiniixxxxxxisiiiiixxxxxxxxxx"; char const AreaTriggerEntryfmt[] = "nifffxxxfffffxxxx"; char const ArmorLocationfmt[] = "nfffff"; char const AuctionHouseEntryfmt[] = "niiix"; @@ -87,6 +88,9 @@ char const GtSpellScalingfmt[] = "df"; char const GtOCTBaseHPByClassfmt[] = "df"; char const GtOCTBaseMPByClassfmt[] = "df"; char const GuildPerkSpellsfmt[] = "dii"; +char const GuildColorBackgroundfmt[] = "nXXX"; +char const GuildColorBorderfmt[] = "nXXX"; +char const GuildColorEmblemfmt[] = "nXXX"; char const ImportPriceArmorfmt[] = "nffff"; char const ImportPriceQualityfmt[] = "nf"; char const ImportPriceShieldfmt[] = "nf"; @@ -113,7 +117,7 @@ char const LiquidTypefmt[] = "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx char const LockEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; char const PhaseEntryfmt[] = "ni"; char const MailTemplateEntryfmt[] = "nxs"; -char const MapEntryfmt[] = "nxiixxsixxixiffxiiiixx"; +char const MapEntryfmt[] = "nxiixxsixxixiffxiiiiix"; char const MapDifficultyEntryfmt[] = "diisiiii"; char const MinorTalentEntryfmt[] = "niii"; char const MovieEntryfmt[] = "nxxxx"; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index b077f3e6110..e786c3b9c7c 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -412,7 +412,7 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const joinData.result = LFG_JOIN_NOT_MEET_REQS; else if (grp) { - if (grp->GetMembersCount() > MAXGROUPSIZE) + if (grp->GetMembersCount() > MAX_GROUP_SIZE) joinData.result = LFG_JOIN_TOO_MUCH_MEMBERS; else { diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index 97f87a4d814..30e9a587353 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -323,7 +323,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) LfgRolesMap proposalRoles; // Check for correct size - if (check.size() > MAXGROUPSIZE || check.empty()) + if (check.size() > MAX_GROUP_SIZE || check.empty()) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s): Size wrong - Not compatibles", strGuids.c_str()); return LFG_INCOMPATIBLES_WRONG_GROUP_SIZE; @@ -349,7 +349,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) // Check if more than one LFG group and number of players joining uint8 numPlayers = 0; uint8 numLfgGroups = 0; - for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAXGROUPSIZE; ++it) + for (GuidList::const_iterator it = check.begin(); it != check.end() && numLfgGroups < 2 && numPlayers <= MAX_GROUP_SIZE; ++it) { ObjectGuid guid = *it; LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(guid); @@ -374,8 +374,8 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) } } - // Group with less that MAXGROUPSIZE members always compatible - if (check.size() == 1 && numPlayers != MAXGROUPSIZE) + // Group with less that MAX_GROUP_SIZE members always compatible + if (check.size() == 1 && numPlayers != MAX_GROUP_SIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) single group. Compatibles", strGuids.c_str()); LfgQueueDataContainer::iterator itQueue = QueueDataStore.find(check.front()); @@ -396,7 +396,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) return LFG_INCOMPATIBLES_MULTIPLE_LFG_GROUPS; } - if (numPlayers > MAXGROUPSIZE) + if (numPlayers > MAX_GROUP_SIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Too much players (%u)", strGuids.c_str(), numPlayers); SetCompatibles(strGuids, LFG_INCOMPATIBLES_TOO_MUCH_PLAYERS); @@ -473,7 +473,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(GuidList check) } // Enough players? - if (numPlayers != MAXGROUPSIZE) + if (numPlayers != MAX_GROUP_SIZE) { TC_LOG_DEBUG("lfg.queue.match.compatibility.check", "Guids: (%s) Compatibles but not enough players(%u)", strGuids.c_str(), numPlayers); LfgCompatibilityData data(LFG_COMPATIBLES_WITH_LESS_PLAYERS); diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 426d47f88d3..b1ce1f0cdbb 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -18,6 +18,7 @@ #include "Unit.h" #include "SpellInfo.h" #include "Log.h" +#include "UpdateData.h" #include "AreaTrigger.h" AreaTrigger::AreaTrigger() : WorldObject(false), _duration(0) diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 4294eb57dbd..15e560a8e7e 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -59,7 +59,7 @@ void Corpse::RemoveFromWorld() if (IsInWorld()) GetMap()->GetObjectsStore().Remove<Corpse>(GetGUID()); - Object::RemoveFromWorld(); + WorldObject::RemoveFromWorld(); } bool Corpse::Create(ObjectGuid::LowType guidlow, Map* map) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index ce7eadcae2b..70a2ab2307a 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -382,13 +382,14 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/) setFaction(cInfo->faction); - uint32 npcflag, unit_flags, dynamicflags; + uint32 unit_flags, dynamicflags; + uint64 npcflag; ObjectMgr::ChooseCreatureFlags(cInfo, npcflag, unit_flags, dynamicflags, data); if (cInfo->flags_extra & CREATURE_FLAG_EXTRA_WORLDEVENT) - SetUInt32Value(UNIT_NPC_FLAGS, npcflag | sGameEventMgr->GetNPCFlag(this)); + SetUInt64Value(UNIT_NPC_FLAGS, npcflag | sGameEventMgr->GetNPCFlag(this)); else - SetUInt32Value(UNIT_NPC_FLAGS, npcflag); + SetUInt64Value(UNIT_NPC_FLAGS, npcflag); SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags); SetUInt32Value(UNIT_FIELD_FLAGS_2, cInfo->unit_flags2); @@ -965,7 +966,7 @@ void Creature::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) CreatureData& data = sObjectMgr->NewOrExistCreatureData(m_spawnId); uint32 displayId = GetNativeDisplayId(); - uint32 npcflag = GetUInt32Value(UNIT_NPC_FLAGS); + uint64 npcflag = GetUInt64Value(UNIT_NPC_FLAGS); uint32 unit_flags = GetUInt32Value(UNIT_FIELD_FLAGS); uint32 dynamicflags = GetUInt32Value(OBJECT_DYNAMIC_FLAGS); @@ -1053,7 +1054,7 @@ void Creature::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) stmt->setUInt32(index++, GetHealth()); stmt->setUInt32(index++, GetPower(POWER_MANA)); stmt->setUInt8(index++, uint8(GetDefaultMovementType())); - stmt->setUInt32(index++, npcflag); + stmt->setUInt64(index++, npcflag); stmt->setUInt32(index++, unit_flags); stmt->setUInt32(index++, dynamicflags); trans->Append(stmt); @@ -1511,7 +1512,7 @@ void Creature::setDeathState(DeathState s) SaveRespawnTime(); SetTarget(ObjectGuid::Empty); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState) - SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + SetUInt64Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 0); // if creature is mounted on a virtual mount, remove it at death @@ -1543,7 +1544,7 @@ void Creature::setDeathState(DeathState s) UpdateMovementFlags(); CreatureTemplate const* cinfo = GetCreatureTemplate(); - SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag); + SetUInt64Value(UNIT_NPC_FLAGS, cinfo->npcflag); ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_IGNORE_PATHFINDING)); SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool)); LoadCreaturesAddon(true); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index adab2ea38bb..0e985ff3648 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -93,7 +93,7 @@ struct CreatureTemplate int32 expansion; uint32 expansionUnknown; // either 0 or 3, sent to the client / wdb uint32 faction; - uint32 npcflag; + uint64 npcflag; float speed_walk; float speed_run; float scale; @@ -304,7 +304,7 @@ struct CreatureData uint32 curmana; uint8 movementType; uint32 spawnMask; - uint32 npcflag; + uint64 npcflag; uint32 unit_flags; // enum UnitFlags mask values uint32 dynamicflags; uint32 phaseid; @@ -373,7 +373,7 @@ struct VendorItem uint8 Type; //helpers - bool IsGoldRequired(ItemTemplate const* pProto) const { return pProto->GetFlags2() & ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD || !ExtendedCost; } + bool IsGoldRequired(ItemTemplate const* pProto) const { return pProto->GetFlags2() & ITEM_FLAG2_EXT_COST_REQUIRES_GOLD || !ExtendedCost; } }; typedef std::vector<VendorItem*> VendorItemList; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index 815c98c9710..faa458d45dc 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -505,7 +505,7 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const packet.Info.SuggestedGroupNum = quest->GetSuggestedPlayers(); packet.Info.RewardNextQuest = quest->GetNextQuestInChain(); packet.Info.RewardXPDifficulty = quest->GetXPDifficulty(); - packet.Info.Float10 = quest->Float10; // Unk + packet.Info.RewardXPMultiplier = quest->GetXPMultiplier(); packet.Info.Float13 = quest->Float13; // Unk if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 852269855df..948579cd419 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -180,7 +180,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u m_stationaryPosition.Relocate(x, y, z, ang); if (!IsPositionValid()) { - TC_LOG_ERROR("misc", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, name_id, x, y); + TC_LOG_ERROR("misc", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)", guidlow, GetSpawnId(), name_id, x, y); return false; } @@ -195,13 +195,13 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(name_id); if (!goinfo) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, name_id, map->GetId(), x, y, z); + TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing entry in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f)", guidlow, GetSpawnId(), name_id, map->GetId(), x, y, z); return false; } if (goinfo->type == GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", guidlow, name_id); + TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: gameobject type GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT cannot be manually created.", guidlow, GetSpawnId(), name_id); return false; } @@ -214,7 +214,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u if (goinfo->type >= MAX_GAMEOBJECT_TYPE) { - TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, name_id, goinfo->type); + TC_LOG_ERROR("sql.sql", "Gameobject (GUID: " UI64FMTD " Spawn id: " UI64FMTD " Entry: %u) not created: non-existing GO type '%u' in `gameobject_template`. It will crash client if created.", guidlow, GetSpawnId(), name_id, goinfo->type); return false; } @@ -310,7 +310,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u break; } - if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(guidlow)) + if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(GetSpawnId())) { if (addon->InvisibilityValue) { @@ -2163,7 +2163,7 @@ void GameObject::SetTransportState(GOState state, uint32 stopFrame /*= 0*/) m_goValue.Transport.StateUpdateTimer = 0; m_goValue.Transport.PathProgress = getMSTime(); if (GetGoState() >= GO_STATE_TRANSPORT_STOPPED) - m_goValue.Transport.StopFrames->at(GetGoState() - GO_STATE_TRANSPORT_STOPPED); + m_goValue.Transport.PathProgress += m_goValue.Transport.StopFrames->at(GetGoState() - GO_STATE_TRANSPORT_STOPPED); SetGoState(GO_STATE_TRANSPORT_ACTIVE); } else @@ -2420,7 +2420,7 @@ void GameObject::UpdateModelPosition() if (GetMap()->ContainsGameObjectModel(*m_model)) { GetMap()->RemoveGameObjectModel(*m_model); - m_model->Relocate(*this); + m_model->UpdatePosition(); GetMap()->InsertGameObjectModel(*m_model); } } diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index ee429c95475..c61f1ba87c4 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -1065,6 +1065,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map float GetStationaryY() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) return m_stationaryPosition.GetPositionY(); return GetPositionY(); } float GetStationaryZ() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); } float GetStationaryO() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); } + void RelocateStationaryPosition(float x, float y, float z, float o) { m_stationaryPosition.Relocate(x, y, z, o); } float GetInteractionDistance() const; diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 50994df7831..7250c0cff23 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -361,7 +361,7 @@ void Item::SaveToDB(SQLTransaction& trans) trans->Append(stmt); - if ((uState == ITEM_CHANGED) && HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if ((uState == ITEM_CHANGED) && HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GIFT_OWNER); stmt->setUInt64(0, GetOwnerGUID().GetCounter()); @@ -376,7 +376,7 @@ void Item::SaveToDB(SQLTransaction& trans) stmt->setUInt64(0, GetGUID().GetCounter()); trans->Append(stmt); - if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); stmt->setUInt64(0, GetGUID().GetCounter()); @@ -451,7 +451,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie // Remove bind flag for items vs NO_BIND set if (IsSoulBound() && proto->GetBonding() == NO_BIND) { - ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, false); + ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, false); need_save = true; } @@ -760,7 +760,7 @@ bool Item::CanBeTraded(bool mail, bool trade) const if (m_lootGenerated) return false; - if ((!mail || !IsBoundAccountWide()) && (IsSoulBound() && (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE) || !trade))) + if ((!mail || !IsBoundAccountWide()) && (IsSoulBound() && (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE) || !trade))) return false; if (IsBag() && (Player::IsBagPos(GetPos()) || !((Bag const*)this)->IsEmpty())) @@ -1071,7 +1071,7 @@ Item* Item::CloneItem(uint32 count, Player const* player) const newItem->SetGuidValue(ITEM_FIELD_CREATOR, GetGuidValue(ITEM_FIELD_CREATOR)); newItem->SetGuidValue(ITEM_FIELD_GIFTCREATOR, GetGuidValue(ITEM_FIELD_GIFTCREATOR)); - newItem->SetUInt32Value(ITEM_FIELD_FLAGS, GetUInt32Value(ITEM_FIELD_FLAGS) & ~(ITEM_FLAG_REFUNDABLE | ITEM_FLAG_BOP_TRADEABLE)); + newItem->SetUInt32Value(ITEM_FIELD_FLAGS, GetUInt32Value(ITEM_FIELD_FLAGS) & ~(ITEM_FIELD_FLAG_REFUNDABLE | ITEM_FIELD_FLAG_BOP_TRADEABLE)); newItem->SetUInt32Value(ITEM_FIELD_DURATION, GetUInt32Value(ITEM_FIELD_DURATION)); // player CAN be NULL in which case we must not update random properties because that accesses player's item update queue if (player) @@ -1089,7 +1089,7 @@ bool Item::IsBindedNotWith(Player const* player) const if (GetOwnerGUID() == player->GetGUID()) return false; - if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE)) if (allowedGUIDs.find(player->GetGUID()) != allowedGUIDs.end()) return false; @@ -1211,10 +1211,10 @@ void Item::DeleteRefundDataFromDB(SQLTransaction* trans) void Item::SetNotRefundable(Player* owner, bool changestate /*=true*/, SQLTransaction* trans /*=NULL*/) { - if (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) + if (!HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) return; - RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE); + RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE); // Following is not applicable in the trading procedure if (changestate) SetState(ITEM_CHANGED, owner); @@ -1269,13 +1269,13 @@ bool Item::IsRefundExpired() void Item::SetSoulboundTradeable(GuidSet const& allowedLooters) { - SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE); + SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE); allowedGUIDs = allowedLooters; } void Item::ClearSoulboundTradeable(Player* currentOwner) { - RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE); + RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE); if (allowedGUIDs.empty()) return; @@ -1315,7 +1315,7 @@ bool Item::CanBeTransmogrified() const if (proto->GetClass() == ITEM_CLASS_WEAPON && proto->GetSubClass() == ITEM_SUBCLASS_WEAPON_FISHING_POLE) return false; - if (proto->GetFlags2() & ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG) + if (proto->GetFlags2() & ITEM_FLAG2_CANNOT_BE_TRANSMOG) return false; if (!HasStats()) @@ -1331,7 +1331,7 @@ bool Item::CanTransmogrify() const if (!proto) return false; - if (proto->GetFlags2() & ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG) + if (proto->GetFlags2() & ITEM_FLAG2_CANNOT_TRANSMOG) return false; if (proto->GetQuality() == ITEM_QUALITY_LEGENDARY) @@ -1344,7 +1344,7 @@ bool Item::CanTransmogrify() const if (proto->GetClass() == ITEM_CLASS_WEAPON && proto->GetSubClass() == ITEM_SUBCLASS_WEAPON_FISHING_POLE) return false; - if (proto->GetFlags2() & ITEM_FLAGS_EXTRA_CAN_TRANSMOG) + if (proto->GetFlags2() & ITEM_FLAG2_CAN_TRANSMOG) return true; if (!HasStats()) @@ -1405,7 +1405,7 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, bool& normalSellPrice) { normalSellPrice = true; - if (proto->GetFlags2() & ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE) + if (proto->GetFlags2() & ITEM_FLAG2_HAS_NORMAL_PRICE) { return proto->GetBuyPrice(); } @@ -1524,7 +1524,7 @@ uint32 Item::GetSpecialPrice(ItemTemplate const* proto, uint32 minimumPrice /*= { uint32 cost = 0; - if (proto->GetFlags2() & ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE) + if (proto->GetFlags2() & ITEM_FLAG2_HAS_NORMAL_PRICE) cost = proto->GetSellPrice(); else { diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index c204cbb1f17..7d03a0a68eb 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -261,10 +261,10 @@ class Item : public Object void SetOwnerGUID(ObjectGuid guid) { SetGuidValue(ITEM_FIELD_OWNER, guid); } Player* GetOwner()const; - void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND, val); } - bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_SOULBOUND); } - bool IsBoundAccountWide() const { return (GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT) != 0; } - bool IsBattlenetAccountBound() const { return (GetTemplate()->GetFlags2() & ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND) != 0; } + void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, val); } + bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND); } + bool IsBoundAccountWide() const { return (GetTemplate()->GetFlags() & ITEM_FLAG_BIND_TO_ACCOUNT) != 0; } + bool IsBattlenetAccountBound() const { return (GetTemplate()->GetFlags2() & ITEM_FLAG2_BNET_ACCOUNT_BOUND) != 0; } bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; virtual void SaveToDB(SQLTransaction& trans); @@ -291,7 +291,7 @@ class Item : public Object Bag* ToBag() { if (IsBag()) return reinterpret_cast<Bag*>(this); else return NULL; } const Bag* ToBag() const { if (IsBag()) return reinterpret_cast<const Bag*>(this); else return NULL; } - bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED); } + bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); } bool IsBag() const { return GetTemplate()->GetInventoryType() == INVTYPE_BAG; } bool IsCurrencyToken() const { return GetTemplate()->IsCurrencyToken(); } bool IsNotEmptyBag() const; diff --git a/src/server/game/Entities/Item/ItemTemplate.cpp b/src/server/game/Entities/Item/ItemTemplate.cpp index 34a6ee635a6..f9e2e2d4236 100644 --- a/src/server/game/Entities/Item/ItemTemplate.cpp +++ b/src/server/game/Entities/Item/ItemTemplate.cpp @@ -89,7 +89,7 @@ void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamag store = &sItemDamageAmmoStore; break; case INVTYPE_2HWEAPON: - if (GetFlags2() & ITEM_FLAGS_EXTRA_CASTER_WEAPON) + if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON) store = &sItemDamageTwoHandCasterStore; else store = &sItemDamageTwoHandStore; @@ -117,7 +117,7 @@ void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamag case INVTYPE_WEAPON: case INVTYPE_WEAPONMAINHAND: case INVTYPE_WEAPONOFFHAND: - if (GetFlags2() & ITEM_FLAGS_EXTRA_CASTER_WEAPON) + if (GetFlags2() & ITEM_FLAG2_CASTER_WEAPON) store = &sItemDamageOneHandCasterStore; else store = &sItemDamageOneHandStore; diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index 47523872151..c578b641ad2 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -127,101 +127,140 @@ enum ItemBondingType #define MAX_BIND_TYPE 6 /* /// @todo: Requiring actual cases in which using (an) item isn't allowed while shapeshifted. Else, this flag would need an implementation. - ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms */ - -enum ItemProtoFlags -{ - ITEM_PROTO_FLAG_UNK1 = 0x00000001, // ? - ITEM_PROTO_FLAG_CONJURED = 0x00000002, // Conjured item - ITEM_PROTO_FLAG_OPENABLE = 0x00000004, // Item can be right clicked to open for loot - ITEM_PROTO_FLAG_HEROIC = 0x00000008, // Makes green "Heroic" text appear on item - ITEM_PROTO_FLAG_DEPRECATED = 0x00000010, // Cannot equip or use - ITEM_PROTO_FLAG_INDESTRUCTIBLE = 0x00000020, // Item can not be destroyed, except by using spell (item can be reagent for spell) - ITEM_PROTO_FLAG_UNK2 = 0x00000040, // ? - ITEM_PROTO_FLAG_NO_EQUIP_COOLDOWN = 0x00000080, // No default 30 seconds cooldown when equipped - ITEM_PROTO_FLAG_UNK3 = 0x00000100, // ? - ITEM_PROTO_FLAG_WRAPPER = 0x00000200, // Item can wrap other items - ITEM_PROTO_FLAG_UNK4 = 0x00000400, // ? - ITEM_PROTO_FLAG_PARTY_LOOT = 0x00000800, // Looting this item does not remove it from available loot - ITEM_PROTO_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost) - ITEM_PROTO_FLAG_CHARTER = 0x00002000, // Item is guild or arena charter - ITEM_PROTO_FLAG_UNK5 = 0x00004000, // Only readable items have this (but not all) - ITEM_PROTO_FLAG_UNK6 = 0x00008000, // ? - ITEM_PROTO_FLAG_UNK7 = 0x00010000, // ? - ITEM_PROTO_FLAG_UNK8 = 0x00020000, // ? - ITEM_PROTO_FLAG_PROSPECTABLE = 0x00040000, // Item can be prospected - ITEM_PROTO_FLAG_UNIQUE_EQUIPPED = 0x00080000, // You can only equip one of these - ITEM_PROTO_FLAG_UNK9 = 0x00100000, // ? - ITEM_PROTO_FLAG_USEABLE_IN_ARENA = 0x00200000, // Item can be used during arena match - ITEM_PROTO_FLAG_THROWABLE = 0x00400000, // Some Thrown weapons have it (and only Thrown) but not all - ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms - ITEM_PROTO_FLAG_UNK10 = 0x01000000, // ? - ITEM_PROTO_FLAG_SMART_LOOT = 0x02000000, // Profession recipes: can only be looted if you meet requirements and don't already know it - ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA = 0x04000000, // Item cannot be used in arena - ITEM_PROTO_FLAG_BIND_TO_ACCOUNT = 0x08000000, // Item binds to account and can be sent only to your own characters - ITEM_PROTO_FLAG_TRIGGERED_CAST = 0x10000000, // Spell is cast with triggered flag - ITEM_PROTO_FLAG_MILLABLE = 0x20000000, // Item can be milled - ITEM_PROTO_FLAG_UNK11 = 0x40000000, // ? - ITEM_PROTO_FLAG_BOP_TRADEABLE = 0x80000000 // bound item that can be traded -}; - -enum ItemFieldFlags -{ - ITEM_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<-- - ITEM_FLAG_UNK1 = 0x00000002, // ? - ITEM_FLAG_UNLOCKED = 0x00000004, // Item had lock but can be opened now - ITEM_FLAG_WRAPPED = 0x00000008, // Item is wrapped and contains another item - ITEM_FLAG_UNK2 = 0x00000010, // ? - ITEM_FLAG_UNK3 = 0x00000020, // ? - ITEM_FLAG_UNK4 = 0x00000040, // ? - ITEM_FLAG_UNK5 = 0x00000080, // ? - ITEM_FLAG_BOP_TRADEABLE = 0x00000100, // Allows trading soulbound items - ITEM_FLAG_READABLE = 0x00000200, // Opens text page when right clicked - ITEM_FLAG_UNK6 = 0x00000400, // ? - ITEM_FLAG_UNK7 = 0x00000800, // ? - ITEM_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost) - ITEM_FLAG_UNK8 = 0x00002000, // ? - ITEM_FLAG_UNK9 = 0x00004000, // ? - ITEM_FLAG_UNK10 = 0x00008000, // ? - ITEM_FLAG_UNK11 = 0x00010000, // ? - ITEM_FLAG_UNK12 = 0x00020000, // ? - ITEM_FLAG_UNK13 = 0x00040000, // ? - ITEM_FLAG_UNK14 = 0x00080000, // ? - ITEM_FLAG_UNK15 = 0x00100000, // ? - ITEM_FLAG_UNK16 = 0x00200000, // ? - ITEM_FLAG_UNK17 = 0x00400000, // ? - ITEM_FLAG_UNK18 = 0x00800000, // ? - ITEM_FLAG_UNK19 = 0x01000000, // ? - ITEM_FLAG_UNK20 = 0x02000000, // ? - ITEM_FLAG_UNK21 = 0x04000000, // ? - ITEM_FLAG_UNK22 = 0x08000000, // ? - ITEM_FLAG_UNK23 = 0x10000000, // ? - ITEM_FLAG_UNK24 = 0x20000000, // ? - ITEM_FLAG_UNK25 = 0x40000000, // ? - ITEM_FLAG_UNK26 = 0x80000000, // ? - - ITEM_FLAG_MAIL_TEXT_MASK = ITEM_FLAG_READABLE | ITEM_FLAG_UNK13 | ITEM_FLAG_UNK14 -}; - -enum ItemFlagsExtra -{ - ITEM_FLAGS_EXTRA_HORDE_ONLY = 0x00000001, - ITEM_FLAGS_EXTRA_ALLIANCE_ONLY = 0x00000002, - ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD = 0x00000004, // when item uses extended cost, gold is also required - ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED = 0x00000100, - ITEM_FLAGS_EXTRA_CASTER_WEAPON = 0x00000200, - ITEM_FLAGS_EXTRA_HAS_NORMAL_PRICE = 0x00004000, - ITEM_FLAGS_EXTRA_BNET_ACCOUNT_BOUND = 0x00020000, - ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG = 0x00200000, - ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG = 0x00400000, - ITEM_FLAGS_EXTRA_CAN_TRANSMOG = 0x00800000, + ITEM_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms */ + +// ITEM_FIELD_FLAGS +enum ItemFieldFlags : uint32 +{ + ITEM_FIELD_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<-- + ITEM_FIELD_FLAG_TRANSLATED = 0x00000002, // Item text will not read as garbage when player does not know the language + ITEM_FIELD_FLAG_UNLOCKED = 0x00000004, // Item had lock but can be opened now + ITEM_FIELD_FLAG_WRAPPED = 0x00000008, // Item is wrapped and contains another item + ITEM_FIELD_FLAG_UNK2 = 0x00000010, + ITEM_FIELD_FLAG_UNK3 = 0x00000020, + ITEM_FIELD_FLAG_UNK4 = 0x00000040, + ITEM_FIELD_FLAG_UNK5 = 0x00000080, + ITEM_FIELD_FLAG_BOP_TRADEABLE = 0x00000100, // Allows trading soulbound items + ITEM_FIELD_FLAG_READABLE = 0x00000200, // Opens text page when right clicked + ITEM_FIELD_FLAG_UNK6 = 0x00000400, + ITEM_FIELD_FLAG_UNK7 = 0x00000800, + ITEM_FIELD_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost) + ITEM_FIELD_FLAG_UNK8 = 0x00002000, + ITEM_FIELD_FLAG_UNK9 = 0x00004000, + ITEM_FIELD_FLAG_UNK10 = 0x00008000, + ITEM_FIELD_FLAG_UNK11 = 0x00010000, + ITEM_FIELD_FLAG_UNK12 = 0x00020000, + ITEM_FIELD_FLAG_UNK13 = 0x00040000, + ITEM_FIELD_FLAG_UNK14 = 0x00080000, + ITEM_FIELD_FLAG_UNK15 = 0x00100000, + ITEM_FIELD_FLAG_UNK16 = 0x00200000, + ITEM_FIELD_FLAG_UNK17 = 0x00400000, + ITEM_FIELD_FLAG_UNK18 = 0x00800000, + ITEM_FIELD_FLAG_UNK19 = 0x01000000, + ITEM_FIELD_FLAG_UNK20 = 0x02000000, + ITEM_FIELD_FLAG_UNK21 = 0x04000000, + ITEM_FIELD_FLAG_UNK22 = 0x08000000, + ITEM_FIELD_FLAG_UNK23 = 0x10000000, + ITEM_FIELD_FLAG_UNK24 = 0x20000000, + ITEM_FIELD_FLAG_UNK25 = 0x40000000, + ITEM_FIELD_FLAG_UNK26 = 0x80000000, + + ITEM_FIELD_FLAG_MAIL_TEXT_MASK = ITEM_FIELD_FLAG_READABLE | ITEM_FIELD_FLAG_UNK13 | ITEM_FIELD_FLAG_UNK14 +}; + +enum ItemFlags : uint32 +{ + ITEM_FLAG_UNK1 = 0x00000001, + ITEM_FLAG_CONJURED = 0x00000002, // Conjured item + ITEM_FLAG_OPENABLE = 0x00000004, // Item can be right clicked to open for loot + ITEM_FLAG_HEROIC = 0x00000008, // Makes green "Heroic" text appear on item + ITEM_FLAG_DEPRECATED = 0x00000010, // Cannot equip or use + ITEM_FLAG_INDESTRUCTIBLE = 0x00000020, // Item can not be destroyed, except by using spell (item can be reagent for spell) + ITEM_FLAG_UNK2 = 0x00000040, + ITEM_FLAG_NO_EQUIP_COOLDOWN = 0x00000080, // No default 30 seconds cooldown when equipped + ITEM_FLAG_UNK3 = 0x00000100, + ITEM_FLAG_WRAPPER = 0x00000200, // Item can wrap other items + ITEM_FLAG_UNK4 = 0x00000400, + ITEM_FLAG_PARTY_LOOT = 0x00000800, // Looting this item does not remove it from available loot + ITEM_FLAG_REFUNDABLE = 0x00001000, // Item can be returned to vendor for its original cost (extended cost) + ITEM_FLAG_CHARTER = 0x00002000, // Item is guild or arena charter + ITEM_FLAG_UNK5 = 0x00004000, // Only readable items have this (but not all) + ITEM_FLAG_UNK6 = 0x00008000, + ITEM_FLAG_UNK7 = 0x00010000, + ITEM_FLAG_UNK8 = 0x00020000, + ITEM_FLAG_PROSPECTABLE = 0x00040000, // Item can be prospected + ITEM_FLAG_UNIQUE_EQUIPPED = 0x00080000, // You can only equip one of these + ITEM_FLAG_UNK9 = 0x00100000, + ITEM_FLAG_USEABLE_IN_ARENA = 0x00200000, // Item can be used during arena match + ITEM_FLAG_THROWABLE = 0x00400000, // Some Thrown weapons have it (and only Thrown) but not all + ITEM_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms + ITEM_FLAG_UNK10 = 0x01000000, + ITEM_FLAG_SMART_LOOT = 0x02000000, // Profession recipes: can only be looted if you meet requirements and don't already know it + ITEM_FLAG_NOT_USEABLE_IN_ARENA = 0x04000000, // Item cannot be used in arena + ITEM_FLAG_BIND_TO_ACCOUNT = 0x08000000, // Item binds to account and can be sent only to your own characters + ITEM_FLAG_TRIGGERED_CAST = 0x10000000, // Spell is cast with triggered flag + ITEM_FLAG_MILLABLE = 0x20000000, // Item can be milled + ITEM_FLAG_UNK11 = 0x40000000, + ITEM_FLAG_BOP_TRADEABLE = 0x80000000 // bound item that can be traded +}; + +enum ItemFlags2 : uint32 +{ + ITEM_FLAG2_HORDE_ONLY = 0x00000001, + ITEM_FLAG2_ALLIANCE_ONLY = 0x00000002, + ITEM_FLAG2_EXT_COST_REQUIRES_GOLD = 0x00000004, // when item uses extended cost, gold is also required + ITEM_FLAG2_UNK1 = 0x00000008, + ITEM_FLAG2_UNK2 = 0x00000010, + ITEM_FLAG2_UNK3 = 0x00000020, + ITEM_FLAG2_UNK4 = 0x00000040, + ITEM_FLAG2_UNK5 = 0x00000080, + ITEM_FLAG2_NEED_ROLL_DISABLED = 0x00000100, + ITEM_FLAG2_CASTER_WEAPON = 0x00000200, + ITEM_FLAG2_UNK6 = 0x00000400, + ITEM_FLAG2_UNK7 = 0x00000800, + ITEM_FLAG2_UNK8 = 0x00001000, + ITEM_FLAG2_UNK9 = 0x00002000, + ITEM_FLAG2_HAS_NORMAL_PRICE = 0x00004000, + ITEM_FLAG2_UNK10 = 0x00008000, + ITEM_FLAG2_UNK11 = 0x00010000, + ITEM_FLAG2_BNET_ACCOUNT_BOUND = 0x00020000, + ITEM_FLAG2_UNK12 = 0x00040000, + ITEM_FLAG2_UNK13 = 0x00080000, + ITEM_FLAG2_UNK14 = 0x00100000, + ITEM_FLAG2_CANNOT_BE_TRANSMOG = 0x00200000, + ITEM_FLAG2_CANNOT_TRANSMOG = 0x00400000, + ITEM_FLAG2_CAN_TRANSMOG = 0x00800000, + ITEM_FLAG2_UNK15 = 0x01000000, + ITEM_FLAG2_UNK16 = 0x02000000, + ITEM_FLAG2_UNK17 = 0x04000000, + ITEM_FLAG2_UNK18 = 0x08000000, + ITEM_FLAG2_UNK19 = 0x10000000, + ITEM_FLAG2_UNK20 = 0x20000000, + ITEM_FLAG2_UNK21 = 0x40000000, + ITEM_FLAG2_CRAFTING_MATERIAL = 0x80000000 }; enum ItemFlags3 { - ITEM_FLAG3_IGNORE_ITEM_LEVEL_DELTAS = 0x080, // Ignore item level adjustments from PLAYER_FIELD_ITEM_LEVEL_DELTA - ITEM_FLAG3_IGNORE_PVP_ITEM_LEVEL_CAP = 0x100, - ITEM_FLAG3_HEIRLOOM_QUALITY = 0x200, // Item appears as having heirloom quality ingame regardless of its real quality (does not affect stat calculation) + ITEM_FLAG3_UNK1 = 0x00000001, + ITEM_FLAG3_UNK2 = 0x00000002, + ITEM_FLAG3_UNK3 = 0x00000004, + ITEM_FLAG3_UNK4 = 0x00000008, + ITEM_FLAG3_UNK5 = 0x00000010, + ITEM_FLAG3_UNK6 = 0x00000020, + ITEM_FLAG3_UNK7 = 0x00000040, + ITEM_FLAG3_IGNORE_ITEM_LEVEL_DELTAS = 0x00000080, // Ignore item level adjustments from PLAYER_FIELD_ITEM_LEVEL_DELTA + ITEM_FLAG3_IGNORE_PVP_ITEM_LEVEL_CAP = 0x00000100, + ITEM_FLAG3_HEIRLOOM_QUALITY = 0x00000200, // Item appears as having heirloom quality ingame regardless of its real quality (does not affect stat calculation) + ITEM_FLAG3_UNK8 = 0x00000400, + ITEM_FLAG3_UNK9 = 0x00000800, + ITEM_FLAG3_DOESNT_APPEAR_IN_GUILD_NEWS = 0x00001000, // Item is not included in the guild news panel + ITEM_FLAG3_UNK10 = 0x00002000, + ITEM_FLAG3_UNK11 = 0x00004000, + ITEM_FLAG3_UNK12 = 0x00008000, + ITEM_FLAG3_UNK13 = 0x00010000, + ITEM_FLAG3_UNK14 = 0x00020000, + ITEM_FLAG3_UNK15 = 0x00040000 }; enum ItemFlagsCustom @@ -710,7 +749,7 @@ struct ItemTemplate bool IsPotion() const { return GetClass() == ITEM_CLASS_CONSUMABLE && GetSubClass() == ITEM_SUBCLASS_POTION; } bool IsVellum() const { return GetClass() == ITEM_CLASS_TRADE_GOODS && GetSubClass() == ITEM_SUBCLASS_ENCHANTMENT; } - bool IsConjuredConsumable() const { return GetClass() == ITEM_CLASS_CONSUMABLE && (GetFlags() & ITEM_PROTO_FLAG_CONJURED); } + bool IsConjuredConsumable() const { return GetClass() == ITEM_CLASS_CONSUMABLE && (GetFlags() & ITEM_FLAG_CONJURED); } bool IsRangedWeapon() const { diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 68650bdff59..655af613220 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -212,11 +212,16 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c break; } - if (!(flags & UPDATEFLAG_LIVING)) - if (WorldObject const* worldObject = dynamic_cast<WorldObject const*>(this)) + if (WorldObject const* worldObject = dynamic_cast<WorldObject const*>(this)) + { + if (!(flags & UPDATEFLAG_LIVING)) if (!worldObject->m_movementInfo.transport.guid.IsEmpty()) flags |= UPDATEFLAG_TRANSPORT_POSITION; + if (worldObject->GetAIAnimKitId() || worldObject->GetMovementAnimKitId() || worldObject->GetMeleeAnimKitId()) + flags |= UPDATEFLAG_ANIMKITS; + } + if (flags & UPDATEFLAG_STATIONARY_POSITION) { // UPDATETYPE_CREATE_OBJECT2 for some gameobject types... @@ -237,14 +242,9 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c } if (Unit const* unit = ToUnit()) - { if (unit->GetVictim()) flags |= UPDATEFLAG_HAS_TARGET; - if (unit->GetAIAnimKitId() || unit->GetMovementAnimKitId() || unit->GetMeleeAnimKitId()) - flags |= UPDATEFLAG_ANIMKITS; - } - ByteBuffer buf(0x400); buf << uint8(updateType); buf << GetPackGUID(); @@ -502,10 +502,10 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint32 flags) const if (AnimKitCreate) { - Unit const* unit = ToUnit(); - *data << uint16(unit->GetAIAnimKitId()); // AiID - *data << uint16(unit->GetMovementAnimKitId()); // MovementID - *data << uint16(unit->GetMeleeAnimKitId()); // MeleeID + WorldObject const* self = static_cast<WorldObject const*>(this); + *data << uint16(self->GetAIAnimKitId()); // AiID + *data << uint16(self->GetMovementAnimKitId()); // MovementID + *data << uint16(self->GetMeleeAnimKitId()); // MeleeID } if (Rotation) @@ -1408,62 +1408,6 @@ bool Object::PrintIndexError(uint32 index, bool set) const return false; } -bool Position::operator==(Position const &a) -{ - return (G3D::fuzzyEq(a.m_positionX, m_positionX) && - G3D::fuzzyEq(a.m_positionY, m_positionY) && - G3D::fuzzyEq(a.m_positionZ, m_positionZ) && - G3D::fuzzyEq(a._orientation, _orientation)); -} - -bool Position::HasInLine(WorldObject const* target, float width) const -{ - if (!HasInArc(float(M_PI), target)) - return false; - width += target->GetObjectSize(); - float angle = GetRelativeAngle(target); - return std::fabs(std::sin(angle)) * GetExactDist2d(target->GetPositionX(), target->GetPositionY()) < width; -} - -std::string Position::ToString() const -{ - std::stringstream sstr; - sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << _orientation; - return sstr.str(); -} - -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) -{ - float x, y, z, o; - buf >> x >> y >> z >> o; - streamer.Pos->Relocate(x, y, z, o); - return buf; -} -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) -{ - buf << streamer.Pos->GetPositionX(); - buf << streamer.Pos->GetPositionY(); - buf << streamer.Pos->GetPositionZ(); - return buf; -} - -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) -{ - float x, y, z; - buf >> x >> y >> z; - streamer.Pos->Relocate(x, y, z); - return buf; -} - -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) -{ - buf << streamer.Pos->GetPositionX(); - buf << streamer.Pos->GetPositionY(); - buf << streamer.Pos->GetPositionZ(); - buf << streamer.Pos->GetOrientation(); - return buf; -} - void MovementInfo::OutDebug() { TC_LOG_DEBUG("misc", "MOVEMENT INFO"); @@ -1502,7 +1446,9 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), -m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0) +m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0), +m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0) + { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -1823,92 +1769,6 @@ bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float m return distsq < maxdist * maxdist; } -void Position::RelocateOffset(const Position & offset) -{ - m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI))); - m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation())); - m_positionZ = GetPositionZ() + offset.GetPositionZ(); - SetOrientation(GetOrientation() + offset.GetOrientation()); -} - -void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const -{ - float dx = endPos.GetPositionX() - GetPositionX(); - float dy = endPos.GetPositionY() - GetPositionY(); - - retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation()); - retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation()); - retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ(); - retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation()); -} - -Position Position::GetPositionWithOffset(Position const& offset) const -{ - Position ret(*this); - ret.RelocateOffset(offset); - return ret; -} - -float Position::GetAngle(const Position* obj) const -{ - if (!obj) - return 0; - - return GetAngle(obj->GetPositionX(), obj->GetPositionY()); -} - -// Return angle in range 0..2*pi -float Position::GetAngle(const float x, const float y) const -{ - float dx = x - GetPositionX(); - float dy = y - GetPositionY(); - - float ang = std::atan2(dy, dx); - ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang; - return ang; -} - -void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const -{ - float dx = GetPositionX() - x; - float dy = GetPositionY() - y; - - if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f) - { - float angle = (float)rand_norm()*static_cast<float>(2*M_PI); - vcos = std::cos(angle); - vsin = std::sin(angle); - } - else - { - float dist = std::sqrt((dx*dx) + (dy*dy)); - vcos = dx / dist; - vsin = dy / dist; - } -} - -bool Position::HasInArc(float arc, const Position* obj, float border) const -{ - // always have self in arc - if (obj == this) - return true; - - // move arc to range 0.. 2*pi - arc = NormalizeOrientation(arc); - - float angle = GetAngle(obj); - angle -= _orientation; - - // move angle to range -pi ... +pi - angle = NormalizeOrientation(angle); - if (angle > float(M_PI)) - angle -= 2.0f * float(M_PI); - - float lborder = -1 * (arc/border); // in range -pi..0 - float rborder = (arc/border); // in range 0..pi - return ((angle >= lborder) && (angle <= rborder)); -} - bool WorldObject::IsInBetween(const WorldObject* obj1, const WorldObject* obj2, float size) const { if (!obj1 || !obj2) @@ -2042,11 +1902,6 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const } } -bool Position::IsPositionValid() const -{ - return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, _orientation); -} - float WorldObject::GetGridActivationRange() const { if (ToPlayer()) @@ -3247,6 +3102,54 @@ ObjectGuid WorldObject::GetTransGUID() const return ObjectGuid::Empty; } +void WorldObject::SetAIAnimKitId(uint16 animKitId) +{ + if (m_aiAnimKitId == animKitId) + return; + + if (animKitId && !sAnimKitStore.LookupEntry(animKitId)) + return; + + m_aiAnimKitId = animKitId; + + WorldPacket data(SMSG_SET_AI_ANIM_KIT, 8 + 2); + data << GetPackGUID(); + data << uint16(animKitId); + SendMessageToSet(&data, true); +} + +void WorldObject::SetMovementAnimKitId(uint16 animKitId) +{ + if (m_movementAnimKitId == animKitId) + return; + + if (animKitId && !sAnimKitStore.LookupEntry(animKitId)) + return; + + m_movementAnimKitId = animKitId; + + WorldPacket data(SMSG_SET_MOVEMENT_ANIM_KIT, 8 + 2); + data << GetPackGUID(); + data << uint16(animKitId); + SendMessageToSet(&data, true); +} + +void WorldObject::SetMeleeAnimKitId(uint16 animKitId) +{ + if (m_meleeAnimKitId == animKitId) + return; + + if (animKitId && !sAnimKitStore.LookupEntry(animKitId)) + return; + + m_meleeAnimKitId = animKitId; + + WorldPacket data(SMSG_SET_MELEE_ANIM_KIT, 8 + 2); + data << GetPackGUID(); + data << uint16(animKitId); + SendMessageToSet(&data, true); +} + void WorldObject::RebuildTerrainSwaps() { // Clear all terrain swaps, will be rebuilt below diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 04d5f306076..b9a6320a835 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -20,6 +20,7 @@ #define _OBJECT_H #include "Common.h" +#include "Position.h" #include "UpdateMask.h" #include "GridReference.h" #include "ObjectDefines.h" @@ -263,141 +264,6 @@ class Object Object& operator=(Object const& right) = delete; }; -struct Position -{ - Position(float x = 0, float y = 0, float z = 0, float o = 0) - : m_positionX(x), m_positionY(y), m_positionZ(z), _orientation(NormalizeOrientation(o)) { } - - Position(Position const& loc) { Relocate(loc); } - - struct PositionXYZStreamer - { - explicit PositionXYZStreamer(Position& pos) : Pos(&pos) { } - Position* Pos; - }; - - struct PositionXYZOStreamer - { - explicit PositionXYZOStreamer(Position& pos) : Pos(&pos) { } - Position* Pos; - }; - - float m_positionX; - float m_positionY; - float m_positionZ; -// Better to limit access to _orientation field, to guarantee the value is normalized -private: - float _orientation; - -public: - bool operator==(Position const &a); - - inline bool operator!=(Position const &a) - { - return !(operator==(a)); - } - - void Relocate(float x, float y) - { m_positionX = x; m_positionY = y;} - void Relocate(float x, float y, float z) - { m_positionX = x; m_positionY = y; m_positionZ = z; } - void Relocate(float x, float y, float z, float orientation) - { m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation); } - void Relocate(Position const &pos) - { m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos._orientation); } - void Relocate(Position const* pos) - { m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->_orientation); } - void RelocateOffset(Position const &offset); - void SetOrientation(float orientation) - { _orientation = NormalizeOrientation(orientation); } - - float GetPositionX() const { return m_positionX; } - float GetPositionY() const { return m_positionY; } - float GetPositionZ() const { return m_positionZ; } - float GetOrientation() const { return _orientation; } - - void GetPosition(float &x, float &y) const - { x = m_positionX; y = m_positionY; } - void GetPosition(float &x, float &y, float &z) const - { x = m_positionX; y = m_positionY; z = m_positionZ; } - void GetPosition(float &x, float &y, float &z, float &o) const - { x = m_positionX; y = m_positionY; z = m_positionZ; o = _orientation; } - - Position GetPosition() const - { - return *this; - } - - Position::PositionXYZStreamer PositionXYZStream() - { - return PositionXYZStreamer(*this); - } - Position::PositionXYZOStreamer PositionXYZOStream() - { - return PositionXYZOStreamer(*this); - } - - bool IsPositionValid() const; - - float GetExactDist2dSq(float x, float y) const - { float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; } - float GetExactDist2d(const float x, const float y) const - { return std::sqrt(GetExactDist2dSq(x, y)); } - float GetExactDist2dSq(Position const* pos) const - { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; } - float GetExactDist2d(Position const* pos) const - { return std::sqrt(GetExactDist2dSq(pos)); } - float GetExactDistSq(float x, float y, float z) const - { float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; } - float GetExactDist(float x, float y, float z) const - { return std::sqrt(GetExactDistSq(x, y, z)); } - float GetExactDistSq(Position const* pos) const - { float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; } - float GetExactDist(Position const* pos) const - { return std::sqrt(GetExactDistSq(pos)); } - - void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const; - Position GetPositionWithOffset(Position const& offset) const; - - float GetAngle(Position const* pos) const; - float GetAngle(float x, float y) const; - float GetRelativeAngle(Position const* pos) const - { return GetAngle(pos) - _orientation; } - float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - _orientation; } - void GetSinCos(float x, float y, float &vsin, float &vcos) const; - - bool IsInDist2d(float x, float y, float dist) const - { return GetExactDist2dSq(x, y) < dist * dist; } - bool IsInDist2d(Position const* pos, float dist) const - { return GetExactDist2dSq(pos) < dist * dist; } - bool IsInDist(float x, float y, float z, float dist) const - { return GetExactDistSq(x, y, z) < dist * dist; } - bool IsInDist(Position const* pos, float dist) const - { return GetExactDistSq(pos) < dist * dist; } - bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const; - bool HasInLine(WorldObject const* target, float width) const; - std::string ToString() const; - - // modulos a radian orientation to the range of 0..2PI - static float NormalizeOrientation(float o) - { - // fmod only supports positive numbers. Thus we have - // to emulate negative numbers - if (o < 0) - { - float mod = o *-1; - mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI)); - mod = -mod + 2.0f * static_cast<float>(M_PI); - return mod; - } - return std::fmod(o, 2.0f * static_cast<float>(M_PI)); - } -}; -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); -ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); -ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); - struct MovementInfo { // common @@ -783,6 +649,13 @@ class WorldObject : public Object, public WorldLocation virtual float GetStationaryZ() const { return GetPositionZ(); } virtual float GetStationaryO() const { return GetOrientation(); } + uint16 GetAIAnimKitId() const { return m_aiAnimKitId; } + void SetAIAnimKitId(uint16 animKitId); + uint16 GetMovementAnimKitId() const { return m_movementAnimKitId; } + void SetMovementAnimKitId(uint16 animKitId); + uint16 GetMeleeAnimKitId() const { return m_meleeAnimKitId; } + void SetMeleeAnimKitId(uint16 animKitId); + protected: std::string m_name; bool m_isActive; @@ -823,6 +696,10 @@ class WorldObject : public Object, public WorldLocation bool CanDetect(WorldObject const* obj, bool ignoreStealth) const; bool CanDetectInvisibilityOf(WorldObject const* obj) const; bool CanDetectStealthOf(WorldObject const* obj) const; + + uint16 m_aiAnimKitId; + uint16 m_movementAnimKitId; + uint16 m_meleeAnimKitId; }; namespace Trinity diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp new file mode 100644 index 00000000000..530e51cd8f5 --- /dev/null +++ b/src/server/game/Entities/Object/Position.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Position.h" +#include "ByteBuffer.h" +#include "G3D/g3dmath.h" +#include "GridDefines.h" + +bool Position::operator==(Position const &a) +{ + return (G3D::fuzzyEq(a.m_positionX, m_positionX) && + G3D::fuzzyEq(a.m_positionY, m_positionY) && + G3D::fuzzyEq(a.m_positionZ, m_positionZ) && + G3D::fuzzyEq(a.m_orientation, m_orientation)); +} + +void Position::RelocateOffset(const Position & offset) +{ + m_positionX = GetPositionX() + (offset.GetPositionX() * std::cos(GetOrientation()) + offset.GetPositionY() * std::sin(GetOrientation() + float(M_PI))); + m_positionY = GetPositionY() + (offset.GetPositionY() * std::cos(GetOrientation()) + offset.GetPositionX() * std::sin(GetOrientation())); + m_positionZ = GetPositionZ() + offset.GetPositionZ(); + SetOrientation(GetOrientation() + offset.GetOrientation()); +} + +bool Position::IsPositionValid() const +{ + return Trinity::IsValidMapCoord(m_positionX, m_positionY, m_positionZ, m_orientation); +} + +void Position::GetPositionOffsetTo(const Position & endPos, Position & retOffset) const +{ + float dx = endPos.GetPositionX() - GetPositionX(); + float dy = endPos.GetPositionY() - GetPositionY(); + + retOffset.m_positionX = dx * std::cos(GetOrientation()) + dy * std::sin(GetOrientation()); + retOffset.m_positionY = dy * std::cos(GetOrientation()) - dx * std::sin(GetOrientation()); + retOffset.m_positionZ = endPos.GetPositionZ() - GetPositionZ(); + retOffset.SetOrientation(endPos.GetOrientation() - GetOrientation()); +} + +Position Position::GetPositionWithOffset(Position const& offset) const +{ + Position ret(*this); + ret.RelocateOffset(offset); + return ret; +} + +float Position::GetAngle(const Position* obj) const +{ + if (!obj) + return 0; + + return GetAngle(obj->GetPositionX(), obj->GetPositionY()); +} + +// Return angle in range 0..2*pi +float Position::GetAngle(float x, float y) const +{ + float dx = x - GetPositionX(); + float dy = y - GetPositionY(); + + float ang = std::atan2(dy, dx); + ang = (ang >= 0) ? ang : 2 * float(M_PI) + ang; + return ang; +} + +void Position::GetSinCos(const float x, const float y, float &vsin, float &vcos) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + + if (std::fabs(dx) < 0.001f && std::fabs(dy) < 0.001f) + { + float angle = (float)rand_norm()*static_cast<float>(2 * M_PI); + vcos = std::cos(angle); + vsin = std::sin(angle); + } + else + { + float dist = std::sqrt((dx*dx) + (dy*dy)); + vcos = dx / dist; + vsin = dy / dist; + } +} + +bool Position::HasInArc(float arc, const Position* obj, float border) const +{ + // always have self in arc + if (obj == this) + return true; + + // move arc to range 0.. 2*pi + arc = NormalizeOrientation(arc); + + float angle = GetAngle(obj); + angle -= m_orientation; + + // move angle to range -pi ... +pi + angle = NormalizeOrientation(angle); + if (angle > float(M_PI)) + angle -= 2.0f * float(M_PI); + + float lborder = -1 * (arc / border); // in range -pi..0 + float rborder = (arc / border); // in range 0..pi + return ((angle >= lborder) && (angle <= rborder)); +} + +bool Position::HasInLine(Position const* pos, float width) const +{ + if (!HasInArc(float(M_PI), pos)) + return false; + + float angle = GetRelativeAngle(pos); + return std::fabs(std::sin(angle)) * GetExactDist2d(pos->GetPositionX(), pos->GetPositionY()) < width; +} + +std::string Position::ToString() const +{ + std::stringstream sstr; + sstr << "X: " << m_positionX << " Y: " << m_positionY << " Z: " << m_positionZ << " O: " << m_orientation; + return sstr.str(); +} + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer) +{ + buf << streamer.Pos->GetPositionX(); + buf << streamer.Pos->GetPositionY(); + return buf; +} + +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer) +{ + float x, y; + buf >> x >> y; + streamer.Pos->Relocate(x, y); + return buf; +} + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) +{ + buf << streamer.Pos->GetPositionX(); + buf << streamer.Pos->GetPositionY(); + buf << streamer.Pos->GetPositionZ(); + return buf; +} + +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer) +{ + float x, y, z; + buf >> x >> y >> z; + streamer.Pos->Relocate(x, y, z); + return buf; +} + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) +{ + buf << streamer.Pos->GetPositionX(); + buf << streamer.Pos->GetPositionY(); + buf << streamer.Pos->GetPositionZ(); + buf << streamer.Pos->GetOrientation(); + return buf; +} + +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer) +{ + float x, y, z, o; + buf >> x >> y >> z >> o; + streamer.Pos->Relocate(x, y, z, o); + return buf; +} diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h new file mode 100644 index 00000000000..5bd37567811 --- /dev/null +++ b/src/server/game/Entities/Object/Position.h @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef Trinity_game_Position_h__ +#define Trinity_game_Position_h__ + +#include "Common.h" + +class ByteBuffer; + +struct Position +{ + Position(float x = 0, float y = 0, float z = 0, float o = 0) + : m_positionX(x), m_positionY(y), m_positionZ(z), m_orientation(NormalizeOrientation(o)) { } + + Position(Position const& loc) { Relocate(loc); } + + struct PositionXYStreamer + { + explicit PositionXYStreamer(Position& pos) : Pos(&pos) { } + Position* Pos; + }; + + struct PositionXYZStreamer + { + explicit PositionXYZStreamer(Position& pos) : Pos(&pos) { } + Position* Pos; + }; + + struct PositionXYZOStreamer + { + explicit PositionXYZOStreamer(Position& pos) : Pos(&pos) { } + Position* Pos; + }; + + float m_positionX; + float m_positionY; + float m_positionZ; + // Better to limit access to _orientation field, to guarantee the value is normalized +private: + float m_orientation; + +public: + bool operator==(Position const &a); + + inline bool operator!=(Position const &a) + { + return !(operator==(a)); + } + + void Relocate(float x, float y) + { + m_positionX = x; m_positionY = y; + } + + void Relocate(float x, float y, float z) + { + m_positionX = x; m_positionY = y; m_positionZ = z; + } + + void Relocate(float x, float y, float z, float orientation) + { + m_positionX = x; m_positionY = y; m_positionZ = z; SetOrientation(orientation); + } + + void Relocate(Position const &pos) + { + m_positionX = pos.m_positionX; m_positionY = pos.m_positionY; m_positionZ = pos.m_positionZ; SetOrientation(pos.m_orientation); + } + + void Relocate(Position const* pos) + { + m_positionX = pos->m_positionX; m_positionY = pos->m_positionY; m_positionZ = pos->m_positionZ; SetOrientation(pos->m_orientation); + } + + void RelocateOffset(Position const &offset); + + void SetOrientation(float orientation) + { + m_orientation = NormalizeOrientation(orientation); + } + + float GetPositionX() const { return m_positionX; } + float GetPositionY() const { return m_positionY; } + float GetPositionZ() const { return m_positionZ; } + float GetOrientation() const { return m_orientation; } + + void GetPosition(float &x, float &y) const + { + x = m_positionX; y = m_positionY; + } + + void GetPosition(float &x, float &y, float &z) const + { + x = m_positionX; y = m_positionY; z = m_positionZ; + } + + void GetPosition(float &x, float &y, float &z, float &o) const + { + x = m_positionX; y = m_positionY; z = m_positionZ; o = m_orientation; + } + + Position GetPosition() const { return *this; } + + Position::PositionXYStreamer PositionXYStream() { return PositionXYStreamer(*this); } + Position::PositionXYZStreamer PositionXYZStream() { return PositionXYZStreamer(*this); } + Position::PositionXYZOStreamer PositionXYZOStream() { return PositionXYZOStreamer(*this); } + + bool IsPositionValid() const; + + float GetExactDist2dSq(float x, float y) const + { + float dx = m_positionX - x; float dy = m_positionY - y; return dx*dx + dy*dy; + } + + float GetExactDist2d(const float x, const float y) const + { + return std::sqrt(GetExactDist2dSq(x, y)); + } + + float GetExactDist2dSq(Position const* pos) const + { + float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; return dx*dx + dy*dy; + } + + float GetExactDist2d(Position const* pos) const + { + return std::sqrt(GetExactDist2dSq(pos)); + } + + float GetExactDistSq(float x, float y, float z) const + { + float dz = m_positionZ - z; return GetExactDist2dSq(x, y) + dz*dz; + } + + float GetExactDist(float x, float y, float z) const + { + return std::sqrt(GetExactDistSq(x, y, z)); + } + + float GetExactDistSq(Position const* pos) const + { + float dx = m_positionX - pos->m_positionX; float dy = m_positionY - pos->m_positionY; float dz = m_positionZ - pos->m_positionZ; return dx*dx + dy*dy + dz*dz; + } + + float GetExactDist(Position const* pos) const + { + return std::sqrt(GetExactDistSq(pos)); + } + + void GetPositionOffsetTo(Position const & endPos, Position & retOffset) const; + Position GetPositionWithOffset(Position const& offset) const; + + float GetAngle(Position const* pos) const; + float GetAngle(float x, float y) const; + float GetRelativeAngle(Position const* pos) const + { + return GetAngle(pos) - m_orientation; + } + + float GetRelativeAngle(float x, float y) const { return GetAngle(x, y) - m_orientation; } + void GetSinCos(float x, float y, float &vsin, float &vcos) const; + + bool IsInDist2d(float x, float y, float dist) const + { + return GetExactDist2dSq(x, y) < dist * dist; + } + + bool IsInDist2d(Position const* pos, float dist) const + { + return GetExactDist2dSq(pos) < dist * dist; + } + + bool IsInDist(float x, float y, float z, float dist) const + { + return GetExactDistSq(x, y, z) < dist * dist; + } + + bool IsInDist(Position const* pos, float dist) const + { + return GetExactDistSq(pos) < dist * dist; + } + + bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const; + bool HasInLine(Position const* pos, float width) const; + std::string ToString() const; + + // modulos a radian orientation to the range of 0..2PI + static float NormalizeOrientation(float o) + { + // fmod only supports positive numbers. Thus we have + // to emulate negative numbers + if (o < 0) + { + float mod = o *-1; + mod = std::fmod(mod, 2.0f * static_cast<float>(M_PI)); + mod = -mod + 2.0f * static_cast<float>(M_PI); + return mod; + } + return std::fmod(o, 2.0f * static_cast<float>(M_PI)); + } +}; + +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYStreamer const& streamer); +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZStreamer const& streamer); +ByteBuffer& operator<<(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); +ByteBuffer& operator>>(ByteBuffer& buf, Position::PositionXYZOStreamer const& streamer); + +#endif // Trinity_game_Position_h__ diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index f91986ddbfd..b6430a8dd26 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -39,7 +39,7 @@ Pet::Pet(Player* owner, PetType type) : Guardian(NULL, owner, true), m_usedTalentCount(0), m_removed(false), - m_petType(type), m_duration(0), m_auraRaidUpdateMask(0), m_loading(false), + m_petType(type), m_duration(0), m_loading(false), m_groupUpdateMask(0), m_declinedname(NULL) { ASSERT(GetOwner()); @@ -208,7 +208,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c SetDisplayId(fields[3].GetUInt32()); SetNativeDisplayId(fields[3].GetUInt32()); uint32 petlevel = fields[4].GetUInt16(); - SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + SetUInt64Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); SetName(fields[8].GetString()); switch (getPetType()) @@ -337,8 +337,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c owner->PetSpellInitialize(); - if (owner->GetGroup()) - owner->SetGroupUpdateFlag(GROUP_UPDATE_PET); + SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); // TODO: 6.x remove/update pet talents //owner->SendTalentsInfoData(true); @@ -785,7 +784,7 @@ bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map) SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, 0); SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, 0); SetUInt32Value(UNIT_FIELD_PETNEXTLEVELEXP, uint32(sObjectMgr->GetXPForLevel(getLevel()+1)*PET_XP_FACTOR)); - SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); + SetUInt64Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); if (cinfo->type == CREATURE_TYPE_BEAST) { @@ -1938,6 +1937,21 @@ void Pet::SetDisplayId(uint32 modelId) if (!isControlled()) return; + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); +} + +void Pet::SetGroupUpdateFlag(uint32 flag) +{ + if (GetOwner()->GetGroup()) + { + m_groupUpdateMask |= flag; + GetOwner()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); + } +} + +void Pet::ResetGroupUpdateFlag() +{ + m_groupUpdateMask = GROUP_UPDATE_FLAG_PET_NONE; if (GetOwner()->GetGroup()) - GetOwner()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MODEL_ID); + GetOwner()->RemoveGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); } diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 494db54208d..70f14fbd7ca 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -134,9 +134,9 @@ class Pet : public Guardian uint32 m_usedTalentCount; - uint64 GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; } - void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); } - void ResetAuraUpdateMaskForRaid() { m_auraRaidUpdateMask = 0; } + uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; } + void SetGroupUpdateFlag(uint32 flag); + void ResetGroupUpdateFlag(); DeclinedName const* GetDeclinedNames() const { return m_declinedname; } @@ -147,9 +147,9 @@ class Pet : public Guardian protected: PetType m_petType; int32 m_duration; // time until unsummon (used mostly for summoned guardians and not used for controlled pets) - uint64 m_auraRaidUpdateMask; bool m_loading; uint32 m_regenTimer; + uint32 m_groupUpdateMask; DeclinedName *m_declinedname; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d7e48947600..3c0510cf3c5 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -31,20 +31,22 @@ #include "ChannelMgr.h" #include "CharacterDatabaseCleaner.h" #include "CharacterPackets.h" -#include "TalentPackets.h" #include "Chat.h" +#include "ChatPackets.h" #include "CombatLogPackets.h" #include "CombatPackets.h" #include "Common.h" #include "ConditionMgr.h" #include "CreatureAI.h" -#include "DatabaseEnv.h" #include "DB2Stores.h" +#include "DatabaseEnv.h" #include "DisableMgr.h" +#include "DuelPackets.h" #include "EquipmentSetPackets.h" #include "Formulas.h" #include "GameEventMgr.h" #include "GameObjectAI.h" +#include "Garrison.h" #include "GossipDef.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -52,14 +54,19 @@ #include "GroupMgr.h" #include "Guild.h" #include "GuildMgr.h" +#include "InstancePackets.h" #include "InstanceSaveMgr.h" #include "InstanceScript.h" +#include "ItemPackets.h" #include "LFGMgr.h" #include "Language.h" #include "Log.h" +#include "LootPackets.h" #include "MailPackets.h" #include "MapInstanced.h" #include "MapManager.h" +#include "MiscPackets.h" +#include "MovementPackets.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -67,6 +74,7 @@ #include "OutdoorPvPMgr.h" #include "Pet.h" #include "QuestDef.h" +#include "QuestPackets.h" #include "ReputationMgr.h" #include "revision.h" #include "SkillDiscovery.h" @@ -77,27 +85,22 @@ #include "SpellHistory.h" #include "SpellMgr.h" #include "SpellPackets.h" +#include "TalentPackets.h" +#include "TradePackets.h" #include "Transport.h" #include "UpdateData.h" #include "UpdateFieldFlags.h" #include "UpdateMask.h" #include "Util.h" #include "Vehicle.h" +#include "VehiclePackets.h" #include "Weather.h" #include "WeatherMgr.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" #include "WorldStatePackets.h" -#include "MiscPackets.h" -#include "ChatPackets.h" -#include "DuelPackets.h" -#include "MovementPackets.h" -#include "ItemPackets.h" -#include "QuestPackets.h" -#include "LootPackets.h" -#include "TradePackets.h" -#include "VehiclePackets.h" +#include "InstancePackets.h" #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -699,7 +702,6 @@ Player::Player(WorldSession* session): Unit(true) // group is initialized in the reference constructor SetGroupInvite(NULL); m_groupUpdateMask = 0; - m_auraRaidUpdateMask = 0; m_bPassOnGroupLoot = false; duel = NULL; @@ -800,7 +802,7 @@ Player::Player(WorldSession* session): Unit(true) m_dungeonDifficulty = DIFFICULTY_NORMAL; m_raidDifficulty = DIFFICULTY_NORMAL_RAID; m_legacyRaidDifficulty = DIFFICULTY_10_N; - m_raidMapDifficulty = DIFFICULTY_NORMAL_RAID; + m_prevMapDifficulty = DIFFICULTY_NORMAL_RAID; m_lastPotionId = 0; _talentMgr = new PlayerTalentInfo(); @@ -885,7 +887,6 @@ Player::Player(WorldSession* session): Unit(true) _maxPersonalArenaRate = 0; memset(_voidStorageItems, 0, VOID_STORAGE_MAX_SLOT * sizeof(VoidStorageItem*)); - memset(_CUFProfiles, 0, MAX_CUF_PROFILES * sizeof(CUFProfile*)); m_achievementMgr = new AchievementMgr<Player>(this); m_reputationMgr = new ReputationMgr(this); @@ -925,9 +926,6 @@ Player::~Player() for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) delete _voidStorageItems[i]; - for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) - delete _CUFProfiles[i]; - ClearResurrectRequestData(); sWorld->DecreasePlayerCount(); @@ -1123,10 +1121,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac UpdateMaxHealth(); // Update max Health (for add bonus from stamina) SetFullHealth(); if (getPowerType() == POWER_MANA) - { - UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect) SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); - } if (getPowerType() == POWER_RUNIC_POWER) { @@ -2057,6 +2052,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // this will be used instead of the current location in SaveToDB m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + m_teleport_options = options; SetFallInformation(0, z); // code for finish transfer called in WorldSession::HandleMovementOpcodes() @@ -2086,6 +2082,12 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!sMapMgr->CanPlayerEnter(mapid, this, false)) return false; + // Seamless teleport can happen only if cosmetic maps match + if (!oldmap || + (oldmap->GetEntry()->CosmeticParentMapID != int32(mapid) && int32(GetMapId()) != mEntry->CosmeticParentMapID && + !((oldmap->GetEntry()->CosmeticParentMapID != -1) ^ (oldmap->GetEntry()->CosmeticParentMapID != mEntry->CosmeticParentMapID)))) + options &= ~TELE_TO_SEAMLESS; + //I think this always returns true. Correct me if I am wrong. // If the map is not created, assume it is possible to enter it. // It will be created in the WorldPortAck. @@ -2148,7 +2150,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati //remove auras before removing from map... RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); - if (!GetSession()->PlayerLogout()) + if (!GetSession()->PlayerLogout() && !(options & TELE_TO_SEAMLESS)) { // send transfer packets WorldPackets::Movement::TransferPending transferPending; @@ -2168,19 +2170,25 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati oldmap->RemovePlayerFromMap(this, false); m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + m_teleport_options = options; SetFallInformation(0, z); // if the player is saved before worldportack (at logout for example) // this will be used instead of the current location in SaveToDB if (!GetSession()->PlayerLogout()) { + if (mEntry->IsDungeon()) + { + WorldPackets::Instance::UpdateLastInstance updateLastInstance; + updateLastInstance.MapID = mapid; + SendDirectMessage(updateLastInstance.Write()); + } + WorldPackets::Movement::NewWorld packet; packet.MapID = mapid; packet.Pos = m_teleport_dest; - packet.Reason = NEW_WORLD_NORMAL; - + packet.Reason = !(options & TELE_TO_SEAMLESS) ? NEW_WORLD_NORMAL : NEW_WORLD_SEAMLESS; SendDirectMessage(packet.Write()); - SendSavedInstances(); } // move packet sent by client always after far teleport @@ -2300,17 +2308,16 @@ void Player::RemoveFromWorld() sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId); } + // Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate + for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) + if (m_items[i]) + m_items[i]->RemoveFromWorld(); + ///- Do not add/remove the player from the object storage ///- It will crash when updating the ObjectAccessor ///- The player should only be removed when logging out Unit::RemoveFromWorld(); - for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) - { - if (m_items[i]) - m_items[i]->RemoveFromWorld(); - } - for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) iter->second->RemoveFromWorld(); @@ -2620,7 +2627,7 @@ bool Player::CanInteractWithQuestGiver(Object* questGiver) return false; } -Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) +Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint64 npcflagmask) { // unit checks if (!guid) @@ -2646,7 +2653,7 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) return NULL; // appropriate npc type - if (npcflagmask && !creature->HasFlag(UNIT_NPC_FLAGS, npcflagmask)) + if (npcflagmask && !creature->HasFlag64(UNIT_NPC_FLAGS, npcflagmask)) return NULL; // not allow interaction under control, but allow with own pets @@ -4136,7 +4143,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell return TRAINER_SPELL_RED; bool hasSpell = true; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_TRAINERSPELL_ABILITY_REQS; ++i) { if (!trainer_spell->ReqAbility[i]) continue; @@ -4159,7 +4166,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell if (getLevel() < trainer_spell->ReqLevel) return TRAINER_SPELL_RED; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_TRAINERSPELL_ABILITY_REQS; ++i) { if (!trainer_spell->ReqAbility[i]) continue; @@ -4186,7 +4193,7 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell // check primary prof. limit // first rank of primary profession spell when there are no proffesions avalible is disabled - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_TRAINERSPELL_ABILITY_REQS; ++i) { if (!trainer_spell->ReqAbility[i]) continue; @@ -4568,6 +4575,22 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(0, guid); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); sWorld->DeleteCharacterInfo(playerguid); @@ -5206,7 +5229,7 @@ void Player::UpdateLocalChannels(uint32 newZone) if (channel->Flags & CHANNEL_DBC_FLAG_CITY_ONLY) currentNameExt = sObjectMgr->GetTrinityStringForDBCLocale(LANG_CHANNEL_CITY); else - currentNameExt = current_zone->ZoneName; + currentNameExt = current_zone->AreaName_lang; snprintf(new_channel_name_buf, 100, channel->Name_lang, currentNameExt); @@ -6182,6 +6205,22 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) return false; } break; + case ACTION_BUTTON_MOUNT: + { + auto mount = sDB2Manager.GetMountById(action); + if (!mount) + { + TC_LOG_ERROR("entities.player", "Mount action %u not added into button %u for player %s (%s): mount does not exist", action, button, GetName().c_str(), GetGUID().ToString().c_str()); + return false; + } + + if (!HasSpell(mount->SpellId)) + { + TC_LOG_ERROR("entities.player", "Mount action %u not added into button %u for player %s (%s): Player does not know this mount", action, button, GetName().c_str(), GetGUID().ToString().c_str()); + return false; + } + break; + } case ACTION_BUTTON_C: case ACTION_BUTTON_CMACRO: case ACTION_BUTTON_MACRO: @@ -6743,12 +6782,12 @@ bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvpto // victim_rank [1..4] HK: <dishonored rank> // victim_rank [5..19] HK: <alliance\horde rank> // victim_rank [0, 20+] HK: <> - WorldPacket data(SMSG_PVP_CREDIT, 4+8+4); - data << uint32(honor); - data << victim_guid; - data << uint32(victim_rank); + WorldPackets::Combat::PvPCredit data; + data.Honor = honor; + data.Target = victim_guid; + data.Rank = victim_rank; - GetSession()->SendPacket(&data); + GetSession()->SendPacket(data.Write()); // add honor points ModifyCurrency(CURRENCY_TYPE_HONOR_POINTS, int32(honor)); @@ -7345,7 +7384,11 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // group update if (GetGroup()) + { SetGroupUpdateFlag(GROUP_UPDATE_FULL); + if (Pet* pet = GetPet()) + pet->SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + } m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; @@ -7656,23 +7699,23 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) break; case ITEM_MOD_AGILITY: // modify agility HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_AGILITY, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_STRENGTH: //modify strength HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STRENGTH, float(val), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_INTELLECT: //modify intellect HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_INTELLECT, float(val), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_SPIRIT: //modify spirit HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_SPIRIT, float(val), apply); + ApplyStatBuffMod(STAT_SPIRIT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_SPIRIT, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_STAMINA: //modify stamina HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply); - ApplyStatBuffMod(STAT_STAMINA, float(val), apply); + ApplyStatBuffMod(STAT_STAMINA, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STAMINA, BASE_PCT_EXCLUDE_CREATE)), apply); break; case ITEM_MOD_DEFENSE_SKILL_RATING: ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply); @@ -7805,6 +7848,32 @@ void Player::_ApplyItemBonuses(Item* item, uint8 slot, bool apply) case ITEM_MOD_ARCANE_RESISTANCE: HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(val), apply); break; + case ITEM_MOD_AGI_STR_INT: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + break; + case ITEM_MOD_AGI_STR: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + break; + case ITEM_MOD_AGI_INT: + HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_AGILITY, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_AGILITY, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + break; + case ITEM_MOD_STR_INT: + HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply); + HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply); + ApplyStatBuffMod(STAT_STRENGTH, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_STRENGTH, BASE_PCT_EXCLUDE_CREATE)), apply); + ApplyStatBuffMod(STAT_INTELLECT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_INTELLECT, BASE_PCT_EXCLUDE_CREATE)), apply); + break; } } @@ -11403,10 +11472,10 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const if (!proto) return EQUIP_ERR_ITEM_NOT_FOUND; - if ((proto->GetFlags2() & ITEM_FLAGS_EXTRA_HORDE_ONLY) && GetTeam() != HORDE) + if ((proto->GetFlags2() & ITEM_FLAG2_HORDE_ONLY) && GetTeam() != HORDE) return EQUIP_ERR_CANT_EQUIP_EVER; - if ((proto->GetFlags2() & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && GetTeam() != ALLIANCE) + if ((proto->GetFlags2() & ITEM_FLAG2_ALLIANCE_ONLY) && GetTeam() != ALLIANCE) return EQUIP_ERR_CANT_EQUIP_EVER; if ((proto->GetAllowableClass() & getClassMask()) == 0 || (proto->GetAllowableRace() & getRaceMask()) == 0) @@ -11996,7 +12065,7 @@ void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool // in case trade we already have item in other player inventory pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this); - if (pLastItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + if (pLastItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE)) AddTradeableItem(pLastItem); } } @@ -12013,7 +12082,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) for (uint8 i = 0; i < MAX_BAG_SIZE; ++i) DestroyItem(slot, i, update); - if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); @@ -12086,7 +12155,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) // Delete rolled money / loot from db. // MUST be done before RemoveFromWorld() or GetTemplate() fails if (ItemTemplate const* pTmp = pItem->GetTemplate()) - if (pTmp->GetFlags() & ITEM_PROTO_FLAG_OPENABLE) + if (pTmp->GetFlags() & ITEM_FLAG_OPENABLE) pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB(); if (IsInWorld() && update) @@ -13670,11 +13739,11 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool if (menuItemBounds.first == menuItemBounds.second && menuId == GetDefaultGossipMenuForSource(source)) menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(0); - uint32 npcflags = 0; + uint64 npcflags = 0; if (source->GetTypeId() == TYPEID_UNIT) { - npcflags = source->GetUInt32Value(UNIT_NPC_FLAGS); + npcflags = source->GetUInt64Value(UNIT_NPC_FLAGS); if (showQuests && npcflags & UNIT_NPC_FLAG_QUESTGIVER) PrepareQuestMenu(source->GetGUID()); } @@ -14115,7 +14184,7 @@ void Player::SendPreparedQuest(ObjectGuid guid) return; } - if (object->GetTypeId() != TYPEID_UNIT || object->ToCreature()->GetUInt32Value(UNIT_NPC_FLAGS) & UNIT_NPC_FLAG_GOSSIP) + if (object->GetTypeId() != TYPEID_UNIT || object->GetUInt64Value(UNIT_NPC_FLAGS) & UNIT_NPC_FLAG_GOSSIP) { if (quest->IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true)) AddQuestAndCheckCompletion(quest, object); @@ -14636,7 +14705,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, DestroyItemCount(obj.ObjectID, obj.Amount, true); break; case QUEST_OBJECTIVE_CURRENCY: - ModifyCurrency(obj.ObjectID, -int32(obj.Amount)); + ModifyCurrency(obj.ObjectID, -int32(obj.Amount), false, true); break; } } @@ -17302,12 +17371,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); - m_achievementMgr->CheckAllAchievementCriteria(this); - _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); _LoadCUFProfiles(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); + std::unique_ptr<Garrison> garrison = Trinity::make_unique<Garrison>(this); + if (garrison->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS), + holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES))) + _garrison = std::move(garrison); + + m_achievementMgr->CheckAllAchievementCriteria(this); return true; } @@ -17321,19 +17397,19 @@ void Player::_LoadCUFProfiles(PreparedQueryResult result) // SELECT id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154 FROM character_cuf_profiles WHERE guid = ? Field* fields = result->Fetch(); - uint8 id = fields[0].GetUInt8(); - std::string name = fields[1].GetString(); - uint16 frameHeight = fields[2].GetUInt16(); - uint16 frameWidth = fields[3].GetUInt16(); - uint8 sortBy = fields[4].GetUInt8(); - uint8 healthText = fields[5].GetUInt8(); - uint32 boolOptions = fields[6].GetUInt32(); - uint8 unk146 = fields[7].GetUInt8(); - uint8 unk147 = fields[8].GetUInt8(); - uint8 unk148 = fields[9].GetUInt8(); - uint16 unk150 = fields[10].GetUInt16(); - uint16 unk152 = fields[11].GetUInt16(); - uint16 unk154 = fields[12].GetUInt16(); + uint8 id = fields[0].GetUInt8(); + std::string name = fields[1].GetString(); + uint16 frameHeight = fields[2].GetUInt16(); + uint16 frameWidth = fields[3].GetUInt16(); + uint8 sortBy = fields[4].GetUInt8(); + uint8 healthText = fields[5].GetUInt8(); + uint32 boolOptions = fields[6].GetUInt32(); + uint8 topPoint = fields[7].GetUInt8(); + uint8 bottomPoint = fields[8].GetUInt8(); + uint8 leftPoint = fields[9].GetUInt8(); + uint16 topOffset = fields[10].GetUInt16(); + uint16 bottomOffset = fields[11].GetUInt16(); + uint16 leftOffset = fields[12].GetUInt16(); if (id > MAX_CUF_PROFILES) { @@ -17341,7 +17417,7 @@ void Player::_LoadCUFProfiles(PreparedQueryResult result) continue; } - _CUFProfiles[id] = new CUFProfile(name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154); + _CUFProfiles[id] = Trinity::make_unique<CUFProfile>(name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset); } while (result->NextRow()); } @@ -17759,13 +17835,13 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F remove = true; } // "Conjured items disappear if you are logged out for more than 15 minutes" - else if (timeDiff > 15 * MINUTE && proto->GetFlags() & ITEM_PROTO_FLAG_CONJURED) + else if (timeDiff > 15 * MINUTE && proto->GetFlags() & ITEM_FLAG_CONJURED) { TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s', diff: %u) has conjured item (%s, entry: %u) with expired lifetime (15 minutes). Deleting item.", GetGUID().ToString().c_str(), GetName().c_str(), timeDiff, item->GetGUID().ToString().c_str(), item->GetEntry()); remove = true; } - else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) + else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) { if (item->GetPlayedTime() > (2 * HOUR)) { @@ -17776,7 +17852,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F stmt->setUInt64(0, item->GetGUID().GetCounter()); trans->Append(stmt); - item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE); + item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE); } else { @@ -17794,11 +17870,11 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F { TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s, entry: %u) with refundable flags, but without data in item_refund_instance. Removing flag.", GetGUID().ToString().c_str(), GetName().c_str(), item->GetGUID().ToString().c_str(), item->GetEntry()); - item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE); + item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE); } } } - else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + else if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_BOP_TRADE); stmt->setUInt64(0, item->GetGUID().GetCounter()); @@ -17820,9 +17896,9 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F } else { - TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s, entry: %u) with ITEM_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.", + TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player (%s, name: '%s') has item (%s, entry: %u) with ITEM_FIELD_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.", GetGUID().ToString().c_str(), GetName().c_str(), item->GetGUID().ToString().c_str(), item->GetEntry()); - item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE); + item->RemoveFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE); } } else if (proto->GetHolidayID()) @@ -18509,12 +18585,7 @@ void Player::SetPendingBind(uint32 instanceId, uint32 bindTimer) void Player::SendRaidInfo() { - uint32 counter = 0; - - WorldPacket data(SMSG_INSTANCE_INFO, 4); - - size_t p_counter = data.wpos(); - data << uint32(counter); // placeholder + WorldPackets::Instance::InstanceInfo instanceInfo; time_t now = time(NULL); @@ -18525,69 +18596,28 @@ void Player::SendRaidInfo() if (itr->second.perm) { InstanceSave* save = itr->second.save; - bool isHeroic = save->GetDifficultyID() == DIFFICULTY_10_HC || save->GetDifficultyID() == DIFFICULTY_25_HC; - uint32 completedEncounters = 0; - if (Map* map = sMapMgr->FindMap(save->GetMapId(), save->GetInstanceId())) - if (InstanceScript* instanceScript = ((InstanceMap*)map)->GetInstanceScript()) - completedEncounters = instanceScript->GetCompletedEncounterMask(); - data << uint32(save->GetMapId()); // map id - data << uint32(save->GetDifficultyID()); // difficulty - data << uint32(isHeroic); // heroic - data << uint64(save->GetInstanceId()); // instance id - data << uint8(1); // expired = 0 - data << uint8(0); // extended = 1 - data << uint32(save->GetResetTime() - now); // reset time - data << uint32(completedEncounters); // completed encounters mask - ++counter; - } - } - } + WorldPackets::Instance::InstanceLockInfos lockInfos; - data.put<uint32>(p_counter, counter); - GetSession()->SendPacket(&data); -} - -/* -- called on every successful teleportation to a map -*/ -void Player::SendSavedInstances() -{ - bool hasBeenSaved = false; - WorldPacket data; + lockInfos.InstanceID = save->GetInstanceId(); + lockInfos.MapID = save->GetMapId(); + lockInfos.DifficultyID = save->GetDifficultyID(); + lockInfos.TimeRemaining = save->GetResetTime() - now; - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) - { - if (itr->second.perm) // only permanent binds are sent - { - hasBeenSaved = true; - break; - } - } - } - - //Send opcode SMSG_UPDATE_INSTANCE_OWNERSHIP. true or false means, whether you have current raid/heroic instances - data.Initialize(SMSG_UPDATE_INSTANCE_OWNERSHIP, 4); - data << uint32(hasBeenSaved); - GetSession()->SendPacket(&data); + lockInfos.CompletedMask = 0; + if (Map* map = sMapMgr->FindMap(save->GetMapId(), save->GetInstanceId())) + if (InstanceScript* instanceScript = ((InstanceMap*)map)->GetInstanceScript()) + lockInfos.CompletedMask = instanceScript->GetCompletedEncounterMask(); - if (!hasBeenSaved) - return; + lockInfos.Locked = lockInfos.TimeRemaining <= 0; + lockInfos.Extended = false; - for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) - { - for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) - { - if (itr->second.perm) - { - data.Initialize(SMSG_UPDATE_LAST_INSTANCE, 4); - data << uint32(itr->second.save->GetMapId()); - GetSession()->SendPacket(&data); + instanceInfo.LockList.push_back(lockInfos); } } } + + GetSession()->SendPacket(instanceInfo.Write()); } /// convert the player's binds to the group @@ -19107,6 +19137,8 @@ void Player::SaveToDB(bool create /*=false*/) _SaveInstanceTimeRestrictions(trans); _SaveCurrency(trans); _SaveCUFProfiles(trans); + if (_garrison) + _garrison->SaveToDB(trans); // check if stats should only be saved on logout // save stats can be out of transaction @@ -19410,13 +19442,13 @@ void Player::_SaveCUFProfiles(SQLTransaction& trans) stmt->setUInt16(4, _CUFProfiles[i]->FrameWidth); stmt->setUInt8(5, _CUFProfiles[i]->SortBy); stmt->setUInt8(6, _CUFProfiles[i]->HealthText); - stmt->setUInt32(7, _CUFProfiles[i]->BoolOptions.to_ulong()); // 27 of 32 fields used, fits in an int - stmt->setUInt8(8, _CUFProfiles[i]->Unk146); - stmt->setUInt8(9, _CUFProfiles[i]->Unk147); - stmt->setUInt8(10, _CUFProfiles[i]->Unk148); - stmt->setUInt16(11, _CUFProfiles[i]->Unk150); - stmt->setUInt16(12, _CUFProfiles[i]->Unk152); - stmt->setUInt16(13, _CUFProfiles[i]->Unk154); + stmt->setUInt32(7, _CUFProfiles[i]->BoolOptions.to_ulong()); // 25 of 32 fields used, fits in an int + stmt->setUInt8(8, _CUFProfiles[i]->TopPoint); + stmt->setUInt8(9, _CUFProfiles[i]->BottomPoint); + stmt->setUInt8(10, _CUFProfiles[i]->LeftPoint); + stmt->setUInt16(11, _CUFProfiles[i]->TopOffset); + stmt->setUInt16(12, _CUFProfiles[i]->BottomOffset); + stmt->setUInt16(13, _CUFProfiles[i]->LeftOffset); } trans->Append(stmt); @@ -19958,10 +19990,10 @@ void Player::SendExplorationExperience(uint32 Area, uint32 Experience) GetSession()->SendPacket(WorldPackets::Misc::ExplorationExperience(Experience, Area).Write()); } -void Player::SendDungeonDifficulty() +void Player::SendDungeonDifficulty(int32 forcedDifficulty /*= -1*/) { WorldPackets::Misc::DungeonDifficultySet dungeonDifficultySet; - dungeonDifficultySet.DifficultyID = GetDungeonDifficultyID(); + dungeonDifficultySet.DifficultyID = forcedDifficulty == -1 ? GetDungeonDifficultyID() : forcedDifficulty; GetSession()->SendPacket(dungeonDifficultySet.Write()); } @@ -19975,8 +20007,8 @@ void Player::SendRaidDifficulty(bool legacy, int32 forcedDifficulty /*= -1*/) void Player::SendResetFailedNotify(uint32 /*mapid*/) { - WorldPacket data(SMSG_RESET_FAILED_NOTIFY, 4); - GetSession()->SendPacket(&data); + WorldPackets::Instance::ResetFailedNotify data; + GetSession()->SendPacket(data.Write()); } /// Reset all solo instances and optionally send a message on success for each @@ -20037,9 +20069,9 @@ void Player::ResetInstances(uint8 method, bool isRaid, bool isLegacy) void Player::SendResetInstanceSuccess(uint32 MapId) { - WorldPacket data(SMSG_INSTANCE_RESET, 4); - data << uint32(MapId); - GetSession()->SendPacket(&data); + WorldPackets::Instance::InstanceReset data; + data.MapID = MapId; + GetSession()->SendPacket(data.Write()); } void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) @@ -20049,10 +20081,11 @@ void Player::SendResetInstanceFailed(uint32 reason, uint32 MapId) // 1: There are players offline in your party. // 2>: There are players in your party attempting to zone into an instance. */ - WorldPacket data(SMSG_INSTANCE_RESET_FAILED, 8); - data << uint32(reason); - data << uint32(MapId); - GetSession()->SendPacket(&data); + + WorldPackets::Instance::InstanceResetFailed data; + data.MapID = MapId; + data.ResetFailedReason = reason; + GetSession()->SendPacket(data.Write()); } /*********************************************************/ @@ -20212,7 +20245,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) GetSession()->SendPacket(&data); if (GetGroup()) - SetGroupUpdateFlag(GROUP_UPDATE_PET); + SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET); } } @@ -20251,7 +20284,7 @@ void Player::Say(std::string const& text, Language language, WorldObject const* sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SAY, language, this, this, _text); + packet.Initialize(CHAT_MSG_SAY, language, this, this, _text); SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); } @@ -20261,7 +20294,7 @@ void Player::Yell(std::string const& text, Language language, WorldObject const* sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_YELL, language, this, this, _text); + packet.Initialize(CHAT_MSG_YELL, language, this, this, _text); SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), true); } @@ -20271,7 +20304,7 @@ void Player::TextEmote(std::string const& text, WorldObject const* /*= nullptr*/ sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); + packet.Initialize(CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text); SendMessageToSetInRange(packet.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !GetSession()->HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)); } @@ -20284,7 +20317,7 @@ void Player::WhisperAddon(std::string const& text, const std::string& prefix, Pl return; WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); + packet.Initialize(CHAT_MSG_WHISPER, LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix); receiver->SendDirectMessage(packet.Write()); } @@ -20301,14 +20334,14 @@ void Player::Whisper(std::string const& text, Language language, Player* target, sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, target); WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_WHISPER, Language(language), this, this, _text); + packet.Initialize(CHAT_MSG_WHISPER, Language(language), this, this, _text); target->SendDirectMessage(packet.Write()); // rest stuff shouldn't happen in case of addon message if (isAddonMessage) return; - packet.Initalize(CHAT_MSG_WHISPER_INFORM, Language(language), target, target, _text); + packet.Initialize(CHAT_MSG_WHISPER_INFORM, Language(language), target, target, _text); SendDirectMessage(packet.Write()); if (!isAcceptWhispers() && !IsGameMaster() && !target->IsGameMaster()) @@ -21235,9 +21268,9 @@ inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 c if (!bStore) AutoUnequipOffhandIfNeed(); - if (pProto->GetFlags() & ITEM_PROTO_FLAG_REFUNDABLE && crItem->ExtendedCost && pProto->GetMaxStackSize() == 1) + if (pProto->GetFlags() & ITEM_FLAG_REFUNDABLE && crItem->ExtendedCost && pProto->GetMaxStackSize() == 1) { - it->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE); + it->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE); it->SetRefundRecipient(GetGUID()); it->SetPaidMoney(price); it->SetPaidExtendedCost(crItem->ExtendedCost); @@ -21427,7 +21460,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin return false; } - if (!IsGameMaster() && ((pProto->GetFlags2() & ITEM_FLAGS_EXTRA_HORDE_ONLY && GetTeam() == ALLIANCE) || (pProto->GetFlags2() == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && GetTeam() == HORDE))) + if (!IsGameMaster() && ((pProto->GetFlags2() & ITEM_FLAG2_HORDE_ONLY && GetTeam() == ALLIANCE) || (pProto->GetFlags2() == ITEM_FLAG2_ALLIANCE_ONLY && GetTeam() == HORDE))) return false; Creature* creature = GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR); @@ -22276,7 +22309,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi m_clientGUIDs.erase(target->GetGUID()); #ifdef TRINITY_DEBUG - TC_LOG_DEBUG("maps", "Object %u (%s) is out of range for %s. Distance = %f", target->GetGUID().ToString().c_str(), target->GetEntry(), GetGUID().ToString().c_str(), GetDistance(target)); + TC_LOG_DEBUG("maps", "Object %s (%u) is out of range for %s. Distance = %f", target->GetGUID().ToString().c_str(), target->GetEntry(), GetGUID().ToString().c_str(), GetDistance(target)); #endif } } @@ -22288,7 +22321,7 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& vi UpdateVisibilityOf_helper(m_clientGUIDs, target, visibleNow); #ifdef TRINITY_DEBUG - TC_LOG_DEBUG("maps", "Object %u (%s) is visible now for %s. Distance = %f", target->GetGUID().ToString().c_str(), target->GetEntry(), GetGUID().ToString().c_str(), GetDistance(target)); + TC_LOG_DEBUG("maps", "Object %s (%u) is visible now for %s. Distance = %f", target->GetGUID().ToString().c_str(), target->GetEntry(), GetGUID().ToString().c_str(), GetDistance(target)); #endif } } @@ -22610,11 +22643,23 @@ void Player::SendInitialPacketsAfterAddToMap() if (GetMap()->IsRaid()) { - DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(GetMap()->GetDifficultyID()); - SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0, GetMap()->GetDifficultyID()); + m_prevMapDifficulty = GetMap()->GetDifficultyID(); + DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(m_prevMapDifficulty); + SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0, m_prevMapDifficulty); } else if (GetMap()->IsNonRaidDungeon()) - SendDungeonDifficulty(); + { + m_prevMapDifficulty = GetMap()->GetDifficultyID(); + SendDungeonDifficulty(m_prevMapDifficulty); + } + else if (!GetMap()->Instanceable()) + { + DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(m_prevMapDifficulty); + SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0); + } + + if (_garrison) + _garrison->SendRemoteInfo(); } void Player::SendUpdateToOutOfRangeGroupMembers() @@ -22625,9 +22670,8 @@ void Player::SendUpdateToOutOfRangeGroupMembers() group->UpdatePlayerOutOfRange(this); m_groupUpdateMask = GROUP_UPDATE_FLAG_NONE; - m_auraRaidUpdateMask = 0; if (Pet* pet = GetPet()) - pet->ResetAuraUpdateMaskForRaid(); + pet->ResetGroupUpdateFlag(); } void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg) @@ -22667,7 +22711,7 @@ void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint3 void Player::ApplyEquipCooldown(Item* pItem) { - if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_PROTO_FLAG_NO_EQUIP_COOLDOWN)) + if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_NO_EQUIP_COOLDOWN)) return; ItemTemplate const* proto = pItem->GetTemplate(); @@ -22686,10 +22730,10 @@ void Player::ApplyEquipCooldown(Item* pItem) GetSpellHistory()->AddCooldown(effectData->SpellID, pItem->GetEntry(), std::chrono::seconds(30)); - WorldPacket data(SMSG_ITEM_COOLDOWN, 12); - data << pItem->GetGUID(); - data << uint32(effectData->SpellID); - GetSession()->SendPacket(&data); + WorldPackets::Item::ItemCooldown data; + data.ItemGuid = pItem->GetGUID(); + data.SpellID = effectData->SpellID; + GetSession()->SendPacket(data.Write()); } } @@ -23057,7 +23101,7 @@ void Player::SetMonthlyQuestStatus(uint32 quest_id) m_MonthlyQuestChanged = true; } -void Player::ResetDailyQuestStatus() +void Player::DailyReset() { for (uint32 questId : GetDynamicValues(PLAYER_DYNAMIC_FIELD_DAILY_QUESTS)) if (uint32 questBit = GetQuestUniqueBitFlag(questId)) @@ -23070,6 +23114,9 @@ void Player::ResetDailyQuestStatus() // DB data deleted in caller m_DailyQuestChanged = false; m_lastDailyQuestTime = 0; + + if (_garrison) + _garrison->ResetFollowerActivationLimit(); } void Player::ResetWeeklyQuestStatus() @@ -23351,7 +23398,7 @@ void Player::UpdateForQuestWorldObjects() continue; // check if this unit requires quest specific flags - if (!obj->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) + if (!obj->HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) continue; SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry()); @@ -24837,7 +24884,7 @@ InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limi InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot, uint32 limit_count) const { // check unique-equipped on item - if (itemProto->GetFlags() & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED) + if (itemProto->GetFlags() & ITEM_FLAG_UNIQUE_EQUIPPED) { // there is an equip limit on this item if (HasItemOrGemWithIdEquipped(itemProto->GetId(), 1, except_slot)) @@ -25132,7 +25179,7 @@ bool Player::IsPetNeedBeTemporaryUnsummoned() const bool Player::CanSeeSpellClickOn(Creature const* c) const { - if (!c->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) + if (!c->HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) return false; SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(c->GetEntry()); @@ -25696,10 +25743,10 @@ void Player::DeleteRefundReference(ObjectGuid it) void Player::SendRefundInfo(Item* item) { - // This function call unsets ITEM_FLAGS_REFUNDABLE if played time is over 2 hours. + // This function call unsets ITEM_FIELD_FLAG_REFUNDABLE if played time is over 2 hours. item->UpdatePlayedTime(this); - if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) + if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) { TC_LOG_DEBUG("entities.player.items", "Item refund: item not refundable!"); return; @@ -25847,7 +25894,7 @@ void Player::SendItemRefundResult(Item* item, ItemExtendedCostEntry const* iece, void Player::RefundItem(Item* item) { - if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) + if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) { TC_LOG_DEBUG("entities.player.items", "Item refund: item not refundable!"); return; @@ -25935,7 +25982,7 @@ void Player::RefundItem(Item* item) uint32 count = iece->RequiredCurrencyCount[i]; uint32 currencyid = iece->RequiredCurrency[i]; if (count && currencyid) - ModifyCurrency(currencyid, count); + ModifyCurrency(currencyid, count, true, true); } // Grant back money @@ -26151,6 +26198,13 @@ void Player::OnCombatExit() m_holyPowerRegenTimerCount = 20000; // first charge of holy power decays 20 seconds after leaving combat } +void Player::CreateGarrison(uint32 garrSiteId) +{ + std::unique_ptr<Garrison> garrison(new Garrison(this)); + if (garrison->Create(garrSiteId)) + _garrison = std::move(garrison); +} + void Player::SendMovementSetCanTransitionBetweenSwimAndFly(bool apply) { WorldPackets::Movement::MoveSetFlag packet(apply ? SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY : SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY); @@ -26217,9 +26271,9 @@ std::string Player::GetMapAreaAndZoneString() std::string zoneName = "Unknown"; if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) { - areaName = area->ZoneName; + areaName = area->AreaName_lang; if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID)) - zoneName = zone->ZoneName; + zoneName = zone->AreaName_lang; } std::ostringstream str; @@ -26301,7 +26355,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); pet->setPowerType(POWER_MANA); - pet->SetUInt32Value(UNIT_NPC_FLAGS, 0); + pet->SetUInt64Value(UNIT_NPC_FLAGS, 0); pet->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); pet->InitStatsForLevel(getLevel()); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d61b7845abf..5bae50edb68 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -47,6 +47,7 @@ class ReputationMgr; class Channel; class Creature; class DynamicObject; +class Garrison; class Group; class Guild; class OutdoorPvP; @@ -206,8 +207,9 @@ enum CUFBoolOptions CUF_DISPLAY_POWER_BAR, CUF_DISPLAY_BORDER, CUF_USE_CLASS_COLORS, - CUF_DISPLAY_NON_BOSS_DEBUFFS, CUF_DISPLAY_HORIZONTAL_GROUPS, + CUF_DISPLAY_NON_BOSS_DEBUFFS, + CUF_DYNAMIC_POSITION, CUF_LOCKED, CUF_SHOWN, CUF_AUTO_ACTIVATE_2_PLAYERS, @@ -221,9 +223,6 @@ enum CUFBoolOptions CUF_AUTO_ACTIVATE_SPEC_2, CUF_AUTO_ACTIVATE_PVP, CUF_AUTO_ACTIVATE_PVE, - CUF_UNK_145, - CUF_UNK_156, - CUF_UNK_157, // The unks is _LOCKED and _SHOWN and _DYNAMIC, unknown order @@ -235,32 +234,32 @@ struct CUFProfile { CUFProfile() : ProfileName(), BoolOptions() // might want to change default value for options { - FrameHeight = 0; - FrameWidth = 0; - SortBy = 0; - HealthText = 0; - Unk146 = 0; - Unk147 = 0; - Unk148 = 0; - Unk150 = 0; - Unk152 = 0; - Unk154 = 0; + FrameHeight = 0; + FrameWidth = 0; + SortBy = 0; + HealthText = 0; + TopPoint = 0; + BottomPoint = 0; + LeftPoint = 0; + TopOffset = 0; + BottomOffset = 0; + LeftOffset = 0; } CUFProfile(const std::string& name, uint16 frameHeight, uint16 frameWidth, uint8 sortBy, uint8 healthText, uint32 boolOptions, - uint8 unk146, uint8 unk147, uint8 unk148, uint16 unk150, uint16 unk152, uint16 unk154) + uint8 topPoint, uint8 bottomPoint, uint8 leftPoint, uint16 topOffset, uint16 bottomOffset, uint16 leftOffset) : ProfileName(name), BoolOptions((int)boolOptions) { - FrameHeight = frameHeight; - FrameWidth = frameWidth; - SortBy = sortBy; - HealthText = healthText; - Unk146 = unk146; - Unk147 = unk147; - Unk148 = unk148; - Unk150 = unk150; - Unk152 = unk152; - Unk154 = unk154; + FrameHeight = frameHeight; + FrameWidth = frameWidth; + SortBy = sortBy; + HealthText = healthText; + TopPoint = topPoint; + BottomPoint = bottomPoint; + LeftPoint = leftPoint; + TopOffset = topOffset; + BottomOffset = bottomOffset; + LeftOffset = leftOffset; } std::string ProfileName; @@ -269,15 +268,15 @@ struct CUFProfile uint8 SortBy; uint8 HealthText; - // LeftAlign, TopAlight, BottomAllign (unk order) - uint8 Unk146; - uint8 Unk147; - uint8 Unk148; + // LeftAlign, TopAlight, BottomAlign + uint8 TopPoint; + uint8 BottomPoint; + uint8 LeftPoint; - // LeftOffset, TopOffset and BottomOffset (unk order) - uint16 Unk150; - uint16 Unk152; - uint16 Unk154; + // LeftOffset, TopOffset and BottomOffset + uint16 TopOffset; + uint16 BottomOffset; + uint16 LeftOffset; std::bitset<CUF_BOOL_OPTIONS_COUNT> BoolOptions; @@ -310,6 +309,7 @@ enum ActionButtonType ACTION_BUTTON_DROPDOWN = 0x30, ACTION_BUTTON_MACRO = 0x40, ACTION_BUTTON_CMACRO = ACTION_BUTTON_C | ACTION_BUTTON_MACRO, + ACTION_BUTTON_MOUNT = 0x60, ACTION_BUTTON_ITEM = 0x80 }; @@ -484,9 +484,9 @@ struct Runes struct EnchantDuration { - EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { }; + EnchantDuration() : item(NULL), slot(MAX_ENCHANTMENT_SLOT), leftduration(0) { } EnchantDuration(Item* _item, EnchantmentSlot _slot, uint32 _leftduration) : item(_item), slot(_slot), - leftduration(_leftduration){ ASSERT(item); }; + leftduration(_leftduration){ ASSERT(item); } Item* item; EnchantmentSlot slot; @@ -918,7 +918,8 @@ enum TeleportToOptions TELE_TO_NOT_LEAVE_TRANSPORT = 0x02, TELE_TO_NOT_LEAVE_COMBAT = 0x04, TELE_TO_NOT_UNSUMMON_PET = 0x08, - TELE_TO_SPELL = 0x10 + TELE_TO_SPELL = 0x10, + TELE_TO_SEAMLESS = 0x20 }; /// Type of environmental damages @@ -983,6 +984,11 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE, PLAYER_LOGIN_QUERY_LOAD_CURRENCY, PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, + PLAYER_LOGIN_QUERY_LOAD_GARRISON, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS, + PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES, MAX_PLAYER_LOGIN_QUERY }; @@ -1319,7 +1325,6 @@ private: PlayerTalentInfo(PlayerTalentInfo const&); }; - class Player : public Unit, public GridObject<Player> { friend class WorldSession; @@ -1364,7 +1369,7 @@ class Player : public Unit, public GridObject<Player> void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); bool CanInteractWithQuestGiver(Object* questGiver); - Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask); + Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint64 npcflagmask); GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTypes type) const; void ToggleAFK(); @@ -1676,7 +1681,7 @@ class Player : public Unit, public GridObject<Player> void SetWeeklyQuestStatus(uint32 quest_id); void SetMonthlyQuestStatus(uint32 quest_id); void SetSeasonalQuestStatus(uint32 quest_id); - void ResetDailyQuestStatus(); + void DailyReset(); void ResetWeeklyQuestStatus(); void ResetMonthlyQuestStatus(); void ResetSeasonalQuestStatus(uint16 event_id); @@ -1732,8 +1737,9 @@ class Player : public Unit, public GridObject<Player> void AddTimedQuest(uint32 questId) { m_timedquests.insert(questId); } void RemoveTimedQuest(uint32 questId) { m_timedquests.erase(questId); } - void SaveCUFProfile(uint8 id, CUFProfile* profile) { delete _CUFProfiles[id]; _CUFProfiles[id] = profile; } ///> Replaces a CUF profile at position 0-4 - CUFProfile* GetCUFProfile(uint8 id) const { return _CUFProfiles[id]; } ///> Retrieves a CUF profile at position 0-4 + void SaveCUFProfile(uint8 id, std::nullptr_t) { _CUFProfiles[id] = nullptr; } ///> Empties a CUF profile at position 0-4 + void SaveCUFProfile(uint8 id, std::unique_ptr<CUFProfile> profile) { _CUFProfiles[id] = std::move(profile); } ///> Replaces a CUF profile at position 0-4 + CUFProfile* GetCUFProfile(uint8 id) const { return _CUFProfiles[id].get(); } ///> Retrieves a CUF profile at position 0-4 uint8 GetCUFProfilesCount() const { uint8 count = 0; @@ -2051,7 +2057,6 @@ class Player : public Unit, public GridObject<Player> uint32 GetSpellByProto(ItemTemplate* proto); float GetHealthBonusFromStamina(); - float GetManaBonusFromIntellect(); bool UpdateStats(Stats stat) override; bool UpdateAllStats() override; @@ -2127,7 +2132,7 @@ class Player : public Unit, public GridObject<Player> void SendAutoRepeatCancel(Unit* target); void SendExplorationExperience(uint32 Area, uint32 Experience); - void SendDungeonDifficulty(); + void SendDungeonDifficulty(int32 forcedDifficulty = -1); void SendRaidDifficulty(bool legacy, int32 forcedDifficulty = -1); void ResetInstances(uint8 method, bool isRaid, bool isLegacy); void SendResetInstanceSuccess(uint32 MapId); @@ -2138,7 +2143,7 @@ class Player : public Unit, public GridObject<Player> bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } void UpdateUnderwaterState(Map* m, float x, float y, float z) override; - void SendMessageToSet(WorldPacket const* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); };// overwrite Object::SendMessageToSet + void SendMessageToSet(WorldPacket const* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) override; // overwrite Object::SendMessageToSetInRange void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool own_team_only); void SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) override; @@ -2188,6 +2193,7 @@ class Player : public Unit, public GridObject<Player> bool IsBeingTeleported() const { return mSemaphoreTeleport_Near || mSemaphoreTeleport_Far; } bool IsBeingTeleportedNear() const { return mSemaphoreTeleport_Near; } bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; } + bool IsBeingTeleportedSeamlessly() const { return IsBeingTeleportedFar() && m_teleport_options & TELE_TO_SEAMLESS; } void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; } void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; } void ProcessDelayedOperations(); @@ -2493,7 +2499,6 @@ class Player : public Unit, public GridObject<Player> void SetPendingBind(uint32 instanceId, uint32 bindTimer); bool HasPendingBind() const { return _pendingBindId > 0; } void SendRaidInfo(); - void SendSavedInstances(); static void ConvertInstancesToGroup(Player* player, Group* group, bool switchLeader); bool Satisfy(AccessRequirement const* ar, uint32 target_map, bool report = false); bool CheckInstanceLoginValid(); @@ -2517,8 +2522,7 @@ class Player : public Unit, public GridObject<Player> uint8 GetSubGroup() const { return m_group.getSubGroup(); } uint32 GetGroupUpdateFlag() const { return m_groupUpdateMask; } void SetGroupUpdateFlag(uint32 flag) { m_groupUpdateMask |= flag; } - uint64 GetAuraUpdateMaskForRaid() const { return m_auraRaidUpdateMask; } - void SetAuraUpdateMaskForRaid(uint8 slot) { m_auraRaidUpdateMask |= (uint64(1) << slot); } + void RemoveGroupUpdateFlag(uint32 flag) { m_groupUpdateMask &= ~flag; } Player* GetNextRandomRaidMember(float radius); PartyResult CanUninviteFromGroup(ObjectGuid guidMember = ObjectGuid::Empty) const; @@ -2624,6 +2628,9 @@ class Player : public Unit, public GridObject<Player> void OnCombatExit(); + void CreateGarrison(uint32 garrSiteId); + Garrison* GetGarrison() { return _garrison.get(); } + protected: // Gamemaster whisper whitelist GuidList WhisperList; @@ -2753,7 +2760,7 @@ class Player : public Unit, public GridObject<Player> Difficulty m_dungeonDifficulty; Difficulty m_raidDifficulty; Difficulty m_legacyRaidDifficulty; - Difficulty m_raidMapDifficulty; + Difficulty m_prevMapDifficulty; uint32 m_atLoginFlags; @@ -2881,7 +2888,6 @@ class Player : public Unit, public GridObject<Player> GroupReference m_originalGroup; Group* m_groupInvite; uint32 m_groupUpdateMask; - uint64 m_auraRaidUpdateMask; bool m_bPassOnGroupLoot; // last used pet number (for BG's) @@ -2904,7 +2910,7 @@ class Player : public Unit, public GridObject<Player> uint8 m_grantableLevels; - CUFProfile* _CUFProfiles[MAX_CUF_PROFILES]; + std::array<std::unique_ptr<CUFProfile>, MAX_CUF_PROFILES> _CUFProfiles = {}; private: // internal common parts for CanStore/StoreItem functions @@ -2973,6 +2979,8 @@ class Player : public Unit, public GridObject<Player> uint32 _activeCheats; uint32 _maxPersonalArenaRate; + + std::unique_ptr<Garrison> _garrison; }; void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 81497029e55..e61c23c8c37 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -36,7 +36,7 @@ Transport::Transport() : GameObject(), _transportInfo(NULL), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), - _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false) + _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false), _delayedTeleport(false) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -231,6 +231,14 @@ void Transport::Update(uint32 diff) sScriptMgr->OnTransportUpdate(this, diff); } +void Transport::DelayedUpdate(uint32 /*diff*/) +{ + if (GetKeyFrames().size() <= 1) + return; + + DelayedTeleportTransport(); +} + void Transport::AddPassenger(WorldObject* passenger) { if (!IsInWorld()) @@ -607,36 +615,8 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl if (oldMap->GetId() != newMapid) { - Map* newMap = sMapMgr->CreateBaseMap(newMapid); + _delayedTeleport = true; UnloadStaticPassengers(); - GetMap()->RemoveFromMap<Transport>(this, false); - SetMap(newMap); - - for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();) - { - WorldObject* obj = (*_passengerTeleportItr++); - - float destX, destY, destZ, destO; - obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); - TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o); - - switch (obj->GetTypeId()) - { - case TYPEID_PLAYER: - if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) - RemovePassenger(obj); - break; - case TYPEID_DYNAMICOBJECT: - obj->AddObjectToRemoveList(); - break; - default: - RemovePassenger(obj); - break; - } - } - - Relocate(x, y, z, o); - GetMap()->AddToMap<Transport>(this); return true; } else @@ -659,6 +639,48 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } } +void Transport::DelayedTeleportTransport() +{ + if (!_delayedTeleport) + return; + + _delayedTeleport = false; + Map* newMap = sMapMgr->CreateBaseMap(_nextFrame->Node->MapID); + GetMap()->RemoveFromMap<Transport>(this, false); + SetMap(newMap); + + float x = _nextFrame->Node->Loc.X, + y = _nextFrame->Node->Loc.Y, + z = _nextFrame->Node->Loc.Z, + o =_nextFrame->InitialOrientation; + + for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();) + { + WorldObject* obj = (*_passengerTeleportItr++); + + float destX, destY, destZ, destO; + obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO); + TransportBase::CalculatePassengerPosition(destX, destY, destZ, &destO, x, y, z, o); + + switch (obj->GetTypeId()) + { + case TYPEID_PLAYER: + if (!obj->ToPlayer()->TeleportTo(_nextFrame->Node->MapID, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) + RemovePassenger(obj); + break; + case TYPEID_DYNAMICOBJECT: + obj->AddObjectToRemoveList(); + break; + default: + RemovePassenger(obj); + break; + } + } + + Relocate(x, y, z, o); + GetMap()->AddToMap<Transport>(this); +} + void Transport::UpdatePassengerPositions(PassengerSet& passengers) { for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr) @@ -697,6 +719,7 @@ void Transport::UpdatePassengerPositions(PassengerSet& passengers) break; case TYPEID_GAMEOBJECT: GetMap()->GameObjectRelocation(passenger->ToGameObject(), x, y, z, o, false); + passenger->ToGameObject()->RelocateStationaryPosition(x, y, z, o); break; case TYPEID_DYNAMICOBJECT: GetMap()->DynamicObjectRelocation(passenger->ToDynObject(), x, y, z, o); diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 193e32300c0..d6598a0036c 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -39,6 +39,7 @@ class Transport : public GameObject, public TransportBase void CleanupsBeforeDelete(bool finalCleanup = true) override; void Update(uint32 diff) override; + void DelayedUpdate(uint32 diff); void BuildUpdate(UpdateDataMapType& data_map) override; @@ -103,6 +104,7 @@ class Transport : public GameObject, public TransportBase void MoveToNextWaypoint(); float CalculateSegmentPos(float perc); bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o); + void DelayedTeleportTransport(); void UpdatePassengerPositions(PassengerSet& passengers); void DoEventIfAny(KeyFrame const& node, bool departure); @@ -127,6 +129,7 @@ class Transport : public GameObject, public TransportBase PassengerSet _staticPassengers; bool _delayedAddModel; + bool _delayedTeleport; }; #endif diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index e9af35ff952..7cc25c5a5a1 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -117,7 +117,6 @@ bool Player::UpdateStats(Stats stat) UpdateMaxHealth(); break; case STAT_INTELLECT: - UpdateMaxPower(POWER_MANA); UpdateAllSpellCritChances(); UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently break; @@ -155,12 +154,18 @@ bool Player::UpdateStats(Stats stat) void Player::ApplySpellPowerBonus(int32 amount, bool apply) { + if (HasAuraType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT)) + return; + apply = _ModifyUInt32(apply, m_baseSpellPower, amount); // For speed just update for client ApplyModUInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, amount, apply); for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, amount, apply); + + if (HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) + UpdateAttackPowerAndDamage(); } void Player::UpdateSpellDamageAndHealingBonus() @@ -172,6 +177,9 @@ void Player::UpdateSpellDamageAndHealingBonus() // Get damage bonus for all schools for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i))); + + if (HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) + UpdateAttackPowerAndDamage(); } bool Player::UpdateAllStats() @@ -266,17 +274,6 @@ float Player::GetHealthBonusFromStamina() return stamina * ratio; } -float Player::GetManaBonusFromIntellect() -{ - // Taken from PaperDollFrame.lua - 4.3.4.15595 - float intellect = GetStat(STAT_INTELLECT); - - float baseInt = std::min(20.0f, intellect); - float moreInt = intellect - baseInt; - - return baseInt + (moreInt * 15.0f); -} - void Player::UpdateMaxHealth() { UnitMods unitMod = UNIT_MOD_HEALTH; @@ -293,11 +290,9 @@ void Player::UpdateMaxPower(Powers power) { UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? GetManaBonusFromIntellect() : 0; - float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); value *= GetModifierValue(unitMod, BASE_PCT); - value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower; + value += GetModifierValue(unitMod, TOTAL_VALUE); value *= GetModifierValue(unitMod, TOTAL_PCT); SetMaxPower(power, uint32(value)); @@ -312,13 +307,17 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; uint16 index = UNIT_FIELD_ATTACK_POWER; + uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MOD_POS; + uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; if (ranged) { index = UNIT_FIELD_RANGED_ATTACK_POWER; + index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MOD_POS; + index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; val2 = (level + std::max(GetStat(STAT_AGILITY), 0.0f)) * entry->RangedAttackPowerPerAgility; } - else + else if (!HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) { float strengthValue = std::max(GetStat(STAT_STRENGTH) * entry->AttackPowerPerStrength, 0.0f); float agilityValue = std::max(GetStat(STAT_AGILITY) * entry->AttackPowerPerAgility, 0.0f); @@ -330,11 +329,20 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) val2 = strengthValue + agilityValue; } + else + { + int32 minSpellPower = GetInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS); + for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) + minSpellPower = std::min(minSpellPower, GetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i)); + + val2 = CalculatePct(float(minSpellPower), GetFloatValue(PLAYER_FIELD_OVERRIDE_AP_BY_SPELL_POWER_PERCENT)); + } SetModifierValue(unitMod, BASE_VALUE, val2); float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); + float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; //add dynamic flat mods if (!ranged) @@ -346,6 +354,8 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) } SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field + SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MOD_POS field + SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field Pet* pet = GetPet(); //update pet's AP Guardian* guardian = GetGuardianPet(); @@ -361,7 +371,9 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) UpdateDamagePhysical(BASE_ATTACK); if (CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon UpdateDamagePhysical(OFF_ATTACK); - if (getClass() == CLASS_SHAMAN || getClass() == CLASS_PALADIN) // mental quickness + if (HasAuraType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER) || + HasAuraType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER) || + HasAuraType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT)) UpdateSpellDamageAndHealingBonus(); if (pet && pet->IsPetGhoul()) // At melee attack power change for DK pet @@ -746,10 +758,6 @@ void Player::UpdateManaRegen() // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen spirit_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); - // SpiritRegen(SPI, INT, LEVEL) = (0.001 + (SPI x sqrt(INT) x BASE_REGEN[LEVEL])) x 5 - if (GetStat(STAT_INTELLECT) > 0.0f) - spirit_regen *= std::sqrt(GetStat(STAT_INTELLECT)); - // CombatRegen = 5% of Base Mana float base_regen = GetCreateMana() * 0.01f + GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 46ef88128cf..4c61f23126f 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -237,6 +237,7 @@ Unit::Unit(bool isWorldObject) : for (uint8 i = 0; i < UNIT_MOD_END; ++i) { m_auraModifiersGroup[i][BASE_VALUE] = 0.0f; + m_auraModifiersGroup[i][BASE_PCT_EXCLUDE_CREATE] = 100.0f; m_auraModifiersGroup[i][BASE_PCT] = 1.0f; m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; @@ -284,10 +285,6 @@ Unit::Unit(bool isWorldObject) : _oldFactionId = 0; _isWalkingBeforeCharm = false; - - _aiAnimKitId = 0; - _movementAnimKitId = 0; - _meleeAnimKitId = 0; } //////////////////////////////////////////////////////////// @@ -4822,50 +4819,29 @@ void Unit::ProcDamageAndSpell(Unit* victim, uint32 procAttacker, uint32 procVict victim->ProcDamageAndSpellFor(true, this, procVictim, procExtra, attType, procSpell, amount, procAura); } -void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* pInfo) +void Unit::SendPeriodicAuraLog(SpellPeriodicAuraLogInfo* info) { - AuraEffect const* aura = pInfo->auraEff; + AuraEffect const* aura = info->auraEff; + WorldPackets::CombatLog::SpellPeriodicAuraLog data; + data.TargetGUID = GetGUID(); + data.CasterGUID = aura->GetCasterGUID(); + data.SpellID = aura->GetId(); - WorldPacket data(SMSG_SPELL_PERIODIC_AURA_LOG, 30); - data << GetPackGUID(); - data << aura->GetCasterGUID().WriteAsPacked(); - data << uint32(aura->GetId()); // spellId - data << uint32(1); // count - data << uint32(aura->GetAuraType()); // auraId - switch (aura->GetAuraType()) - { - case SPELL_AURA_PERIODIC_DAMAGE: - case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: - data << uint32(pInfo->damage); // damage - data << uint32(pInfo->overDamage); // overkill? - data << uint32(aura->GetSpellInfo()->GetSchoolMask()); - data << uint32(pInfo->absorb); // absorb - data << uint32(pInfo->resist); // resist - data << uint8(pInfo->critical); // new 3.1.2 critical tick - break; - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: - data << uint32(pInfo->damage); // damage - data << uint32(pInfo->overDamage); // overheal - data << uint32(pInfo->absorb); // absorb - data << uint8(pInfo->critical); // new 3.1.2 critical tick - break; - case SPELL_AURA_OBS_MOD_POWER: - case SPELL_AURA_PERIODIC_ENERGIZE: - data << uint32(aura->GetMiscValue()); // power type - data << uint32(pInfo->damage); // damage - break; - case SPELL_AURA_PERIODIC_MANA_LEECH: - data << uint32(aura->GetMiscValue()); // power type - data << uint32(pInfo->damage); // amount - data << float(pInfo->multiplier); // gain multiplier - break; - default: - TC_LOG_ERROR("entities.unit", "Unit::SendPeriodicAuraLog: unknown aura %u", uint32(aura->GetAuraType())); - return; - } + /// @todo: should send more logs in one packet when multistrike + WorldPackets::CombatLog::SpellPeriodicAuraLog::SpellLogEffect spellLogEffect; + spellLogEffect.Effect = aura->GetAuraType(); + spellLogEffect.Amount = info->damage; + spellLogEffect.OverHealOrKill = info->overDamage; + spellLogEffect.SchoolMaskOrPower = aura->GetSpellInfo()->GetSchoolMask(); + spellLogEffect.AbsorbedOrAmplitude = info->absorb; + spellLogEffect.Resisted = info->resist; + spellLogEffect.Crit = info->critical; + spellLogEffect.Multistrike = false; // NYI + /// @todo: implement debug info - SendMessageToSet(&data, true); + data.Effects.push_back(spellLogEffect); + + SendMessageToSet(data.Write(), true); } void Unit::SendSpellMiss(Unit* target, uint32 spellID, SpellMissInfo missInfo) @@ -6957,15 +6933,11 @@ void Unit::setPowerType(Powers new_powertype) if (ToPlayer()->GetGroup()) ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE); } - else if (Pet* pet = ToCreature()->ToPet()) + /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE); + }*/ float powerMultiplier = 1.0f; if (!IsPet()) @@ -8157,13 +8129,14 @@ int32 Unit::HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHeal void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellId, int32 damage, Powers powerType) { - WorldPacket data(SMSG_SPELL_ENERGIZE_LOG, (8+8+4+4+4+1)); - data << victim->GetPackGUID(); - data << GetPackGUID(); - data << uint32(spellId); - data << uint32(powerType); - data << int32(damage); - SendMessageToSet(&data, true); + WorldPackets::CombatLog::SpellEnergizeLog data; + data.CasterGUID = GetGUID(); + data.TargetGUID = victim->GetGUID(); + data.SpellID = spellId; + data.Type = powerType; + data.Amount = damage; + + SendMessageToSet(data.Write(), true); } void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers powerType) @@ -8547,6 +8520,13 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const { + if (GetTypeId() == TYPEID_PLAYER) + { + float overrideSP = GetFloatValue(PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT); + if (overrideSP > 0.0f) + return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f); + } + int32 DoneAdvertisedBenefit = 0; AuraEffectList const& mDamageDone = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE); @@ -9117,6 +9097,13 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const { + if (GetTypeId() == TYPEID_PLAYER) + { + float overrideSP = GetFloatValue(PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT); + if (overrideSP > 0.0f) + return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f); + } + int32 advertisedBenefit = 0; AuraEffectList const& mHealingDone = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE); @@ -9675,9 +9662,9 @@ void Unit::Dismount() if (Player* thisPlayer = ToPlayer()) thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(false)); - WorldPacket data(SMSG_DISMOUNT, 8); - data << GetPackGUID(); - SendMessageToSet(&data, true); + WorldPackets::Misc::Dismount data; + data.Guid = GetGUID(); + SendMessageToSet(data.Write(), true); // dismount as a vehicle if (GetTypeId() == TYPEID_PLAYER && GetVehicleKit()) @@ -9763,7 +9750,7 @@ MountCapabilityEntry const* Unit::GetMountCapability(uint32 mountType) const bool Unit::IsServiceProvider() const { - return HasFlag(UNIT_NPC_FLAGS, + return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_FLIGHTMASTER | UNIT_NPC_FLAG_PETITIONER | UNIT_NPC_FLAG_BATTLEMASTER | UNIT_NPC_FLAG_BANKER | UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_SPIRITHEALER | @@ -11245,6 +11232,7 @@ bool Unit::HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, f switch (modifierType) { case BASE_VALUE: + case BASE_PCT_EXCLUDE_CREATE: case TOTAL_VALUE: m_auraModifiersGroup[unitMod][modifierType] += apply ? amount : -amount; break; @@ -11320,7 +11308,8 @@ float Unit::GetTotalStatValue(Stats stat) const return 0.0f; // value = ((base_value * base_pct) + total_value) * total_pct - float value = m_auraModifiersGroup[unitMod][BASE_VALUE] + GetCreateStat(stat); + float value = CalculatePct(m_auraModifiersGroup[unitMod][BASE_VALUE], std::max(m_auraModifiersGroup[unitMod][BASE_PCT_EXCLUDE_CREATE], -100.0f)); + value += GetCreateStat(stat); value *= m_auraModifiersGroup[unitMod][BASE_PCT]; value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; @@ -11339,7 +11328,7 @@ float Unit::GetTotalAuraModValue(UnitMods unitMod) const if (m_auraModifiersGroup[unitMod][TOTAL_PCT] <= 0.0f) return 0.0f; - float value = m_auraModifiersGroup[unitMod][BASE_VALUE]; + float value = CalculatePct(m_auraModifiersGroup[unitMod][BASE_VALUE], std::max(m_auraModifiersGroup[unitMod][BASE_PCT_EXCLUDE_CREATE], -100.0f)); value *= m_auraModifiersGroup[unitMod][BASE_PCT]; value += m_auraModifiersGroup[unitMod][TOTAL_VALUE]; value *= m_auraModifiersGroup[unitMod][TOTAL_PCT]; @@ -11470,11 +11459,7 @@ void Unit::SetHealth(uint32 val) else if (Pet* pet = ToCreature()->ToPet()) { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP); } } @@ -11495,11 +11480,7 @@ void Unit::SetMaxHealth(uint32 val) else if (Pet* pet = ToCreature()->ToPet()) { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP); } if (val < health) @@ -11551,15 +11532,11 @@ void Unit::SetPower(Powers power, int32 val) if (player->GetGroup()) player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER); } - else if (Pet* pet = ToCreature()->ToPet()) + /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER); + }*/ } void Unit::SetMaxPower(Powers power, int32 val) @@ -11577,15 +11554,11 @@ void Unit::SetMaxPower(Powers power, int32 val) if (ToPlayer()->GetGroup()) ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_MAX_POWER); } - else if (Pet* pet = ToCreature()->ToPet()) + /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x { if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER); + }*/ if (val < cur_power) SetPower(power, val); @@ -13007,23 +12980,13 @@ void Unit::UpdateAuraForGroup(uint8 slot) if (Player* player = ToPlayer()) { if (player->GetGroup()) - { player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS); - player->SetAuraUpdateMaskForRaid(slot); - } } else if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsPet()) { Pet* pet = ((Pet*)this); if (pet->isControlled()) - { - Unit* owner = GetOwner(); - if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup()) - { - owner->ToPlayer()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); - pet->SetAuraUpdateMaskForRaid(slot); - } - } + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_AURAS); } } @@ -13401,45 +13364,6 @@ void Unit::SendDurabilityLoss(Player* receiver, uint32 percent) receiver->GetSession()->SendPacket(packet.Write()); } -void Unit::SetAIAnimKitId(uint16 animKitId) -{ - if (_aiAnimKitId == animKitId) - return; - - _aiAnimKitId = animKitId; - - WorldPacket data(SMSG_SET_AI_ANIM_KIT, 8 + 2); - data << GetPackGUID(); - data << uint16(animKitId); - SendMessageToSet(&data, true); -} - -void Unit::SetMovementAnimKitId(uint16 animKitId) -{ - if (_movementAnimKitId == animKitId) - return; - - _movementAnimKitId = animKitId; - - WorldPacket data(SMSG_SET_MOVEMENT_ANIM_KIT, 8 + 2); - data << GetPackGUID(); - data << uint16(animKitId); - SendMessageToSet(&data, true); -} - -void Unit::SetMeleeAnimKitId(uint16 animKitId) -{ - if (_meleeAnimKitId == animKitId) - return; - - _meleeAnimKitId = animKitId; - - WorldPacket data(SMSG_SET_MELEE_ANIM_KIT, 8 + 2); - data << GetPackGUID(); - data << uint16(animKitId); - SendMessageToSet(&data, true); -} - void Unit::PlayOneShotAnimKit(uint16 animKitId) { WorldPacket data(SMSG_PLAY_ONE_SHOT_ANIM_KIT, 7+2); @@ -14276,7 +14200,7 @@ void Unit::RemoveVehicleKit(bool onRemoveFromWorld /*= false*/) m_updateFlag &= ~UPDATEFLAG_VEHICLE; m_unitTypeMask &= ~UNIT_MASK_VEHICLE; - RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK | UNIT_NPC_FLAG_PLAYER_VEHICLE); + RemoveFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK | UNIT_NPC_FLAG_PLAYER_VEHICLE); } bool Unit::IsOnVehicle(const Unit* vehicle) const @@ -16401,7 +16325,7 @@ void Unit::Whisper(std::string const& text, Language language, Player* target, b LocaleConstant locale = target->GetSession()->GetSessionDbLocaleIndex(); WorldPackets::Chat::Chat packet; - packet.Initalize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale); + packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale); target->SendDirectMessage(packet.Write()); } @@ -16448,7 +16372,7 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/ LocaleConstant locale = target->GetSession()->GetSessionDbLocaleIndex(); WorldPackets::Chat::Chat packet; - packet.Initalize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, getGender()), 0, "", locale); + packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, getGender()), 0, "", locale); target->SendDirectMessage(packet.Write()); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index f92c2f278f3..538bcea9eba 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -330,13 +330,6 @@ enum UnitRename #define MAX_AGGRO_RESET_TIME 10 // in seconds #define MAX_AGGRO_RADIUS 45.0f // yards -enum Swing -{ - NOSWING = 0, - SINGLEHANDEDSWING = 1, - TWOHANDEDSWING = 2 -}; - enum VictimState { VICTIMSTATE_INTACT = 0, // set when attacker misses @@ -418,7 +411,7 @@ namespace Movement } typedef std::list<Unit*> UnitList; -typedef std::list< std::pair<Aura*, uint8> > DispelChargesList; +typedef std::list<std::pair<Aura*, uint8>> DispelChargesList; struct SpellImmune { @@ -431,10 +424,11 @@ typedef std::list<SpellImmune> SpellImmuneList; enum UnitModifierType { BASE_VALUE = 0, - BASE_PCT = 1, - TOTAL_VALUE = 2, - TOTAL_PCT = 3, - MODIFIER_TYPE_END = 4 + BASE_PCT_EXCLUDE_CREATE = 1, // percent modifier affecting all stat values from auras and gear but not player base for level + BASE_PCT = 2, + TOTAL_VALUE = 3, + TOTAL_PCT = 4, + MODIFIER_TYPE_END = 5 }; enum WeaponDamageRange @@ -443,13 +437,6 @@ enum WeaponDamageRange MAXDAMAGE }; -enum DamageTypeToSchool -{ - RESISTANCE, - DAMAGE_DEALT, - DAMAGE_TAKEN -}; - enum AuraRemoveMode { AURA_REMOVE_NONE = 0, @@ -729,40 +716,45 @@ enum UnitFlags2 }; /// Non Player Character flags -enum NPCFlags : uint32 -{ - UNIT_NPC_FLAG_NONE = 0x00000000, - UNIT_NPC_FLAG_GOSSIP = 0x00000001, // 100% - UNIT_NPC_FLAG_QUESTGIVER = 0x00000002, // 100% - UNIT_NPC_FLAG_UNK1 = 0x00000004, - UNIT_NPC_FLAG_UNK2 = 0x00000008, - UNIT_NPC_FLAG_TRAINER = 0x00000010, // 100% - UNIT_NPC_FLAG_TRAINER_CLASS = 0x00000020, // 100% - UNIT_NPC_FLAG_TRAINER_PROFESSION = 0x00000040, // 100% - UNIT_NPC_FLAG_VENDOR = 0x00000080, // 100% - UNIT_NPC_FLAG_VENDOR_AMMO = 0x00000100, // 100%, general goods vendor - UNIT_NPC_FLAG_VENDOR_FOOD = 0x00000200, // 100% - UNIT_NPC_FLAG_VENDOR_POISON = 0x00000400, // guessed - UNIT_NPC_FLAG_VENDOR_REAGENT = 0x00000800, // 100% - UNIT_NPC_FLAG_REPAIR = 0x00001000, // 100% - UNIT_NPC_FLAG_FLIGHTMASTER = 0x00002000, // 100% - UNIT_NPC_FLAG_SPIRITHEALER = 0x00004000, // guessed - UNIT_NPC_FLAG_SPIRITGUIDE = 0x00008000, // guessed - UNIT_NPC_FLAG_INNKEEPER = 0x00010000, // 100% - UNIT_NPC_FLAG_BANKER = 0x00020000, // 100% - UNIT_NPC_FLAG_PETITIONER = 0x00040000, // 100% 0xC0000 = guild petitions, 0x40000 = arena team petitions - UNIT_NPC_FLAG_TABARDDESIGNER = 0x00080000, // 100% - UNIT_NPC_FLAG_BATTLEMASTER = 0x00100000, // 100% - UNIT_NPC_FLAG_AUCTIONEER = 0x00200000, // 100% - UNIT_NPC_FLAG_STABLEMASTER = 0x00400000, // 100% - UNIT_NPC_FLAG_GUILD_BANKER = 0x00800000, // cause client to send 997 opcode - UNIT_NPC_FLAG_SPELLCLICK = 0x01000000, // cause client to send 1015 opcode (spell click) - UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x02000000, // players with mounts that have vehicle data should have it set - UNIT_NPC_FLAG_MAILBOX = 0x04000000, // mailbox - UNIT_NPC_FLAG_REFORGER = 0x08000000, // reforging - UNIT_NPC_FLAG_TRANSMOGRIFIER = 0x10000000, // transmogrification - UNIT_NPC_FLAG_VAULTKEEPER = 0x20000000, // void storage - UNIT_NPC_FLAG_BLACK_MARKET = 0x80000000 // black market +enum NPCFlags : uint64 +{ + UNIT_NPC_FLAG_NONE = 0x0000000000, + UNIT_NPC_FLAG_GOSSIP = 0x0000000001, // 100% + UNIT_NPC_FLAG_QUESTGIVER = 0x0000000002, // 100% + UNIT_NPC_FLAG_UNK1 = 0x0000000004, + UNIT_NPC_FLAG_UNK2 = 0x0000000008, + UNIT_NPC_FLAG_TRAINER = 0x0000000010, // 100% + UNIT_NPC_FLAG_TRAINER_CLASS = 0x0000000020, // 100% + UNIT_NPC_FLAG_TRAINER_PROFESSION = 0x0000000040, // 100% + UNIT_NPC_FLAG_VENDOR = 0x0000000080, // 100% + UNIT_NPC_FLAG_VENDOR_AMMO = 0x0000000100, // 100%, general goods vendor + UNIT_NPC_FLAG_VENDOR_FOOD = 0x0000000200, // 100% + UNIT_NPC_FLAG_VENDOR_POISON = 0x0000000400, // guessed + UNIT_NPC_FLAG_VENDOR_REAGENT = 0x0000000800, // 100% + UNIT_NPC_FLAG_REPAIR = 0x0000001000, // 100% + UNIT_NPC_FLAG_FLIGHTMASTER = 0x0000002000, // 100% + UNIT_NPC_FLAG_SPIRITHEALER = 0x0000004000, // guessed + UNIT_NPC_FLAG_SPIRITGUIDE = 0x0000008000, // guessed + UNIT_NPC_FLAG_INNKEEPER = 0x0000010000, // 100% + UNIT_NPC_FLAG_BANKER = 0x0000020000, // 100% + UNIT_NPC_FLAG_PETITIONER = 0x0000040000, // 100% 0xC0000 = guild petitions, 0x40000 = arena team petitions + UNIT_NPC_FLAG_TABARDDESIGNER = 0x0000080000, // 100% + UNIT_NPC_FLAG_BATTLEMASTER = 0x0000100000, // 100% + UNIT_NPC_FLAG_AUCTIONEER = 0x0000200000, // 100% + UNIT_NPC_FLAG_STABLEMASTER = 0x0000400000, // 100% + UNIT_NPC_FLAG_GUILD_BANKER = 0x0000800000, // cause client to send 997 opcode + UNIT_NPC_FLAG_SPELLCLICK = 0x0001000000, // cause client to send 1015 opcode (spell click) + UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x0002000000, // players with mounts that have vehicle data should have it set + UNIT_NPC_FLAG_MAILBOX = 0x0004000000, // mailbox + UNIT_NPC_FLAG_REFORGER = 0x0008000000, // reforging + UNIT_NPC_FLAG_TRANSMOGRIFIER = 0x0010000000, // transmogrification + UNIT_NPC_FLAG_VAULTKEEPER = 0x0020000000, // void storage + UNIT_NPC_FLAG_BLACK_MARKET = 0x0080000000, // black market + UNIT_NPC_FLAG_ITEM_UPGRADE_MASTER = 0x0100000000, + UNIT_NPC_FLAG_GARRISON_ARCHITECT = 0x0200000000, + UNIT_NPC_FLAG_SHIPMENT_CRAFTER = 0x2000000000, + UNIT_NPC_FLAG_GARRISON_MISSION_NPC = 0x4000000000, + UNIT_NPC_FLAG_TRADESKILL_NPC = 0x8000000000 }; enum MovementFlags @@ -1484,12 +1476,6 @@ class Unit : public WorldObject MountCapabilityEntry const* GetMountCapability(uint32 mountType) const; void SendDurabilityLoss(Player* receiver, uint32 percent); - uint16 GetAIAnimKitId() const { return _aiAnimKitId; } - void SetAIAnimKitId(uint16 animKitId); - uint16 GetMovementAnimKitId() const { return _movementAnimKitId; } - void SetMovementAnimKitId(uint16 animKitId); - uint16 GetMeleeAnimKitId() const { return _meleeAnimKitId; } - void SetMeleeAnimKitId(uint16 animKitId); void PlayOneShotAnimKit(uint16 animKitId); uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } @@ -1547,22 +1533,22 @@ class Unit : public WorldObject MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType) const; MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance) const; - bool IsVendor() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR); } - bool IsTrainer() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER); } - bool IsQuestGiver() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } - bool IsGossip() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - bool IsTaxi() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_FLIGHTMASTER); } - bool IsGuildMaster() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PETITIONER); } - bool IsBattleMaster() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BATTLEMASTER); } - bool IsBanker() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BANKER); } - bool IsInnkeeper() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_INNKEEPER); } - bool IsSpiritHealer() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER); } - bool IsSpiritGuide() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITGUIDE); } - bool IsTabardDesigner()const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TABARDDESIGNER); } - bool IsAuctioner() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_AUCTIONEER); } - bool IsArmorer() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_REPAIR); } + bool IsVendor() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_VENDOR); } + bool IsTrainer() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TRAINER); } + bool IsQuestGiver() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); } + bool IsGossip() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } + bool IsTaxi() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_FLIGHTMASTER); } + bool IsGuildMaster() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PETITIONER); } + bool IsBattleMaster() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BATTLEMASTER); } + bool IsBanker() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_BANKER); } + bool IsInnkeeper() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_INNKEEPER); } + bool IsSpiritHealer() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER); } + bool IsSpiritGuide() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITGUIDE); } + bool IsTabardDesigner()const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TABARDDESIGNER); } + bool IsAuctioner() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_AUCTIONEER); } + bool IsArmorer() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_REPAIR); } bool IsServiceProvider() const; - bool IsSpiritService() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE); } + bool IsSpiritService() const { return HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE); } bool IsCritter() const { return GetCreatureType() == CREATURE_TYPE_CRITTER; } bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); } @@ -1981,7 +1967,7 @@ class Unit : public WorldObject void TauntApply(Unit* victim); void TauntFadeOut(Unit* taunter); ThreatManager& getThreatManager() { return m_ThreatManager; } - void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); }; + void addHatedBy(HostileReference* pHostileReference) { m_HostileRefManager.insertFirst(pHostileReference); } void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ } HostileRefManager& getHostileRefManager() { return m_HostileRefManager; } @@ -2341,10 +2327,6 @@ class Unit : public WorldObject time_t _lastDamagedTime; // Part of Evade mechanics - uint16 _aiAnimKitId; - uint16 _movementAnimKitId; - uint16 _meleeAnimKitId; - SpellHistory* _spellHistory; }; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index c2f298beeb7..08efa9b9cae 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -50,9 +50,9 @@ UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry // Set or remove correct flags based on available seats. Will overwrite db data (if wrong). if (UsableSeatNum) - _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); + _me->SetFlag64(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); else - _me->RemoveFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); + _me->RemoveFlag64(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); InitMovementInfoForBase(); } @@ -479,7 +479,7 @@ Vehicle* Vehicle::RemovePassenger(Unit* unit) unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->ID, _me->GetGUID().ToString().c_str(), (int32)seat->first); if (seat->second.SeatInfo->CanEnterOrExit() && ++UsableSeatNum) - _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); + _me->SetFlag64(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); // Remove UNIT_FLAG_NOT_SELECTABLE if passenger did not have it before entering vehicle if (seat->second.SeatInfo->Flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE && !seat->second.Passenger.IsUnselectable) @@ -768,9 +768,9 @@ bool VehicleJoinEvent::Execute(uint64, uint32) if (!Target->UsableSeatNum) { if (Target->GetBase()->GetTypeId() == TYPEID_PLAYER) - Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); + Target->GetBase()->RemoveFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); else - Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + Target->GetBase()->RemoveFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); } } diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 00d6afdd6e4..0d6b971ec15 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -715,7 +715,7 @@ void GameEventMgr::LoadFromDB() ObjectGuid::LowType guid = fields[0].GetUInt64(); uint16 event_id = fields[1].GetUInt8(); - uint32 npcflag = fields[2].GetUInt32(); + uint64 npcflag = fields[2].GetUInt64(); if (event_id >= mGameEvent.size()) { @@ -916,9 +916,9 @@ void GameEventMgr::LoadFromDB() } } -uint32 GameEventMgr::GetNPCFlag(Creature* cr) +uint64 GameEventMgr::GetNPCFlag(Creature* cr) { - uint32 mask = 0; + uint64 mask = 0; ObjectGuid::LowType guid = cr->GetSpawnId(); for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr) @@ -1139,7 +1139,7 @@ void GameEventMgr::UpdateEventNPCFlags(uint16 event_id) if (CreatureTemplate const* creatureTemplate = creature->GetCreatureTemplate()) npcflag |= creatureTemplate->npcflag; - creature->SetUInt32Value(UNIT_NPC_FLAGS, npcflag); + creature->SetUInt64Value(UNIT_NPC_FLAGS, npcflag); // reset gossip options, since the flag change might have added / removed some //cr->ResetGossipOptions(); } @@ -1266,8 +1266,12 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) sMapMgr->DoForAllMapsWithMapId(data->mapid, [&itr](Map* map) { auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(*itr); - for (auto itr = creatureBounds.first; itr != creatureBounds.second; ++itr) - itr->second->AddObjectToRemoveList(); + for (auto itr2 = creatureBounds.first; itr2 != creatureBounds.second;) + { + Creature* creature = itr2->second; + ++itr2; + creature->AddObjectToRemoveList(); + } }); } } @@ -1292,11 +1296,16 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) sMapMgr->DoForAllMapsWithMapId(data->mapid, [&itr](Map* map) { auto gameobjectBounds = map->GetGameObjectBySpawnIdStore().equal_range(*itr); - for (auto itr = gameobjectBounds.first; itr != gameobjectBounds.second; ++itr) - itr->second->AddObjectToRemoveList(); + for (auto itr2 = gameobjectBounds.first; itr2 != gameobjectBounds.second;) + { + GameObject* go = itr2->second; + ++itr2; + go->AddObjectToRemoveList(); + } }); } } + if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size())) { TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %u (size: %zu)", internal_event_id, mGameEventPoolIds.size()); diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index bbddd5698d8..6f3b5c63180 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -98,7 +98,7 @@ class GameEventMgr { private: GameEventMgr(); - ~GameEventMgr() { }; + ~GameEventMgr() { } public: static GameEventMgr* instance() @@ -124,7 +124,7 @@ class GameEventMgr void StopEvent(uint16 event_id, bool overwrite = false); void HandleQuestComplete(uint32 quest_id); // called on world event type quest completions void HandleWorldEventGossip(Player* player, Creature* c); - uint32 GetNPCFlag(Creature* cr); + uint64 GetNPCFlag(Creature* cr); uint32 GetNpcTextId(uint32 guid); uint16 GetEventIdForQuest(Quest const* quest) const; private: @@ -162,7 +162,7 @@ class GameEventMgr typedef std::list<NPCVendorEntry> NPCVendorList; typedef std::vector<NPCVendorList> GameEventNPCVendorMap; typedef std::map<uint32 /*quest id*/, GameEventQuestToEventConditionNum> QuestIdToEventConditionMap; - typedef std::pair<ObjectGuid::LowType /*guid*/, uint32 /*npcflag*/> GuidNPCFlagPair; + typedef std::pair<ObjectGuid::LowType /*guid*/, uint64 /*npcflag*/> GuidNPCFlagPair; typedef std::list<GuidNPCFlagPair> NPCFlagList; typedef std::vector<NPCFlagList> GameEventNPCFlagMap; typedef std::vector<uint32> GameEventBitmask; diff --git a/src/server/game/Garrison/Garrison.cpp b/src/server/game/Garrison/Garrison.cpp new file mode 100644 index 00000000000..749ebb562c5 --- /dev/null +++ b/src/server/game/Garrison/Garrison.cpp @@ -0,0 +1,690 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Garrison.h" +#include "GameObject.h" +#include "GarrisonMgr.h" +#include "MapManager.h" +#include "ObjectMgr.h" + +Garrison::Garrison(Player* owner) : _owner(owner), _siteLevel(nullptr), _followerActivationsRemainingToday(1) +{ +} + +bool Garrison::LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, + PreparedQueryResult followers, PreparedQueryResult abilities) +{ + if (!garrison) + return false; + + Field* fields = garrison->Fetch(); + _siteLevel = sGarrSiteLevelStore.LookupEntry(fields[0].GetUInt32()); + _followerActivationsRemainingToday = fields[1].GetUInt32(); + if (!_siteLevel) + return false; + + InitializePlots(); + + if (blueprints) + { + do + { + fields = blueprints->Fetch(); + if (GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(fields[0].GetUInt32())) + _knownBuildings.insert(building->ID); + + } while (blueprints->NextRow()); + } + + if (buildings) + { + do + { + fields = buildings->Fetch(); + uint32 plotInstanceId = fields[0].GetUInt32(); + uint32 buildingId = fields[1].GetUInt32(); + time_t timeBuilt = time_t(fields[2].GetUInt64()); + bool active = fields[3].GetBool(); + + + Plot* plot = GetPlot(plotInstanceId); + if (!plot) + continue; + + if (!sGarrBuildingStore.LookupEntry(buildingId)) + continue; + + plot->BuildingInfo.PacketInfo = boost::in_place(); + plot->BuildingInfo.PacketInfo->GarrPlotInstanceID = plotInstanceId; + plot->BuildingInfo.PacketInfo->GarrBuildingID = buildingId; + plot->BuildingInfo.PacketInfo->TimeBuilt = timeBuilt; + plot->BuildingInfo.PacketInfo->Active = active; + + } while (buildings->NextRow()); + } + + // 0 1 2 3 4 5 6 7 8 9 + // SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ? + if (followers) + { + do + { + Field* fields = followers->Fetch(); + + uint64 dbId = fields[0].GetUInt64(); + uint32 followerId = fields[1].GetUInt32(); + if (!sGarrFollowerStore.LookupEntry(followerId)) + continue; + + _followerIds.insert(followerId); + Follower& follower = _followers[dbId]; + follower.PacketInfo.DbID = dbId; + follower.PacketInfo.GarrFollowerID = followerId; + follower.PacketInfo.Quality = fields[2].GetUInt32(); + follower.PacketInfo.FollowerLevel = fields[3].GetUInt32(); + follower.PacketInfo.ItemLevelWeapon = fields[4].GetUInt32(); + follower.PacketInfo.ItemLevelArmor = fields[5].GetUInt32(); + follower.PacketInfo.Xp = fields[6].GetUInt32(); + follower.PacketInfo.CurrentBuildingID = fields[7].GetUInt32(); + follower.PacketInfo.CurrentMissionID = fields[8].GetUInt32(); + follower.PacketInfo.FollowerStatus = fields[9].GetUInt32(); + if (!sGarrBuildingStore.LookupEntry(follower.PacketInfo.CurrentBuildingID)) + follower.PacketInfo.CurrentBuildingID = 0; + + //if (!sGarrMissionStore.LookupEntry(follower.PacketInfo.CurrentMissionID)) + // follower.PacketInfo.CurrentMissionID = 0; + + } while (followers->NextRow()); + + if (abilities) + { + do + { + Field* fields = abilities->Fetch(); + uint64 dbId = fields[0].GetUInt64(); + GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(fields[1].GetUInt32()); + + if (!ability) + continue; + + auto itr = _followers.find(dbId); + if (itr == _followers.end()) + continue; + + itr->second.PacketInfo.AbilityID.push_back(ability); + } while (abilities->NextRow()); + } + } + + return true; +} + +void Garrison::SaveToDB(SQLTransaction& trans) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, _siteLevel->ID); + stmt->setUInt32(2, _followerActivationsRemainingToday); + trans->Append(stmt); + + for (uint32 building : _knownBuildings) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, building); + trans->Append(stmt); + } + + for (auto const& p : _plots) + { + Plot const& plot = p.second; + if (plot.BuildingInfo.PacketInfo) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS); + stmt->setUInt64(0, _owner->GetGUID().GetCounter()); + stmt->setUInt32(1, plot.BuildingInfo.PacketInfo->GarrPlotInstanceID); + stmt->setUInt32(2, plot.BuildingInfo.PacketInfo->GarrBuildingID); + stmt->setUInt64(3, plot.BuildingInfo.PacketInfo->TimeBuilt); + stmt->setBool(4, plot.BuildingInfo.PacketInfo->Active); + trans->Append(stmt); + } + } + + for (auto const& p : _followers) + { + Follower const& follower = p.second; + uint8 index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(index++, follower.PacketInfo.DbID); + stmt->setUInt64(index++, _owner->GetGUID().GetCounter()); + stmt->setUInt32(index++, follower.PacketInfo.GarrFollowerID); + stmt->setUInt32(index++, follower.PacketInfo.Quality); + stmt->setUInt32(index++, follower.PacketInfo.FollowerLevel); + stmt->setUInt32(index++, follower.PacketInfo.ItemLevelWeapon); + stmt->setUInt32(index++, follower.PacketInfo.ItemLevelArmor); + stmt->setUInt32(index++, follower.PacketInfo.Xp); + stmt->setUInt32(index++, follower.PacketInfo.CurrentBuildingID); + stmt->setUInt32(index++, follower.PacketInfo.CurrentMissionID); + stmt->setUInt32(index++, follower.PacketInfo.FollowerStatus); + trans->Append(stmt); + + uint8 slot = 0; + for (GarrAbilityEntry const* ability : follower.PacketInfo.AbilityID) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES); + stmt->setUInt64(0, follower.PacketInfo.DbID); + stmt->setUInt32(1, ability->ID); + stmt->setUInt8(2, slot++); + trans->Append(stmt); + } + } +} + +bool Garrison::Create(uint32 garrSiteId) +{ + _siteLevel = sGarrisonMgr.GetGarrSiteLevelEntry(garrSiteId, 1); + if (!_siteLevel) + return false; + + InitializePlots(); + + WorldPackets::Garrison::GarrisonCreateResult garrisonCreateResult; + garrisonCreateResult.GarrSiteLevelID = _siteLevel->ID; + _owner->SendDirectMessage(garrisonCreateResult.Write()); + _owner->SendUpdatePhasing(); + SendRemoteInfo(); + return true; +} + +void Garrison::InitializePlots() +{ + if (std::vector<GarrSiteLevelPlotInstEntry const*> const* plots = sGarrisonMgr.GetGarrPlotInstForSiteLevel(_siteLevel->ID)) + { + for (std::size_t i = 0; i < plots->size(); ++i) + { + uint32 garrPlotInstanceId = plots->at(i)->GarrPlotInstanceID; + GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId); + GameObjectsEntry const* gameObject = sGarrisonMgr.GetPlotGameObject(_siteLevel->MapID, garrPlotInstanceId); + if (!plotInstance || !gameObject) + continue; + + GarrPlotEntry const* plot = sGarrPlotStore.LookupEntry(plotInstance->GarrPlotID); + if (!plot) + continue; + + Plot& plotInfo = _plots[garrPlotInstanceId]; + plotInfo.PacketInfo.GarrPlotInstanceID = garrPlotInstanceId; + plotInfo.PacketInfo.PlotPos.Relocate(gameObject->Position.X, gameObject->Position.Y, gameObject->Position.Z, 2 * std::acos(gameObject->RotationW)); + plotInfo.PacketInfo.PlotType = plot->PlotType; + plotInfo.EmptyGameObjectId = gameObject->ID; + plotInfo.GarrSiteLevelPlotInstId = plots->at(i)->ID; + } + } +} + +void Garrison::Upgrade() +{ +} + +void Garrison::Enter() const +{ + WorldLocation loc(_siteLevel->MapID); + loc.Relocate(_owner); + _owner->TeleportTo(loc, TELE_TO_SEAMLESS); +} + +void Garrison::Leave() const +{ + if (MapEntry const* map = sMapStore.LookupEntry(_siteLevel->MapID)) + { + WorldLocation loc(map->ParentMapID); + loc.Relocate(_owner); + _owner->TeleportTo(loc, TELE_TO_SEAMLESS); + } +} + +GarrisonFactionIndex Garrison::GetFaction() const +{ + return _owner->GetTeam() == HORDE ? GARRISON_FACTION_INDEX_HORDE : GARRISON_FACTION_INDEX_ALLIANCE; +} + +std::vector<Garrison::Plot*> Garrison::GetPlots() +{ + std::vector<Plot*> plots; + plots.reserve(_plots.size()); + for (auto& p : _plots) + plots.push_back(&p.second); + + return plots; +} + +Garrison::Plot* Garrison::GetPlot(uint32 garrPlotInstanceId) +{ + auto itr = _plots.find(garrPlotInstanceId); + if (itr != _plots.end()) + return &itr->second; + + return nullptr; +} + +Garrison::Plot const* Garrison::GetPlot(uint32 garrPlotInstanceId) const +{ + auto itr = _plots.find(garrPlotInstanceId); + if (itr != _plots.end()) + return &itr->second; + + return nullptr; +} + +void Garrison::LearnBlueprint(uint32 garrBuildingId) +{ + WorldPackets::Garrison::GarrisonLearnBlueprintResult learnBlueprintResult; + learnBlueprintResult.BuildingID = garrBuildingId; + learnBlueprintResult.Result = GARRISON_SUCCESS; + + if (!sGarrBuildingStore.LookupEntry(garrBuildingId)) + learnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID; + else if (_knownBuildings.count(garrBuildingId)) + learnBlueprintResult.Result = GARRISON_ERROR_BLUEPRINT_KNOWN; + else + _knownBuildings.insert(garrBuildingId); + + _owner->SendDirectMessage(learnBlueprintResult.Write()); +} + +void Garrison::UnlearnBlueprint(uint32 garrBuildingId) +{ + WorldPackets::Garrison::GarrisonUnlearnBlueprintResult unlearnBlueprintResult; + unlearnBlueprintResult.BuildingID = garrBuildingId; + unlearnBlueprintResult.Result = GARRISON_SUCCESS; + + if (!sGarrBuildingStore.LookupEntry(garrBuildingId)) + unlearnBlueprintResult.Result = GARRISON_ERROR_INVALID_BUILDINGID; + else if (!_knownBuildings.count(garrBuildingId)) + unlearnBlueprintResult.Result = GARRISON_ERROR_BLUEPRINT_NOT_KNOWN; + else + _knownBuildings.erase(garrBuildingId); + + _owner->SendDirectMessage(unlearnBlueprintResult.Write()); +} + +void Garrison::PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId) +{ + WorldPackets::Garrison::GarrisonPlaceBuildingResult placeBuildingResult; + placeBuildingResult.Result = CheckBuildingPlacement(garrPlotInstanceId, garrBuildingId); + if (placeBuildingResult.Result == GARRISON_SUCCESS) + { + placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId; + placeBuildingResult.BuildingInfo.GarrBuildingID = garrBuildingId; + placeBuildingResult.BuildingInfo.TimeBuilt = time(nullptr); + + Plot* plot = GetPlot(garrPlotInstanceId); + uint32 oldBuildingId = 0; + Map* map = FindMap(); + GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(garrBuildingId); + if (map) + plot->DeleteGameObject(map); + + if (plot->BuildingInfo.PacketInfo) + { + oldBuildingId = plot->BuildingInfo.PacketInfo->GarrBuildingID; + if (sGarrBuildingStore.AssertEntry(oldBuildingId)->Type != building->Type) + plot->ClearBuildingInfo(_owner); + } + + plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner); + if (map) + if (GameObject* go = plot->CreateGameObject(map, GetFaction())) + map->AddToMap(go); + + _owner->ModifyCurrency(building->CostCurrencyID, -building->CostCurrencyAmount, false, true); + _owner->ModifyMoney(-building->CostMoney * GOLD, false); + + if (oldBuildingId) + { + WorldPackets::Garrison::GarrisonBuildingRemoved buildingRemoved; + buildingRemoved.Result = GARRISON_SUCCESS; + buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId; + buildingRemoved.GarrBuildingID = oldBuildingId; + _owner->SendDirectMessage(buildingRemoved.Write()); + } + } + + _owner->SendDirectMessage(placeBuildingResult.Write()); +} + +void Garrison::CancelBuildingConstruction(uint32 garrPlotInstanceId) +{ + WorldPackets::Garrison::GarrisonBuildingRemoved buildingRemoved; + buildingRemoved.Result = CheckBuildingRemoval(garrPlotInstanceId); + if (buildingRemoved.Result == GARRISON_SUCCESS) + { + Plot* plot = GetPlot(garrPlotInstanceId); + + buildingRemoved.GarrPlotInstanceID = garrPlotInstanceId; + buildingRemoved.GarrBuildingID = plot->BuildingInfo.PacketInfo->GarrBuildingID; + + Map* map = FindMap(); + if (map) + plot->DeleteGameObject(map); + + plot->ClearBuildingInfo(_owner); + _owner->SendDirectMessage(buildingRemoved.Write()); + + GarrBuildingEntry const* constructing = sGarrBuildingStore.AssertEntry(buildingRemoved.GarrBuildingID); + // Refund construction/upgrade cost + _owner->ModifyCurrency(constructing->CostCurrencyID, constructing->CostCurrencyAmount, false, true); + _owner->ModifyMoney(constructing->CostMoney * GOLD, false); + + if (constructing->Level > 1) + { + // Restore previous level building + GarrBuildingEntry const* restored = sGarrisonMgr.GetPreviousLevelBuilding(constructing->Type, constructing->Level); + ASSERT(restored); + + WorldPackets::Garrison::GarrisonPlaceBuildingResult placeBuildingResult; + placeBuildingResult.Result = GARRISON_SUCCESS; + placeBuildingResult.BuildingInfo.GarrPlotInstanceID = garrPlotInstanceId; + placeBuildingResult.BuildingInfo.GarrBuildingID = restored->ID; + placeBuildingResult.BuildingInfo.TimeBuilt = time(nullptr); + placeBuildingResult.BuildingInfo.Active = true; + + plot->SetBuildingInfo(placeBuildingResult.BuildingInfo, _owner); + _owner->SendDirectMessage(placeBuildingResult.Write()); + } + + if (map) + if (GameObject* go = plot->CreateGameObject(map, GetFaction())) + map->AddToMap(go); + } + else + _owner->SendDirectMessage(buildingRemoved.Write()); +} + +void Garrison::AddFollower(uint32 garrFollowerId) +{ + WorldPackets::Garrison::GarrisonAddFollowerResult addFollowerResult; + GarrFollowerEntry const* followerEntry = sGarrFollowerStore.LookupEntry(garrFollowerId); + if (_followerIds.count(garrFollowerId) || !followerEntry) + { + addFollowerResult.Result = GARRISON_GENERIC_UNKNOWN_ERROR; + _owner->SendDirectMessage(addFollowerResult.Write()); + return; + } + + _followerIds.insert(garrFollowerId); + uint64 dbId = sGarrisonMgr.GenerateFollowerDbId(); + Follower& follower = _followers[dbId]; + follower.PacketInfo.DbID = dbId; + follower.PacketInfo.GarrFollowerID = garrFollowerId; + follower.PacketInfo.Quality = followerEntry->Quality; // TODO: handle magic upgrades + follower.PacketInfo.FollowerLevel = followerEntry->Level; + follower.PacketInfo.ItemLevelWeapon = followerEntry->ItemLevelWeapon; + follower.PacketInfo.ItemLevelArmor = followerEntry->ItemLevelArmor; + follower.PacketInfo.Xp = 0; + follower.PacketInfo.CurrentBuildingID = 0; + follower.PacketInfo.CurrentMissionID = 0; + follower.PacketInfo.AbilityID = sGarrisonMgr.RollFollowerAbilities(followerEntry, follower.PacketInfo.Quality, GetFaction(), true); + follower.PacketInfo.FollowerStatus = 0; + + addFollowerResult.Follower = follower.PacketInfo; + _owner->SendDirectMessage(addFollowerResult.Write()); + + _owner->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER, follower.PacketInfo.DbID); +} + +Garrison::Follower const* Garrison::GetFollower(uint64 dbId) const +{ + auto itr = _followers.find(dbId); + if (itr != _followers.end()) + return &itr->second; + + return nullptr; +} + +void Garrison::SendInfo() +{ + WorldPackets::Garrison::GetGarrisonInfoResult garrisonInfo; + garrisonInfo.GarrSiteID = _siteLevel->SiteID; + garrisonInfo.GarrSiteLevelID = _siteLevel->ID; + garrisonInfo.FactionIndex = GetFaction(); + garrisonInfo.NumFollowerActivationsRemaining = _followerActivationsRemainingToday; + for (auto& p : _plots) + { + Plot& plot = p.second; + garrisonInfo.Plots.push_back(&plot.PacketInfo); + if (plot.BuildingInfo.PacketInfo) + garrisonInfo.Buildings.push_back(plot.BuildingInfo.PacketInfo.get_ptr()); + } + + for (auto const& p : _followers) + garrisonInfo.Followers.push_back(&p.second.PacketInfo); + + _owner->SendDirectMessage(garrisonInfo.Write()); +} + +void Garrison::SendRemoteInfo() const +{ + MapEntry const* garrisonMap = sMapStore.LookupEntry(_siteLevel->MapID); + if (!garrisonMap || int32(_owner->GetMapId()) != garrisonMap->ParentMapID) + return; + + WorldPackets::Garrison::GarrisonRemoteInfo remoteInfo; + remoteInfo.Sites.resize(1); + + WorldPackets::Garrison::GarrisonRemoteSiteInfo& remoteSiteInfo = remoteInfo.Sites[0]; + remoteSiteInfo.GarrSiteLevelID = _siteLevel->ID; + for (auto const& p : _plots) + if (p.second.BuildingInfo.PacketInfo) + remoteSiteInfo.Buildings.emplace_back(p.first, p.second.BuildingInfo.PacketInfo->GarrBuildingID); + + _owner->SendDirectMessage(remoteInfo.Write()); +} + +void Garrison::SendBlueprintAndSpecializationData() +{ + WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationDataResult data; + data.BlueprintsKnown = &_knownBuildings; + _owner->SendDirectMessage(data.Write()); +} + +void Garrison::SendBuildingLandmarks(Player* receiver) const +{ + WorldPackets::Garrison::GarrisonBuildingLandmarks buildingLandmarks; + buildingLandmarks.Landmarks.reserve(_plots.size()); + + for (auto const& p : _plots) + { + Plot const& plot = p.second; + if (plot.BuildingInfo.PacketInfo) + if (uint32 garrBuildingPlotInstId = sGarrisonMgr.GetGarrBuildingPlotInst(plot.BuildingInfo.PacketInfo->GarrBuildingID, plot.GarrSiteLevelPlotInstId)) + buildingLandmarks.Landmarks.emplace_back(garrBuildingPlotInstId, plot.PacketInfo.PlotPos); + } + + receiver->SendDirectMessage(buildingLandmarks.Write()); +} + +Map* Garrison::FindMap() const +{ + return sMapMgr->FindMap(_siteLevel->MapID, _owner->GetGUID().GetCounter()); +} + +GarrisonError Garrison::CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const +{ + GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.LookupEntry(garrPlotInstanceId); + Plot const* plot = GetPlot(garrPlotInstanceId); + if (!plotInstance || !plot) + return GARRISON_ERROR_INVALID_PLOT; + + GarrBuildingEntry const* building = sGarrBuildingStore.LookupEntry(garrBuildingId); + if (!building) + return GARRISON_ERROR_INVALID_BUILDINGID; + + if (!sGarrisonMgr.IsPlotMatchingBuilding(plotInstance->GarrPlotID, garrBuildingId)) + return GARRISON_ERROR_INVALID_PLOT_BUILDING; + + // Cannot place buldings of higher level than garrison level + if (building->Level > _siteLevel->Level) + return GARRISON_ERROR_INVALID_BUILDINGID; + + if (building->Flags & GARRISON_BUILDING_FLAG_NEEDS_PLAN) + { + if (!_knownBuildings.count(garrBuildingId)) + return GARRISON_ERROR_BLUEPRINT_NOT_KNOWN; + } + else // Building is built as a quest reward + return GARRISON_ERROR_INVALID_BUILDINGID; + + // Check all plots to find if we already have this building + GarrBuildingEntry const* existingBuilding; + for (auto const& p : _plots) + { + if (p.second.BuildingInfo.PacketInfo) + { + existingBuilding = sGarrBuildingStore.AssertEntry(p.second.BuildingInfo.PacketInfo->GarrBuildingID); + if (existingBuilding->Type == building->Type) + if (p.first != garrPlotInstanceId || existingBuilding->Level + 1 != building->Level) // check if its an upgrade in same plot + return GARRISON_ERROR_BUILDING_EXISTS; + } + } + + if (!_owner->HasCurrency(building->CostCurrencyID, building->CostCurrencyAmount)) + return GARRISON_ERROR_NOT_ENOUGH_CURRENCY; + + if (!_owner->HasEnoughMoney(uint64(building->CostMoney) * GOLD)) + return GARRISON_ERROR_NOT_ENOUGH_GOLD; + + // New building cannot replace another building currently under construction + if (plot->BuildingInfo.PacketInfo) + if (!plot->BuildingInfo.PacketInfo->Active) + return GARRISON_ERROR_NO_BUILDING; + + return GARRISON_SUCCESS; +} + +GarrisonError Garrison::CheckBuildingRemoval(uint32 garrPlotInstanceId) const +{ + Plot const* plot = GetPlot(garrPlotInstanceId); + if (!plot) + return GARRISON_ERROR_INVALID_PLOT; + + if (!plot->BuildingInfo.PacketInfo) + return GARRISON_ERROR_NO_BUILDING; + + if (plot->BuildingInfo.CanActivate()) + return GARRISON_ERROR_BUILDING_EXISTS; + + return GARRISON_SUCCESS; +} + +GameObject* Garrison::Plot::CreateGameObject(Map* map, GarrisonFactionIndex faction) +{ + uint32 entry = EmptyGameObjectId; + if (BuildingInfo.PacketInfo) + { + GarrPlotInstanceEntry const* plotInstance = sGarrPlotInstanceStore.AssertEntry(PacketInfo.GarrPlotInstanceID); + GarrPlotEntry const* plot = sGarrPlotStore.AssertEntry(plotInstance->GarrPlotID); + GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(BuildingInfo.PacketInfo->GarrBuildingID); + if (BuildingInfo.PacketInfo->Active) + entry = faction == GARRISON_FACTION_INDEX_HORDE ? building->HordeGameObjectID : building->AllianceGameObjectID; + else + entry = faction == GARRISON_FACTION_INDEX_HORDE ? plot->HordeConstructionGameObjectID : plot->AllianceConstructionGameObjectID; + } + + if (!sObjectMgr->GetGameObjectTemplate(entry)) + { + TC_LOG_ERROR("garrison", "Garrison attempted to spawn gameobject whose template doesn't exist (%u)", entry); + return nullptr; + } + + Position const& pos = PacketInfo.PlotPos; + GameObject* go = new GameObject(); + if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, 0, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), + 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_ACTIVE)) + { + delete go; + return nullptr; + } + + BuildingInfo.Guid = go->GetGUID(); + return go; +} + +void Garrison::Plot::DeleteGameObject(Map* map) +{ + if (BuildingInfo.Guid.IsEmpty()) + return; + + if (GameObject* oldBuilding = map->GetGameObject(BuildingInfo.Guid)) + oldBuilding->Delete(); + + BuildingInfo.Guid.Clear(); +} + +void Garrison::Plot::ClearBuildingInfo(Player* owner) +{ + WorldPackets::Garrison::GarrisonPlotPlaced plotPlaced; + plotPlaced.PlotInfo = &PacketInfo; + owner->SendDirectMessage(plotPlaced.Write()); + + BuildingInfo.PacketInfo = boost::none; +} + +void Garrison::Plot::SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo, Player* owner) +{ + if (!BuildingInfo.PacketInfo) + { + WorldPackets::Garrison::GarrisonPlotRemoved plotRemoved; + plotRemoved.GarrPlotInstanceID = PacketInfo.GarrPlotInstanceID; + owner->SendDirectMessage(plotRemoved.Write()); + } + + BuildingInfo.PacketInfo = buildingInfo; +} + +bool Garrison::Building::CanActivate() const +{ + if (PacketInfo) + { + GarrBuildingEntry const* building = sGarrBuildingStore.AssertEntry(PacketInfo->GarrBuildingID); + if (PacketInfo->TimeBuilt + building->BuildDuration <= time(nullptr)) + return true; + } + + return false; +} + +uint32 Garrison::Follower::GetItemLevel() const +{ + return (PacketInfo.ItemLevelWeapon + PacketInfo.ItemLevelArmor) / 2; +} diff --git a/src/server/game/Garrison/Garrison.h b/src/server/game/Garrison/Garrison.h new file mode 100644 index 00000000000..71d67a1b6b5 --- /dev/null +++ b/src/server/game/Garrison/Garrison.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef Garrison_h__ +#define Garrison_h__ + +#include "Player.h" +#include "GarrisonPackets.h" + +enum GarrisonFactionIndex +{ + GARRISON_FACTION_INDEX_HORDE = 0, + GARRISON_FACTION_INDEX_ALLIANCE = 1 +}; + +enum GarrisonBuildingFlags +{ + GARRISON_BUILDING_FLAG_NEEDS_PLAN = 0x1 +}; + +enum GarrisonFollowerFlags +{ + GARRISON_FOLLOWER_FLAG_UNIQUE = 0x1 +}; + +enum GarrisonAbilityFlags +{ + GARRISON_ABILITY_FLAG_TRAIT = 0x01, + GARRISON_ABILITY_CANNOT_ROLL = 0x02, + GARRISON_ABILITY_HORDE_ONLY = 0x04, + GARRISON_ABILITY_ALLIANCE_ONLY = 0x08, + GARRISON_ABILITY_FLAG_CANNOT_REMOVE = 0x10, + GARRISON_ABILITY_FLAG_EXCLUSIVE = 0x20 +}; + +enum GarrisonError +{ + GARRISON_SUCCESS = 0, + GARRISON_ERROR_INVALID_PLOT = 1, + GARRISON_ERROR_INVALID_BUILDINGID = 2, + GARRISON_ERROR_INVALID_PLOT_BUILDING = 7, + GARRISON_ERROR_NO_BUILDING = 8, + GARRISON_ERROR_SPECIALIZATION_KNOWN = 19, + GARRISON_ERROR_BLUEPRINT_KNOWN = 21, + GARRISON_ERROR_BLUEPRINT_NOT_KNOWN = 22, + GARRISON_ERROR_BUILDING_EXISTS = 24, + GARRISON_ERROR_NOT_ENOUGH_CURRENCY = 46, + GARRISON_ERROR_NOT_ENOUGH_GOLD = 47, + + GARRISON_GENERIC_UNKNOWN_ERROR = 255 // custom value for packets whose handlers only check if error != 0 +}; + +enum GarrisonFollowerStatus +{ + FOLLOWER_STATUS_FAVORITE = 0x01, + FOLLOWER_STATUS_EXHAUSTED = 0x02, + FOLLOWER_STATUS_INACTIVE = 0x04 +}; + +class GameObject; +class Map; + +class Garrison +{ +public: + struct Building + { + bool CanActivate() const; + + ObjectGuid Guid; + Optional<WorldPackets::Garrison::GarrisonBuildingInfo> PacketInfo; + }; + + struct Plot + { + GameObject* CreateGameObject(Map* map, GarrisonFactionIndex faction); + void DeleteGameObject(Map* map); + void ClearBuildingInfo(Player* owner); + void SetBuildingInfo(WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo, Player* owner); + + WorldPackets::Garrison::GarrisonPlotInfo PacketInfo; + uint32 EmptyGameObjectId = 0; + uint32 GarrSiteLevelPlotInstId = 0; + Building BuildingInfo; + }; + + struct Follower + { + uint32 GetItemLevel() const; + + WorldPackets::Garrison::GarrisonFollower PacketInfo; + }; + + explicit Garrison(Player* owner); + + bool LoadFromDB(PreparedQueryResult garrison, PreparedQueryResult blueprints, PreparedQueryResult buildings, + PreparedQueryResult followers, PreparedQueryResult abilities); + void SaveToDB(SQLTransaction& trans); + + bool Create(uint32 garrSiteId); + void Upgrade(); + + void Enter() const; + void Leave() const; + + GarrisonFactionIndex GetFaction() const; + + // Plots + std::vector<Plot*> GetPlots(); + Plot* GetPlot(uint32 garrPlotInstanceId); + Plot const* GetPlot(uint32 garrPlotInstanceId) const; + + // Buildings + void LearnBlueprint(uint32 garrBuildingId); + void UnlearnBlueprint(uint32 garrBuildingId); + void PlaceBuilding(uint32 garrPlotInstanceId, uint32 garrBuildingId); + void CancelBuildingConstruction(uint32 garrPlotInstanceId); + + // Followers + void AddFollower(uint32 garrFollowerId); + Follower const* GetFollower(uint64 dbId) const; + + void SendInfo(); + void SendRemoteInfo() const; + void SendBlueprintAndSpecializationData(); + void SendBuildingLandmarks(Player* receiver) const; + + void ResetFollowerActivationLimit() { _followerActivationsRemainingToday = 1; } + +private: + Map* FindMap() const; + void InitializePlots(); + GarrisonError CheckBuildingPlacement(uint32 garrPlotInstanceId, uint32 garrBuildingId) const; + GarrisonError CheckBuildingRemoval(uint32 garrPlotInstanceId) const; + Player* _owner; + GarrSiteLevelEntry const* _siteLevel; + uint32 _followerActivationsRemainingToday; + + std::unordered_map<uint32 /*garrPlotInstanceId*/, Plot> _plots; + std::unordered_set<uint32 /*garrBuildingId*/> _knownBuildings; + std::unordered_map<uint64 /*dbId*/, Follower> _followers; + std::unordered_set<uint32> _followerIds; +}; + +#endif // Garrison_h__ diff --git a/src/server/game/Garrison/GarrisonMap.cpp b/src/server/game/Garrison/GarrisonMap.cpp new file mode 100644 index 00000000000..b9cf63140b4 --- /dev/null +++ b/src/server/game/Garrison/GarrisonMap.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "GarrisonMap.h" +#include "Garrison.h" +#include "ObjectAccessor.h" +#include "ObjectGridLoader.h" +#include "GameObject.h" + +class GarrisonGridLoader +{ +public: + GarrisonGridLoader(NGridType* grid, GarrisonMap* map, Cell const& cell) + : i_cell(cell), i_grid(grid), i_map(map), i_garrison(map->GetGarrison()), i_gameObjects(0), i_creatures(0) + { } + + void Visit(GameObjectMapType& m); + void Visit(CreatureMapType& m); + + void LoadN(); + + template<class T> static void SetObjectCell(T* obj, CellCoord const& cellCoord); + template<class T> void Visit(GridRefManager<T>& /*m*/) { } + +private: + Cell i_cell; + NGridType* i_grid; + GarrisonMap* i_map; + Garrison* i_garrison; + uint32 i_gameObjects; + uint32 i_creatures; +}; + +void GarrisonGridLoader::LoadN() +{ + if (i_garrison) + { + i_cell.data.Part.cell_y = 0; + for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x) + { + i_cell.data.Part.cell_x = x; + for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y) + { + i_cell.data.Part.cell_y = y; + + //Load creatures and game objects + TypeContainerVisitor<GarrisonGridLoader, GridTypeMapContainer> visitor(*this); + i_grid->VisitGrid(x, y, visitor); + } + } + } + + TC_LOG_DEBUG("maps", "%u GameObjects and %u Creatures loaded for grid %u on map %u", i_gameObjects, i_creatures, i_grid->GetGridId(), i_map->GetId()); +} + +void GarrisonGridLoader::Visit(GameObjectMapType& m) +{ + std::vector<Garrison::Plot*> plots = i_garrison->GetPlots(); + if (!plots.empty()) + { + CellCoord cellCoord = i_cell.GetCellCoord(); + for (Garrison::Plot* plot : plots) + { + Position const& spawn = plot->PacketInfo.PlotPos; + if (cellCoord != Trinity::ComputeCellCoord(spawn.GetPositionX(), spawn.GetPositionY())) + continue; + + GameObject* go = plot->CreateGameObject(i_map, i_garrison->GetFaction()); + if (!go) + continue; + + go->AddToGrid(m); + ObjectGridLoader::SetObjectCell(go, cellCoord); + go->AddToWorld(); + ++i_gameObjects; + } + } +} + +void GarrisonGridLoader::Visit(CreatureMapType& /*m*/) +{ + +} + +GarrisonMap::GarrisonMap(uint32 id, time_t expiry, uint32 instanceId, Map* parent, ObjectGuid const& owner) + : Map(id, expiry, instanceId, DIFFICULTY_NORMAL, parent), _owner(owner), _loadingPlayer(nullptr) +{ + GarrisonMap::InitVisibilityDistance(); +} + +void GarrisonMap::LoadGridObjects(NGridType* grid, Cell const& cell) +{ + Map::LoadGridObjects(grid, cell); + + GarrisonGridLoader loader(grid, this, cell); + loader.LoadN(); +} + +Garrison* GarrisonMap::GetGarrison() +{ + if (_loadingPlayer) + return _loadingPlayer->GetGarrison(); + + if (Player* owner = ObjectAccessor::FindConnectedPlayer(_owner)) + return owner->GetGarrison(); + + return nullptr; +} + +void GarrisonMap::InitVisibilityDistance() +{ + //init visibility distance for instances + m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas(); + m_VisibilityNotifyPeriod = World::GetVisibilityNotifyPeriodInBGArenas(); +} + +bool GarrisonMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) +{ + if (player->GetGUID() == _owner) + _loadingPlayer = player; + + bool result = Map::AddPlayerToMap(player, initPlayer); + + if (player->GetGUID() == _owner) + _loadingPlayer = nullptr; + + return result; +} diff --git a/src/server/game/Garrison/GarrisonMap.h b/src/server/game/Garrison/GarrisonMap.h new file mode 100644 index 00000000000..5f5c9b134b7 --- /dev/null +++ b/src/server/game/Garrison/GarrisonMap.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GarrisonMap_h__ +#define GarrisonMap_h__ + +#include "Map.h" + +class Garrison; +class Player; + +class GarrisonMap : public Map +{ +public: + GarrisonMap(uint32 id, time_t, uint32 instanceId, Map* parent, ObjectGuid const& owner); + + void LoadGridObjects(NGridType* grid, Cell const& cell) override; + Garrison* GetGarrison(); + + void InitVisibilityDistance() override; + + bool AddPlayerToMap(Player* player, bool initPlayer = true) override; + +private: + ObjectGuid _owner; + Player* _loadingPlayer; ///< @workaround Player is not registered in ObjectAccessor during login +}; + +#endif // GarrisonMap_h__ diff --git a/src/server/game/Garrison/GarrisonMgr.cpp b/src/server/game/Garrison/GarrisonMgr.cpp new file mode 100644 index 00000000000..f95acef952c --- /dev/null +++ b/src/server/game/Garrison/GarrisonMgr.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "GarrisonMgr.h" +#include "Containers.h" +#include "DatabaseEnv.h" +#include "Garrison.h" +#include "ObjectDefines.h" +#include "World.h" + +void GarrisonMgr::Initialize() +{ + for (GarrSiteLevelPlotInstEntry const* plotInstance : sGarrSiteLevelPlotInstStore) + _garrisonPlotInstBySiteLevel[plotInstance->GarrSiteLevelID].push_back(plotInstance); + + for (GameObjectsEntry const* gameObject : sGameObjectsStore) + if (gameObject->Type == GAMEOBJECT_TYPE_GARRISON_PLOT) + _garrisonPlots[gameObject->MapID][gameObject->Data[0]] = gameObject; + + for (GarrPlotBuildingEntry const* plotBuilding : sGarrPlotBuildingStore) + _garrisonBuildingsByPlot[plotBuilding->GarrPlotID].insert(plotBuilding->GarrBuildingID); + + for (GarrBuildingPlotInstEntry const* buildingPlotInst : sGarrBuildingPlotInstStore) + _garrisonBuildingPlotInstances[MAKE_PAIR64(buildingPlotInst->GarrBuildingID, buildingPlotInst->GarrSiteLevelPlotInstID)] = buildingPlotInst->ID; + + for (GarrBuildingEntry const* building : sGarrBuildingStore) + _garrisonBuildingsByType[building->Type].push_back(building); + + for (GarrFollowerXAbilityEntry const* followerAbility : sGarrFollowerXAbilityStore) + { + if (GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(followerAbility->GarrAbilityID)) + { + if (!(ability->Flags & GARRISON_ABILITY_CANNOT_ROLL) && ability->Flags & GARRISON_ABILITY_FLAG_TRAIT) + _garrisonFollowerRandomTraits.insert(ability); + + if (followerAbility->FactionIndex < 2) + { + if (ability->Flags & GARRISON_ABILITY_FLAG_TRAIT) + _garrisonFollowerAbilities[followerAbility->FactionIndex][followerAbility->GarrFollowerID].Traits.insert(ability); + else + _garrisonFollowerAbilities[followerAbility->FactionIndex][followerAbility->GarrFollowerID].Counters.insert(ability); + } + } + } + + InitializeDbIdSequences(); + LoadFollowerClassSpecAbilities(); +} + +GarrSiteLevelEntry const* GarrisonMgr::GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const +{ + for (GarrSiteLevelEntry const* garrSiteLevel : sGarrSiteLevelStore) + if (garrSiteLevel->SiteID == garrSiteId && garrSiteLevel->Level == level) + return garrSiteLevel; + + return nullptr; +} + +std::vector<GarrSiteLevelPlotInstEntry const*> const* GarrisonMgr::GetGarrPlotInstForSiteLevel(uint32 garrSiteLevelId) const +{ + auto itr = _garrisonPlotInstBySiteLevel.find(garrSiteLevelId); + if (itr != _garrisonPlotInstBySiteLevel.end()) + return &itr->second; + + return nullptr; +} + +GameObjectsEntry const* GarrisonMgr::GetPlotGameObject(uint32 mapId, uint32 garrPlotInstanceId) const +{ + auto mapItr = _garrisonPlots.find(mapId); + if (mapItr != _garrisonPlots.end()) + { + auto plotItr = mapItr->second.find(garrPlotInstanceId); + if (plotItr != mapItr->second.end()) + return plotItr->second; + } + + return nullptr; +} + +bool GarrisonMgr::IsPlotMatchingBuilding(uint32 garrPlotId, uint32 garrBuildingId) const +{ + auto plotItr = _garrisonBuildingsByPlot.find(garrPlotId); + if (plotItr != _garrisonBuildingsByPlot.end()) + return plotItr->second.count(garrBuildingId) > 0; + + return false; +} + +uint32 GarrisonMgr::GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const +{ + auto itr = _garrisonBuildingPlotInstances.find(MAKE_PAIR64(garrBuildingId, garrSiteLevelPlotInstId)); + if (itr != _garrisonBuildingPlotInstances.end()) + return itr->second; + + return 0; +} + +GarrBuildingEntry const* GarrisonMgr::GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const +{ + auto itr = _garrisonBuildingsByType.find(buildingType); + if (itr != _garrisonBuildingsByType.end()) + for (GarrBuildingEntry const* building : itr->second) + if (building->Level == currentLevel - 1) + return building; + + return nullptr; +} + +uint64 GarrisonMgr::GenerateFollowerDbId() +{ + if (_followerDbIdGenerator >= std::numeric_limits<uint64>::max()) + { + TC_LOG_ERROR("misc", "Garrison follower db id overflow! Can't continue, shutting down server. "); + World::StopNow(ERROR_EXIT_CODE); + } + + return _followerDbIdGenerator++; +} + +uint32 const AbilitiesForQuality[][2] = +{ + // Counters, Traits + { 0, 0 }, + { 1, 0 }, + { 1, 1 }, // Uncommon + { 1, 2 }, // Rare + { 2, 3 }, // Epic + { 2, 3 } // Legendary +}; + +std::list<GarrAbilityEntry const*> GarrisonMgr::RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const +{ + ASSERT(faction < 2); + + bool hasForcedExclusiveTrait = false; + std::list<GarrAbilityEntry const*> result; + int32 slots[2] = { AbilitiesForQuality[quality][0], AbilitiesForQuality[quality][1] }; + + GarrAbilities const* abilities = nullptr; + auto itr = _garrisonFollowerAbilities[faction].find(follower->ID); + if (itr != _garrisonFollowerAbilities[faction].end()) + abilities = &itr->second; + + std::list<GarrAbilityEntry const*> abilityList, forcedAbilities, traitList, forcedTraits; + if (abilities) + { + for (GarrAbilityEntry const* ability : abilities->Counters) + { + if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE) + continue; + else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE) + continue; + + if (ability->Flags & GARRISON_ABILITY_FLAG_CANNOT_REMOVE) + forcedAbilities.push_back(ability); + else + abilityList.push_back(ability); + } + + for (GarrAbilityEntry const* ability : abilities->Traits) + { + if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE) + continue; + else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE) + continue; + + if (ability->Flags & GARRISON_ABILITY_FLAG_CANNOT_REMOVE) + forcedTraits.push_back(ability); + else + traitList.push_back(ability); + } + } + + Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size())); + Trinity::Containers::RandomResizeList(traitList, std::max<int32>(0, slots[1] - forcedTraits.size())); + + // Add abilities specified in GarrFollowerXAbility.db2 before generic classspec ones on follower creation + if (initial) + { + forcedAbilities.splice(forcedAbilities.end(), abilityList); + forcedTraits.splice(forcedTraits.end(), traitList); + } + + forcedAbilities.sort(); + abilityList.sort(); + forcedTraits.sort(); + traitList.sort(); + + // check if we have a trait from exclusive category + for (GarrAbilityEntry const* ability : forcedTraits) + { + if (ability->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + { + hasForcedExclusiveTrait = true; + break; + } + } + + if (slots[0] > forcedAbilities.size() + abilityList.size()) + { + std::list<GarrAbilityEntry const*> classSpecAbilities = GetClassSpecAbilities(follower, faction); + std::list<GarrAbilityEntry const*> classSpecAbilitiesTemp, classSpecAbilitiesTemp2; + classSpecAbilitiesTemp2.swap(abilityList); + std::set_difference(classSpecAbilities.begin(), classSpecAbilities.end(), forcedAbilities.begin(), forcedAbilities.end(), std::back_inserter(classSpecAbilitiesTemp)); + std::set_union(classSpecAbilitiesTemp.begin(), classSpecAbilitiesTemp.end(), classSpecAbilitiesTemp2.begin(), classSpecAbilitiesTemp2.end(), std::back_inserter(abilityList)); + + Trinity::Containers::RandomResizeList(abilityList, std::max<int32>(0, slots[0] - forcedAbilities.size())); + } + + if (slots[1] > forcedTraits.size() + traitList.size()) + { + std::list<GarrAbilityEntry const*> genericTraits, genericTraitsTemp; + for (GarrAbilityEntry const* ability : _garrisonFollowerRandomTraits) + { + if (ability->Flags & GARRISON_ABILITY_HORDE_ONLY && faction != GARRISON_FACTION_INDEX_HORDE) + continue; + else if (ability->Flags & GARRISON_ABILITY_ALLIANCE_ONLY && faction != GARRISON_FACTION_INDEX_ALLIANCE) + continue; + + // forced exclusive trait exists, skip other ones entirely + if (hasForcedExclusiveTrait && ability->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + continue; + + genericTraitsTemp.push_back(ability); + } + + std::set_difference(genericTraitsTemp.begin(), genericTraitsTemp.end(), forcedTraits.begin(), forcedTraits.end(), std::back_inserter(genericTraits)); + genericTraits.splice(genericTraits.begin(), traitList); + // "split" the list into two parts [nonexclusive, exclusive] to make selection later easier + genericTraits.sort([](GarrAbilityEntry const* a1, GarrAbilityEntry const* a2) + { + uint32 e1 = a1->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE; + uint32 e2 = a2->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE; + if (e1 != e2) + return e1 < e2; + + return a1->ID < a2->ID; + }); + genericTraits.unique(); + + std::size_t firstExclusive = 0, total = genericTraits.size(); + for (auto itr = genericTraits.begin(); itr != genericTraits.end(); ++itr, ++firstExclusive) + if ((*itr)->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + break; + + while (traitList.size() < std::max<int32>(0, slots[1] - forcedTraits.size()) && total) + { + auto itr = genericTraits.begin(); + std::advance(itr, urand(0, total-- - 1)); + if ((*itr)->Flags & GARRISON_ABILITY_FLAG_EXCLUSIVE) + total = firstExclusive; // selected exclusive trait - no other can be selected now + else + --firstExclusive; + + traitList.push_back(*itr); + genericTraits.erase(itr); + } + } + + result.splice(result.end(), forcedAbilities); + result.splice(result.end(), abilityList); + result.splice(result.end(), forcedTraits); + result.splice(result.end(), traitList); + + return result; +} + +std::list<GarrAbilityEntry const*> GarrisonMgr::GetClassSpecAbilities(GarrFollowerEntry const* follower, uint32 faction) const +{ + std::list<GarrAbilityEntry const*> abilities; + uint32 classSpecId; + switch (faction) + { + case GARRISON_FACTION_INDEX_HORDE: + classSpecId = follower->HordeGarrClassSpecID; + break; + case GARRISON_FACTION_INDEX_ALLIANCE: + classSpecId = follower->AllianceGarrClassSpecID; + break; + default: + return abilities; + } + + if (!sGarrClassSpecStore.LookupEntry(classSpecId)) + return abilities; + + auto itr = _garrisonFollowerClassSpecAbilities.find(classSpecId); + if (itr != _garrisonFollowerClassSpecAbilities.end()) + abilities = itr->second; + + return abilities; +} + +void GarrisonMgr::InitializeDbIdSequences() +{ + if (QueryResult result = CharacterDatabase.Query("SELECT MAX(dbId) FROM character_garrison_followers")) + _followerDbIdGenerator = (*result)[0].GetUInt64() + 1; +} + +void GarrisonMgr::LoadFollowerClassSpecAbilities() +{ + QueryResult result = WorldDatabase.Query("SELECT classSpecId, abilityId FROM garrison_follower_class_spec_abilities"); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 garrison follower class spec abilities. DB table `garrison_follower_class_spec_abilities` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + uint32 classSpecId = fields[0].GetUInt32(); + uint32 abilityId = fields[1].GetUInt32(); + + if (!sGarrClassSpecStore.LookupEntry(classSpecId)) + { + TC_LOG_ERROR("sql.sql", "Non-existing GarrClassSpec.db2 entry %u was referenced in `garrison_follower_class_spec_abilities` by row (%u, %u).", classSpecId, classSpecId, abilityId); + continue; + } + + GarrAbilityEntry const* ability = sGarrAbilityStore.LookupEntry(abilityId); + if (!ability) + { + TC_LOG_ERROR("sql.sql", "Non-existing GarrAbility.db2 entry %u was referenced in `garrison_follower_class_spec_abilities` by row (%u, %u).", abilityId, classSpecId, abilityId); + continue; + } + + _garrisonFollowerClassSpecAbilities[classSpecId].push_back(ability); + ++count; + + } while (result->NextRow()); + + for (auto& pair : _garrisonFollowerClassSpecAbilities) + pair.second.sort(); + + TC_LOG_INFO("server.loading", ">> Loaded %u garrison follower class spec abilities.", count); +} diff --git a/src/server/game/Garrison/GarrisonMgr.h b/src/server/game/Garrison/GarrisonMgr.h new file mode 100644 index 00000000000..63810e3c3ab --- /dev/null +++ b/src/server/game/Garrison/GarrisonMgr.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GarrisonMgr_h__ +#define GarrisonMgr_h__ + +#include "DB2Stores.h" +#include <unordered_set> + +struct GarrAbilities +{ + std::unordered_set<GarrAbilityEntry const*> Counters; + std::unordered_set<GarrAbilityEntry const*> Traits; +}; + +class GarrisonMgr +{ +public: + static GarrisonMgr& Instance() + { + static GarrisonMgr instance; + return instance; + } + + void Initialize(); + + GarrSiteLevelEntry const* GetGarrSiteLevelEntry(uint32 garrSiteId, uint32 level) const; + std::vector<GarrSiteLevelPlotInstEntry const*> const* GetGarrPlotInstForSiteLevel(uint32 garrSiteLevelId) const; + GameObjectsEntry const* GetPlotGameObject(uint32 mapId, uint32 garrPlotInstanceId) const; + bool IsPlotMatchingBuilding(uint32 garrPlotId, uint32 garrBuildingId) const; + uint32 GetGarrBuildingPlotInst(uint32 garrBuildingId, uint32 garrSiteLevelPlotInstId) const; + GarrBuildingEntry const* GetPreviousLevelBuilding(uint32 buildingType, uint32 currentLevel) const; + uint64 GenerateFollowerDbId(); + std::list<GarrAbilityEntry const*> RollFollowerAbilities(GarrFollowerEntry const* follower, uint32 quality, uint32 faction, bool initial) const; + std::list<GarrAbilityEntry const*> GetClassSpecAbilities(GarrFollowerEntry const* follower, uint32 faction) const; + +private: + void InitializeDbIdSequences(); + void LoadFollowerClassSpecAbilities(); + + std::unordered_map<uint32 /*garrSiteId*/, std::vector<GarrSiteLevelPlotInstEntry const*>> _garrisonPlotInstBySiteLevel; + std::unordered_map<uint32 /*mapId*/, std::unordered_map<uint32 /*garrPlotId*/, GameObjectsEntry const*>> _garrisonPlots; + std::unordered_map<uint32 /*garrPlotId*/, std::unordered_set<uint32/*garrBuildingId*/>> _garrisonBuildingsByPlot; + std::unordered_map<uint64 /*garrBuildingId | garrSiteLevelPlotInstId << 32*/, uint32 /*garrBuildingPlotInstId*/> _garrisonBuildingPlotInstances; + std::unordered_map<uint32 /*buildingType*/, std::vector<GarrBuildingEntry const*>> _garrisonBuildingsByType; + std::unordered_map<uint32 /*garrFollowerId*/, GarrAbilities> _garrisonFollowerAbilities[2]; + std::unordered_map<uint32 /*classSpecId*/, std::list<GarrAbilityEntry const*>> _garrisonFollowerClassSpecAbilities; + std::set<GarrAbilityEntry const*> _garrisonFollowerRandomTraits; + + uint64 _followerDbIdGenerator = UI64LIT(1); +}; + +#define sGarrisonMgr GarrisonMgr::Instance() + +#endif // GarrisonMgr_h__ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 6beae09bb20..fa52653811f 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -474,7 +474,7 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.expansion = fields[17].GetInt16(); creatureTemplate.expansionUnknown = fields[18].GetUInt16(); creatureTemplate.faction = fields[19].GetUInt16(); - creatureTemplate.npcflag = fields[20].GetUInt32(); + creatureTemplate.npcflag = fields[20].GetUInt64(); creatureTemplate.speed_walk = fields[21].GetFloat(); creatureTemplate.speed_run = fields[22].GetFloat(); creatureTemplate.scale = fields[23].GetFloat(); @@ -678,9 +678,9 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) if (cInfo->npcflag != difficultyInfo->npcflag) { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, `npcflag`: %u) has different `npcflag` in difficulty %u mode (Entry: %u, `npcflag`: %u).", + TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, `npcflag`: " UI64FMTD ") has different `npcflag` in difficulty %u mode (Entry: %u, `npcflag`: " UI64FMTD ").", cInfo->Entry, cInfo->npcflag, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->npcflag); - TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `npcflag`=%u WHERE `entry`=%u;", + TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `npcflag`=" UI64FMTD " WHERE `entry`=%u;", cInfo->npcflag, cInfo->DifficultyEntry[diff]); continue; } @@ -1171,7 +1171,7 @@ void ObjectMgr::LoadEquipmentTemplates() uint32 oldMSTime = getMSTime(); // 0 1 2 3 4 - QueryResult result = WorldDatabase.Query("SELECT entry, id, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template"); + QueryResult result = WorldDatabase.Query("SELECT CreatureID, ID, ItemID1, ItemID2, ItemID3 FROM creature_equip_template"); if (!result) { @@ -1188,7 +1188,7 @@ void ObjectMgr::LoadEquipmentTemplates() if (!sObjectMgr->GetCreatureTemplate(entry)) { - TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_equip_template`", entry); + TC_LOG_ERROR("sql.sql", "Creature template (CreatureID: %u) does not exist but has a record in `creature_equip_template`", entry); continue; } @@ -1214,7 +1214,7 @@ void ObjectMgr::LoadEquipmentTemplates() if (!dbcItem) { - TC_LOG_ERROR("sql.sql", "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id=%u, forced to 0.", + TC_LOG_ERROR("sql.sql", "Unknown item (ID=%u) in creature_equip_template.ItemID%u for CreatureID = %u and ID=%u, forced to 0.", equipmentInfo.ItemEntry[i], i+1, entry, id); equipmentInfo.ItemEntry[i] = 0; continue; @@ -1230,7 +1230,7 @@ void ObjectMgr::LoadEquipmentTemplates() dbcItem->InventoryType != INVTYPE_THROWN && dbcItem->InventoryType != INVTYPE_RANGEDRIGHT) { - TC_LOG_ERROR("sql.sql", "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id = %u is not equipable in a hand, forced to 0.", + TC_LOG_ERROR("sql.sql", "Item (ID=%u) in creature_equip_template.ItemID%u for CreatureID = %u and ID = %u is not equipable in a hand, forced to 0.", equipmentInfo.ItemEntry[i], i+1, entry, id); equipmentInfo.ItemEntry[i] = 0; } @@ -1261,7 +1261,7 @@ uint32 ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData co return cinfo->GetRandomValidModelId(); } -void ObjectMgr::ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data /*= NULL*/) +void ObjectMgr::ChooseCreatureFlags(CreatureTemplate const* cinfo, uint64& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data /*= NULL*/) { npcflag = cinfo->npcflag; unit_flags = cinfo->unit_flags; @@ -1743,11 +1743,11 @@ void ObjectMgr::LoadCreatures() data.spawnMask = fields[15].GetUInt32(); int16 gameEvent = fields[16].GetInt8(); uint32 PoolId = fields[17].GetUInt32(); - data.npcflag = fields[18].GetUInt32(); + data.npcflag = fields[18].GetUInt64(); data.unit_flags = fields[19].GetUInt32(); data.dynamicflags = fields[20].GetUInt32(); - data.phaseid = fields[21].GetUInt32(); - data.phaseGroup = fields[22].GetUInt32(); + data.phaseid = fields[21].GetUInt32(); + data.phaseGroup = fields[22].GetUInt32(); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); if (!mapEntry) @@ -1825,6 +1825,25 @@ void ObjectMgr::LoadCreatures() data.phaseGroup = 0; } + if (data.phaseid) + { + PhaseEntry const* phase = sPhaseStore.LookupEntry(data.phaseid); + if (!phase) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `phaseid` %u does not exist, set to 0", guid, data.id, data.phaseid); + data.phaseid = 0; + } + } + + if (data.phaseGroup) + { + if (sDB2Manager.GetPhasesForGroup(data.phaseGroup).empty()) + { + TC_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: " UI64FMTD " Entry: %u) with `phasegroup` %u does not exist, set to 0", guid, data.id, data.phaseGroup); + data.phaseGroup = 0; + } + } + if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA)) { uint32 zoneId = 0; @@ -2084,8 +2103,8 @@ void ObjectMgr::LoadGameobjects() int16 gameEvent = fields[15].GetInt8(); uint32 PoolId = fields[16].GetUInt32(); - data.phaseid = fields[17].GetUInt32(); - data.phaseGroup = fields[18].GetUInt32(); + data.phaseid = fields[17].GetUInt32(); + data.phaseGroup = fields[18].GetUInt32(); if (data.phaseGroup && data.phaseid) { @@ -2093,6 +2112,25 @@ void ObjectMgr::LoadGameobjects() data.phaseGroup = 0; } + if (data.phaseid) + { + PhaseEntry const* phase = sPhaseStore.LookupEntry(data.phaseid); + if (!phase) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `phaseid` %u does not exist, set to 0", guid, data.id, data.phaseid); + data.phaseid = 0; + } + } + + if (data.phaseGroup) + { + if (sDB2Manager.GetPhasesForGroup(data.phaseGroup).empty()) + { + TC_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: " UI64FMTD " Entry: %u) with `phaseGroup` %u does not exist, set to 0", guid, data.id, data.phaseGroup); + data.phaseGroup = 0; + } + } + if (std::abs(data.orientation) > 2 * float(M_PI)) { TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u) with abs(`orientation`) > 2*PI (orientation is expressed in radians), normalized.", guid, data.id); @@ -2204,6 +2242,25 @@ bool ObjectMgr::GetPlayerNameByGUID(ObjectGuid const& guid, std::string& name) return false; } +bool ObjectMgr::GetPlayerNameAndClassByGUID(ObjectGuid const& guid, std::string& name, uint8& _class) +{ + if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) + { + name = player->GetName(); + _class = player->getClass(); + return true; + } + + if (CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(guid)) + { + name = characterInfo->Name; + _class = characterInfo->Class; + return true; + } + + return false; +} + uint32 ObjectMgr::GetPlayerTeamByGUID(ObjectGuid const& guid) { if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) @@ -2328,7 +2385,7 @@ void FillDisenchantFields(uint32* disenchantID, uint32* requiredDisenchantSkill, { *disenchantID = 0; *(int32*)requiredDisenchantSkill = -1; - if ((itemTemplate.GetFlags() & (ITEM_PROTO_FLAG_CONJURED | ITEM_PROTO_FLAG_UNK6)) || + if ((itemTemplate.GetFlags() & (ITEM_FLAG_CONJURED | ITEM_FLAG_UNK6)) || itemTemplate.GetBonding() == BIND_QUEST_ITEM || itemTemplate.GetArea() || itemTemplate.GetMap() || itemTemplate.GetMaxStackSize() > 1 || itemTemplate.GetQuality() < ITEM_QUALITY_UNCOMMON || itemTemplate.GetQuality() > ITEM_QUALITY_EPIC || @@ -3582,10 +3639,10 @@ void ObjectMgr::LoadQuests() mExclusiveQuestGroups.clear(); QueryResult result = WorldDatabase.Query("SELECT " - //0 1 2 3 4 5 6 7 8 9 10 11 12 - "ID, QuestType, QuestLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, Float10, RewardMoney, RewardMoneyDifficulty, " - //13 14 15 16 17 18 19 20 21 - "Float13, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor, RewardKillHonor, StartItem, Flags, FlagsEx, " + //0 1 2 3 4 5 6 7 8 9 10 + "ID, QuestType, QuestLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, RewardXPMultiplier, " + //11 12 13 14 15 16 17 18 19 20 21 + "RewardMoney, RewardMoneyDifficulty, Float13, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor, RewardKillHonor, StartItem, Flags, FlagsEx, " //22 23 24 25 26 27 28 29 "RewardItem1, RewardAmount1, ItemDrop1, ItemDropQuantity1, RewardItem2, RewardAmount2, ItemDrop2, ItemDropQuantity2, " //30 31 32 33 34 35 36 37 @@ -5236,14 +5293,8 @@ void ObjectMgr::LoadNPCText() uint32 oldMSTime = getMSTime(); QueryResult result = WorldDatabase.Query("SELECT ID, " - "BroadcastTextID0, Probability0, " - "BroadcastTextID1, Probability1, " - "BroadcastTextID2, Probability2, " - "BroadcastTextID3, Probability3, " - "BroadcastTextID4, Probability4, " - "BroadcastTextID5, Probability5, " - "BroadcastTextID6, Probability6, " - "BroadcastTextID7, Probability7" + "Probability0, Probability1, Probability2, Probability3, Probability4, Probability5, Probability6, Probability7, " + "BroadcastTextID0, BroadcastTextID1, BroadcastTextID2, BroadcastTextID3, BroadcastTextID4, BroadcastTextID5, BroadcastTextID6, BroadcastTextID7" " FROM npc_text"); if (!result) { @@ -5268,27 +5319,30 @@ void ObjectMgr::LoadNPCText() for (uint8 i = 0; i < MAX_NPC_TEXT_OPTIONS; ++i) { - npcText.Data[i].BroadcastTextID = fields[1 + i].GetUInt32(); - npcText.Data[i].Probability = fields[1 + i * 2].GetFloat(); + npcText.Data[i].Probability = fields[1 + i].GetFloat(); + npcText.Data[i].BroadcastTextID = fields[9 + i].GetUInt32(); } - bool isValid = false; for (uint8 i = 0; i < MAX_NPC_TEXT_OPTIONS; i++) { if (npcText.Data[i].BroadcastTextID) { if (!sBroadcastTextStore.LookupEntry(npcText.Data[i].BroadcastTextID)) { - TC_LOG_ERROR("sql.sql", "NpcText (Id: %u) in table `npc_text` has non-existing or incompatible Index: %u BroadcastTextID %u.", textID, i, npcText.Data[i].BroadcastTextID); + TC_LOG_ERROR("sql.sql", "NPCText (ID: %u) has a non-existing or incompatible BroadcastText (ID: %u, Index: %u)", textID, npcText.Data[i].BroadcastTextID, i); npcText.Data[i].BroadcastTextID = 0; } - else - isValid = true; } } - if (!isValid) - TC_LOG_ERROR("sql.sql", "NpcText (Id: %u) in table `npc_text` is invalid", textID); + for (uint8 i = 0; i < MAX_NPC_TEXT_OPTIONS; i++) + { + if (npcText.Data[i].Probability > 0 && npcText.Data[i].BroadcastTextID == 0) + { + TC_LOG_ERROR("sql.sql", "NPCText (ID: %u) has a probability (Index: %u) set, but no BroadcastTextID to go with it", textID, i); + npcText.Data[i].Probability = 0; + } + } } while (result->NextRow()); @@ -6421,6 +6475,22 @@ void ObjectMgr::LoadGameObjectTemplate() { uint32 oldMSTime = getMSTime(); + for (GameObjectsEntry const* db2go : sGameObjectsStore) + { + GameObjectTemplate& go = _gameObjectTemplateStore[db2go->ID]; + go.entry = db2go->ID; + go.type = db2go->Type; + go.displayId = db2go->DisplayID; + go.name = db2go->Name->Str[sWorld->GetDefaultDbcLocale()]; + go.faction = 0; + go.flags = 0; + go.size = db2go->Size; + memset(go.raw.data, 0, sizeof(go.raw.data)); + memcpy(go.raw.data, db2go->Data, std::min(sizeof(db2go->Data), sizeof(go.raw.data))); + go.unkInt32 = 0; + go.ScriptId = 0; + } + // 0 1 2 3 4 5 6 7 8 9 QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, faction, flags, size, " // 10 11 12 13 14 15 16 17 18 19 20 21 22 @@ -7075,6 +7145,9 @@ void ObjectMgr::LoadQuestPOI() int32 PlayerConditionID = fields[12].GetInt32(); int32 WoDUnk1 = fields[13].GetInt32(); + if (!sObjectMgr->GetQuestTemplate(QuestID)) + TC_LOG_ERROR("sql.sql", "`quest_poi` quest id (%u) Idx1 (%u) does not exist in `quest_template`", QuestID, Idx1); + QuestPOI POI(BlobIndex, ObjectiveIndex, QuestObjectiveID, QuestObjectID, MapID, WorldMapAreaId, Floor, Priority, Flags, WorldEffectID, PlayerConditionID, WoDUnk1); if (QuestID < int32(POIs.size()) && Idx1 < int32(POIs[QuestID].size())) { @@ -8198,7 +8271,7 @@ void ObjectMgr::LoadGossipMenuItems() gMenuItem.OptionText = fields[3].GetString(); gMenuItem.OptionBroadcastTextId = fields[4].GetUInt32(); gMenuItem.OptionType = fields[5].GetUInt8(); - gMenuItem.OptionNpcflag = fields[6].GetUInt32(); + gMenuItem.OptionNpcflag = fields[6].GetUInt64(); gMenuItem.ActionMenuId = fields[7].GetUInt32(); gMenuItem.ActionPoiId = fields[8].GetUInt32(); gMenuItem.BoxCoded = fields[9].GetBool(); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index d55492ac0f1..4277ab74048 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -510,7 +510,7 @@ struct GossipMenuItems std::string OptionText; uint32 OptionBroadcastTextId; uint32 OptionType; - uint32 OptionNpcflag; + uint64 OptionNpcflag; uint32 ActionMenuId; uint32 ActionPoiId; bool BoxCoded; @@ -728,7 +728,7 @@ class ObjectMgr CreatureModelInfo const* GetCreatureModelInfo(uint32 modelId); CreatureModelInfo const* GetCreatureModelRandomGender(uint32* displayID); static uint32 ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = NULL); - static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL); + static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint64& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL); EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id); CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid); GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid); @@ -780,6 +780,7 @@ class ObjectMgr * @return true if player was found, false otherwise */ static bool GetPlayerNameByGUID(ObjectGuid const& guid, std::string& name); + static bool GetPlayerNameAndClassByGUID(ObjectGuid const& guid, std::string& name, uint8& _class); static uint32 GetPlayerTeamByGUID(ObjectGuid const& guid); static uint32 GetPlayerAccountIdByGUID(ObjectGuid const& guid); static uint32 GetPlayerAccountIdByPlayerName(std::string const& name); @@ -1364,7 +1365,7 @@ class ObjectMgr { auto itr = _guidGenerators.find(high); if (itr == _guidGenerators.end()) - itr = _guidGenerators.insert(std::make_pair(high, std::unique_ptr<ObjectGuidGenerator<high>>(new ObjectGuidGenerator<high>()))).first; + itr = _guidGenerators.insert(std::make_pair(high, Trinity::make_unique<ObjectGuidGenerator<high>>())).first; return *itr->second; } diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 8a5386684bb..aea2d8ec383 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -736,18 +736,6 @@ namespace Trinity NearestGameObjectTypeInObjectRangeCheck(NearestGameObjectTypeInObjectRangeCheck const&); }; - class GameObjectWithDbGUIDCheck - { - public: - GameObjectWithDbGUIDCheck(WorldObject const& /*obj*/, ObjectGuid::LowType db_guid) : i_db_guid(db_guid) { } - bool operator()(GameObject const* go) const - { - return go->GetSpawnId() == i_db_guid; - } - private: - ObjectGuid::LowType i_db_guid; - }; - // Unit checks class MostHPMissingInRange @@ -849,18 +837,6 @@ namespace Trinity float i_range; }; - class CreatureWithDbGUIDCheck - { - public: - CreatureWithDbGUIDCheck(WorldObject const* /*obj*/, ObjectGuid::LowType lowguid) : i_lowguid(lowguid) { } - bool operator()(Creature* u) - { - return u->GetSpawnId() == i_lowguid; - } - private: - ObjectGuid::LowType i_lowguid; - }; - class AnyFriendlyUnitInObjectRangeCheck { public: diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index c73aeb3a719..fadf7e1970e 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -21,6 +21,7 @@ #include "WorldPacket.h" #include "WorldSession.h" #include "Player.h" +#include "Pet.h" #include "World.h" #include "ObjectMgr.h" #include "GroupMgr.h" @@ -35,6 +36,7 @@ #include "Util.h" #include "LFGMgr.h" #include "UpdateFieldFlags.h" +#include "PartyPackets.h" Roll::Roll(ObjectGuid _guid, LootItem const& li) : itemGUID(_guid), itemid(li.itemid), itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), itemCount(li.count), @@ -55,11 +57,15 @@ Loot* Roll::getLoot() Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(DIFFICULTY_NORMAL), m_raidDifficulty(DIFFICULTY_NORMAL_RAID), m_legacyRaidDifficulty(DIFFICULTY_10_N), -m_bgGroup(NULL), m_bfGroup(NULL), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), -m_masterLooterGuid(), m_subGroupsCounts(NULL), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0) +m_bgGroup(nullptr), m_bfGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), +m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), +m_readyCheckStarted(false), m_readyCheckTimer(0), m_activeMarkers(0) { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; ++i) + m_markers[i] = nullptr; } Group::~Group() @@ -176,7 +182,7 @@ void Group::LoadGroupFromDB(Field* fields) m_looterGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt64()); m_lootThreshold = ItemQualities(fields[3].GetUInt8()); - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].SetRawValue(fields[4 + i].GetBinary()); m_groupType = GroupType(fields[12].GetUInt8()); @@ -199,7 +205,7 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin member.guid = ObjectGuid::Create<HighGuid::Player>(guidLow); // skip non-existed member - if (!ObjectMgr::GetPlayerNameByGUID(member.guid, member.name)) + if (!ObjectMgr::GetPlayerNameAndClassByGUID(member.guid, member.name, member._class)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); stmt->setUInt64(0, guidLow); @@ -207,9 +213,10 @@ void Group::LoadMemberFromDB(ObjectGuid::LowType guidLow, uint8 memberFlags, uin return; } - member.group = subgroup; - member.flags = memberFlags; - member.roles = roles; + member.group = subgroup; + member.flags = memberFlags; + member.roles = roles; + member.readyChecked = false; m_memberSlots.push_back(member); @@ -368,7 +375,7 @@ bool Group::AddMember(Player* player) bool groupFound = false; for (; subGroup < MAX_RAID_SUBGROUPS; ++subGroup) { - if (m_subGroupsCounts[subGroup] < MAXGROUPSIZE) + if (m_subGroupsCounts[subGroup] < MAX_GROUP_SIZE) { groupFound = true; break; @@ -380,11 +387,13 @@ bool Group::AddMember(Player* player) } MemberSlot member; - member.guid = player->GetGUID(); - member.name = player->GetName(); - member.group = subGroup; - member.flags = 0; - member.roles = 0; + member.guid = player->GetGUID(); + member.name = player->GetName(); + member._class = player->getClass(); + member.group = subGroup; + member.flags = 0; + member.roles = 0; + member.readyChecked = false; m_memberSlots.push_back(member); SubGroupCounterIncrease(subGroup); @@ -407,7 +416,7 @@ bool Group::AddMember(Player* player) if (!isRaidGroup()) // reset targetIcons for non-raid-groups { - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); } @@ -455,7 +464,11 @@ bool Group::AddMember(Player* player) } } } + player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); + if (Pet* pet = player->GetPet()) + pet->SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL); + UpdatePlayerOutOfRange(player); // quest related GO state dependent from raid membership @@ -552,12 +565,6 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R player->GetSession()->SendPacket(&data); } - // Do we really need to send this opcode? - data.Initialize(SMSG_PARTY_UPDATE, 1+1+1+1+8+4+4+8); - data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0); - data << m_guid << uint32(m_counter) << uint32(0) << uint64(0); - player->GetSession()->SendPacket(&data); - _homebindIfInstance(player); } @@ -644,7 +651,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R } } -void Group::ChangeLeader(ObjectGuid newLeaderGuid) +void Group::ChangeLeader(ObjectGuid newLeaderGuid, int8 partyIndex) { member_witerator slot = _getMemberWSlot(newLeaderGuid); @@ -707,9 +714,10 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid) m_leaderName = newLeader->GetName(); ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, false); - WorldPacket data(SMSG_GROUP_NEW_LEADER, m_leaderName.size()+1); - data << slot->name; - BroadcastPacket(&data, true); + WorldPackets::Party::GroupNewLeader groupNewLeader; + groupNewLeader.Name = m_leaderName; + groupNewLeader.PartyIndex = partyIndex; + BroadcastPacket(groupNewLeader.Write(), true); } void Group::Disband(bool hideDestroy /* = false */) @@ -1136,7 +1144,7 @@ void Group::NeedBeforeGreed(Loot* loot, WorldObject* lootedObject) if (item->DisenchantID && m_maxEnchantingLevel >= item->RequiredDisenchantSkill) r->rollVoteMask |= ROLL_FLAG_TYPE_DISENCHANT; - if (item->GetFlags2() & ITEM_FLAGS_EXTRA_NEED_ROLL_DISABLED) + if (item->GetFlags2() & ITEM_FLAG2_NEED_ROLL_DISABLED) r->rollVoteMask &= ~ROLL_FLAG_TYPE_NEED; loot->items[itemSlot].is_blocked = true; @@ -1491,45 +1499,38 @@ void Group::CountTheRoll(Rolls::iterator rollI) delete roll; } -void Group::SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid) +void Group::SetTargetIcon(uint8 symbol, ObjectGuid target, ObjectGuid changedBy, uint8 partyIndex) { - if (id >= TARGETICONCOUNT) + if (symbol >= TARGET_ICONS_COUNT) return; // clean other icons - if (!targetGuid.IsEmpty()) - for (int i = 0; i < TARGETICONCOUNT; ++i) - if (m_targetIcons[i] == targetGuid) - SetTargetIcon(i, ObjectGuid::Empty, ObjectGuid::Empty); + if (!target.IsEmpty()) + for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) + if (m_targetIcons[i] == target) + SetTargetIcon(i, ObjectGuid::Empty, changedBy, partyIndex); - m_targetIcons[id] = targetGuid; + m_targetIcons[symbol] = target; - WorldPacket data(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, (1+8+1+8)); - data << uint8(0); // set targets - data << whoGuid; - data << uint8(id); - data << targetGuid; - BroadcastPacket(&data, true); + WorldPackets::Party::SendRaidTargetUpdateSingle updateSingle; + updateSingle.PartyIndex = partyIndex; + updateSingle.Target = target; + updateSingle.ChangedBy = changedBy; + updateSingle.Symbol = symbol; + BroadcastPacket(updateSingle.Write(), true); } -void Group::SendTargetIconList(WorldSession* session) +void Group::SendTargetIconList(WorldSession* session, int8 partyIndex) { if (!session) return; - WorldPacket data(SMSG_SEND_RAID_TARGET_UPDATE_ALL, (1+TARGETICONCOUNT*9)); - data << uint8(1); // list targets + WorldPackets::Party::SendRaidTargetUpdateAll updateAll; + updateAll.PartyIndex = partyIndex; + for (uint8 i = 0; i < TARGET_ICONS_COUNT; i++) + updateAll.TargetIcons.insert(std::pair<uint8, ObjectGuid>(i, m_targetIcons[i])); - for (uint8 i = 0; i < TARGETICONCOUNT; ++i) - { - if (m_targetIcons[i].IsEmpty()) - continue; - - data << uint8(i); - data << m_targetIcons[i]; - } - - session->SendPacket(&data); + session->SendPacket(updateAll.Write()); } void Group::SendUpdate() @@ -1556,56 +1557,79 @@ void Group::SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot) slot = &(*witr); } - WorldPacket data(SMSG_PARTY_UPDATE, (1+1+1+1+1+4+8+4+4+(GetMembersCount()-1)*(13+8+1+1+1+1)+8+1+8+1+1+1+1)); - data << uint8(m_groupType); // group type (flags in 3.3) - data << uint8(slot->group); - data << uint8(slot->flags); - data << uint8(slot->roles); - if (isLFGGroup()) - { - data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done - data << uint32(sLFGMgr->GetDungeon(m_guid)); - data << uint8(0); // 4.x new - } + WorldPackets::Party::PartyUpdate partyUpdate; - data << m_guid; - data << uint32(m_counter++); // 3.3, value increases every time this packet gets sent - data << uint32(GetMembersCount()-1); - for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + partyUpdate.PartyType = m_groupType; + partyUpdate.PartyIndex = 0; + partyUpdate.PartyFlags = uint8(IsCreated()); + + partyUpdate.PartyGUID = m_guid; + partyUpdate.LeaderGUID = m_leaderGuid; + + partyUpdate.SequenceNum = m_counter++; // 3.3, value increases every time this packet gets sent + + partyUpdate.MyIndex = -1; + uint8 index = 0; + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr, ++index) { if (slot->guid == citr->guid) - continue; + partyUpdate.MyIndex = index; Player* member = ObjectAccessor::FindConnectedPlayer(citr->guid); - uint8 onlineState = (member && !member->GetSession()->PlayerLogout()) ? MEMBER_STATUS_ONLINE : MEMBER_STATUS_OFFLINE; - onlineState = onlineState | ((isBGGroup() || isBFGroup()) ? MEMBER_STATUS_PVP : 0); + WorldPackets::Party::GroupPlayerInfos playerInfos; - data << citr->name; - data << citr->guid; // guid - data << uint8(onlineState); // online-state - data << uint8(citr->group); // groupid - data << uint8(citr->flags); // See enum GroupMemberFlags - data << uint8(citr->roles); // Lfg Roles + playerInfos.GUID = citr->guid; + playerInfos.Name = citr->name; + playerInfos.Class = citr->_class; + + playerInfos.Status = MEMBER_STATUS_OFFLINE; + if (member && member->GetSession() && !member->GetSession()->PlayerLogout()) + playerInfos.Status = MEMBER_STATUS_ONLINE | (isBGGroup() || isBFGroup() ? MEMBER_STATUS_PVP : 0); + + playerInfos.Subgroup = citr->group; // groupid + playerInfos.Flags = citr->flags; // See enum GroupMemberFlags + playerInfos.RolesAssigned = citr->roles; // Lfg Roles + + partyUpdate.PlayerList.push_back(playerInfos); } - data << m_leaderGuid; // leader guid + if (GetMembersCount() > 1) + { + // LootSettings + partyUpdate.LootSettings = boost::in_place(); + partyUpdate.LootSettings->Method = m_lootMethod; + partyUpdate.LootSettings->Threshold = m_lootThreshold; + partyUpdate.LootSettings->LootMaster = m_lootMethod == MASTER_LOOT ? m_masterLooterGuid : ObjectGuid::Empty; + + // Difficulty Settings + partyUpdate.DifficultySettings = boost::in_place(); + partyUpdate.DifficultySettings->DungeonDifficultyID = m_dungeonDifficulty; + partyUpdate.DifficultySettings->RaidDifficultyID = m_raidDifficulty; + partyUpdate.DifficultySettings->LegacyRaidDifficultyID = m_legacyRaidDifficulty; + } - if (GetMembersCount() - 1) + // LfgInfos + if (isLFGGroup()) { - data << uint8(m_lootMethod); // loot method + partyUpdate.LfgInfos = boost::in_place(); - if (m_lootMethod == MASTER_LOOT) - data << m_masterLooterGuid; // master looter guid - else - data << uint64(0); + partyUpdate.LfgInfos->Slot = sLFGMgr->GetDungeon(m_guid); + partyUpdate.LfgInfos->BootCount = 0; // new 6.x + partyUpdate.LfgInfos->Aborted = false; // new 6.x + + partyUpdate.LfgInfos->MyFlags = 0; // new 6.x + partyUpdate.LfgInfos->MyRandomSlot = 0; // new 6.x + + partyUpdate.LfgInfos->MyPartialClear = sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0; // FIXME - Dungeon save status? 2 = done + partyUpdate.LfgInfos->MyGearDiff = 0.f; // new 6.x + partyUpdate.LfgInfos->MyFirstReward = false; // new 6.x - data << uint8(m_lootThreshold); // loot threshold - data << uint8(m_dungeonDifficulty); // Dungeon Difficulty - data << uint8(m_raidDifficulty); // Raid Difficulty + partyUpdate.LfgInfos->MyStrangerCount = 0; // new 6.x + partyUpdate.LfgInfos->MyKickVoteCount = 0; // new 6.x } - player->GetSession()->SendPacket(&data); + player->GetSession()->SendPacket(partyUpdate.Write()); } void Group::UpdatePlayerOutOfRange(Player* player) @@ -1613,15 +1637,15 @@ void Group::UpdatePlayerOutOfRange(Player* player) if (!player || !player->IsInWorld()) return; - WorldPacket data; - player->GetSession()->BuildPartyMemberStatsChangedPacket(player, &data); + WorldPackets::Party::PartyMemberStats packet; + packet.Initialize(player); Player* member; for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { member = itr->GetSource(); if (member && member != player && (!member->IsInMap(player) || !member->IsWithinDist(player, member->GetSightRange(), false))) - member->GetSession()->SendPacket(&data); + member->GetSession()->SendPacket(packet.Write()); } } @@ -1653,32 +1677,6 @@ void Group::BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRai } } -void Group::BroadcastReadyCheck(WorldPacket const* packet) -{ - for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) - { - Player* player = itr->GetSource(); - if (player && player->GetSession()) - if (IsLeader(player->GetGUID()) || IsAssistant(player->GetGUID())) - player->GetSession()->SendPacket(packet); - } -} - -void Group::OfflineReadyCheck() -{ - for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) - { - Player* player = ObjectAccessor::FindConnectedPlayer(citr->guid); - if (!player || !player->GetSession()) - { - WorldPacket data(SMSG_READY_CHECK_RESPONSE, 9); - data << citr->guid; - data << uint8(0); - BroadcastReadyCheck(&data); - } - } -} - bool Group::_setMembersGroup(ObjectGuid guid, uint8 group) { member_witerator slot = _getMemberWSlot(guid); @@ -1725,8 +1723,8 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) if (slot == m_memberSlots.end()) return; + uint8 prevSubGroup = slot->group; // Abort if the player is already in the target sub group - uint8 prevSubGroup = GetMemberGroup(guid); if (prevSubGroup == group) return; @@ -1758,7 +1756,6 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) else { // If player is in BG raid, it is possible that he is also in normal raid - and that normal raid is stored in m_originalGroup reference - prevSubGroup = player->GetOriginalSubGroup(); player->GetOriginalGroupRef().setSubGroup(group); } } @@ -1767,6 +1764,51 @@ void Group::ChangeMembersGroup(ObjectGuid guid, uint8 group) SendUpdate(); } +void Group::SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid) +{ + if (!isRaidGroup()) + return; + + member_witerator slots[2]; + slots[0] = _getMemberWSlot(firstGuid); + slots[1] = _getMemberWSlot(secondGuid); + if (slots[0] == m_memberSlots.end() || slots[1] == m_memberSlots.end()) + return; + + if (slots[0]->group == slots[1]->group) + return; + + uint8 tmp = slots[0]->group; + slots[0]->group = slots[1]->group; + slots[1]->group = tmp; + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + for (uint8 i = 0; i < 2; i++) + { + // Preserve new sub group in database for non-raid groups + if (!isBGGroup() && !isBFGroup()) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_MEMBER_SUBGROUP); + + stmt->setUInt8(0, slots[i]->group); + stmt->setUInt64(1, slots[i]->guid.GetCounter()); + + trans->Append(stmt); + } + + if (Player* player = ObjectAccessor::FindConnectedPlayer(slots[i]->guid)) + { + if (player->GetGroup() == this) + player->GetGroupRef().setSubGroup(slots[i]->group); + else + player->GetOriginalGroupRef().setSubGroup(slots[i]->group); + } + } + CharacterDatabase.CommitTransaction(trans); + + SendUpdate(); +} + // Retrieve the next Round-Roubin player for the group // // No update done if loot method is FFA. @@ -2262,9 +2304,167 @@ void Group::SetLfgRoles(ObjectGuid guid, uint8 roles) SendUpdate(); } +uint8 Group::GetLfgRoles(ObjectGuid guid) +{ + member_witerator slot = _getMemberWSlot(guid); + if (slot == m_memberSlots.end()) + return 0; + + return slot->roles; +} + +void Group::Update(uint32 diff) +{ + UpdateReadyCheck(diff); +} + +void Group::UpdateReadyCheck(uint32 diff) +{ + if (!m_readyCheckStarted) + return; + + m_readyCheckTimer -= diff; + if (m_readyCheckTimer <= 0) + EndReadyCheck(); +} + +void Group::StartReadyCheck(ObjectGuid starterGuid, int8 partyIndex, uint32 duration) +{ + if (m_readyCheckStarted) + return; + + member_witerator slot = _getMemberWSlot(starterGuid); + if (slot == m_memberSlots.end()) + return ; + + m_readyCheckStarted = true; + m_readyCheckTimer = duration; + + SetOfflineMembersReadyChecked(); + + SetMemberReadyChecked(&(*slot)); + + WorldPackets::Party::ReadyCheckStarted readyCheckStarted; + readyCheckStarted.PartyGUID = m_guid; + readyCheckStarted.PartyIndex = partyIndex; + readyCheckStarted.InitiatorGUID = starterGuid; + readyCheckStarted.Duration = duration; + BroadcastPacket(readyCheckStarted.Write(), false); +} + +void Group::EndReadyCheck(void) +{ + if (!m_readyCheckStarted) + return; + + m_readyCheckStarted = false; + m_readyCheckTimer = 0; + + ResetMemberReadyChecked(); + + WorldPackets::Party::ReadyCheckCompleted readyCheckCompleted; + readyCheckCompleted.PartyIndex = 0; + readyCheckCompleted.PartyGUID = m_guid; + BroadcastPacket(readyCheckCompleted.Write(), false); +} + +bool Group::IsReadyCheckCompleted(void) const +{ + for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) + if (!citr->readyChecked) + return false; + return true; +} + +void Group::SetMemberReadyCheck(ObjectGuid guid, bool ready) +{ + if (!m_readyCheckStarted) + return; + + member_witerator slot = _getMemberWSlot(guid); + if (slot != m_memberSlots.end()) + SetMemberReadyCheck(&(*slot), ready); +} + +void Group::SetMemberReadyCheck(MemberSlot* slot, bool ready) +{ + WorldPackets::Party::ReadyCheckResponse response; + response.PartyGUID = m_guid; + response.Player = slot->guid; + response.IsReady = ready; + BroadcastPacket(response.Write(), false); + + SetMemberReadyChecked(slot); +} + +void Group::SetOfflineMembersReadyChecked(void) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + { + Player* player = ObjectAccessor::FindConnectedPlayer(itr->guid); + if (!player || !player->GetSession()) + SetMemberReadyCheck(&(*itr), false); + } +} + +void Group::SetMemberReadyChecked(MemberSlot* slot) +{ + slot->readyChecked = true; + if (IsReadyCheckCompleted()) + EndReadyCheck(); +} + +void Group::ResetMemberReadyChecked(void) +{ + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + itr->readyChecked = false; +} + +void Group::AddRaidMarker(uint8 markerId, uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid) +{ + if (markerId >= RAID_MARKERS_COUNT || m_markers[markerId]) + return; + + m_activeMarkers |= (1 << markerId); + m_markers[markerId] = Trinity::make_unique<RaidMarker>(mapId, positionX, positionY, positionZ, transportGuid); + SendRaidMarkersChanged(); +} + +void Group::DeleteRaidMarker(uint8 markerId) +{ + if (markerId > RAID_MARKERS_COUNT) + return; + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; i++) + if (m_markers[i] && (markerId == i || markerId == RAID_MARKERS_COUNT)) + { + m_markers[i] = nullptr; + m_activeMarkers &= ~(1 << i); + } + + SendRaidMarkersChanged(); +} + +void Group::SendRaidMarkersChanged(WorldSession* session, int8 partyIndex) +{ + WorldPackets::Party::RaidMarkersChanged packet; + + packet.PartyIndex = partyIndex; + packet.ActiveMarkers = m_activeMarkers; + + for (uint8 i = 0; i < RAID_MARKERS_COUNT; i++) + if (m_markers[i]) + packet.RaidMarkers.push_back(m_markers[i].get()); + + if (session) + session->SendPacket(packet.Write()); + else + BroadcastPacket(packet.Write(), false); +} + bool Group::IsFull() const { - return isRaidGroup() ? (m_memberSlots.size() >= MAXRAIDSIZE) : (m_memberSlots.size() >= MAXGROUPSIZE); + return isRaidGroup() ? (m_memberSlots.size() >= MAX_RAID_SIZE) : (m_memberSlots.size() >= MAX_GROUP_SIZE); } bool Group::isLFGGroup() const @@ -2371,10 +2571,9 @@ bool Group::SameSubGroup(ObjectGuid guid1, MemberSlot const* slot2) const bool Group::HasFreeSlotSubGroup(uint8 subgroup) const { - return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAXGROUPSIZE); + return (m_subGroupsCounts && m_subGroupsCounts[subgroup] < MAX_GROUP_SIZE); } - uint8 Group::GetMemberGroup(ObjectGuid guid) const { member_citerator mslot = _getMemberCSlot(guid); @@ -2522,3 +2721,15 @@ void Group::ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply) slot->flags &= ~flag; } +void Group::SetEveryoneIsAssistant(bool apply) +{ + if (apply) + m_groupType = GroupType(m_groupType | GROUPTYPE_EVERYONE_ASSISTANT); + else + m_groupType = GroupType(m_groupType & ~GROUPTYPE_EVERYONE_ASSISTANT); + + for (member_witerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr) + ToggleGroupMemberFlag(itr, MEMBER_FLAG_ASSISTANT, apply); + + SendUpdate(); +} diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 4154f31a410..634d1f0f37b 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -24,6 +24,7 @@ #include "LootMgr.h" #include "QueryResult.h" #include "SharedDefines.h" +#include "Object.h" class Battlefield; class Battleground; @@ -38,10 +39,14 @@ class WorldSession; struct MapEntry; -#define MAXGROUPSIZE 5 -#define MAXRAIDSIZE 40 -#define MAX_RAID_SUBGROUPS MAXRAIDSIZE/MAXGROUPSIZE -#define TARGETICONCOUNT 8 +#define MAX_GROUP_SIZE 5 +#define MAX_RAID_SIZE 40 +#define MAX_RAID_SUBGROUPS MAX_RAID_SIZE / MAX_GROUP_SIZE + +#define TARGET_ICONS_COUNT 8 +#define RAID_MARKERS_COUNT 8 + +#define READYCHECK_DURATION 35000 enum RollVote { @@ -81,50 +86,59 @@ enum GroupMemberAssignment enum GroupType { - GROUPTYPE_NORMAL = 0x00, - GROUPTYPE_BG = 0x01, - GROUPTYPE_RAID = 0x02, - GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask - GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions() - GROUPTYPE_LFG = 0x08, + GROUPTYPE_NORMAL = 0x00, + GROUPTYPE_BG = 0x01, + GROUPTYPE_RAID = 0x02, + GROUPTYPE_BGRAID = GROUPTYPE_BG | GROUPTYPE_RAID, // mask + GROUPTYPE_LFG_RESTRICTED = 0x04, // Script_HasLFGRestrictions() + GROUPTYPE_LFG = 0x08, + GROUPTYPE_EVERYONE_ASSISTANT = 0x40, // Script_IsEveryoneAssistant() (4.x) // 0x10, leave/change group?, I saw this flag when leaving group and after leaving BG while in group // GROUPTYPE_ONE_PERSON_PARTY = 0x20, 4.x Script_IsOnePersonParty() - // GROUPTYPE_EVERYONE_ASSISTANT = 0x40 4.x Script_IsEveryoneAssistant() }; enum GroupUpdateFlags { GROUP_UPDATE_FLAG_NONE = 0x00000000, // nothing - GROUP_UPDATE_FLAG_STATUS = 0x00000001, // uint16 (GroupMemberStatusFlag) - GROUP_UPDATE_FLAG_CUR_HP = 0x00000002, // uint32 (HP) - GROUP_UPDATE_FLAG_MAX_HP = 0x00000004, // uint32 (HP) - GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000008, // uint8 (PowerType) - GROUP_UPDATE_FLAG_CUR_POWER = 0x00000010, // int16 (power value) - GROUP_UPDATE_FLAG_MAX_POWER = 0x00000020, // int16 (power value) - GROUP_UPDATE_FLAG_LEVEL = 0x00000040, // uint16 (level value) - GROUP_UPDATE_FLAG_ZONE = 0x00000080, // uint16 (zone id) - GROUP_UPDATE_FLAG_UNK100 = 0x00000100, // int16 (unk) - GROUP_UPDATE_FLAG_POSITION = 0x00000200, // uint16 (x), uint16 (y), uint16 (z) - GROUP_UPDATE_FLAG_AURAS = 0x00000400, // uint8 (unk), uint64 (mask), uint32 (count), for each bit set: uint32 (spell id) + uint16 (AuraFlags) (if has flags Scalable -> 3x int32 (bps)) - GROUP_UPDATE_FLAG_PET_GUID = 0x00000800, // uint64 (pet guid) - GROUP_UPDATE_FLAG_PET_NAME = 0x00001000, // cstring (name, NULL terminated string) - GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00002000, // uint16 (model id) - GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00004000, // uint32 (HP) - GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00008000, // uint32 (HP) - GROUP_UPDATE_FLAG_PET_POWER_TYPE = 0x00010000, // uint8 (PowerType) - GROUP_UPDATE_FLAG_PET_CUR_POWER = 0x00020000, // uint16 (power value) - GROUP_UPDATE_FLAG_PET_MAX_POWER = 0x00040000, // uint16 (power value) - GROUP_UPDATE_FLAG_PET_AURAS = 0x00080000, // [see GROUP_UPDATE_FLAG_AURAS] - GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00100000, // int32 (vehicle seat id) - GROUP_UPDATE_FLAG_PHASE = 0x00200000, // int32 (unk), uint32 (phase count), for (count) uint16(phaseId) - - GROUP_UPDATE_PET = GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | - GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP | GROUP_UPDATE_FLAG_PET_POWER_TYPE | - GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER | GROUP_UPDATE_FLAG_PET_AURAS, // all pet flags - GROUP_UPDATE_FULL = GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP | - GROUP_UPDATE_FLAG_POWER_TYPE | GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | - GROUP_UPDATE_FLAG_LEVEL | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_POSITION | - GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_PET | GROUP_UPDATE_FLAG_PHASE // all known flags, except UNK100 and VEHICLE_SEAT + GROUP_UPDATE_FLAG_UNK704 = 0x00000001, // uint8[2] (unk) + GROUP_UPDATE_FLAG_STATUS = 0x00000002, // uint16 (GroupMemberStatusFlag) + GROUP_UPDATE_FLAG_POWER_TYPE = 0x00000004, // uint8 (PowerType) + GROUP_UPDATE_FLAG_UNK322 = 0x00000008, // uint16 (unk) + GROUP_UPDATE_FLAG_CUR_HP = 0x00000010, // uint32 (HP) + GROUP_UPDATE_FLAG_MAX_HP = 0x00000020, // uint32 (max HP) + GROUP_UPDATE_FLAG_CUR_POWER = 0x00000040, // int16 (power value) + GROUP_UPDATE_FLAG_MAX_POWER = 0x00000080, // int16 (max power value) + GROUP_UPDATE_FLAG_LEVEL = 0x00000100, // uint16 (level value) + GROUP_UPDATE_FLAG_UNK200000 = 0x00000200, // int16 (unk) + GROUP_UPDATE_FLAG_ZONE = 0x00000400, // uint16 (zone id) + GROUP_UPDATE_FLAG_UNK2000000 = 0x00000800, // int16 (unk) + GROUP_UPDATE_FLAG_UNK4000000 = 0x00001000, // int32 (unk) + GROUP_UPDATE_FLAG_POSITION = 0x00002000, // uint16 (x), uint16 (y), uint16 (z) + GROUP_UPDATE_FLAG_VEHICLE_SEAT = 0x00104000, // int32 (vehicle seat id) + GROUP_UPDATE_FLAG_AURAS = 0x00008000, // uint8 (unk), uint64 (mask), uint32 (count), for each bit set: uint32 (spell id) + uint16 (AuraFlags) (if has flags Scalable -> 3x int32 (bps)) + GROUP_UPDATE_FLAG_PET = 0x00010000, // complex (pet) + GROUP_UPDATE_FLAG_PHASE = 0x00020000, // int32 (unk), uint32 (phase count), for (count) uint16(phaseId) + + GROUP_UPDATE_FULL = GROUP_UPDATE_FLAG_UNK704 | GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_POWER_TYPE | + GROUP_UPDATE_FLAG_UNK322 | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP | + GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | GROUP_UPDATE_FLAG_LEVEL | + GROUP_UPDATE_FLAG_UNK200000 | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_UNK2000000 | + GROUP_UPDATE_FLAG_UNK4000000 | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_VEHICLE_SEAT | + GROUP_UPDATE_FLAG_AURAS | GROUP_UPDATE_FLAG_PET | GROUP_UPDATE_FLAG_PHASE // all known flags +}; + +enum GroupUpdatePetFlags +{ + GROUP_UPDATE_FLAG_PET_NONE = 0x00000000, // nothing + GROUP_UPDATE_FLAG_PET_GUID = 0x00000001, // ObjectGuid (pet guid) + GROUP_UPDATE_FLAG_PET_NAME = 0x00000002, // cstring (name, NULL terminated string) + GROUP_UPDATE_FLAG_PET_MODEL_ID = 0x00000004, // uint16 (model id) + GROUP_UPDATE_FLAG_PET_CUR_HP = 0x00000008, // uint32 (HP) + GROUP_UPDATE_FLAG_PET_MAX_HP = 0x00000010, // uint32 (max HP) + GROUP_UPDATE_FLAG_PET_AURAS = 0x00000020, // [see GROUP_UPDATE_FLAG_AURAS] + + GROUP_UPDATE_PET_FULL = GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | + GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP | GROUP_UPDATE_FLAG_PET_AURAS // all pet flags }; class Roll : public LootValidatorRef @@ -160,6 +174,18 @@ struct InstanceGroupBind InstanceGroupBind() : save(NULL), perm(false) { } }; +struct RaidMarker +{ + WorldLocation Location; + ObjectGuid TransportGUID; + + RaidMarker(uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid = ObjectGuid::Empty) + { + Location.WorldRelocate(mapId, positionX, positionY, positionZ); + TransportGUID = transportGuid; + } +}; + /** request member stats checken **/ /// @todo uninvite people that not accepted invite class Group @@ -169,9 +195,11 @@ class Group { ObjectGuid guid; std::string name; + uint8 _class; uint8 group; uint8 flags; uint8 roles; + bool readyChecked; }; typedef std::list<MemberSlot> MemberSlotList; typedef MemberSlotList::const_iterator member_citerator; @@ -197,7 +225,7 @@ class Group bool AddLeaderInvite(Player* player); bool AddMember(Player* player); bool RemoveMember(ObjectGuid guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker = ObjectGuid::Empty, const char* reason = NULL); - void ChangeLeader(ObjectGuid guid); + void ChangeLeader(ObjectGuid guid, int8 partyIndex = 0); void SetLootMethod(LootMethod method); void SetLooterGuid(ObjectGuid guid); void SetMasterLooterGuid(ObjectGuid guid); @@ -205,6 +233,31 @@ class Group void SetLootThreshold(ItemQualities threshold); void Disband(bool hideDestroy = false); void SetLfgRoles(ObjectGuid guid, uint8 roles); + uint8 GetLfgRoles(ObjectGuid guid); + void SetEveryoneIsAssistant(bool apply); + + // Update + void Update(uint32 diff); + void UpdateReadyCheck(uint32 diff); + + // Ready check + void StartReadyCheck(ObjectGuid starterGuid, int8 partyIndex, uint32 duration = READYCHECK_DURATION); + void EndReadyCheck(); + + bool IsReadyCheckStarted(void) const { return m_readyCheckStarted; } + bool IsReadyCheckCompleted(void) const; + + void SetOfflineMembersReadyChecked(void); + void SetMemberReadyCheck(ObjectGuid guid, bool ready); + void SetMemberReadyCheck(MemberSlot* slot, bool ready); + + void SetMemberReadyChecked(MemberSlot* slot); + void ResetMemberReadyChecked(void); + + // Raid Markers + void AddRaidMarker(uint8 markerId, uint32 mapId, float positionX, float positionY, float positionZ, ObjectGuid transportGuid = ObjectGuid::Empty); + void DeleteRaidMarker(uint8 markerId); + void SendRaidMarkersChanged(WorldSession* session = nullptr, int8 partyIndex = 0); // properties accessories bool IsFull() const; @@ -221,7 +274,7 @@ class Group ObjectGuid GetMasterLooterGuid() const; ItemQualities GetLootThreshold() const; - uint32 GetDbStoreId() const { return m_dbStoreId; }; + uint32 GetDbStoreId() const { return m_dbStoreId; } // member manipulation methods bool IsMember(ObjectGuid guid) const; @@ -254,7 +307,8 @@ class Group GroupJoinBattlegroundResult CanJoinBattlegroundQueue(Battleground const* bgOrTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot, ObjectGuid& errorGuid); void ChangeMembersGroup(ObjectGuid guid, uint8 group); - void SetTargetIcon(uint8 id, ObjectGuid whoGuid, ObjectGuid targetGuid); + void SwapMembersGroups(ObjectGuid firstGuid, ObjectGuid secondGuid); + void SetTargetIcon(uint8 symbol, ObjectGuid target, ObjectGuid changedBy, uint8 partyIndex); void SetGroupMemberFlag(ObjectGuid guid, bool apply, GroupMemberFlags flag); void RemoveUniqueGroupMemberFlag(GroupMemberFlags flag); @@ -269,7 +323,7 @@ class Group // -no description- //void SendInit(WorldSession* session); - void SendTargetIconList(WorldSession* session); + void SendTargetIconList(WorldSession* session, int8 partyIndex = 0); void SendUpdate(); void SendUpdateToPlayer(ObjectGuid playerGUID, MemberSlot* slot = NULL); void UpdatePlayerOutOfRange(Player* player); @@ -290,8 +344,6 @@ class Group void BroadcastPacket(WorldPacket const* packet, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignoredPlayer = ObjectGuid::Empty); void BroadcastAddonMessagePacket(WorldPacket const* packet, const std::string& prefix, bool ignorePlayersInBGRaid, int group = -1, ObjectGuid ignore = ObjectGuid::Empty); - void BroadcastReadyCheck(WorldPacket const* packet); - void OfflineReadyCheck(); /*********************************************************/ /*** LOOT SYSTEM ***/ @@ -351,7 +403,7 @@ class Group Difficulty m_legacyRaidDifficulty; Battleground* m_bgGroup; Battlefield* m_bfGroup; - ObjectGuid m_targetIcons[TARGETICONCOUNT]; + ObjectGuid m_targetIcons[TARGET_ICONS_COUNT]; LootMethod m_lootMethod; ItemQualities m_lootThreshold; ObjectGuid m_looterGuid; @@ -363,5 +415,13 @@ class Group uint32 m_counter; // used only in SMSG_GROUP_LIST uint32 m_maxEnchantingLevel; uint32 m_dbStoreId; // Represents the ID used in database (Can be reused by other groups if group was disbanded) + + // Ready Check + bool m_readyCheckStarted; + int32 m_readyCheckTimer; + + // Raid markers + std::array<std::unique_ptr<RaidMarker>, RAID_MARKERS_COUNT> m_markers; + uint32 m_activeMarkers; }; #endif diff --git a/src/server/game/Groups/GroupMgr.cpp b/src/server/game/Groups/GroupMgr.cpp index f0c764e7269..7fb239cec48 100644 --- a/src/server/game/Groups/GroupMgr.cpp +++ b/src/server/game/Groups/GroupMgr.cpp @@ -233,3 +233,10 @@ void GroupMgr::LoadGroups() TC_LOG_INFO("server.loading", ">> Loaded %u group-instance saves in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } } + +void GroupMgr::Update(uint32 diff) +{ + for (GroupContainer::iterator itr = GroupStore.begin(); itr != GroupStore.end(); itr++) + if (itr->second) + itr->second->Update(diff); +} diff --git a/src/server/game/Groups/GroupMgr.h b/src/server/game/Groups/GroupMgr.h index 6aafe77432c..2fdd6d978e9 100644 --- a/src/server/game/Groups/GroupMgr.h +++ b/src/server/game/Groups/GroupMgr.h @@ -50,6 +50,8 @@ public: void AddGroup(Group* group); void RemoveGroup(Group* group); + void Update(uint32 diff); + protected: ObjectGuid::LowType NextGroupId; diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index c5812999490..d4ba420d44d 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -678,13 +678,23 @@ void EmblemInfo::ReadPacket(WorldPackets::Guild::SaveGuildEmblem& packet) m_backgroundColor = packet.Bg; } -void EmblemInfo::LoadFromDB(Field* fields) +bool EmblemInfo::ValidateEmblemColors() +{ + return sGuildColorBackgroundStore.LookupEntry(m_backgroundColor) && + sGuildColorBorderStore.LookupEntry(m_borderColor) && + sGuildColorEmblemStore.LookupEntry(m_color); + +} + +bool EmblemInfo::LoadFromDB(Field* fields) { m_style = fields[3].GetUInt8(); m_color = fields[4].GetUInt8(); m_borderStyle = fields[5].GetUInt8(); m_borderColor = fields[6].GetUInt8(); m_backgroundColor = fields[7].GetUInt8(); + + return ValidateEmblemColors(); } void EmblemInfo::SaveToDB(ObjectGuid::LowType guildId) const @@ -1602,11 +1612,11 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name) } // Invited player cannot be in another guild - /*if (pInvitee->GetGuildId()) + if (pInvitee->GetGuildId()) { SendCommandResult(session, GUILD_COMMAND_INVITE_PLAYER, ERR_ALREADY_IN_GUILD_S, name); return; - }*/ + } // Invited player cannot be invited if (pInvitee->GetGuildIdInvited()) @@ -2244,7 +2254,14 @@ bool Guild::LoadFromDB(Field* fields) m_id = fields[0].GetUInt64(); m_name = fields[1].GetString(); m_leaderGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt64()); - m_emblemInfo.LoadFromDB(fields); + + if (!m_emblemInfo.LoadFromDB(fields)) + { + TC_LOG_ERROR("guild", "Guild " UI64FMTD " has invalid emblem colors (Background: %u, Border: %u, Emblem: %u), skipped.", + m_id, m_emblemInfo.GetBackgroundColor(), m_emblemInfo.GetBorderColor(), m_emblemInfo.GetColor()); + return false; + } + m_info = fields[8].GetString(); m_motd = fields[9].GetString(); m_createdDate = time_t(fields[10].GetUInt32()); @@ -2466,7 +2483,7 @@ void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::strin if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPackets::Chat::Chat packet; - packet.Initalize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); + packet.Initialize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg); WorldPacket const* data = packet.Write(); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindConnectedPlayer()) @@ -2481,7 +2498,7 @@ void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std:: if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) { WorldPackets::Chat::Chat packet; - packet.Initalize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), nullptr, msg, 0, "", DEFAULT_LOCALE, prefix); + packet.Initialize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, LANG_ADDON, session->GetPlayer(), nullptr, msg, 0, "", DEFAULT_LOCALE, prefix); WorldPacket const* data = packet.Write(); for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) if (Player* player = itr->second->FindPlayer()) diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 42951320885..777147f2595 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -266,9 +266,10 @@ class EmblemInfo public: EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } - void LoadFromDB(Field* fields); + bool LoadFromDB(Field* fields); void SaveToDB(ObjectGuid::LowType guildId) const; void ReadPacket(WorldPackets::Guild::SaveGuildEmblem& packet); + bool ValidateEmblemColors(); uint32 GetStyle() const { return m_style; } uint32 GetColor() const { return m_color; } diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 0d9f292c4c2..88f45056187 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -174,7 +174,7 @@ void WorldSession::HandleAuctionSellItem(WorldPackets::AuctionHouse::AuctionSell } if (sAuctionMgr->GetAItem(item->GetGUID().GetCounter()) || !item->CanBeTraded() || item->IsNotEmptyBag() || - item->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || + item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION) || item->GetCount() < packetItem.UseCount) { SendAuctionCommandResult(NULL, AUCTION_SELL_ITEM, ERR_AUCTION_DATABASE_ERROR); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e7818a841aa..7b22d46d67b 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -236,6 +236,26 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CURRENCY, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS, stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES); + stmt->setUInt64(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES, stmt); + return res; } @@ -2554,25 +2574,18 @@ void WorldSession::SendCharRename(ResponseCodes result, WorldPackets::Character: void WorldSession::SendCharCustomize(ResponseCodes result, WorldPackets::Character::CharCustomizeInfo const* customizeInfo) { - /// @todo: fix 6.x implementation - (void)result; - (void)customizeInfo; - /* - WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1 + 8 + customizeInfo.NewName.size() + 1 + 6); - data << uint8(result); if (result == RESPONSE_SUCCESS) { - data << customizeInfo.Guid; - data << customizeInfo.NewName; - data << uint8(customizeInfo.Gender); - data << uint8(customizeInfo.Skin); - data << uint8(customizeInfo.Face); - data << uint8(customizeInfo.HairStyle); - data << uint8(customizeInfo.HairColor); - data << uint8(customizeInfo.FacialHair); + WorldPackets::Character::CharCustomizeResponse response(customizeInfo); + SendPacket(response.Write()); + } + else + { + WorldPackets::Character::CharCustomizeFailed failed; + failed.Result = uint8(result); + failed.CharGUID = customizeInfo->CharGUID; + SendPacket(failed.Write()); } - SendPacket(&data); - */ } void WorldSession::SendCharFactionChange(ResponseCodes result, WorldPackets::Character::CharRaceOrFactionChangeInfo const* factionChangeInfo) diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index b5550c2c073..b9fd383b19d 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -288,7 +288,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), Language(lang), sender, nullptr, msg); + packet.Initialize(ChatMsg(type), Language(lang), sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false, group->GetMemberGroup(GetPlayer()->GetGUID())); break; } @@ -320,8 +320,8 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, } case CHAT_MSG_RAID: { - Group* group = GetPlayer()->GetOriginalGroup(); - if (!group) + Group* group = GetPlayer()->GetGroup(); + if (!group || !group->isRaidGroup() || group->isBGGroup()) return; if (group->IsLeader(GetPlayer()->GetGUID())) @@ -330,7 +330,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), Language(lang), sender, nullptr, msg); + packet.Initialize(ChatMsg(type), Language(lang), sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false); break; } @@ -344,7 +344,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, WorldPackets::Chat::Chat packet; //in battleground, raid warning is sent only to players in battleground - code is ok - packet.Initalize(CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); + packet.Initialize(CHAT_MSG_RAID_WARNING, Language(lang), sender, NULL, msg); group->BroadcastPacket(packet.Write(), false); break; } @@ -381,7 +381,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg, sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), Language(lang), sender, nullptr, msg); + packet.Initialize(ChatMsg(type), Language(lang), sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false); break; } @@ -484,7 +484,7 @@ void WorldSession::HandleChatAddonMessage(ChatMsg type, std::string prefix, std: } WorldPackets::Chat::Chat packet; - packet.Initalize(type, LANG_ADDON, sender, nullptr, text, 0, "", DEFAULT_LOCALE, prefix); + packet.Initialize(type, LANG_ADDON, sender, nullptr, text, 0, "", DEFAULT_LOCALE, prefix); group->BroadcastAddonMessagePacket(packet.Write(), prefix, true, subGroup, sender->GetGUID()); break; } @@ -666,7 +666,7 @@ void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recvData) return; WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_IGNORED, LANG_UNIVERSAL, _player, _player, GetPlayer()->GetName()); + packet.Initialize(CHAT_MSG_IGNORED, LANG_UNIVERSAL, _player, _player, GetPlayer()->GetName()); player->SendDirectMessage(packet.Write()); } diff --git a/src/server/game/Handlers/GarrisonHandler.cpp b/src/server/game/Handlers/GarrisonHandler.cpp new file mode 100644 index 00000000000..54c7f4242fd --- /dev/null +++ b/src/server/game/Handlers/GarrisonHandler.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WorldSession.h" +#include "Garrison.h" +#include "GarrisonPackets.h" + +void WorldSession::HandleGetGarrisonInfo(WorldPackets::Garrison::GetGarrisonInfo& /*getGarrisonInfo*/) +{ + if (Garrison* garrison = _player->GetGarrison()) + garrison->SendInfo(); +} + +void WorldSession::HandleGarrisonPurchaseBuilding(WorldPackets::Garrison::GarrisonPurchaseBuilding& garrisonPurchaseBuilding) +{ + if (!_player->GetNPCIfCanInteractWith(garrisonPurchaseBuilding.NpcGUID, UNIT_NPC_FLAG_GARRISON_ARCHITECT)) + return; + + if (Garrison* garrison = _player->GetGarrison()) + garrison->PlaceBuilding(garrisonPurchaseBuilding.PlotInstanceID, garrisonPurchaseBuilding.BuildingID); +} + +void WorldSession::HandleGarrisonCancelConstruction(WorldPackets::Garrison::GarrisonCancelConstruction& garrisonCancelConstruction) +{ + if (!_player->GetNPCIfCanInteractWith(garrisonCancelConstruction.NpcGUID, UNIT_NPC_FLAG_GARRISON_ARCHITECT)) + return; + + if (Garrison* garrison = _player->GetGarrison()) + garrison->CancelBuildingConstruction(garrisonCancelConstruction.PlotInstanceID); +} + +void WorldSession::HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& /*garrisonRequestBlueprintAndSpecializationData*/) +{ + if (Garrison* garrison = _player->GetGarrison()) + garrison->SendBlueprintAndSpecializationData(); +} + +void WorldSession::HandleGarrisonGetBuildingLandmarks(WorldPackets::Garrison::GarrisonGetBuildingLandmarks& /*garrisonGetBuildingLandmarks*/) +{ + if (Garrison* garrison = _player->GetGarrison()) + garrison->SendBuildingLandmarks(_player); +} diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp index 9552c9a0655..eefe89fef74 100644 --- a/src/server/game/Handlers/GroupHandler.cpp +++ b/src/server/game/Handlers/GroupHandler.cpp @@ -35,6 +35,7 @@ #include "SpellAuraEffects.h" #include "MiscPackets.h" #include "LootPackets.h" +#include "PartyPackets.h" class Aura; @@ -51,103 +52,59 @@ class Aura; void WorldSession::SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val /* = 0 */) { - WorldPacket data(SMSG_PARTY_COMMAND_RESULT, 4 + member.size() + 1 + 4 + 4 + 8); - data << uint32(operation); - data << member; - data << uint32(res); - data << uint32(val); // LFD cooldown related (used with ERR_PARTY_LFG_BOOT_COOLDOWN_S and ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S) - data << uint64(0); // player who caused error (in some cases). - - SendPacket(&data); -} - -void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) -{ - ObjectGuid crossRealmGuid; // unused - - recvData.read_skip<uint32>(); // Non-zero in cross realm invites - recvData.read_skip<uint32>(); // Always 0 - - crossRealmGuid[2] = recvData.ReadBit(); - crossRealmGuid[7] = recvData.ReadBit(); - - uint8 realmLen = recvData.ReadBits(9); - - crossRealmGuid[3] = recvData.ReadBit(); - - uint8 nameLen = recvData.ReadBits(10); - - crossRealmGuid[5] = recvData.ReadBit(); - crossRealmGuid[4] = recvData.ReadBit(); - crossRealmGuid[6] = recvData.ReadBit(); - crossRealmGuid[0] = recvData.ReadBit(); - crossRealmGuid[1] = recvData.ReadBit(); + WorldPackets::Party::PartyCommandResult packet; - recvData.ReadByteSeq(crossRealmGuid[4]); - recvData.ReadByteSeq(crossRealmGuid[7]); - recvData.ReadByteSeq(crossRealmGuid[6]); + packet.Name = member; + packet.Command = uint8(operation); + packet.Result = uint8(res); + packet.ResultData = val; + packet.ResultGUID = ObjectGuid::Empty; - std::string memberName, realmName; - memberName = recvData.ReadString(nameLen); - realmName = recvData.ReadString(realmLen); // unused - - recvData.ReadByteSeq(crossRealmGuid[1]); - recvData.ReadByteSeq(crossRealmGuid[0]); - recvData.ReadByteSeq(crossRealmGuid[5]); - recvData.ReadByteSeq(crossRealmGuid[3]); - recvData.ReadByteSeq(crossRealmGuid[2]); - - // attempt add selected player - - // cheating - if (!normalizePlayerName(memberName)) - { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); - return; - } + SendPacket(packet.Write()); +} - Player* player = ObjectAccessor::FindPlayerByName(memberName); +void WorldSession::HandlePartyInviteOpcode(WorldPackets::Party::PartyInviteClient& packet) +{ + Player* player = ObjectAccessor::FindPlayerByName(packet.TargetName); // no player if (!player) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); + SendPartyResult(PARTY_OP_INVITE, packet.TargetName, ERR_BAD_PLAYER_NAME_S); return; } // restrict invite to GMs if (!sWorld->getBoolConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->IsGameMaster() && player->IsGameMaster()) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_BAD_PLAYER_NAME_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_BAD_PLAYER_NAME_S); return; } // can't group with if (!GetPlayer()->IsGameMaster() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam()) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_PLAYER_WRONG_FACTION); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_PLAYER_WRONG_FACTION); return; } if (GetPlayer()->GetInstanceId() != 0 && player->GetInstanceId() != 0 && GetPlayer()->GetInstanceId() != player->GetInstanceId() && GetPlayer()->GetMapId() == player->GetMapId()) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_TARGET_NOT_IN_INSTANCE_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_TARGET_NOT_IN_INSTANCE_S); return; } // just ignore us if (player->GetInstanceId() != 0 && player->GetDungeonDifficultyID() != GetPlayer()->GetDungeonDifficultyID()) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_IGNORING_YOU_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_IGNORING_YOU_S); return; } if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUID())) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_IGNORING_YOU_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_IGNORING_YOU_S); return; } - ObjectGuid invitedGuid = player->GetGUID(); - Group* group = GetPlayer()->GetGroup(); if (group && group->isBGGroup()) group = GetPlayer()->GetOriginalGroup(); @@ -155,67 +112,18 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) Group* group2 = player->GetGroup(); if (group2 && group2->isBGGroup()) group2 = player->GetOriginalGroup(); + // player already in another group or invited if (group2 || player->GetGroupInvite()) { - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_ALREADY_IN_GROUP_S); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_ALREADY_IN_GROUP_S); if (group2) { // tell the player that they were invited but it failed as they were already in a group - WorldPacket data(SMSG_PARTY_INVITE, 45); - - data.WriteBit(0); - - data.WriteBit(invitedGuid[0]); - data.WriteBit(invitedGuid[3]); - data.WriteBit(invitedGuid[2]); - - data.WriteBit(0); // Inverse already in group - - data.WriteBit(invitedGuid[6]); - data.WriteBit(invitedGuid[5]); - - data.WriteBits(0, 9); // Realm name - - data.WriteBit(invitedGuid[4]); - - data.WriteBits(GetPlayer()->GetName().size(), 7); // Inviter name length - - data.WriteBits(0, 24); // Count 2 - - data.WriteBit(0); - - data.WriteBit(invitedGuid[1]); - data.WriteBit(invitedGuid[7]); - - data.FlushBits(); - - data.WriteByteSeq(invitedGuid[1]); - data.WriteByteSeq(invitedGuid[4]); - - data << int32(getMSTime()); - data << int32(0); - data << int32(0); - - data.WriteByteSeq(invitedGuid[6]); - data.WriteByteSeq(invitedGuid[0]); - data.WriteByteSeq(invitedGuid[2]); - data.WriteByteSeq(invitedGuid[3]); - - // for count2 { int32(0) } - - data.WriteByteSeq(invitedGuid[5]); - - // data.append(realm name); - - data.WriteByteSeq(invitedGuid[7]); - - data.WriteString(GetPlayer()->GetName()); // inviter name - - data << int32(0); - - player->GetSession()->SendPacket(&data); + WorldPackets::Party::PartyInvite partyInvite; + partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, false); + player->GetSession()->SendPacket(partyInvite.Write()); } return; @@ -264,79 +172,21 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData) } } - // ok, we do it - WorldPacket data(SMSG_PARTY_INVITE, 45); - - data.WriteBit(0); - - data.WriteBit(invitedGuid[0]); - data.WriteBit(invitedGuid[3]); - data.WriteBit(invitedGuid[2]); - - data.WriteBit(1); // Inverse already in group - - data.WriteBit(invitedGuid[6]); - data.WriteBit(invitedGuid[5]); - - data.WriteBits(0, 9); // Realm name - - data.WriteBit(invitedGuid[4]); - - data.WriteBits(GetPlayer()->GetName().size(), 7); // Inviter name length - - data.WriteBits(0, 24); // Count 2 - - data.WriteBit(0); - - data.WriteBit(invitedGuid[1]); - data.WriteBit(invitedGuid[7]); - - data.FlushBits(); + WorldPackets::Party::PartyInvite partyInvite; + partyInvite.Initialize(GetPlayer(), packet.ProposedRoles, true); + player->GetSession()->SendPacket(partyInvite.Write()); - data.WriteByteSeq(invitedGuid[1]); - data.WriteByteSeq(invitedGuid[4]); - - data << int32(getMSTime()); - data << int32(0); - data << int32(0); - - data.WriteByteSeq(invitedGuid[6]); - data.WriteByteSeq(invitedGuid[0]); - data.WriteByteSeq(invitedGuid[2]); - data.WriteByteSeq(invitedGuid[3]); - - // for count2 { int32(0) } - - data.WriteByteSeq(invitedGuid[5]); - - // data.append(realm name); - - data.WriteByteSeq(invitedGuid[7]); - - data.WriteString(GetPlayer()->GetName()); - - data << int32(0); - - player->GetSession()->SendPacket(&data); - - SendPartyResult(PARTY_OP_INVITE, memberName, ERR_PARTY_RESULT_OK); + SendPartyResult(PARTY_OP_INVITE, player->GetName(), ERR_PARTY_RESULT_OK); } -void WorldSession::HandleGroupInviteResponseOpcode(WorldPacket& recvData) +void WorldSession::HandlePartyInviteResponseOpcode(WorldPackets::Party::PartyInviteResponse& packet) { - recvData.ReadBit(); // unk always 0 - bool accept = recvData.ReadBit(); - - // Never actually received? - /*if (accept) - recvData.read_skip<uint32>(); // unk*/ - Group* group = GetPlayer()->GetGroupInvite(); if (!group) return; - if (accept) + if (packet.Accept) { // Remove player from invitees in any case group->RemoveInvite(GetPlayer()); @@ -391,28 +241,22 @@ void WorldSession::HandleGroupInviteResponseOpcode(WorldPacket& recvData) return; // report - WorldPacket data(SMSG_GROUP_DECLINE, GetPlayer()->GetName().size()); - data << GetPlayer()->GetName(); - leader->GetSession()->SendPacket(&data); + WorldPackets::Party::GroupDecline decline(GetPlayer()->GetName()); + leader->GetSession()->SendPacket(decline.Write()); } } -void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData) +void WorldSession::HandlePartyUninviteOpcode(WorldPackets::Party::PartyUninvite& packet) { - ObjectGuid guid; - std::string reason; - recvData >> guid; - recvData >> reason; - - //can't uninvite yourself - if (guid == GetPlayer()->GetGUID()) + // can't uninvite yourself + if (packet.TargetGUID == GetPlayer()->GetGUID()) { TC_LOG_ERROR("network", "WorldSession::HandleGroupUninviteGuidOpcode: leader %s (%s) tried to uninvite himself from the group.", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str()); return; } - PartyResult res = GetPlayer()->CanUninviteFromGroup(guid); + PartyResult res = GetPlayer()->CanUninviteFromGroup(packet.TargetGUID); if (res != ERR_PARTY_RESULT_OK) { SendPartyResult(PARTY_OP_UNINVITE, "", res); @@ -423,13 +267,13 @@ void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData) // grp is checked already above in CanUninviteFromGroup() ASSERT(grp); - if (grp->IsMember(guid)) + if (grp->IsMember(packet.TargetGUID)) { - Player::RemoveFromGroup(grp, guid, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), reason.c_str()); + Player::RemoveFromGroup(grp, packet.TargetGUID, GROUP_REMOVEMETHOD_KICK, GetPlayer()->GetGUID(), packet.Reason.c_str()); return; } - if (Player* player = grp->GetInvited(guid)) + if (Player* player = grp->GetInvited(packet.TargetGUID)) { player->UninviteFromGroup(); return; @@ -438,12 +282,9 @@ void WorldSession::HandleGroupUninviteOpcode(WorldPacket& recvData) SendPartyResult(PARTY_OP_UNINVITE, "", ERR_TARGET_NOT_IN_GROUP_S); } -void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket& recvData) +void WorldSession::HandleSetPartyLeaderOpcode(WorldPackets::Party::SetPartyLeader& packet) { - ObjectGuid guid; - recvData >> guid; - - Player* player = ObjectAccessor::FindConnectedPlayer(guid); + Player* player = ObjectAccessor::FindConnectedPlayer(packet.TargetGUID); Group* group = GetPlayer()->GetGroup(); if (!group || !player) @@ -453,87 +294,35 @@ void WorldSession::HandleGroupSetLeaderOpcode(WorldPacket& recvData) return; // Everything's fine, accepted. - group->ChangeLeader(guid); + group->ChangeLeader(packet.TargetGUID, packet.PartyIndex); group->SendUpdate(); } -void WorldSession::HandleGroupSetRolesOpcode(WorldPacket& recvData) +void WorldSession::HandleSetRoleOpcode(WorldPackets::Party::SetRole& packet) { - uint32 newRole; - ObjectGuid guid1; // Assigner GUID - ObjectGuid guid2; // Target GUID - - guid1 = GetPlayer()->GetGUID(); - - recvData >> newRole; - - guid2[2] = recvData.ReadBit(); - guid2[6] = recvData.ReadBit(); - guid2[3] = recvData.ReadBit(); - guid2[7] = recvData.ReadBit(); - guid2[5] = recvData.ReadBit(); - guid2[1] = recvData.ReadBit(); - guid2[0] = recvData.ReadBit(); - guid2[4] = recvData.ReadBit(); - - recvData.ReadByteSeq(guid2[6]); - recvData.ReadByteSeq(guid2[4]); - recvData.ReadByteSeq(guid2[1]); - recvData.ReadByteSeq(guid2[3]); - recvData.ReadByteSeq(guid2[0]); - recvData.ReadByteSeq(guid2[5]); - recvData.ReadByteSeq(guid2[2]); - recvData.ReadByteSeq(guid2[7]); - - WorldPacket data(SMSG_ROLE_CHANGED_INFORM, 24); - - data.WriteBit(guid1[1]); - data.WriteBit(guid2[0]); - data.WriteBit(guid2[2]); - data.WriteBit(guid2[4]); - data.WriteBit(guid2[7]); - data.WriteBit(guid2[3]); - data.WriteBit(guid1[7]); - data.WriteBit(guid2[5]); - data.WriteBit(guid1[5]); - data.WriteBit(guid1[4]); - data.WriteBit(guid1[3]); - data.WriteBit(guid2[6]); - data.WriteBit(guid1[2]); - data.WriteBit(guid1[6]); - data.WriteBit(guid2[1]); - data.WriteBit(guid1[0]); - - data.WriteByteSeq(guid1[7]); - data.WriteByteSeq(guid2[3]); - data.WriteByteSeq(guid1[6]); - data.WriteByteSeq(guid2[4]); - data.WriteByteSeq(guid2[0]); - data << uint32(newRole); // New Role - data.WriteByteSeq(guid2[6]); - data.WriteByteSeq(guid2[2]); - data.WriteByteSeq(guid1[0]); - data.WriteByteSeq(guid1[4]); - data.WriteByteSeq(guid2[1]); - data.WriteByteSeq(guid1[3]); - data.WriteByteSeq(guid1[5]); - data.WriteByteSeq(guid1[2]); - data.WriteByteSeq(guid2[5]); - data.WriteByteSeq(guid2[7]); - data.WriteByteSeq(guid1[1]); - data << uint32(0); // Old Role - - if (Group* group = GetPlayer()->GetGroup()) + WorldPackets::Party::RoleChangedInform roleChangedInform; + + Group* group = GetPlayer()->GetGroup(); + uint8 oldRole = group ? group->GetLfgRoles(packet.TargetGUID) : 0; + if (oldRole == packet.Role) + return; + + roleChangedInform.PartyIndex = packet.PartyIndex; + roleChangedInform.From = GetPlayer()->GetGUID(); + roleChangedInform.ChangedUnit = packet.TargetGUID; + roleChangedInform.OldRole = oldRole; + roleChangedInform.NewRole = packet.Role; + + if (group) { - /// @todo probably should be sent only if (oldRole != newRole) - group->BroadcastPacket(&data, false); - group->SetLfgRoles(guid2, newRole); + group->BroadcastPacket(roleChangedInform.Write(), false); + group->SetLfgRoles(packet.TargetGUID, packet.Role); } else - SendPacket(&data); + SendPacket(roleChangedInform.Write()); } -void WorldSession::HandleGroupDisbandOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleLeaveGroupOpcode(WorldPackets::Party::LeaveGroup& /*packet*/) { Group* grp = GetPlayer()->GetGroup(); if (!grp) @@ -554,13 +343,8 @@ void WorldSession::HandleGroupDisbandOpcode(WorldPacket& /*recvData*/) GetPlayer()->RemoveFromGroup(GROUP_REMOVEMETHOD_LEAVE); } -void WorldSession::HandleLootMethodOpcode(WorldPacket& recvData) +void WorldSession::HandleSetLootMethodOpcode(WorldPackets::Party::SetLootMethod& packet) { - uint32 lootMethod; - ObjectGuid lootMaster; - uint32 lootThreshold; - recvData >> lootMethod >> lootMaster >> lootThreshold; - Group* group = GetPlayer()->GetGroup(); if (!group) return; @@ -569,20 +353,20 @@ void WorldSession::HandleLootMethodOpcode(WorldPacket& recvData) if (!group->IsLeader(GetPlayer()->GetGUID())) return; - if (lootMethod > NEED_BEFORE_GREED) + if (packet.LootMethod > NEED_BEFORE_GREED) return; - if (lootThreshold < ITEM_QUALITY_UNCOMMON || lootThreshold > ITEM_QUALITY_ARTIFACT) + if (packet.LootThreshold < ITEM_QUALITY_UNCOMMON || packet.LootThreshold > ITEM_QUALITY_ARTIFACT) return; - if (lootMethod == MASTER_LOOT && !group->IsMember(lootMaster)) + if (packet.LootMethod == MASTER_LOOT && !group->IsMember(packet.LootMasterGUID)) return; /********************/ // everything's fine, do it - group->SetLootMethod((LootMethod)lootMethod); - group->SetMasterLooterGuid(lootMaster); - group->SetLootThreshold((ItemQualities)lootThreshold); + group->SetLootMethod((LootMethod)packet.LootMethod); + group->SetMasterLooterGuid(packet.LootMasterGUID); + group->SetLootThreshold((ItemQualities)packet.LootThreshold); group->SendUpdate(); } @@ -605,28 +389,16 @@ void WorldSession::HandleLootRoll(WorldPackets::Loot::LootRoll& packet) } } -void WorldSession::HandleMinimapPingOpcode(WorldPacket& recvData) +void WorldSession::HandleMinimapPingOpcode(WorldPackets::Party::MinimapPingClient& packet) { - TC_LOG_DEBUG("network", "WORLD: Received MSG_MINIMAP_PING"); - if (!GetPlayer()->GetGroup()) return; - float x, y; - recvData >> x; - recvData >> y; - - //TC_LOG_DEBUG("misc", "Received opcode MSG_MINIMAP_PING X: %f, Y: %f", x, y); - - /** error handling **/ - /********************/ - - // everything's fine, do it - WorldPacket data(SMSG_MINIMAP_PING, (8+4+4)); - data << GetPlayer()->GetGUID(); - data << float(x); - data << float(y); - GetPlayer()->GetGroup()->BroadcastPacket(&data, true, -1, GetPlayer()->GetGUID()); + WorldPackets::Party::MinimapPing minimapPing; + minimapPing.Sender = GetPlayer()->GetGUID(); + minimapPing.PositionX = packet.PositionX; + minimapPing.PositionY = packet.PositionY; + GetPlayer()->GetGroup()->BroadcastPacket(minimapPing.Write(), true, -1, GetPlayer()->GetGUID()); } void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet) @@ -643,8 +415,6 @@ void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& // everything's fine, do it roll = urand(minimum, maximum); - //TC_LOG_DEBUG("misc", "ROLL: MIN: %u, MAX: %u, ROLL: %u", minimum, maximum, roll); - WorldPackets::Misc::RandomRoll randomRoll; randomRoll.Min = minimum; randomRoll.Max = maximum; @@ -657,44 +427,31 @@ void WorldSession::HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& SendPacket(randomRoll.Write()); } -void WorldSession::HandleRaidTargetUpdateOpcode(WorldPacket& recvData) +void WorldSession::HandleUpdateRaidTargetOpcode(WorldPackets::Party::UpdateRaidTarget& packet) { - TC_LOG_DEBUG("network", "WORLD: Received MSG_RAID_TARGET_UPDATE"); - Group* group = GetPlayer()->GetGroup(); if (!group) return; - uint8 x; - recvData >> x; - - /** error handling **/ - /********************/ - - // everything's fine, do it - if (x == 0xFF) // target icon request - group->SendTargetIconList(this); - else // target icon update + if (packet.Symbol == 0xFF) // target icon request + group->SendTargetIconList(this, packet.PartyIndex); + else // target icon update { if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) return; - ObjectGuid guid; - recvData >> guid; - - if (guid.IsPlayer()) + if (packet.Target.IsPlayer()) { - Player* target = ObjectAccessor::FindConnectedPlayer(guid); - + Player* target = ObjectAccessor::FindConnectedPlayer(packet.Target); if (!target || target->IsHostileTo(GetPlayer())) return; } - group->SetTargetIcon(x, _player->GetGUID(), guid); + group->SetTargetIcon(packet.Symbol, packet.Target, GetPlayer()->GetGUID(), packet.PartyIndex); } } -void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket& recvData) +void WorldSession::HandleConvertRaidOpcode(WorldPackets::Party::ConvertRaid& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) @@ -711,71 +468,56 @@ void WorldSession::HandleGroupRaidConvertOpcode(WorldPacket& recvData) SendPartyResult(PARTY_OP_INVITE, "", ERR_PARTY_RESULT_OK); // New 4.x: it is now possible to convert a raid to a group if member count is 5 or less - - bool toRaid; - recvData >> toRaid; - - if (toRaid) + if (packet.Raid) group->ConvertToRaid(); else group->ConvertToGroup(); } -void WorldSession::HandleGroupRequestJoinUpdates(WorldPacket& /*recvData*/) +void WorldSession::HandleRequestPartyJoinUpdates(WorldPackets::Party::RequestPartyJoinUpdates& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) return; - // does some stuff. dunno what. + group->SendTargetIconList(this, packet.PartyIndex); + group->SendRaidMarkersChanged(this, packet.PartyIndex); } -void WorldSession::HandleGroupChangeSubGroupOpcode(WorldPacket& recvData) +void WorldSession::HandleChangeSubGroupOpcode(WorldPackets::Party::ChangeSubGroup& packet) { // we will get correct pointer for group here, so we don't have to check if group is BG raid Group* group = GetPlayer()->GetGroup(); if (!group) return; - std::string name; - uint8 groupNr; - recvData >> name; - recvData >> groupNr; - - if (groupNr >= MAX_RAID_SUBGROUPS) + if (packet.NewSubGroup >= MAX_RAID_SUBGROUPS) return; ObjectGuid senderGuid = GetPlayer()->GetGUID(); if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) return; - if (!group->HasFreeSlotSubGroup(groupNr)) + if (!group->HasFreeSlotSubGroup(packet.NewSubGroup)) return; - Player* movedPlayer = ObjectAccessor::FindConnectedPlayerByName(name); - ObjectGuid guid; - - if (movedPlayer) - guid = movedPlayer->GetGUID(); - else - { - CharacterDatabase.EscapeString(name); - guid = ObjectMgr::GetPlayerGUIDByName(name.c_str()); - } - - group->ChangeMembersGroup(guid, groupNr); + group->ChangeMembersGroup(packet.TargetGUID, packet.NewSubGroup); } -void WorldSession::HandleGroupSwapSubGroupOpcode(WorldPacket& recvData) +void WorldSession::HandleSwapSubGroupsOpcode(WorldPackets::Party::SwapSubGroups& packet) { - std::string unk1; - std::string unk2; + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; - recvData >> unk1; - recvData >> unk2; + ObjectGuid senderGuid = GetPlayer()->GetGUID(); + if (!group->IsLeader(senderGuid) && !group->IsAssistant(senderGuid)) + return; + + group->SwapMembersGroups(packet.FirstTarget, packet.SecondTarget); } -void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData) +void WorldSession::HandleSetAssistantLeaderOpcode(WorldPackets::Party::SetAssistantLeader& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) @@ -784,12 +526,7 @@ void WorldSession::HandleGroupAssistantLeaderOpcode(WorldPacket& recvData) if (!group->IsLeader(GetPlayer()->GetGUID())) return; - ObjectGuid guid; - bool apply; - recvData >> guid; - recvData >> apply; - - group->SetGroupMemberFlag(guid, apply, MEMBER_FLAG_ASSISTANT); + group->SetGroupMemberFlag(packet.Target, packet.Apply, MEMBER_FLAG_ASSISTANT); } void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) @@ -826,509 +563,102 @@ void WorldSession::HandlePartyAssignmentOpcode(WorldPacket& recvData) group->SendUpdate(); } -void WorldSession::HandleRaidReadyCheckOpcode(WorldPacket& recvData) +void WorldSession::HandleDoReadyCheckOpcode(WorldPackets::Party::DoReadyCheck& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) return; - if (recvData.empty()) // request - { - /** error handling **/ - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; - /********************/ - - // everything's fine, do it - WorldPacket data(SMSG_READY_CHECK_STARTED, 8); - data << GetPlayer()->GetGUID(); - group->BroadcastPacket(&data, false, -1); + /** error handling **/ + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + /********************/ - group->OfflineReadyCheck(); - } - else // answer - { - uint8 state; - recvData >> state; - - // everything's fine, do it - WorldPacket data(SMSG_READY_CHECK_RESPONSE, 9); - data << GetPlayer()->GetGUID(); - data << uint8(state); - group->BroadcastReadyCheck(&data); - } + // everything's fine, do it + group->StartReadyCheck(GetPlayer()->GetGUID(), packet.PartyIndex); } -void WorldSession::BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data) +void WorldSession::HandleReadyCheckResponseOpcode(WorldPackets::Party::ReadyCheckResponseClient& packet) { - uint32 mask = player->GetGroupUpdateFlag(); - - if (mask == GROUP_UPDATE_FLAG_NONE) + Group* group = GetPlayer()->GetGroup(); + if (!group) return; - std::set<uint32> const& phases = player->GetPhases(); - - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) // if update power type, update current/max power also - mask |= (GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER); - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) // same for pets - mask |= (GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER); - - data->Initialize(SMSG_PARTY_MEMBER_STATE, 80); // average value - *data << player->GetPackGUID(); - *data << uint32(mask); - - if (mask & GROUP_UPDATE_FLAG_STATUS) - { - uint16 playerStatus = MEMBER_STATUS_ONLINE; - if (player->IsPvP()) - playerStatus |= MEMBER_STATUS_PVP; - - if (!player->IsAlive()) - { - if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - playerStatus |= MEMBER_STATUS_GHOST; - else - playerStatus |= MEMBER_STATUS_DEAD; - } - - if (player->IsFFAPvP()) - playerStatus |= MEMBER_STATUS_PVP_FFA; - - if (player->isAFK()) - playerStatus |= MEMBER_STATUS_AFK; - - if (player->isDND()) - playerStatus |= MEMBER_STATUS_DND; - - *data << uint16(playerStatus); - } - - if (mask & GROUP_UPDATE_FLAG_CUR_HP) - *data << uint32(player->GetHealth()); - - if (mask & GROUP_UPDATE_FLAG_MAX_HP) - *data << uint32(player->GetMaxHealth()); - - Powers powerType = player->getPowerType(); - if (mask & GROUP_UPDATE_FLAG_POWER_TYPE) - *data << uint8(powerType); - - if (mask & GROUP_UPDATE_FLAG_CUR_POWER) - *data << uint16(player->GetPower(powerType)); - - if (mask & GROUP_UPDATE_FLAG_MAX_POWER) - *data << uint16(player->GetMaxPower(powerType)); - - if (mask & GROUP_UPDATE_FLAG_LEVEL) - *data << uint16(player->getLevel()); - - if (mask & GROUP_UPDATE_FLAG_ZONE) - *data << uint16(player->GetZoneId()); - - if (mask & GROUP_UPDATE_FLAG_UNK100) - *data << uint16(0); - - if (mask & GROUP_UPDATE_FLAG_POSITION) - { - *data << uint16(player->GetPositionX()); - *data << uint16(player->GetPositionY()); - *data << uint16(player->GetPositionZ()); - } - - if (mask & GROUP_UPDATE_FLAG_AURAS) - { - *data << uint8(0); - uint64 auramask = player->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - *data << uint32(MAX_AURAS); // count - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const* aurApp = player->GetVisibleAura(i); - if (!aurApp) - { - *data << uint32(0); - *data << uint16(0); - continue; - } - - *data << uint32(aurApp->GetBase()->GetId()); - *data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - *data << int32(eff->GetAmount()); - else - *data << int32(0); - } - } - } - } - } - - Pet* pet = player->GetPet(); - if (mask & GROUP_UPDATE_FLAG_PET_GUID) - { - if (pet) - *data << pet->GetGUID(); - else - *data << ObjectGuid::Empty; - } - - if (mask & GROUP_UPDATE_FLAG_PET_NAME) - { - if (pet) - *data << pet->GetName(); - else - *data << uint8(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MODEL_ID) - { - if (pet) - *data << uint16(pet->GetDisplayId()); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_HP) - { - if (pet) - *data << uint32(pet->GetHealth()); - else - *data << uint32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_HP) - { - if (pet) - *data << uint32(pet->GetMaxHealth()); - else - *data << uint32(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - { - if (pet) - *data << uint8(pet->getPowerType()); - else - *data << uint8(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_CUR_POWER) - { - if (pet) - *data << uint16(pet->GetPower(pet->getPowerType())); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_MAX_POWER) - { - if (pet) - *data << uint16(pet->GetMaxPower(pet->getPowerType())); - else - *data << uint16(0); - } - - if (mask & GROUP_UPDATE_FLAG_PET_AURAS) - { - if (pet) - { - *data << uint8(0); - uint64 auramask = pet->GetAuraUpdateMaskForRaid(); - *data << uint64(auramask); - *data << uint32(MAX_AURAS); // count - for (uint32 i = 0; i < MAX_AURAS; ++i) - { - if (auramask & (uint64(1) << i)) - { - AuraApplication const* aurApp = pet->GetVisibleAura(i); - if (!aurApp) - { - *data << uint32(0); - *data << uint16(0); - continue; - } - - *data << uint32(aurApp->GetBase()->GetId()); - *data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - *data << int32(eff->GetAmount()); - else - *data << int32(0); - } - } - } - } - } - else - { - *data << uint8(0); - *data << uint64(0); - } - } - - if (mask & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - { - if (Vehicle* veh = player->GetVehicle()) - *data << uint32(veh->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]); - else - *data << uint32(0); - - } - - if (mask & GROUP_UPDATE_FLAG_PHASE) - { - *data << uint32(phases.empty() ? 8 : 0); - *data << uint32(phases.size()); - for (std::set<uint32>::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - *data << uint16(*itr); - } + // everything's fine, do it + group->SetMemberReadyCheck(GetPlayer()->GetGUID(), packet.IsReady); } -/*this procedure handles clients CMSG_REQUEST_PARTY_MEMBER_STATS request*/ -void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData) +void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPackets::Party::RequestPartyMemberStats& packet) { - ObjectGuid Guid; - recvData >> Guid; + WorldPackets::Party::PartyMemberStats partyMemberStats; - Player* player = ObjectAccessor::FindConnectedPlayer(Guid); + Player* player = ObjectAccessor::FindConnectedPlayer(packet.TargetGUID); if (!player) { - WorldPacket data(SMSG_PARTY_MEMBER_STATE, 3 + 4 + 2); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data << Guid.WriteAsPacked(); - data << uint32(GROUP_UPDATE_FLAG_STATUS); - data << uint16(MEMBER_STATUS_OFFLINE); - SendPacket(&data); - return; - } - - Pet* pet = player->GetPet(); - Powers powerType = player->getPowerType(); - std::set<uint32> const& phases = player->GetPhases(); - - WorldPacket data(SMSG_PARTY_MEMBER_STATE, 4 + 2 + 2 + 2 + 1 + 2 * 6 + 8 + 1 + 8); - data << uint8(0); // only for SMSG_PARTY_MEMBER_STATS_FULL, probably arena/bg related - data << player->GetPackGUID(); - - uint32 updateFlags = GROUP_UPDATE_FLAG_STATUS | GROUP_UPDATE_FLAG_CUR_HP | GROUP_UPDATE_FLAG_MAX_HP - | GROUP_UPDATE_FLAG_CUR_POWER | GROUP_UPDATE_FLAG_MAX_POWER | GROUP_UPDATE_FLAG_LEVEL - | GROUP_UPDATE_FLAG_ZONE | GROUP_UPDATE_FLAG_POSITION | GROUP_UPDATE_FLAG_AURAS - | GROUP_UPDATE_FLAG_PET_NAME | GROUP_UPDATE_FLAG_PET_MODEL_ID | GROUP_UPDATE_FLAG_PET_AURAS; - - if (powerType != POWER_MANA) - updateFlags |= GROUP_UPDATE_FLAG_POWER_TYPE; - - if (pet) - updateFlags |= GROUP_UPDATE_FLAG_PET_GUID | GROUP_UPDATE_FLAG_PET_CUR_HP | GROUP_UPDATE_FLAG_PET_MAX_HP - | GROUP_UPDATE_FLAG_PET_POWER_TYPE | GROUP_UPDATE_FLAG_PET_CUR_POWER | GROUP_UPDATE_FLAG_PET_MAX_POWER; - - if (player->GetVehicle()) - updateFlags |= GROUP_UPDATE_FLAG_VEHICLE_SEAT; - - if (!phases.empty()) - updateFlags |= GROUP_UPDATE_FLAG_PHASE; - - uint16 playerStatus = MEMBER_STATUS_ONLINE; - if (player->IsPvP()) - playerStatus |= MEMBER_STATUS_PVP; - - if (!player->IsAlive()) - { - if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) - playerStatus |= MEMBER_STATUS_GHOST; - else - playerStatus |= MEMBER_STATUS_DEAD; - } - - if (player->IsFFAPvP()) - playerStatus |= MEMBER_STATUS_PVP_FFA; - - if (player->isAFK()) - playerStatus |= MEMBER_STATUS_AFK; - - if (player->isDND()) - playerStatus |= MEMBER_STATUS_DND; - - data << uint32(updateFlags); - data << uint16(playerStatus); // GROUP_UPDATE_FLAG_STATUS - data << uint32(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP - data << uint32(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP - if (updateFlags & GROUP_UPDATE_FLAG_POWER_TYPE) - data << uint8(powerType); - - data << uint16(player->GetPower(powerType)); // GROUP_UPDATE_FLAG_CUR_POWER - data << uint16(player->GetMaxPower(powerType)); // GROUP_UPDATE_FLAG_MAX_POWER - data << uint16(player->getLevel()); // GROUP_UPDATE_FLAG_LEVEL - data << uint16(player->GetZoneId()); // GROUP_UPDATE_FLAG_ZONE - data << uint16(player->GetPositionX()); // GROUP_UPDATE_FLAG_POSITION - data << uint16(player->GetPositionY()); // GROUP_UPDATE_FLAG_POSITION - data << uint16(player->GetPositionZ()); // GROUP_UPDATE_FLAG_POSITION - - // GROUP_UPDATE_FLAG_AURAS - data << uint8(1); - uint64 auramask = 0; - size_t maskPos = data.wpos(); - data << uint64(auramask); // placeholder - data << uint32(MAX_AURAS); // count - - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication const* aurApp = player->GetVisibleAura(i)) - { - auramask |= (uint64(1) << i); - - data << uint32(aurApp->GetBase()->GetId()); - data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - data << int32(eff->GetAmount()); - else - data << int32(0); - } - } - } - } - - data.put<uint64>(maskPos, auramask); // GROUP_UPDATE_FLAG_AURAS - - if (updateFlags & GROUP_UPDATE_FLAG_PET_GUID) - data << pet->GetGUID(); - - data << std::string(pet ? pet->GetName() : ""); // GROUP_UPDATE_FLAG_PET_NAME - data << uint16(pet ? pet->GetDisplayId() : 0); // GROUP_UPDATE_FLAG_PET_MODEL_ID - - if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_HP) - data << uint32(pet->GetHealth()); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_HP) - data << uint32(pet->GetMaxHealth()); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_POWER_TYPE) - data << (uint8)pet->getPowerType(); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_CUR_POWER) - data << uint16(pet->GetPower(pet->getPowerType())); - - if (updateFlags & GROUP_UPDATE_FLAG_PET_MAX_POWER) - data << uint16(pet->GetMaxPower(pet->getPowerType())); - - // GROUP_UPDATE_FLAG_PET_AURAS - uint64 petAuraMask = 0; - data << uint8(1); - maskPos = data.wpos(); - data << uint64(petAuraMask); // placeholder - data << uint32(MAX_AURAS); // count - if (pet) - { - for (uint8 i = 0; i < MAX_AURAS; ++i) - { - if (AuraApplication const* aurApp = pet->GetVisibleAura(i)) - { - petAuraMask |= (uint64(1) << i); - - data << uint32(aurApp->GetBase()->GetId()); - data << uint16(aurApp->GetFlags()); - - if (aurApp->GetFlags() & AFLAG_SCALABLE) - { - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - { - if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) - data << int32(eff->GetAmount()); - else - data << int32(0); - } - } - } - } - } - - data.put<uint64>(maskPos, petAuraMask); // GROUP_UPDATE_FLAG_PET_AURAS - - if (updateFlags & GROUP_UPDATE_FLAG_VEHICLE_SEAT) - data << uint32(player->GetVehicle()->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]); - - if (updateFlags & GROUP_UPDATE_FLAG_PHASE) - { - data << uint32(phases.empty() ? 8 : 0); - data << uint32(phases.size()); - for (std::set<uint32>::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - data << uint16(*itr); + partyMemberStats.MemberStats.GUID = packet.TargetGUID; + partyMemberStats.MemberStats.Status = MEMBER_STATUS_OFFLINE; } + else + partyMemberStats.Initialize(player); - SendPacket(&data); + SendPacket(partyMemberStats.Write()); } -void WorldSession::HandleRequestRaidInfoOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleRequestRaidInfoOpcode(WorldPackets::Party::RequestRaidInfo& /*packet*/) { // every time the player checks the character screen _player->SendRaidInfo(); } -void WorldSession::HandleOptOutOfLootOpcode(WorldPacket& recvData) +void WorldSession::HandleOptOutOfLootOpcode(WorldPackets::Party::OptOutOfLoot& packet) { - bool passOnLoot; - recvData >> passOnLoot; // 1 always pass, 0 do not pass - // ignore if player not loaded if (!GetPlayer()) // needed because STATUS_AUTHED { - if (passOnLoot) + if (packet.PassOnLoot) TC_LOG_ERROR("network", "CMSG_OPT_OUT_OF_LOOT value<>0 for not-loaded character!"); return; } - GetPlayer()->SetPassOnGroupLoot(passOnLoot != 0); + GetPlayer()->SetPassOnGroupLoot(packet.PassOnLoot); } -void WorldSession::HandleRolePollBeginOpcode(WorldPacket& recvData) +void WorldSession::HandleInitiateRolePoll(WorldPackets::Party::InitiateRolePoll& packet) { Group* group = GetPlayer()->GetGroup(); if (!group) return; - if (recvData.empty()) - { - if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) - return; + ObjectGuid guid = GetPlayer()->GetGUID(); + if (!group->IsLeader(guid) && !group->IsAssistant(guid)) + return; - ObjectGuid guid = GetPlayer()->GetGUID(); - - WorldPacket data(SMSG_ROLE_POLL_INFORM, 8); - data.WriteBit(guid[1]); - data.WriteBit(guid[5]); - data.WriteBit(guid[7]); - data.WriteBit(guid[3]); - data.WriteBit(guid[2]); - data.WriteBit(guid[4]); - data.WriteBit(guid[0]); - data.WriteBit(guid[6]); - data.WriteByteSeq(guid[4]); - data.WriteByteSeq(guid[7]); - data.WriteByteSeq(guid[0]); - data.WriteByteSeq(guid[5]); - data.WriteByteSeq(guid[1]); - data.WriteByteSeq(guid[6]); - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[3]); - - GetPlayer()->GetGroup()->BroadcastPacket(&data, true); - } + WorldPackets::Party::RolePollInform rolePollInform; + rolePollInform.From = GetPlayer()->GetGUID(); + rolePollInform.PartyIndex = packet.PartyIndex; + group->BroadcastPacket(rolePollInform.Write(), true); +} + +void WorldSession::HandleSetEveryoneIsAssistant(WorldPackets::Party::SetEveryoneIsAssistant& packet) +{ + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (!group->IsLeader(GetPlayer()->GetGUID())) + return; + + group->SetEveryoneIsAssistant(packet.EveryoneIsAssistant); +} + +void WorldSession::HandleClearRaidMarker(WorldPackets::Party::ClearRaidMarker& packet) +{ + Group* group = GetPlayer()->GetGroup(); + if (!group) + return; + + if (group->isRaidGroup() && !group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return; + + group->DeleteRaidMarker(packet.MarkerId); } diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index ad3de84beb5..fbd1d5a7183 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -191,6 +191,12 @@ void WorldSession::HandleSaveGuildEmblem(WorldPackets::Guild::SaveGuildEmblem& p if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + if (!emblemInfo.ValidateEmblemColors()) + { + Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_INVALID_TABARD_COLORS); + return; + } + if (Guild* guild = GetPlayer()->GetGuild()) guild->HandleSetEmblem(this, emblemInfo); else diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 9e282582b7d..e6aecff9137 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -295,7 +295,7 @@ void WorldSession::HandleDestroyItemOpcode(WorldPackets::Item::DestroyItem& dest return; } - if (item->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_INDESTRUCTIBLE) + if (item->GetTemplate()->GetFlags() & ITEM_FLAG_INDESTRUCTIBLE) { _player->SendEquipError(EQUIP_ERR_DROP_BOUND_ITEM, NULL, NULL); return; @@ -388,7 +388,7 @@ void WorldSession::HandleSellItemOpcode(WorldPackets::Item::SellItem& packet) // prevent selling item for sellprice when the item is still refundable // this probably happens when right clicking a refundable item, the client sends both // CMSG_SELL_ITEM and CMSG_REFUND_ITEM (unverified) - if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_REFUNDABLE)) + if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_REFUNDABLE)) return; // Therefore, no feedback to client // special case at auto sell (sell all) @@ -494,38 +494,6 @@ void WorldSession::HandleBuybackItem(WorldPackets::Item::BuyBackItem& packet) _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, 0, 0); } -void WorldSession::HandleBuyItemInSlotOpcode(WorldPacket& recvData) -{ - ObjectGuid vendorguid, bagguid; - uint32 item, slot, count; - uint8 bagslot; - - recvData >> vendorguid >> item >> slot >> bagguid >> bagslot >> count; - - // client expects count starting at 1, and we send vendorslot+1 to client already - if (slot > 0) - --slot; - else - return; // cheating - - uint8 bag = NULL_BAG; // init for case invalid bagGUID - Item* bagItem = NULL; - // find bag slot by bag guid - if (bagguid == _player->GetGUID()) - bag = INVENTORY_SLOT_BAG_0; - else - bagItem = _player->GetItemByGuid(bagguid); - - if (bagItem && bagItem->IsBag()) - bag = bagItem->GetSlot(); - - // bag not found, cheating? - if (bag == NULL_BAG) - return; - - GetPlayer()->BuyItemFromVendorSlot(vendorguid, slot, item, count, bag, bagslot); -} - void WorldSession::HandleBuyItemOpcode(WorldPackets::Item::BuyItem& packet) { // client expects count starting at 1, and we send vendorslot+1 to client already @@ -623,8 +591,8 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) continue; // Only display items in vendor lists for the team the player is on - if ((itemTemplate->GetFlags2() & ITEM_FLAGS_EXTRA_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || - (itemTemplate->GetFlags2() & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && _player->GetTeam() == HORDE)) + if ((itemTemplate->GetFlags2() & ITEM_FLAG2_HORDE_ONLY && _player->GetTeam() == ALLIANCE) || + (itemTemplate->GetFlags2() & ITEM_FLAG2_ALLIANCE_ONLY && _player->GetTeam() == HORDE)) continue; // Items sold out are not displayed in list @@ -748,13 +716,12 @@ void WorldSession::SendEnchantmentLog(ObjectGuid target, ObjectGuid caster, uint void WorldSession::SendItemEnchantTimeUpdate(ObjectGuid Playerguid, ObjectGuid Itemguid, uint32 slot, uint32 Duration) { - // last check 2.0.10 - WorldPacket data(SMSG_ITEM_ENCHANT_TIME_UPDATE, (8+4+4+8)); - data << Itemguid; - data << uint32(slot); - data << uint32(Duration); - data << Playerguid; - SendPacket(&data); + WorldPackets::Item::ItemEnchantTimeUpdate data; + data.ItemGuid = Itemguid; + data.DurationLeft = Duration; + data.Slot = slot; + data.OwnerGuid = Playerguid; + SendPacket(data.Write()); } void WorldSession::HandleWrapItem(WorldPackets::Item::WrapItem& packet) @@ -782,7 +749,7 @@ void WorldSession::HandleWrapItem(WorldPackets::Item::WrapItem& packet) return; } - if (!(gift->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_WRAPPER)) // cheating: non-wrapper wrapper + if (!(gift->GetTemplate()->GetFlags() & ITEM_FLAG_WRAPPER)) // cheating: non-wrapper wrapper { _player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, gift, NULL); return; @@ -872,7 +839,7 @@ void WorldSession::HandleWrapItem(WorldPackets::Item::WrapItem& packet) } item->SetGuidValue(ITEM_FIELD_GIFTCREATOR, _player->GetGUID()); - item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED); + item->SetUInt32Value(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED); item->SetState(ITEM_CHANGED, _player); if (item->GetState() == ITEM_NEW) // save new item, to have alway for `character_gifts` record in `item_instance` @@ -979,7 +946,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData) ItemTemplate const* iGemProto = Gems[i]->GetTemplate(); // unique item (for new and already placed bit removed enchantments - if (iGemProto->GetFlags() & ITEM_PROTO_FLAG_UNIQUE_EQUIPPED) + if (iGemProto->GetFlags() & ITEM_FLAG_UNIQUE_EQUIPPED) { for (int j = 0; j < MAX_GEM_SOCKETS; ++j) { @@ -1094,17 +1061,13 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recvData) itemTarget->SendUpdateSockets(); } -void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recvData) +void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPackets::Item::CancelTempEnchantment& cancelTempEnchantment) { - uint32 slot; - - recvData >> slot; - // apply only to equipped item - if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, slot)) + if (!Player::IsEquipmentPos(INVENTORY_SLOT_BAG_0, cancelTempEnchantment.Slot)) return; - Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot); + Item* item = GetPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, cancelTempEnchantment.Slot); if (!item) return; @@ -1149,34 +1112,6 @@ void WorldSession::HandleItemRefund(WorldPacket &recvData) GetPlayer()->RefundItem(item); } -/** - * Handles the packet sent by the client when requesting information about item text. - * - * This function is called when player clicks on item which has some flag set - */ -void WorldSession::HandleItemTextQuery(WorldPacket& recvData ) -{ - ObjectGuid itemGuid; - recvData >> itemGuid; - - TC_LOG_DEBUG("network", "CMSG_ITEM_TEXT_QUERY %s", itemGuid.ToString().c_str()); - - WorldPacket data(SMSG_QUERY_ITEM_TEXT_RESPONSE, 14); // guess size - - if (Item* item = _player->GetItemByGuid(itemGuid)) - { - data << uint8(0); // has text - data << itemGuid; // item guid - data << item->GetText(); - } - else - { - data << uint8(1); // no text - } - - SendPacket(&data); -} - void WorldSession::HandleTransmogrifyItems(WorldPacket& recvData) { Player* player = GetPlayer(); diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index c4d3358a333..4a3866cbb1b 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -86,7 +86,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) { if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) || (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && - (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) + (GetPlayer()->GetGroup()->GetMembersCount() == MAX_GROUP_SIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) { recvData.rfinish(); return; diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 4f7a42c3770..ddd084cbd9d 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -325,7 +325,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) ItemTemplate const* proto = pItem->GetTemplate(); // destroy only 5 items from stack in case prospecting and milling - if (proto->GetFlags() & (ITEM_PROTO_FLAG_PROSPECTABLE | ITEM_PROTO_FLAG_MILLABLE)) + if (proto->GetFlags() & (ITEM_FLAG_PROSPECTABLE | ITEM_FLAG_MILLABLE)) { pItem->m_lootGenerated = false; pItem->loot.clear(); @@ -341,7 +341,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) else { // Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item - if (pItem->loot.isLooted() || !(proto->GetFlags() & ITEM_PROTO_FLAG_OPENABLE)) + if (pItem->loot.isLooted() || !(proto->GetFlags() & ITEM_FLAG_OPENABLE)) player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } return; // item can be looted only single player diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index b8ac779887b..dd55c6f2f06 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -196,7 +196,7 @@ void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) if (Item* item = player->GetItemByGuid(att.ItemGUID)) { ItemTemplate const* itemProto = item->GetTemplate(); - if (!itemProto || !(itemProto->GetFlags() & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) + if (!itemProto || !(itemProto->GetFlags() & ITEM_FLAG_BIND_TO_ACCOUNT)) { accountBound = false; break; @@ -250,13 +250,13 @@ void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) } } - if (item->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) + if (item->GetTemplate()->GetFlags() & ITEM_FLAG_CONJURED || item->GetUInt32Value(ITEM_FIELD_DURATION)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } - if (packet.Info.Cod && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (packet.Info.Cod && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; @@ -636,7 +636,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextIt if (m->messageType == MAIL_NORMAL) bodyItem->SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Player>(m->sender)); - bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK); + bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_MAIL_TEXT_MASK); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index b01f0c6c147..0aa941de4e2 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -209,7 +209,7 @@ void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest) { std::string aName; if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(target->GetZoneId())) - aName = areaEntry->ZoneName; + aName = areaEntry->AreaName_lang; bool show = false; for (size_t i = 0; i < wWords.size(); ++i) @@ -848,12 +848,9 @@ void WorldSession::HandleRealmSplitOpcode(WorldPacket& recvData) //TC_LOG_DEBUG("response sent %u", unk); } -void WorldSession::HandleFarSightOpcode(WorldPacket& recvData) +void WorldSession::HandleFarSightOpcode(WorldPackets::Misc::FarSight& packet) { - bool apply; - recvData >> apply; - - if (apply) + if (packet.Enable) { TC_LOG_DEBUG("network", "Added FarSight %s to %s", _player->GetGuidValue(PLAYER_FARSIGHT).ToString().c_str(), _player->GetGUID().ToString().c_str()); if (WorldObject* target = _player->GetViewpoint()) @@ -907,7 +904,7 @@ void WorldSession::HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& _player->m_timeSyncQueue.pop(); } -void WorldSession::HandleResetInstancesOpcode(WorldPacket& /*recvData*/) +void WorldSession::HandleResetInstancesOpcode(WorldPackets::Instance::ResetInstances& /*packet*/) { if (Group* group = _player->GetGroup()) { @@ -1216,129 +1213,29 @@ void WorldSession::HandleObjectUpdateRescuedOpcode(WorldPackets::Misc::ObjectUpd _player->m_clientGUIDs.insert(objectUpdateRescued.ObjectGUID); } -void WorldSession::HandleSaveCUFProfiles(WorldPacket& recvPacket) +void WorldSession::HandleSaveCUFProfiles(WorldPackets::Misc::SaveCUFProfiles& packet) { - uint8 count = (uint8)recvPacket.ReadBits(20); - - if (count > MAX_CUF_PROFILES) + if (packet.CUFProfiles.size() > MAX_CUF_PROFILES) { TC_LOG_ERROR("entities.player", "HandleSaveCUFProfiles - %s tried to save more than %i CUF profiles. Hacking attempt?", GetPlayerName().c_str(), MAX_CUF_PROFILES); - recvPacket.rfinish(); return; } - CUFProfile* profiles[MAX_CUF_PROFILES]; - uint8 strlens[MAX_CUF_PROFILES]; - - for (uint8 i = 0; i < count; ++i) - { - profiles[i] = new CUFProfile; - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_SPEC_2 , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_10_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_UNK_157 , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_HEAL_PREDICTION , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_SPEC_1 , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_PVP , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_POWER_BAR , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_15_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_40_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_PETS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_5_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_ONLY_DISPELLABLE_DEBUFFS, recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_2_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_UNK_156 , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_NON_BOSS_DEBUFFS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_MAIN_TANK_AND_ASSIST , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_AGGRO_HIGHLIGHT , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_3_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_BORDER , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_USE_CLASS_COLORS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_UNK_145 , recvPacket.ReadBit()); - strlens[i] = (uint8)recvPacket.ReadBits(8); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_PVE , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_DISPLAY_HORIZONTAL_GROUPS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_AUTO_ACTIVATE_25_PLAYERS , recvPacket.ReadBit()); - profiles[i]->BoolOptions.set(CUF_KEEP_GROUPS_TOGETHER , recvPacket.ReadBit()); - } - - for (uint8 i = 0; i < count; ++i) - { - recvPacket >> profiles[i]->Unk146; - profiles[i]->ProfileName = recvPacket.ReadString(strlens[i]); - recvPacket >> profiles[i]->Unk152; - recvPacket >> profiles[i]->FrameHeight; - recvPacket >> profiles[i]->FrameWidth; - recvPacket >> profiles[i]->Unk150; - recvPacket >> profiles[i]->HealthText; - recvPacket >> profiles[i]->Unk147; - recvPacket >> profiles[i]->SortBy; - recvPacket >> profiles[i]->Unk154; - recvPacket >> profiles[i]->Unk148; - - GetPlayer()->SaveCUFProfile(i, profiles[i]); - } + for (uint8 i = 0; i < packet.CUFProfiles.size(); ++i) + GetPlayer()->SaveCUFProfile(i, std::move(packet.CUFProfiles[i])); - for (uint8 i = count; i < MAX_CUF_PROFILES; ++i) - GetPlayer()->SaveCUFProfile(i, NULL); + for (uint8 i = packet.CUFProfiles.size(); i < MAX_CUF_PROFILES; ++i) + GetPlayer()->SaveCUFProfile(i, nullptr); } void WorldSession::SendLoadCUFProfiles() { Player* player = GetPlayer(); - uint8 count = player->GetCUFProfilesCount(); - - ByteBuffer byteBuffer(25 * count); - WorldPacket data(SMSG_LOAD_CUF_PROFILES, 5 * count + 25 * count); - - data.WriteBits(count, 20); - for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i) - { - CUFProfile* profile = player->GetCUFProfile(i); - if (!profile) - continue; - - data.WriteBit(profile->BoolOptions[CUF_UNK_157]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_10_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_5_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_25_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_HEAL_PREDICTION]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_PVE]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_HORIZONTAL_GROUPS]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_40_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_3_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_AGGRO_HIGHLIGHT]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_BORDER]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_2_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_NON_BOSS_DEBUFFS]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_MAIN_TANK_AND_ASSIST]); - data.WriteBit(profile->BoolOptions[CUF_UNK_156]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_SPEC_2]); - data.WriteBit(profile->BoolOptions[CUF_USE_CLASS_COLORS]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_POWER_BAR]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_SPEC_1]); - data.WriteBits(profile->ProfileName.size(), 8); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_ONLY_DISPELLABLE_DEBUFFS]); - data.WriteBit(profile->BoolOptions[CUF_KEEP_GROUPS_TOGETHER]); - data.WriteBit(profile->BoolOptions[CUF_UNK_145]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_15_PLAYERS]); - data.WriteBit(profile->BoolOptions[CUF_DISPLAY_PETS]); - data.WriteBit(profile->BoolOptions[CUF_AUTO_ACTIVATE_PVP]); - - byteBuffer << uint16(profile->Unk154); - byteBuffer << uint16(profile->FrameHeight); - byteBuffer << uint16(profile->Unk152); - byteBuffer << uint8(profile->Unk147); - byteBuffer << uint16(profile->Unk150); - byteBuffer << uint8(profile->Unk146); - byteBuffer << uint8(profile->HealthText); - byteBuffer << uint8(profile->SortBy); - byteBuffer << uint16(profile->FrameWidth); - byteBuffer << uint8(profile->Unk148); - byteBuffer.WriteString(profile->ProfileName); - } + WorldPackets::Misc::LoadCUFProfiles loadCUFProfiles; - data.FlushBits(); - data.append(byteBuffer); - SendPacket(&data); + for (uint8 i = 0; i < MAX_CUF_PROFILES; i++) + if (CUFProfile* cufProfile = player->GetCUFProfile(i)) + loadCUFProfiles.CUFProfiles.push_back(cufProfile); + SendPacket(loadCUFProfiles.Write()); } diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 3835a0642f9..240825faade 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -23,6 +23,7 @@ #include "Log.h" #include "Corpse.h" #include "Player.h" +#include "Garrison.h" #include "SpellAuras.h" #include "MapManager.h" #include "Transport.h" @@ -46,6 +47,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() if (!GetPlayer()->IsBeingTeleportedFar()) return; + bool seamlessTeleport = GetPlayer()->IsBeingTeleportedSeamlessly(); GetPlayer()->SetSemaphoreTeleportFar(false); // get the teleport destination @@ -88,13 +90,16 @@ void WorldSession::HandleMoveWorldportAckOpcode() float z = loc.GetPositionZ(); if (GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) z += GetPlayer()->GetFloatValue(UNIT_FIELD_HOVERHEIGHT); + GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); GetPlayer()->ResetMap(); GetPlayer()->SetMap(newMap); - GetPlayer()->SendInitialPacketsBeforeAddToMap(); - if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer())) + if (!seamlessTeleport) + GetPlayer()->SendInitialPacketsBeforeAddToMap(); + + if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer(), !seamlessTeleport)) { TC_LOG_ERROR("network", "WORLD: failed to teleport player %s (%s) to map %d (%s) because of unknown reason!", GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown"); @@ -124,16 +129,26 @@ void WorldSession::HandleMoveWorldportAckOpcode() } } - GetPlayer()->SendInitialPacketsAfterAddToMap(); + if (!seamlessTeleport) + GetPlayer()->SendInitialPacketsAfterAddToMap(); + else + { + GetPlayer()->UpdateVisibilityForPlayer(); + if (Garrison* garrison = GetPlayer()->GetGarrison()) + garrison->SendRemoteInfo(); + } // flight fast teleport case if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { if (!_player->InBattleground()) { - // short preparations to continue flight - FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - flight->Initialize(GetPlayer()); + if (!seamlessTeleport) + { + // short preparations to continue flight + FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); + flight->Initialize(GetPlayer()); + } return; } diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index a5dc60b8494..2418bb84cac 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -130,7 +130,7 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) bool valid = true; bool primary_prof_first_rank = false; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_TRAINERSPELL_ABILITY_REQS; ++i) { if (!tSpell->ReqAbility[i]) continue; @@ -173,7 +173,7 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) break; SpellsRequiringSpellMapBounds spellsRequired = sSpellMgr->GetSpellsRequiredForSpellBounds(tSpell->ReqAbility[i]); - for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2) + for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < MAX_TRAINERSPELL_ABILITY_REQS; ++itr2) { spell.ReqAbility[maxReq] = itr2->second; ++maxReq; @@ -189,19 +189,14 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) SendPacket(packet.Write()); } -void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) +void WorldSession::HandleTrainerBuySpellOpcode(WorldPackets::NPC::TrainerBuySpell& packet) { - ObjectGuid guid; - uint32 spellId; - uint32 trainerId; - - recvData >> guid >> trainerId >> spellId; - TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRAINER_BUY_SPELL %s, learn spell id is: %u", guid.ToString().c_str(), spellId); + TC_LOG_DEBUG("network", "WORLD: Received CMSG_TRAINER_BUY_SPELL %s, learn spell id is: %i", packet.TrainerGUID.ToString().c_str(), packet.SpellID); - Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER); + Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(packet.TrainerGUID, UNIT_NPC_FLAG_TRAINER); if (!unit) { - TC_LOG_DEBUG("network", "WORLD: HandleTrainerBuySpellOpcode - %s not found or you can not interact with him.", guid.ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleTrainerBuySpellOpcode - %s not found or you can not interact with him.", packet.TrainerGUID.ToString().c_str()); return; } @@ -213,32 +208,32 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); if (!trainer_spells) { - SendTrainerBuyFailed(guid, spellId, 0); + SendTrainerBuyFailed(packet.TrainerGUID, packet.SpellID, 0); return; } // not found, cheat? - TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); - if (!trainer_spell) + TrainerSpell const* trainerSpell = trainer_spells->Find(packet.SpellID); + if (!trainerSpell) { - SendTrainerBuyFailed(guid, spellId, 0); + SendTrainerBuyFailed(packet.TrainerGUID, packet.SpellID, 0); return; } // can't be learn, cheat? Or double learn with lags... - if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) + if (_player->GetTrainerSpellState(trainerSpell) != TRAINER_SPELL_GREEN) { - SendTrainerBuyFailed(guid, spellId, 0); + SendTrainerBuyFailed(packet.TrainerGUID, packet.SpellID, 0); return; } // apply reputation discount - uint32 nSpellCost = uint32(floor(trainer_spell->MoneyCost * _player->GetReputationPriceDiscount(unit))); + uint32 nSpellCost = uint32(floor(trainerSpell->MoneyCost * _player->GetReputationPriceDiscount(unit))); // check money requirement if (!_player->HasEnoughMoney(uint64(nSpellCost))) { - SendTrainerBuyFailed(guid, spellId, 1); + SendTrainerBuyFailed(packet.TrainerGUID, packet.SpellID, 1); return; } @@ -248,19 +243,19 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) _player->SendPlaySpellVisualKit(362, 1); // 113 EmoteSalute // learn explicitly or cast explicitly - if (trainer_spell->IsCastable()) - _player->CastSpell(_player, trainer_spell->SpellID, true); + if (trainerSpell->IsCastable()) + _player->CastSpell(_player, trainerSpell->SpellID, true); else - _player->LearnSpell(spellId, false); + _player->LearnSpell(packet.SpellID, false); } -void WorldSession::SendTrainerBuyFailed(ObjectGuid guid, uint32 spellId, uint32 reason) +void WorldSession::SendTrainerBuyFailed(ObjectGuid trainerGUID, uint32 spellID, int32 trainerFailedReason) { - WorldPacket data(SMSG_TRAINER_BUY_FAILED, 16); - data << guid; - data << uint32(spellId); // should be same as in packet from client - data << uint32(reason); // 1 == "Not enough money for trainer service." 0 == "Trainer service %d unavailable." - SendPacket(&data); + WorldPackets::NPC::TrainerBuyFailed trainerBuyFailed; + trainerBuyFailed.TrainerGUID = trainerGUID; + trainerBuyFailed.SpellID = spellID; // should be same as in packet from client + trainerBuyFailed.TrainerFailedReason = trainerFailedReason; // 1 == "Not enough money for trainer service." 0 == "Trainer service %d unavailable." + SendPacket(trainerBuyFailed.Write()); } void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 7f1782ea1f0..429d3565052 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -616,8 +616,7 @@ void WorldSession::HandlePetRename(WorldPacket& recvData) pet->SetName(name); - if (pet->GetOwner()->GetGroup()) - pet->GetOwner()->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); + pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME); pet->RemoveByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED); diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index e92fdab9409..eec80888559 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -414,3 +414,22 @@ void WorldSession::HandleDBQueryBulk(WorldPackets::Query::DBQueryBulk& packet) SendPacket(response.Write()); } } + +/** +* Handles the packet sent by the client when requesting information about item text. +* +* This function is called when player clicks on item which has some flag set +*/ +void WorldSession::HandleItemTextQuery(WorldPackets::Query::ItemTextQuery& itemTextQuery) +{ + WorldPackets::Query::QueryItemTextResponse queryItemTextResponse; + queryItemTextResponse.Id = itemTextQuery.Id; + + if (Item* item = _player->GetItemByGuid(itemTextQuery.Id)) + { + queryItemTextResponse.Valid = true; + queryItemTextResponse.Item.Text = item->GetText(); + } + + SendPacket(queryItemTextResponse.Write()); +} diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 36296355577..c1d61ca49f4 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -659,7 +659,7 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPackets::Quest::Ques Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*GetPlayer(), *itr); if (!questgiver || questgiver->IsHostileTo(_player)) continue; - if (!questgiver->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) + if (!questgiver->HasFlag64(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) continue; response.QuestGiver.emplace_back(questgiver->GetGUID(), _player->GetQuestDialogStatus(questgiver)); diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 2cfa14164fe..2d3090825da 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -81,14 +81,14 @@ void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet) } // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB) - if (proto->GetClass() == ITEM_CLASS_CONSUMABLE && !(proto->GetFlags() & ITEM_PROTO_FLAG_USEABLE_IN_ARENA) && user->InArena()) + if (proto->GetClass() == ITEM_CLASS_CONSUMABLE && !(proto->GetFlags() & ITEM_FLAG_USEABLE_IN_ARENA) && user->InArena()) { user->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, item, NULL); return; } // don't allow items banned in arena - if (proto->GetFlags() & ITEM_PROTO_FLAG_NOT_USEABLE_IN_ARENA && user->InArena()) + if (proto->GetFlags() & ITEM_FLAG_NOT_USEABLE_IN_ARENA && user->InArena()) { user->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH, item, NULL); return; @@ -153,7 +153,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPackets::Spells::OpenItem& packet) } // Verify that the bag is an actual bag or wrapped item that can be used "normally" - if (!(proto->GetFlags() & ITEM_PROTO_FLAG_OPENABLE) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (!(proto->GetFlags() & ITEM_FLAG_OPENABLE) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { player->SendEquipError(EQUIP_ERR_CLIENT_LOCKED_OUT, item, NULL); TC_LOG_ERROR("network", "Possible hacking attempt: Player %s [%s] tried to open item [%s, entry: %u] which is not openable!", @@ -182,7 +182,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPackets::Spells::OpenItem& packet) } } - if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))// wrapped? + if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))// wrapped? { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM); @@ -281,8 +281,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) caster = _player; } - // check known spell - if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id)) + // check known spell or raid marker spell (which not requires player to know it) + if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->HasEffect(SPELL_EFFECT_CHANGE_RAID_MARKER)) return; // Check possible spell cast overrides diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 159876fdebd..ddfc0cef55c 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -67,7 +67,7 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) tradeItem.EntryID = item->GetEntry(); tradeItem.StackCount = item->GetCount(); tradeItem.GiftCreator = item->GetGuidValue(ITEM_FIELD_GIFTCREATOR); - if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED)) { tradeItem.Unwrapped = boost::in_place(); @@ -76,7 +76,7 @@ void WorldSession::SendUpdateTrade(bool trader_data /*= true*/) tradeItem.Unwrapped->OnUseEnchantmentID = item->GetEnchantmentId(USE_ENCHANTMENT_SLOT); tradeItem.Unwrapped->Creator = item->GetGuidValue(ITEM_FIELD_CREATOR); tradeItem.Unwrapped->Charges = item->GetSpellCharges(); - tradeItem.Unwrapped->Lock = item->GetTemplate()->GetLockID() && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED); + tradeItem.Unwrapped->Lock = item->GetTemplate()->GetLockID() && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); tradeItem.Unwrapped->MaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); tradeItem.Unwrapped->Durability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); @@ -124,7 +124,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) } // adjust time (depends on /played) - if (myItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + if (myItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE)) myItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, trader->GetTotalPlayedTime()-(_player->GetTotalPlayedTime()-myItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME))); // store trader->MoveItemToInventory(traderDst, myItems[i], true, true); @@ -142,7 +142,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) } // adjust time (depends on /played) - if (hisItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE)) + if (hisItems[i]->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_BOP_TRADEABLE)) hisItems[i]->SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, _player->GetTotalPlayedTime()-(trader->GetTotalPlayedTime()-hisItems[i]->GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME))); // store _player->MoveItemToInventory(playerDst, hisItems[i], true, true); diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp index dcca2f81711..46e2f1270c1 100644 --- a/src/server/game/Handlers/VoidStorageHandler.cpp +++ b/src/server/game/Handlers/VoidStorageHandler.cpp @@ -158,7 +158,7 @@ void WorldSession::HandleVoidStorageTransfer(WorldPackets::VoidStorage::VoidStor Item* item = _player->GetItemByGuid(voidStorageTransfer.Deposits[i]); if (!item) { - TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - %s %s wants to deposit an invalid item (%s).", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), item->GetGUID().ToString().c_str()); + TC_LOG_DEBUG("network", "WORLD: HandleVoidStorageTransfer - %s %s wants to deposit an invalid item (%s).", _player->GetGUID().ToString().c_str(), _player->GetName().c_str(), voidStorageTransfer.Deposits[i].ToString().c_str()); continue; } diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index efb3810d00c..189b620b805 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -155,12 +155,6 @@ uint32 LootStore::LoadLootTable() uint8 mincount = fields[7].GetUInt8(); uint8 maxcount = fields[8].GetUInt8(); - if (maxcount > std::numeric_limits<uint8>::max()) - { - TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: MaxCount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount, std::numeric_limits<uint8>::max()); - continue; // error already printed to log/console. - } - if (groupid >= 1 << 7) // it stored in 7 bit field { TC_LOG_ERROR("sql.sql", "Table '%s' Entry %d Item %d: GroupId (%u) must be less %u - skipped", GetName(), entry, item, groupid, 1 << 7); @@ -365,7 +359,7 @@ LootItem::LootItem(LootStoreItem const& li) conditions = li.conditions; ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemid); - freeforall = proto && (proto->GetFlags() & ITEM_PROTO_FLAG_PARTY_LOOT); + freeforall = proto && (proto->GetFlags() & ITEM_FLAG_PARTY_LOOT); follow_loot_rules = proto && (proto->FlagsCu & ITEM_FLAGS_CU_FOLLOW_LOOT_RULES); needs_quest = li.needs_quest; @@ -392,14 +386,14 @@ bool LootItem::AllowedForPlayer(Player const* player) const return false; // not show loot for players without profession or those who already know the recipe - if ((pProto->GetFlags() & ITEM_PROTO_FLAG_SMART_LOOT) && (!player->HasSkill(pProto->GetRequiredSkill()) || player->HasSpell(pProto->Effects[1]->SpellID))) + if ((pProto->GetFlags() & ITEM_FLAG_SMART_LOOT) && (!player->HasSkill(pProto->GetRequiredSkill()) || player->HasSpell(pProto->Effects[1]->SpellID))) return false; // not show loot for not own team - if ((pProto->GetFlags2() & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeam() != HORDE) + if ((pProto->GetFlags2() & ITEM_FLAG2_HORDE_ONLY) && player->GetTeam() != HORDE) return false; - if ((pProto->GetFlags2() & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE) + if ((pProto->GetFlags2() & ITEM_FLAG2_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE) return false; // check quest requirements @@ -447,7 +441,7 @@ void Loot::AddItem(LootStoreItem const& item) // non-conditional one-player only items are counted here, // free for all items are counted in FillFFALoot(), // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot() - if (!item.needs_quest && item.conditions.empty() && !(proto->GetFlags() & ITEM_PROTO_FLAG_PARTY_LOOT)) + if (!item.needs_quest && item.conditions.empty() && !(proto->GetFlags() & ITEM_FLAG_PARTY_LOOT)) ++unlootedCount; } } @@ -1651,7 +1645,7 @@ void LoadLootTemplates_Item() // remove real entries and check existence loot ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) - if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end() && itr->second.GetFlags() & ITEM_PROTO_FLAG_OPENABLE) + if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end() && itr->second.GetFlags() & ITEM_FLAG_OPENABLE) lootIdSet.erase(itr->second.GetId()); // output error for any still listed (not referenced from appropriate table) ids @@ -1676,7 +1670,7 @@ void LoadLootTemplates_Milling() ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) { - if (!(itr->second.GetFlags() & ITEM_PROTO_FLAG_MILLABLE)) + if (!(itr->second.GetFlags() & ITEM_FLAG_MILLABLE)) continue; if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end()) @@ -1739,7 +1733,7 @@ void LoadLootTemplates_Prospecting() ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) { - if (!(itr->second.GetFlags() & ITEM_PROTO_FLAG_PROSPECTABLE)) + if (!(itr->second.GetFlags() & ITEM_FLAG_PROSPECTABLE)) continue; if (lootIdSet.find(itr->second.GetId()) != lootIdSet.end()) diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index ebfdaaf3b73..26a3d38635d 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -40,7 +40,7 @@ #include "Weather.h" u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','4'} }; +u_map_magic MapVersionMagic = { {'v','1','.','5'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -78,33 +78,29 @@ Map::~Map() bool Map::ExistMap(uint32 mapid, int gx, int gy) { - int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1; - char* fileName = new char[len]; - snprintf(fileName, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), mapid, gx, gy); + std::string fileName = Trinity::StringFormat("%smaps/%04u_%02u_%02u.map", sWorld->GetDataPath().c_str(), mapid, gx, gy); bool ret = false; - FILE* pf = fopen(fileName, "rb"); - - if (!pf) + FILE* file = fopen(fileName.c_str(), "rb"); + if (!file) { - TC_LOG_ERROR("maps", "Map file '%s' does not exist!", fileName); + TC_LOG_ERROR("maps", "Map file '%s' does not exist!", fileName.c_str()); TC_LOG_ERROR("maps", "Please place MAP-files (*.map) in the appropriate directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath()+"maps/").c_str()); } else { map_fileheader header; - if (fread(&header, sizeof(header), 1, pf) == 1) + if (fread(&header, sizeof(header), 1, file) == 1) { if (header.mapMagic.asUInt != MapMagic.asUInt || header.versionMagic.asUInt != MapVersionMagic.asUInt) TC_LOG_ERROR("maps", "Map file '%s' is from an incompatible map version (%.*s %.*s), %.*s %.*s is expected. Please recreate using the mapextractor.", - fileName, 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar); + fileName.c_str(), 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar); else ret = true; } - fclose(pf); + fclose(file); } - delete[] fileName; return ret; } @@ -191,16 +187,12 @@ void Map::LoadMap(int gx, int gy, bool reload) } // map file name - char* tmp = NULL; - int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1; - tmp = new char[len]; - snprintf(tmp, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy); - TC_LOG_DEBUG("maps", "Loading map %s", tmp); + std::string fileName = Trinity::StringFormat("%smaps/%04u_%02u_%02u.map", sWorld->GetDataPath().c_str(), GetId(), gx, gy); + TC_LOG_DEBUG("maps", "Loading map %s", fileName.c_str()); // loading data GridMaps[gx][gy] = new GridMap(); - if (!GridMaps[gx][gy]->loadData(tmp)) - TC_LOG_ERROR("maps", "Error loading map file: \n %s\n", tmp); - delete[] tmp; + if (!GridMaps[gx][gy]->loadData(fileName.c_str())) + TC_LOG_ERROR("maps", "Error loading map file: %s", fileName.c_str()); sScriptMgr->OnLoadGridMap(this, GridMaps[gx][gy], gx, gy); } @@ -456,8 +448,7 @@ bool Map::EnsureGridLoaded(const Cell &cell) setGridObjectDataLoaded(true, cell.GridX(), cell.GridY()); - ObjectGridLoader loader(*grid, this, cell); - loader.LoadN(); + LoadGridObjects(grid, cell); // Add resurrectable corpses to world object list in grid sObjectAccessor->AddCorpsesToGrid(GridCoord(cell.GridX(), cell.GridY()), grid->GetGridType(cell.CellX(), cell.CellY()), this); @@ -468,12 +459,18 @@ bool Map::EnsureGridLoaded(const Cell &cell) return false; } +void Map::LoadGridObjects(NGridType* grid, Cell const& cell) +{ + ObjectGridLoader loader(*grid, this, cell); + loader.LoadN(); +} + void Map::LoadGrid(float x, float y) { EnsureGridLoaded(Cell(x, y)); } -bool Map::AddPlayerToMap(Player* player) +bool Map::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) { CellCoord cellCoord = Trinity::ComputeCellCoord(player->GetPositionX(), player->GetPositionY()); if (!cellCoord.IsCoordValid()) @@ -491,13 +488,16 @@ bool Map::AddPlayerToMap(Player* player) player->SetMap(this); player->AddToWorld(); - SendInitSelf(player); + if (initPlayer) + SendInitSelf(player); + SendInitTransports(player); SendZoneDynamicInfo(player); - player->m_clientGUIDs.clear(); - player->UpdateObjectVisibility(false); + if (initPlayer) + player->m_clientGUIDs.clear(); + player->UpdateObjectVisibility(false); player->SendUpdatePhasing(); sScriptMgr->OnPlayerEnterMap(this, player); @@ -2600,7 +2600,7 @@ void Map::SendObjectUpdates() while (!_updateObjects.empty()) { Object* obj = *_updateObjects.begin(); - ASSERT(obj && obj->IsInWorld()); + ASSERT(obj->IsInWorld()); _updateObjects.erase(_updateObjects.begin()); obj->BuildUpdate(update_players); } @@ -2616,6 +2616,17 @@ void Map::SendObjectUpdates() void Map::DelayedUpdate(const uint32 t_diff) { + for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) + { + Transport* transport = *_transportsUpdateIter; + ++_transportsUpdateIter; + + if (!transport->IsInWorld()) + continue; + + transport->DelayedUpdate(t_diff); + } + RemoveAllObjectsInRemoveList(); // Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load ! @@ -2955,7 +2966,7 @@ bool InstanceMap::CanEnter(Player* player) /* Do map specific checks and add the player to the map if successful. */ -bool InstanceMap::AddPlayerToMap(Player* player) +bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) { /// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode // GMs still can teleport player in instance. @@ -3065,7 +3076,7 @@ bool InstanceMap::AddPlayerToMap(Player* player) } // this will acquire the same mutex so it cannot be in the previous block - Map::AddPlayerToMap(player); + Map::AddPlayerToMap(player, initPlayer); if (i_data) i_data->OnPlayerEnter(player); @@ -3323,7 +3334,7 @@ bool BattlegroundMap::CanEnter(Player* player) return Map::CanEnter(player); } -bool BattlegroundMap::AddPlayerToMap(Player* player) +bool BattlegroundMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) { { std::lock_guard<std::mutex> lock(_mapLock); @@ -3333,7 +3344,7 @@ bool BattlegroundMap::AddPlayerToMap(Player* player) // reset instance validity, battleground maps do not homebind player->m_InstanceValid = true; } - return Map::AddPlayerToMap(player); + return Map::AddPlayerToMap(player, initPlayer); } void BattlegroundMap::RemovePlayerFromMap(Player* player, bool remove) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 1394808b2cc..fb1ac3cc62d 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -274,7 +274,7 @@ class Map : public GridRefManager<NGridType> return false; } - virtual bool AddPlayerToMap(Player*); + virtual bool AddPlayerToMap(Player* player, bool initPlayer = true); virtual void RemovePlayerFromMap(Player*, bool); template<class T> bool AddToMap(T *); template<class T> void RemoveFromMap(T *, bool); @@ -394,6 +394,7 @@ class Map : public GridRefManager<NGridType> bool IsBattleground() const { return i_mapEntry && i_mapEntry->IsBattleground(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattlegroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattlegroundOrArena(); } + bool IsGarrison() const { return i_mapEntry && i_mapEntry->IsGarrison(); } bool GetEntrancePos(int32 &mapid, float &x, float &y) { if (!i_mapEntry) @@ -601,6 +602,7 @@ class Map : public GridRefManager<NGridType> protected: void SetUnloadReferenceLock(const GridCoord &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } + virtual void LoadGridObjects(NGridType* grid, Cell const& cell); std::mutex _mapLock; std::mutex _gridLock; @@ -697,7 +699,7 @@ class Map : public GridRefManager<NGridType> { auto itr = _guidGenerators.find(high); if (itr == _guidGenerators.end()) - itr = _guidGenerators.insert(std::make_pair(high, std::unique_ptr<ObjectGuidGenerator<high>>(new ObjectGuidGenerator<high>()))).first; + itr = _guidGenerators.insert(std::make_pair(high, Trinity::make_unique<ObjectGuidGenerator<high>>())).first; return *itr->second; } @@ -725,7 +727,7 @@ class InstanceMap : public Map public: InstanceMap(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent); ~InstanceMap(); - bool AddPlayerToMap(Player*) override; + bool AddPlayerToMap(Player* player, bool initPlayer = true) override; void RemovePlayerFromMap(Player*, bool) override; void Update(const uint32) override; void CreateInstanceData(bool load); @@ -755,7 +757,7 @@ class BattlegroundMap : public Map BattlegroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); ~BattlegroundMap(); - bool AddPlayerToMap(Player*) override; + bool AddPlayerToMap(Player* player, bool initPlayer = true) override; void RemovePlayerFromMap(Player*, bool) override; bool CanEnter(Player* player) override; void SetUnload(); diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index c48b616788e..bd69844ae7c 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -26,6 +26,7 @@ #include "World.h" #include "Group.h" #include "Player.h" +#include "GarrisonMap.h" MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DIFFICULTY_NORMAL) { @@ -138,7 +139,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) } } } - else + else if (!IsGarrison()) { InstancePlayerBind* pBind = player->GetBoundInstance(GetId(), player->GetDifficultyID(GetEntry())); InstanceSave* pSave = pBind ? pBind->save : NULL; @@ -180,6 +181,13 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player) map = CreateInstance(newInstanceId, NULL, diff); } } + else + { + newInstanceId = player->GetGUID().GetCounter(); + map = FindInstanceMap(newInstanceId); + if (!map) + map = CreateGarrison(newInstanceId, player); + } return map; } @@ -206,7 +214,7 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, // some instances only have one difficulty GetDownscaledMapDifficultyData(GetId(), difficulty); - TC_LOG_DEBUG("maps", "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); + TC_LOG_DEBUG("maps", "MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save ? "" : "new ", InstanceId, GetId(), difficulty ? "heroic" : "normal"); InstanceMap* map = new InstanceMap(GetId(), GetGridExpiry(), InstanceId, difficulty, this); ASSERT(map->IsDungeon()); @@ -237,6 +245,17 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun return map; } +GarrisonMap* MapInstanced::CreateGarrison(uint32 instanceId, Player* owner) +{ + std::lock_guard<std::mutex> lock(_mapLock); + + GarrisonMap* map = new GarrisonMap(GetId(), GetGridExpiry(), instanceId, this, owner->GetGUID()); + ASSERT(map->IsGarrison()); + + m_InstancedMaps[instanceId] = map; + return map; +} + // increments the iterator after erase bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) { diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index c385215ba76..e487957ed6e 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -23,6 +23,8 @@ #include "InstanceSaveMgr.h" #include "DBCEnums.h" +class GarrisonMap; + class MapInstanced : public Map { friend class MapManager; @@ -66,6 +68,7 @@ class MapInstanced : public Map private: InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty); BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg); + GarrisonMap* CreateGarrison(uint32 instanceId, Player* owner); InstancedMaps m_InstancedMaps; diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index d8dba57d438..fd52bdd4c14 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -29,8 +29,8 @@ class ZoneScript ZoneScript() { } virtual ~ZoneScript() { } - virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, CreatureData const* data) { return data->id; } - virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; } + virtual uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) { return data->id; } + virtual uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) { return entry; } virtual void OnCreatureCreate(Creature* ) { } virtual void OnCreatureRemove(Creature* ) { } diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 975d74795fc..86e1c80bbd1 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1113,7 +1113,7 @@ enum SpellEffectName SPELL_EFFECT_REPUTATION = 103, SPELL_EFFECT_SUMMON_OBJECT_SLOT1 = 104, SPELL_EFFECT_SUMMON_OBJECT_SLOT2 = 105, - SPELL_EFFECT_SUMMON_OBJECT_SLOT3 = 106, + SPELL_EFFECT_CHANGE_RAID_MARKER = 106, SPELL_EFFECT_SUMMON_OBJECT_SLOT4 = 107, SPELL_EFFECT_DISPEL_MECHANIC = 108, SPELL_EFFECT_RESURRECT_PET = 109, @@ -1174,7 +1174,7 @@ enum SpellEffectName SPELL_EFFECT_REMOVE_AURA = 164, SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT = 165, SPELL_EFFECT_GIVE_CURRENCY = 166, - SPELL_EFFECT_167 = 167, + SPELL_EFFECT_UPDATE_PLAYER_PHASE = 167, SPELL_EFFECT_ALLOW_CONTROL_PET = 168, // NYI SPELL_EFFECT_DESTROY_ITEM = 169, SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES = 170, // NYI @@ -1199,8 +1199,8 @@ enum SpellEffectName SPELL_EFFECT_LOOT = 189, // NYI, lootid in MiscValue ? SPELL_EFFECT_190 = 190, SPELL_EFFECT_TELEPORT_TO_DIGSITE = 191, // NYI - SPELL_EFFECT_192 = 192, - SPELL_EFFECT_193 = 193, + SPELL_EFFECT_UNCAGE_BATTLEPET = 192, + SPELL_EFFECT_START_PET_BATTLE = 193, SPELL_EFFECT_194 = 194, SPELL_EFFECT_195 = 195, SPELL_EFFECT_196 = 196, @@ -1211,53 +1211,53 @@ enum SpellEffectName SPELL_EFFECT_ENABLE_BATTLE_PETS = 201, // NYI SPELL_EFFECT_202 = 202, SPELL_EFFECT_203 = 203, - SPELL_EFFECT_204 = 204, - SPELL_EFFECT_205 = 205, + SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY = 204, + SPELL_EFFECT_LAUNCH_QUEST_CHOICE = 205, SPELL_EFFECT_206 = 206, - SPELL_EFFECT_207 = 207, + SPELL_EFFECT_LAUNCH_QUEST_TASK = 207, // Starts one of the "progress bar" quests SPELL_EFFECT_208 = 208, SPELL_EFFECT_209 = 209, - SPELL_EFFECT_210 = 210, - SPELL_EFFECT_211 = 211, + SPELL_EFFECT_LEARN_GARRISON_BUILDING = 210, + SPELL_EFFECT_LEARN_GARRISON_SPECIALIZATION = 211, SPELL_EFFECT_212 = 212, SPELL_EFFECT_213 = 213, - SPELL_EFFECT_214 = 214, - SPELL_EFFECT_215 = 215, - SPELL_EFFECT_216 = 216, - SPELL_EFFECT_217 = 217, + SPELL_EFFECT_CREATE_GARRISON = 214, + SPELL_EFFECT_UPGRADE_CHARACTER_SPELLS = 215, // Unlocks boosted players' spells (ChrUpgrade*.db2) + SPELL_EFFECT_CREATE_SHIPMENT = 216, + SPELL_EFFECT_UPGRADE_GARRISON = 217, SPELL_EFFECT_218 = 218, SPELL_EFFECT_219 = 219, - SPELL_EFFECT_220 = 220, + SPELL_EFFECT_ADD_GARRISON_FOLLOWER = 220, SPELL_EFFECT_221 = 221, - SPELL_EFFECT_222 = 222, - SPELL_EFFECT_223 = 223, - SPELL_EFFECT_224 = 224, - SPELL_EFFECT_225 = 225, + SPELL_EFFECT_CREATE_HEIRLOOM_ITEM = 222, + SPELL_EFFECT_CHANGE_ITEM_BONUSES = 223, + SPELL_EFFECT_ACTIVATE_GARRISON_BUILDING = 224, + SPELL_EFFECT_GRANT_BATTLEPET_LEVEL = 225, SPELL_EFFECT_226 = 226, SPELL_EFFECT_227 = 227, SPELL_EFFECT_228 = 228, - SPELL_EFFECT_229 = 229, - SPELL_EFFECT_230 = 230, - SPELL_EFFECT_231 = 231, - SPELL_EFFECT_232 = 232, - SPELL_EFFECT_233 = 233, + SPELL_EFFECT_SET_FOLLOWER_QUALITY = 229, + SPELL_EFFECT_INCREASE_FOLLOWER_ITEM_LEVEL = 230, + SPELL_EFFECT_INCREASE_FOLLOWER_EXPERIENCE = 231, + SPELL_EFFECT_REMOVE_PHASE = 232, + SPELL_EFFECT_RANDOMIZE_FOLLOWER_ABILITIES = 233, SPELL_EFFECT_234 = 234, SPELL_EFFECT_235 = 235, - SPELL_EFFECT_236 = 236, - SPELL_EFFECT_237 = 237, - SPELL_EFFECT_238 = 238, - SPELL_EFFECT_239 = 239, + SPELL_EFFECT_GIVE_EXPERIENCE = 236, // Increases players XP + SPELL_EFFECT_GIVE_RESTED_EXPERIENCE_BONUS = 237, + SPELL_EFFECT_INCREASE_SKILL = 238, + SPELL_EFFECT_END_GARRISON_BUILDING_CONSTRUCTION = 239, // Instantly finishes building construction SPELL_EFFECT_240 = 240, SPELL_EFFECT_241 = 241, SPELL_EFFECT_242 = 242, - SPELL_EFFECT_243 = 243, - SPELL_EFFECT_244 = 244, - SPELL_EFFECT_245 = 245, - SPELL_EFFECT_246 = 246, - SPELL_EFFECT_247 = 247, - SPELL_EFFECT_248 = 248, + SPELL_EFFECT_APPLY_ENCHANT_ILLUSION = 243, + SPELL_EFFECT_LEARN_FOLLOWER_ABILITY = 244, + SPELL_EFFECT_UPGRADE_HEIRLOOM = 245, + SPELL_EFFECT_FINISH_GARRISON_MISSION = 246, + SPELL_EFFECT_ADD_GARRISON_MISSION = 247, + SPELL_EFFECT_FINISH_SHIPMENT = 248, SPELL_EFFECT_249 = 249, - SPELL_EFFECT_250 = 250, + SPELL_EFFECT_TAKE_SCREENSHOT = 250, // Serverside marker for selfie screenshot - achievement check TOTAL_SPELL_EFFECTS = 251, }; @@ -4882,7 +4882,7 @@ enum PartyResult }; const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP' -#define MMAP_VERSION 6 +#define MMAP_VERSION 7 struct MmapTileHeader { diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 0b547d96e7f..c8da50364ba 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -182,7 +182,7 @@ class MotionMaster //: private std::stack<MovementGenerator *> void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); void MoveJumpTo(float angle, float speedXY, float speedZ); void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP) - { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); }; + { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); } void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP); void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount); void MoveFall(uint32 id = 0); diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h index f50633205aa..acd0c94bbf1 100644 --- a/src/server/game/Movement/Spline/MoveSplineFlag.h +++ b/src/server/game/Movement/Spline/MoveSplineFlag.h @@ -32,12 +32,12 @@ namespace Movement { None = 0x00000000, // x00-x07 used as animation Ids storage in pair with Animation flag - Unknown0 = 0x00000008, // NOT VERIFIED + Unknown0 = 0x00000008, // NOT VERIFIED - does someting related to falling/fixed orientation FallingSlow = 0x00000010, Done = 0x00000020, Falling = 0x00000040, // Affects elevation computation, can't be combined with Parabolic flag No_Spline = 0x00000080, - Unknown2 = 0x00000100, // NOT VERIFIED + Unknown1 = 0x00000100, // NOT VERIFIED Flying = 0x00000200, // Smooth movement(Catmullrom interpolation mode), flying animation OrientationFixed = 0x00000400, // Model orientation fixed Catmullrom = 0x00000800, // Used Catmullrom interpolation mode @@ -46,21 +46,21 @@ namespace Movement Frozen = 0x00004000, // Will never arrive TransportEnter = 0x00008000, TransportExit = 0x00010000, - Unknown3 = 0x00020000, // NOT VERIFIED - Unknown4 = 0x00040000, // NOT VERIFIED + Unknown2 = 0x00020000, // NOT VERIFIED + Unknown3 = 0x00040000, // NOT VERIFIED OrientationInversed = 0x00080000, SmoothGroundPath = 0x00100000, Walkmode = 0x00200000, UncompressedPath = 0x00400000, - Unknown6 = 0x00800000, // NOT VERIFIED - Animation = 0x01000000, // Plays animation after some time passed - Parabolic = 0x02000000, // Affects elevation computation, can't be combined with Falling flag - Final_Point = 0x04000000, - Final_Target = 0x08000000, - Final_Angle = 0x10000000, - Unknown7 = 0x20000000, // NOT VERIFIED - Unknown8 = 0x40000000, // NOT VERIFIED - Unknown9 = 0x80000000, // NOT VERIFIED + Unknown4 = 0x00800000, // NOT VERIFIED + Unknown5 = 0x01000000, // NOT VERIFIED + Animation = 0x02000000, // Plays animation after some time passed + Parabolic = 0x04000000, // Affects elevation computation, can't be combined with Falling flag + Final_Point = 0x08000000, + Final_Target = 0x10000000, + Final_Angle = 0x20000000, + Unknown6 = 0x40000000, // NOT VERIFIED + Unknown7 = 0x80000000, // NOT VERIFIED // Masks Mask_Final_Facing = Final_Point | Final_Target | Final_Angle, @@ -69,7 +69,7 @@ namespace Movement // flags that shouldn't be appended into SMSG_MONSTER_MOVE\SMSG_MONSTER_MOVE_TRANSPORT packet, should be more probably Mask_No_Monster_Move = Mask_Final_Facing | Mask_Animations | Done, // Unused, not suported flags - Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown0|Unknown2|Unknown3|Unknown4|Unknown6|Unknown7|Unknown8|Unknown9 + Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown0|Unknown1|Unknown2|Unknown3|Unknown4|Unknown5|Unknown6|Unknown7 }; inline uint32& raw() { return (uint32&)*this; } @@ -114,7 +114,7 @@ namespace Movement bool done : 1; bool falling : 1; bool no_spline : 1; - bool unknown2 : 1; + bool unknown1 : 1; bool flying : 1; bool orientationFixed : 1; bool catmullrom : 1; @@ -123,21 +123,21 @@ namespace Movement bool frozen : 1; bool transportEnter : 1; bool transportExit : 1; + bool unknown2 : 1; bool unknown3 : 1; - bool unknown4 : 1; bool orientationInversed : 1; bool smoothGroundPath : 1; bool walkmode : 1; bool uncompressedPath : 1; - bool unknown6 : 1; + bool unknown4 : 1; + bool unknown5 : 1; bool animation : 1; bool parabolic : 1; bool final_point : 1; bool final_target : 1; bool final_angle : 1; + bool unknown6 : 1; bool unknown7 : 1; - bool unknown8 : 1; - bool unknown9 : 1; }; #pragma pack(pop) } diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index 0343e92c506..117891140da 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -162,12 +162,14 @@ bool OPvPCapturePoint::DelCreature(uint32 type) } auto bounds = m_PvP->GetMap()->GetCreatureBySpawnIdStore().equal_range(spawnId); - for (auto itr = bounds.first; itr != bounds.second; ++itr) + for (auto itr = bounds.first; itr != bounds.second;) { + Creature* c = itr->second; + ++itr; // Don't save respawn time - itr->second->SetRespawnTime(0); - itr->second->RemoveCorpse(); - itr->second->AddObjectToRemoveList(); + c->SetRespawnTime(0); + c->RemoveCorpse(); + c->AddObjectToRemoveList(); } TC_LOG_DEBUG("outdoorpvp", "deleting opvp creature type %u", type); @@ -196,11 +198,13 @@ bool OPvPCapturePoint::DelObject(uint32 type) ObjectGuid::LowType spawnId = m_Objects[type]; auto bounds = m_PvP->GetMap()->GetGameObjectBySpawnIdStore().equal_range(spawnId); - for (auto itr = bounds.first; itr != bounds.second; ++itr) + for (auto itr = bounds.first; itr != bounds.second;) { + GameObject* go = itr->second; + ++itr; // Don't save respawn time - itr->second->SetRespawnTime(0); - itr->second->Delete(); + go->SetRespawnTime(0); + go->Delete(); } sObjectMgr->DeleteGOData(spawnId); diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp index 15f378e138a..a82652d2f03 100644 --- a/src/server/game/Pools/PoolMgr.cpp +++ b/src/server/game/Pools/PoolMgr.cpp @@ -225,8 +225,12 @@ void PoolGroup<Creature>::Despawn1Object(uint64 guid) if (!map->Instanceable()) { auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(guid); - for (auto itr = creatureBounds.first; itr != creatureBounds.second; ++itr) - itr->second->AddObjectToRemoveList(); + for (auto itr = creatureBounds.first; itr != creatureBounds.second;) + { + Creature* creature = itr->second; + ++itr; + creature->AddObjectToRemoveList(); + } } } } @@ -243,8 +247,12 @@ void PoolGroup<GameObject>::Despawn1Object(uint64 guid) if (!map->Instanceable()) { auto gameobjectBounds = map->GetGameObjectBySpawnIdStore().equal_range(guid); - for (auto itr = gameobjectBounds.first; itr != gameobjectBounds.second; ++itr) - itr->second->AddObjectToRemoveList(); + for (auto itr = gameobjectBounds.first; itr != gameobjectBounds.second;) + { + GameObject* go = itr->second; + ++itr; + go->AddObjectToRemoveList(); + } } } } diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index c878287b4ac..148cdeab68e 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -34,7 +34,7 @@ Quest::Quest(Field* questRecord) SuggestedPlayers = questRecord[7].GetUInt8(); NextQuestInChain = questRecord[8].GetUInt32(); RewardXPDifficulty = questRecord[9].GetUInt32(); - Float10 = questRecord[10].GetFloat(); + RewardXPMultiplier = questRecord[10].GetFloat(); RewardMoney = questRecord[11].GetUInt32(); RewardMoneyDifficulty = questRecord[12].GetUInt32(); Float13 = questRecord[13].GetFloat(); @@ -225,7 +225,7 @@ uint32 Quest::XPValue(uint32 playerLevel) const else if (diffFactor > 10) diffFactor = 10; - uint32 xp = diffFactor * xpentry->Exp[RewardXPDifficulty] / 10; + uint32 xp = diffFactor * xpentry->Exp[RewardXPDifficulty] * RewardXPMultiplier / 10; if (xp <= 100) xp = 5 * ((xp + 2) / 5); else if (xp <= 500) diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 8433a549c60..e11794dc64c 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -226,7 +226,8 @@ enum QuestObjectiveType QUEST_OBJECTIVE_AREATRIGGER = 10, QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC = 11, QUEST_OBJECTIVE_DEFEATBATTLEPET = 12, - QUEST_OBJECTIVE_WINPVPPETBATTLES = 13 + QUEST_OBJECTIVE_WINPVPPETBATTLES = 13, + QUEST_OBJECTIVE_CRITERIA_TREE = 14 }; struct QuestTemplateLocale @@ -318,6 +319,7 @@ class Quest uint32 GetBonusTalents() const { return RewardTalents; } int32 GetRewArenaPoints() const {return RewardArenaPoints; } uint32 GetXPDifficulty() const { return RewardXPDifficulty; } + float GetXPMultiplier() const { return RewardXPMultiplier; } uint32 GetSrcItemId() const { return SourceItemId; } uint32 GetSrcItemCount() const { return SourceItemIdCount; } uint32 GetSrcSpell() const { return SourceSpellID; } @@ -332,7 +334,7 @@ class Quest std::string const& GetPortraitGiverName() const { return PortraitGiverName; } std::string const& GetPortraitTurnInText() const { return PortraitTurnInText; } std::string const& GetPortraitTurnInName() const { return PortraitTurnInName; } - QuestObjectives const& GetObjectives() const { return Objectives; }; + QuestObjectives const& GetObjectives() const { return Objectives; } uint32 GetRewMoney() const; uint32 GetRewMoneyDifficulty() const { return RewardMoneyDifficulty; } uint32 GetRewHonor() const { return RewardHonor; } @@ -401,7 +403,7 @@ class Quest uint32 SuggestedPlayers; uint32 NextQuestInChain; uint32 RewardXPDifficulty; - float Float10; + float RewardXPMultiplier; int32 RewardMoney; uint32 RewardMoneyDifficulty; float Float13; diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp index 1db3dbb9f93..ecfc069ca78 100644 --- a/src/server/game/Scripting/MapScripts.cpp +++ b/src/server/game/Scripting/MapScripts.cpp @@ -283,18 +283,11 @@ inline void Map::_ScriptProcessDoor(Object* source, Object* target, const Script inline GameObject* Map::_FindGameObject(WorldObject* searchObject, ObjectGuid::LowType guid) const { - GameObject* gameobject = NULL; + auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid); + if (bounds.first == bounds.second) + return nullptr; - 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->GetGridActivationRange()); - - return gameobject; + return bounds.first->second; } /// Process queued scripts @@ -806,26 +799,17 @@ void Map::ScriptsProcess() } Creature* cTarget = NULL; - WorldObject* wSource = dynamic_cast <WorldObject*> (source); - if (wSource) //using grid searcher + WorldObject* wSource = dynamic_cast<WorldObject*>(source); + auto creatureBounds = _creatureBySpawnIdStore.equal_range(step.script->CallScript.CreatureEntry); + if (creatureBounds.first != creatureBounds.second) { - CellCoord p(Trinity::ComputeCellCoord(wSource->GetPositionX(), wSource->GetPositionY())); - Cell cell(p); - - Trinity::CreatureWithDbGUIDCheck target_check(wSource, uint64(step.script->CallScript.CreatureEntry)); - Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(wSource, cTarget, target_check); - - TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker); - cell.Visit(p, unit_checker, *wSource->GetMap(), *wSource, wSource->GetGridActivationRange()); - } - else //check hashmap holders - { - if (CreatureData const* data = sObjectMgr->GetCreatureData(step.script->CallScript.CreatureEntry)) + // Prefer alive (last respawned) creature + auto creatureItr = std::find_if(creatureBounds.first, creatureBounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair) { - auto creatureBounds = _creatureBySpawnIdStore.equal_range(step.script->CallScript.CreatureEntry); - if (creatureBounds.first != creatureBounds.second) - cTarget = creatureBounds.first->second; - } + return pair.second->IsAlive(); + }); + + cTarget = creatureItr != creatureBounds.second ? creatureItr->second : creatureBounds.first->second; } if (!cTarget) diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 553c752ccce..aa8be4946e4 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -634,6 +634,7 @@ void AddSC_instance_magtheridons_lair(); void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls void AddSC_boss_warbringer_omrogg(); void AddSC_boss_warchief_kargath_bladefist(); +void AddSC_shattered_halls(); void AddSC_instance_shattered_halls(); void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts void AddSC_boss_omor_the_unscarred(); @@ -1188,6 +1189,7 @@ void AddOutlandScripts() AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls AddSC_boss_warbringer_omrogg(); AddSC_boss_warchief_kargath_bladefist(); + AddSC_shattered_halls(); AddSC_instance_shattered_halls(); AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts AddSC_boss_omor_the_unscarred(); diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index 12161867004..40af397e110 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -60,6 +60,7 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket << uint8(Result); _worldPacket.WriteBit(SuccessInfo.is_initialized()); _worldPacket.WriteBit(WaitInfo.is_initialized()); + _worldPacket.FlushBits(); if (SuccessInfo) { @@ -83,6 +84,8 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket.WriteBit(realm.IsInternalRealm); _worldPacket.WriteBits(realm.RealmNameActual.length(), 8); _worldPacket.WriteBits(realm.RealmNameNormalized.length(), 8); + _worldPacket.FlushBits(); + _worldPacket.WriteString(realm.RealmNameActual); _worldPacket.WriteString(realm.RealmNameNormalized); } @@ -111,6 +114,8 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket.WriteBits(templat.Name.length(), 7); _worldPacket.WriteBits(templat.Description.length(), 10); + _worldPacket.FlushBits(); + _worldPacket.WriteString(templat.Name); _worldPacket.WriteString(templat.Description); } @@ -120,6 +125,7 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() _worldPacket.WriteBit(SuccessInfo->NumPlayersHorde.is_initialized()); _worldPacket.WriteBit(SuccessInfo->NumPlayersAlliance.is_initialized()); _worldPacket.WriteBit(SuccessInfo->IsVeteranTrial); + _worldPacket.FlushBits(); if (SuccessInfo->NumPlayersHorde) _worldPacket << uint16(*SuccessInfo->NumPlayersHorde); @@ -132,9 +138,9 @@ WorldPacket const* WorldPackets::Auth::AuthResponse::Write() { _worldPacket << uint32(WaitInfo->WaitCount); _worldPacket.WriteBit(WaitInfo->HasFCM); + _worldPacket.FlushBits(); } - _worldPacket.FlushBits(); return &_worldPacket; } diff --git a/src/server/game/Server/Packets/ChannelPackets.cpp b/src/server/game/Server/Packets/ChannelPackets.cpp index 5acb018b46f..cc6406b81bc 100644 --- a/src/server/game/Server/Packets/ChannelPackets.cpp +++ b/src/server/game/Server/Packets/ChannelPackets.cpp @@ -83,6 +83,49 @@ WorldPacket const* WorldPackets::Channel::ChannelNotifyLeft::Write() return &_worldPacket; } +WorldPacket const* WorldPackets::Channel::UserlistAdd::Write() +{ + _worldPacket << AddedUserGUID; + _worldPacket << uint8(_ChannelFlags); + _worldPacket << uint8(UserFlags); + + _worldPacket << uint32(ChannelID); + + _worldPacket.WriteBits(ChannelName.length(), 7); + _worldPacket.FlushBits(); + _worldPacket.WriteString(ChannelName); + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Channel::UserlistRemove::Write() +{ + _worldPacket << RemovedUserGUID; + + _worldPacket << uint8(_ChannelFlags); + + _worldPacket << uint32(ChannelID); + + _worldPacket.WriteBits(ChannelName.length(), 7); + _worldPacket.FlushBits(); + _worldPacket.WriteString(ChannelName); + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Channel::UserlistUpdate::Write() +{ + _worldPacket << UpdatedUserGUID; + + _worldPacket << uint8(_ChannelFlags); + _worldPacket << uint8(UserFlags); + + _worldPacket << uint32(ChannelID); + + _worldPacket.WriteBits(ChannelName.length(), 7); + _worldPacket.FlushBits(); + _worldPacket.WriteString(ChannelName); + return &_worldPacket; +} + void WorldPackets::Channel::ChannelPlayerCommand::Read() { switch (GetOpcode()) diff --git a/src/server/game/Server/Packets/ChannelPackets.h b/src/server/game/Server/Packets/ChannelPackets.h index ca47c76edc9..7464e9bd391 100644 --- a/src/server/game/Server/Packets/ChannelPackets.h +++ b/src/server/game/Server/Packets/ChannelPackets.h @@ -95,6 +95,56 @@ namespace WorldPackets bool Suspended = false; ///< User Leave - false, On Zone Change - true }; + class UserlistAdd final : public ServerPacket + { + public: + UserlistAdd() : ServerPacket(SMSG_USERLIST_ADD, 30) { } + + WorldPacket const* Write() override; + + ObjectGuid AddedUserGUID; + + uint8 _ChannelFlags = CHANNEL_FLAG_NONE; ///< @see enum ChannelFlags + uint8 UserFlags = MEMBER_FLAG_NONE; + + int32 ChannelID = 0; + + std::string ChannelName; + }; + + class UserlistRemove final : public ServerPacket + { + public: + UserlistRemove() : ServerPacket(SMSG_USERLIST_REMOVE, 30) { } + + WorldPacket const* Write() override; + + ObjectGuid RemovedUserGUID; + + uint8 _ChannelFlags = CHANNEL_FLAG_NONE; ///< @see enum ChannelFlags + + uint32 ChannelID = 0; + + std::string ChannelName; + }; + + class UserlistUpdate final : public ServerPacket + { + public: + UserlistUpdate() : ServerPacket(SMSG_USERLIST_UPDATE, 30) { } + + WorldPacket const* Write() override; + + ObjectGuid UpdatedUserGUID; + + uint8 _ChannelFlags = CHANNEL_FLAG_NONE; ///< @see enum ChannelFlags + uint8 UserFlags = MEMBER_FLAG_NONE; + + int32 ChannelID = 0; + + std::string ChannelName; + }; + class ChannelPlayerCommand final : public ClientPacket { public: diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index d3b3050216c..9c6bb07f56e 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -154,6 +154,8 @@ WorldPacket const* WorldPackets::Character::EnumCharactersResult::Write() _worldPacket.WriteBit(charInfo.FirstLogin); _worldPacket.WriteBit(charInfo.BoostInProgress); _worldPacket.WriteBits(charInfo.unkWod61x, 5); + _worldPacket.FlushBits(); + _worldPacket.WriteString(charInfo.Name); } @@ -215,11 +217,13 @@ WorldPacket const* WorldPackets::Character::CharacterRenameResult::Write() _worldPacket << uint8(Result); _worldPacket.WriteBit(Guid.is_initialized()); _worldPacket.WriteBits(Name.length(), 6); + _worldPacket.FlushBits(); if (Guid) _worldPacket << *Guid; _worldPacket.WriteString(Name); + return &_worldPacket; } @@ -305,19 +309,21 @@ WorldPacket const* WorldPackets::Character::GenerateRandomCharacterNameResult::W { _worldPacket.WriteBit(Success); _worldPacket.WriteBits(Name.length(), 6); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Name); + return &_worldPacket; } void WorldPackets::Character::ReorderCharacters::Read() { uint32 count = std::min<uint32>(_worldPacket.ReadBits(9), sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM)); - while (count--) + Entries.resize(count); + for (ReorderInfo& reorderInfo : Entries) { - ReorderInfo reorderInfo; _worldPacket >> reorderInfo.PlayerGUID; _worldPacket >> reorderInfo.NewPosition; - Entries.emplace_back(reorderInfo); } } @@ -492,3 +498,40 @@ WorldPacket const* WorldPackets::Character::SetFactionVisible::Write() _worldPacket << FactionIndex; return &_worldPacket; } + +WorldPackets::Character::CharCustomizeResponse::CharCustomizeResponse(WorldPackets::Character::CharCustomizeInfo const* info) + : ServerPacket(SMSG_CHAR_CUSTOMIZE, 16 + 1 + 1 + 1 + 1 + 1 + 1 + 1) +{ + CharGUID = info->CharGUID; + SexID = info->SexID; + SkinID = info->SkinID; + HairColorID = info->HairColorID; + HairStyleID = info->HairStyleID; + FacialHairStyleID = info->FacialHairStyleID; + FaceID = info->FaceID; + CharName = info->CharName; +} + +WorldPacket const* WorldPackets::Character::CharCustomizeResponse::Write() +{ + _worldPacket << CharGUID; + _worldPacket << uint8(SexID); + _worldPacket << uint8(SkinID); + _worldPacket << uint8(HairColorID); + _worldPacket << uint8(HairStyleID); + _worldPacket << uint8(FacialHairStyleID); + _worldPacket << uint8(FaceID); + _worldPacket.WriteBits(CharName.length(), 6); + _worldPacket.FlushBits(); + _worldPacket.WriteString(CharName); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Character::CharCustomizeFailed::Write() +{ + _worldPacket << uint8(Result); + _worldPacket << CharGUID; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CharacterPackets.h b/src/server/game/Server/Packets/CharacterPackets.h index cee4f5edb5c..10f1053f8ee 100644 --- a/src/server/game/Server/Packets/CharacterPackets.h +++ b/src/server/game/Server/Packets/CharacterPackets.h @@ -608,7 +608,7 @@ namespace WorldPackets WorldPacket const* Write() override; - BarberShopResult Result; + BarberShopResult Result = BARBER_SHOP_RESULT_SUCCESS; }; class LogXPGain final : public ServerPacket @@ -686,6 +686,35 @@ namespace WorldPackets uint32 FactionIndex = 0; }; + + class CharCustomizeResponse final : public ServerPacket + { + public: + CharCustomizeResponse() : ServerPacket(SMSG_CHAR_CUSTOMIZE, 16 + 1 + 1 + 1 + 1 + 1 + 1 + 1) { } + CharCustomizeResponse(CharCustomizeInfo const* customizeInfo); + + WorldPacket const* Write() override; + + ObjectGuid CharGUID; + std::string CharName; + uint8 SexID = 0; + uint8 SkinID = 0; + uint8 HairColorID = 0; + uint8 HairStyleID = 0; + uint8 FacialHairStyleID = 0; + uint8 FaceID = 0; + }; + + class CharCustomizeFailed final : public ServerPacket + { + public: + CharCustomizeFailed() : ServerPacket(SMSG_CHAR_CUSTOMIZE_FAILED, 1 + 16) { } + + WorldPacket const* Write() override; + + uint8 Result = 0; + ObjectGuid CharGUID; + }; } } diff --git a/src/server/game/Server/Packets/ChatPackets.cpp b/src/server/game/Server/Packets/ChatPackets.cpp index de4194db023..4204278d514 100644 --- a/src/server/game/Server/Packets/ChatPackets.cpp +++ b/src/server/game/Server/Packets/ChatPackets.cpp @@ -92,7 +92,7 @@ void WorldPackets::Chat::ChatMessageEmote::Read() Text = _worldPacket.ReadString(len); } -void WorldPackets::Chat::Chat::Initalize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, +void WorldPackets::Chat::Chat::Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId /*= 0*/, std::string channelName /*= ""*/, LocaleConstant locale /*= DEFAULT_LOCALE*/, std::string addonPrefix /*= ""*/) { // Clear everything because same packet can be used multiple times @@ -165,6 +165,8 @@ WorldPacket const* WorldPackets::Chat::Chat::Write() _worldPacket.WriteBits(_ChatFlags, 11); _worldPacket.WriteBit(HideChatLog); _worldPacket.WriteBit(FakeSenderName); + _worldPacket.FlushBits(); + _worldPacket.WriteString(SenderName); _worldPacket.WriteString(TargetName); _worldPacket.WriteString(Prefix); @@ -203,14 +205,43 @@ WorldPacket const* WorldPackets::Chat::STextEmote::Write() WorldPacket const* WorldPackets::Chat::PrintNotification::Write() { _worldPacket.WriteBits(NotifyText.size(), 12); + _worldPacket.FlushBits(); + _worldPacket.WriteString(NotifyText); + return &_worldPacket; } WorldPacket const* WorldPackets::Chat::ChatPlayerNotfound::Write() { _worldPacket.WriteBits(Name.length(), 9); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Name); return &_worldPacket; } + +WorldPacket const* WorldPackets::Chat::ChatServerMessage::Write() +{ + _worldPacket << MessageID; + + _worldPacket.WriteBits(StringParam.length(), 11); + _worldPacket.FlushBits(); + + _worldPacket.WriteString(StringParam); + + return &_worldPacket; +} + +void WorldPackets::Chat::ChatRegisterAddonPrefixes::Read() +{ + int32 count; + _worldPacket >> count; + + for (int32 i = 0; i < count; ++i) + { + uint32 lenghts = _worldPacket.ReadBits(5); + Prefixes.push_back(_worldPacket.ReadString(lenghts)); + } +} diff --git a/src/server/game/Server/Packets/ChatPackets.h b/src/server/game/Server/Packets/ChatPackets.h index b794d118d88..c8bb038ce19 100644 --- a/src/server/game/Server/Packets/ChatPackets.h +++ b/src/server/game/Server/Packets/ChatPackets.h @@ -151,7 +151,7 @@ namespace WorldPackets public: Chat() : ServerPacket(SMSG_CHAT, 100) { } - void Initalize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId = 0, std::string channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string addonPrefix = ""); + void Initialize(ChatMsg chatType, Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId = 0, std::string channelName = "", LocaleConstant locale = DEFAULT_LOCALE, std::string addonPrefix = ""); WorldPacket const* Write() override; uint8 SlashCmd = 0; ///< @see enum ChatMsg @@ -239,6 +239,35 @@ namespace WorldPackets std::string Name; }; + + class ChatServerMessage final : public ServerPacket + { + public: + ChatServerMessage() : ServerPacket(SMSG_CHAT_SERVER_MESSAGE, 4 + 2) { } + + WorldPacket const* Write() override; + + int32 MessageID = 0; + std::string StringParam; + }; + + class ChatRegisterAddonPrefixes final : public ClientPacket + { + public: + ChatRegisterAddonPrefixes(WorldPacket&& packet) : ClientPacket(CMSG_CHAT_REGISTER_ADDON_PREFIXES, std::move(packet)) { } + + void Read() override; + + std::vector<std::string> Prefixes; + }; + + class ChatUnregisterAllAddonPrefixes final : public ClientPacket + { + public: + ChatUnregisterAllAddonPrefixes(WorldPacket&& packet) : ClientPacket(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, std::move(packet)) { } + + void Read() override { } + }; } } diff --git a/src/server/game/Server/Packets/CombatLogPackets.cpp b/src/server/game/Server/Packets/CombatLogPackets.cpp index 0702ad63f05..295f27375da 100644 --- a/src/server/game/Server/Packets/CombatLogPackets.cpp +++ b/src/server/game/Server/Packets/CombatLogPackets.cpp @@ -147,3 +147,76 @@ WorldPacket const* WorldPackets::CombatLog::SpellHealLog::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::CombatLog::SpellPeriodicAuraLog::Write() +{ + _worldPacket << TargetGUID; + _worldPacket << CasterGUID; + _worldPacket << SpellID; + + _worldPacket << uint32(Effects.size()); + + for (SpellLogEffect const& effect : Effects) + { + _worldPacket << effect.Effect; + _worldPacket << int32(effect.Amount); + _worldPacket << int32(effect.OverHealOrKill); + _worldPacket << int32(effect.SchoolMaskOrPower); + _worldPacket << int32(effect.AbsorbedOrAmplitude); + _worldPacket << int32(effect.Resisted); + + _worldPacket.WriteBit(effect.Crit); + _worldPacket.WriteBit(effect.Multistrike); + + if (_worldPacket.WriteBit(effect.DebugInfo.is_initialized())) + { + _worldPacket << float(effect.DebugInfo->CritRollMade); + _worldPacket << float(effect.DebugInfo->CritRollNeeded); + } + + _worldPacket.FlushBits(); + } + + _worldPacket.WriteBit(LogData.is_initialized()); + _worldPacket.FlushBits(); + if (LogData) + _worldPacket << *LogData; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::CombatLog::SpellInterruptLog::Write() +{ + _worldPacket << Caster; + _worldPacket << Victim; + _worldPacket << int32(InterruptedSpellID); + _worldPacket << int32(SpellID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::CombatLog::SpellEnergizeLog::Write() +{ + _worldPacket << CasterGUID; + _worldPacket << TargetGUID; + + _worldPacket << int32(SpellID); + _worldPacket << int32(Type); + _worldPacket << int32(Amount); + + _worldPacket.WriteBit(LogData.is_initialized()); + _worldPacket.FlushBits(); + if (LogData) + _worldPacket << *LogData; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::CombatLog::SpellInstakillLog::Write() +{ + _worldPacket << Target; + _worldPacket << Caster; + _worldPacket << int32(SpellID); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CombatLogPackets.h b/src/server/game/Server/Packets/CombatLogPackets.h index c74e8112698..1962bc2c2fc 100644 --- a/src/server/game/Server/Packets/CombatLogPackets.h +++ b/src/server/game/Server/Packets/CombatLogPackets.h @@ -91,7 +91,6 @@ namespace WorldPackets class SpellHealLog final : public ServerPacket { public: - SpellHealLog() : ServerPacket(SMSG_SPELL_HEAL_LOG, 16 + 16 + 4 * 4 + 1) { } WorldPacket const* Write() override; @@ -108,6 +107,79 @@ namespace WorldPackets Optional<float> CritRollNeeded; Optional<Spells::SpellCastLogData> LogData; /// @todo: find the correct way where to use it, in sniff always false }; + + class SpellPeriodicAuraLog final : public ServerPacket + { + public: + struct PeriodicalAuraLogEffectDebugInfo + { + float CritRollMade = 0.0f; + float CritRollNeeded = 0.0f; + }; + + struct SpellLogEffect + { + int32 Effect = 0; + int32 Amount = 0; + int32 OverHealOrKill = 0; + int32 SchoolMaskOrPower = 0; + int32 AbsorbedOrAmplitude = 0; + int32 Resisted = 0; + bool Crit = false; + bool Multistrike = false; + Optional<PeriodicalAuraLogEffectDebugInfo> DebugInfo; + }; + + SpellPeriodicAuraLog() : ServerPacket(SMSG_SPELL_PERIODIC_AURA_LOG, 16 + 16 + 4 + 4 + 1) { } + + WorldPacket const* Write() override; + + ObjectGuid TargetGUID; + ObjectGuid CasterGUID; + int32 SpellID = 0; + std::vector<SpellLogEffect> Effects; + Optional<Spells::SpellCastLogData> LogData; /// @todo: find the correct way where to use it, in sniff always false + }; + + class SpellInterruptLog final : public ServerPacket + { + public: + SpellInterruptLog() : ServerPacket(SMSG_SPELL_INTERRUPT_LOG, 16 + 16 + 4 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid Caster; + ObjectGuid Victim; + int32 InterruptedSpellID = 0; + int32 SpellID = 0; + }; + + class SpellEnergizeLog final : public ServerPacket + { + public: + SpellEnergizeLog() : ServerPacket(SMSG_SPELL_ENERGIZE_LOG, 16 + 16 + 4 + 4 + 4 + 1) { } + + WorldPacket const* Write() override; + + ObjectGuid CasterGUID; + ObjectGuid TargetGUID; + int32 SpellID = 0; + int32 Type = 0; + int32 Amount = 0; + Optional<Spells::SpellCastLogData> LogData; /// @todo: find the correct way where to use it, in sniff always false + }; + + class SpellInstakillLog final : public ServerPacket + { + public: + SpellInstakillLog() : ServerPacket(SMSG_SPELL_INSTAKILL_LOG, 16 + 16 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid Target; + ObjectGuid Caster; + int32 SpellID; + }; } } diff --git a/src/server/game/Server/Packets/CombatPackets.cpp b/src/server/game/Server/Packets/CombatPackets.cpp index e095e951e36..d47f2275ee6 100644 --- a/src/server/game/Server/Packets/CombatPackets.cpp +++ b/src/server/game/Server/Packets/CombatPackets.cpp @@ -198,3 +198,12 @@ WorldPacket const* WorldPackets::Combat::ThreatClear::Write() _worldPacket << UnitGUID; return &_worldPacket; } + +WorldPacket const* WorldPackets::Combat::PvPCredit::Write() +{ + _worldPacket << int32(Honor); + _worldPacket << Target; + _worldPacket << int32(Rank); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/CombatPackets.h b/src/server/game/Server/Packets/CombatPackets.h index 0cab58044eb..deeb98fe335 100644 --- a/src/server/game/Server/Packets/CombatPackets.h +++ b/src/server/game/Server/Packets/CombatPackets.h @@ -246,6 +246,18 @@ namespace WorldPackets ObjectGuid UnitGUID; }; + + class PvPCredit final : public ServerPacket + { + public: + PvPCredit() : ServerPacket(SMSG_PVP_CREDIT, 4 + 16 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid Target; + int32 Honor = 0; + int32 Rank = 0; + }; } } diff --git a/src/server/game/Server/Packets/EquipmentSetPackets.cpp b/src/server/game/Server/Packets/EquipmentSetPackets.cpp index 0dc948f5170..3fe30d2b8e7 100644 --- a/src/server/game/Server/Packets/EquipmentSetPackets.cpp +++ b/src/server/game/Server/Packets/EquipmentSetPackets.cpp @@ -40,9 +40,10 @@ WorldPacket const* WorldPackets::EquipmentSet::LoadEquipmentSet::Write() _worldPacket.WriteBits(equipSet->SetName.length(), 8); _worldPacket.WriteBits(equipSet->SetIcon.length(), 9); + _worldPacket.FlushBits(); + _worldPacket.WriteString(equipSet->SetName); _worldPacket.WriteString(equipSet->SetIcon); - _worldPacket.FlushBits(); } return &_worldPacket; diff --git a/src/server/game/Server/Packets/EquipmentSetPackets.h b/src/server/game/Server/Packets/EquipmentSetPackets.h index a26eee383ae..a7936cc1b79 100644 --- a/src/server/game/Server/Packets/EquipmentSetPackets.h +++ b/src/server/game/Server/Packets/EquipmentSetPackets.h @@ -63,7 +63,7 @@ namespace WorldPackets void Read() override; - uint64 ID; + uint64 ID = 0; }; class UseEquipmentSet final : public ClientPacket diff --git a/src/server/game/Server/Packets/GarrisonPackets.cpp b/src/server/game/Server/Packets/GarrisonPackets.cpp new file mode 100644 index 00000000000..88374e7ce62 --- /dev/null +++ b/src/server/game/Server/Packets/GarrisonPackets.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "GarrisonPackets.h" + +WorldPacket const* WorldPackets::Garrison::GarrisonCreateResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(GarrSiteLevelID); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonPlotInfo& plotInfo) +{ + data << uint32(plotInfo.GarrPlotInstanceID); + data << plotInfo.PlotPos.PositionXYZOStream(); + data << uint32(plotInfo.PlotType); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonBuildingInfo const& buildingInfo) +{ + data << uint32(buildingInfo.GarrPlotInstanceID); + data << uint32(buildingInfo.GarrBuildingID); + data << uint32(buildingInfo.TimeBuilt); + data << uint32(buildingInfo.CurrentGarSpecID); + data << uint32(buildingInfo.TimeSpecCooldown); + data.WriteBit(buildingInfo.Active); + data.FlushBits(); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonFollower const& follower) +{ + data << uint64(follower.DbID); + data << uint32(follower.GarrFollowerID); + data << uint32(follower.Quality); + data << uint32(follower.FollowerLevel); + data << uint32(follower.ItemLevelWeapon); + data << uint32(follower.ItemLevelArmor); + data << uint32(follower.Xp); + data << uint32(follower.CurrentBuildingID); + data << uint32(follower.CurrentMissionID); + data << uint32(follower.AbilityID.size()); + data << uint32(follower.FollowerStatus); + for (GarrAbilityEntry const* ability : follower.AbilityID) + data << uint32(ability->ID); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonMission const& mission) +{ + data << uint64(mission.DbID); + data << uint32(mission.MissionRecID); + data << uint32(mission.OfferTime); + data << uint32(mission.OfferDuration); + data << uint32(mission.StartTime); + data << uint32(mission.TravelDuration); + data << uint32(mission.MissionDuration); + data << uint32(mission.MissionState); + + return data; +} + +WorldPacket const* WorldPackets::Garrison::GetGarrisonInfoResult::Write() +{ + _worldPacket.reserve(4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + + Buildings.size() * sizeof(GarrisonBuildingInfo) + + Plots.size() * sizeof(GarrisonPlotInfo) + + Followers.size() * (sizeof(GarrisonFollower) + 5 * 4) + + Missions.size() * sizeof(GarrisonMission) + + ArchivedMissions.size() * 4); + + _worldPacket << int32(GarrSiteID); + _worldPacket << int32(GarrSiteLevelID); + _worldPacket << int32(FactionIndex); + _worldPacket << uint32(Buildings.size()); + _worldPacket << uint32(Plots.size()); + _worldPacket << uint32(Followers.size()); + _worldPacket << uint32(Missions.size()); + _worldPacket << uint32(ArchivedMissions.size()); + _worldPacket << int32(NumFollowerActivationsRemaining); + + for (GarrisonBuildingInfo const* building : Buildings) + _worldPacket << *building; + + for (GarrisonPlotInfo* plot : Plots) + _worldPacket << *plot; + + for (GarrisonFollower const* follower : Followers) + _worldPacket << *follower; + + for (GarrisonMission const* mission : Missions) + _worldPacket << *mission; + + if (!ArchivedMissions.empty()) + _worldPacket.append(ArchivedMissions.data(), ArchivedMissions.size()); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonRemoteBuildingInfo const& building) +{ + data << uint32(building.GarrPlotInstanceID); + data << uint32(building.GarrBuildingID); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonRemoteSiteInfo const& site) +{ + data << uint32(site.GarrSiteLevelID); + data << uint32(site.Buildings.size()); + for (WorldPackets::Garrison::GarrisonRemoteBuildingInfo const& building : site.Buildings) + data << building; + + return data; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonRemoteInfo::Write() +{ + _worldPacket << uint32(Sites.size()); + for (GarrisonRemoteSiteInfo const& site : Sites) + _worldPacket << site; + + return &_worldPacket; +} + +void WorldPackets::Garrison::GarrisonPurchaseBuilding::Read() +{ + _worldPacket >> NpcGUID; + _worldPacket >> PlotInstanceID; + _worldPacket >> BuildingID; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonPlaceBuildingResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << BuildingInfo; + _worldPacket.WriteBit(PlayActivationCinematic); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Garrison::GarrisonCancelConstruction::Read() +{ + _worldPacket >> NpcGUID; + _worldPacket >> PlotInstanceID; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonBuildingRemoved::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(GarrPlotInstanceID); + _worldPacket << uint32(GarrBuildingID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonLearnBlueprintResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(BuildingID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonUnlearnBlueprintResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << uint32(BuildingID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationDataResult::Write() +{ + _worldPacket << uint32(BlueprintsKnown ? BlueprintsKnown->size() : 0); + _worldPacket << uint32(SpecializationsKnown ? SpecializationsKnown->size() : 0); + if (BlueprintsKnown) + for (uint32 blueprint : *BlueprintsKnown) + _worldPacket << uint32(blueprint); + + if (SpecializationsKnown) + for (uint32 specialization : *SpecializationsKnown) + _worldPacket << uint32(specialization); + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Garrison::GarrisonBuildingLandmark& landmark) +{ + data << uint32(landmark.GarrBuildingPlotInstID); + data << landmark.Pos.PositionXYZStream(); + + return data; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonBuildingLandmarks::Write() +{ + _worldPacket << uint32(Landmarks.size()); + for (GarrisonBuildingLandmark& landmark : Landmarks) + _worldPacket << landmark; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonPlotPlaced::Write() +{ + _worldPacket << *PlotInfo; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonPlotRemoved::Write() +{ + _worldPacket << uint32(GarrPlotInstanceID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Garrison::GarrisonAddFollowerResult::Write() +{ + _worldPacket << uint32(Result); + _worldPacket << Follower; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/GarrisonPackets.h b/src/server/game/Server/Packets/GarrisonPackets.h new file mode 100644 index 00000000000..1bb04c7ba95 --- /dev/null +++ b/src/server/game/Server/Packets/GarrisonPackets.h @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GarrisonPackets_h__ +#define GarrisonPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" +#include "Position.h" +#include "PacketUtilities.h" +#include "DB2Structure.h" + +namespace WorldPackets +{ + namespace Garrison + { + class GarrisonCreateResult final : public ServerPacket + { + public: + GarrisonCreateResult() : ServerPacket(SMSG_GARRISON_CREATE_RESULT, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 GarrSiteLevelID = 0; + uint32 Result = 0; + }; + + class GetGarrisonInfo final : public ClientPacket + { + public: + GetGarrisonInfo(WorldPacket&& packet) : ClientPacket(CMSG_GET_GARRISON_INFO, std::move(packet)) { } + + void Read() override { } + }; + + struct GarrisonPlotInfo + { + uint32 GarrPlotInstanceID = 0; + Position PlotPos; + uint32 PlotType = 0; + }; + + struct GarrisonBuildingInfo + { + uint32 GarrPlotInstanceID = 0; + uint32 GarrBuildingID = 0; + time_t TimeBuilt = time_t(0); + uint32 CurrentGarSpecID = 0; + time_t TimeSpecCooldown = time_t(2288912640); // 06/07/1906 18:35:44 - another in the series of magic blizz dates + bool Active = false; + }; + + struct GarrisonFollower + { + uint64 DbID = 0; + uint32 GarrFollowerID = 0; + uint32 Quality = 0; + uint32 FollowerLevel = 0; + uint32 ItemLevelWeapon = 0; + uint32 ItemLevelArmor = 0; + uint32 Xp = 0; + uint32 CurrentBuildingID = 0; + uint32 CurrentMissionID = 0; + std::list<GarrAbilityEntry const*> AbilityID; + uint32 FollowerStatus; + }; + + struct GarrisonMission + { + uint64 DbID = 0; + uint32 MissionRecID = 0; + time_t OfferTime = time_t(0); + uint32 OfferDuration = 0; + time_t StartTime = time_t(2288912640); + uint32 TravelDuration = 0; + uint32 MissionDuration = 0; + uint32 MissionState = 0; + }; + + class GetGarrisonInfoResult final : public ServerPacket + { + public: + GetGarrisonInfoResult() : ServerPacket(SMSG_GET_GARRISON_INFO_RESULT) { } + + WorldPacket const* Write() override; + + uint32 GarrSiteID = 0; + uint32 GarrSiteLevelID = 0; + uint32 FactionIndex = 0; + uint32 NumFollowerActivationsRemaining = 0; + std::vector<GarrisonPlotInfo*> Plots; + std::vector<GarrisonBuildingInfo const*> Buildings; + std::vector<GarrisonFollower const*> Followers; + std::vector<GarrisonMission const*> Missions; + std::vector<int32> ArchivedMissions; + }; + + struct GarrisonRemoteBuildingInfo + { + GarrisonRemoteBuildingInfo() : GarrPlotInstanceID(0), GarrBuildingID(0) { } + GarrisonRemoteBuildingInfo(uint32 plotInstanceId, uint32 buildingId) : GarrPlotInstanceID(plotInstanceId), GarrBuildingID(buildingId) { } + + uint32 GarrPlotInstanceID; + uint32 GarrBuildingID; + }; + + struct GarrisonRemoteSiteInfo + { + uint32 GarrSiteLevelID = 0; + std::vector<GarrisonRemoteBuildingInfo> Buildings; + }; + + class GarrisonRemoteInfo final : public ServerPacket + { + public: + GarrisonRemoteInfo() : ServerPacket(SMSG_GARRISON_REMOTE_INFO) { } + + WorldPacket const* Write() override; + + std::vector<GarrisonRemoteSiteInfo> Sites; + }; + + class GarrisonPurchaseBuilding final : public ClientPacket + { + public: + GarrisonPurchaseBuilding(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_PURCHASE_BUILDING, std::move(packet)) { } + + void Read() override; + + ObjectGuid NpcGUID; + uint32 BuildingID = 0; + uint32 PlotInstanceID = 0; + }; + + class GarrisonPlaceBuildingResult final : public ServerPacket + { + public: + GarrisonPlaceBuildingResult() : ServerPacket(SMSG_GARRISON_PLACE_BUILDING_RESULT) { } + + WorldPacket const* Write() override; + + uint32 Result = 0; + GarrisonBuildingInfo BuildingInfo; + bool PlayActivationCinematic = false; + }; + + class GarrisonCancelConstruction final : public ClientPacket + { + public: + GarrisonCancelConstruction(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_CANCEL_CONSTRUCTION, std::move(packet)) { } + + void Read() override; + + ObjectGuid NpcGUID; + uint32 PlotInstanceID = 0; + }; + + class GarrisonBuildingRemoved final : public ServerPacket + { + public: + GarrisonBuildingRemoved() : ServerPacket(SMSG_GARRISON_BUILDING_REMOVED, 4 + 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 Result = 0; + uint32 GarrPlotInstanceID = 0; + uint32 GarrBuildingID = 0; + }; + + class GarrisonLearnBlueprintResult final : public ServerPacket + { + public: + GarrisonLearnBlueprintResult() : ServerPacket(SMSG_GARRISON_LEARN_BLUEPRINT_RESULT, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 BuildingID = 0; + uint32 Result = 0; + }; + + class GarrisonUnlearnBlueprintResult final : public ServerPacket + { + public: + GarrisonUnlearnBlueprintResult() : ServerPacket(SMSG_GARRISON_UNLEARN_BLUEPRINT_RESULT, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 BuildingID = 0; + uint32 Result = 0; + }; + + class GarrisonRequestBlueprintAndSpecializationData final : public ClientPacket + { + public: + GarrisonRequestBlueprintAndSpecializationData(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA, std::move(packet)) { } + + void Read() override { } + }; + + class GarrisonRequestBlueprintAndSpecializationDataResult final : public ServerPacket + { + public: + GarrisonRequestBlueprintAndSpecializationDataResult() : ServerPacket(SMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA_RESULT, 400) { } + + WorldPacket const* Write() override; + + std::unordered_set<uint32> const* SpecializationsKnown = nullptr; + std::unordered_set<uint32> const* BlueprintsKnown = nullptr; + }; + + class GarrisonGetBuildingLandmarks final : public ClientPacket + { + public: + GarrisonGetBuildingLandmarks(WorldPacket&& packet) : ClientPacket(CMSG_GARRISON_GET_BUILDING_LANDMARKS, std::move(packet)) { } + + void Read() override { } + }; + + struct GarrisonBuildingLandmark + { + GarrisonBuildingLandmark() : GarrBuildingPlotInstID(0), Pos() { } + GarrisonBuildingLandmark(uint32 buildingPlotInstId, Position const& pos) : GarrBuildingPlotInstID(buildingPlotInstId), Pos(pos) { } + + uint32 GarrBuildingPlotInstID; + Position Pos; + }; + + class GarrisonBuildingLandmarks final : public ServerPacket + { + public: + GarrisonBuildingLandmarks() : ServerPacket(SMSG_GARRISON_BUILDING_LANDMARKS) { } + + WorldPacket const* Write() override; + + std::vector<GarrisonBuildingLandmark> Landmarks; + }; + + class GarrisonPlotPlaced final : public ServerPacket + { + public: + GarrisonPlotPlaced() : ServerPacket(SMSG_GARRISON_PLOT_PLACED) { } + + WorldPacket const* Write() override; + + GarrisonPlotInfo* PlotInfo = nullptr; + }; + + class GarrisonPlotRemoved final : public ServerPacket + { + public: + GarrisonPlotRemoved() : ServerPacket(SMSG_GARRISON_PLOT_REMOVED, 4) { } + + WorldPacket const* Write() override; + + uint32 GarrPlotInstanceID = 0; + }; + + class GarrisonAddFollowerResult final : public ServerPacket + { + public: + GarrisonAddFollowerResult() : ServerPacket(SMSG_GARRISON_ADD_FOLLOWER_RESULT, 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 5 * 4 + 4) { } + + WorldPacket const* Write() override; + + GarrisonFollower Follower; + uint32 Result = 0; + }; + } +} + +#endif // GarrisonPackets_h__ diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index d0383a82160..34ea92ce27c 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -30,6 +30,7 @@ WorldPacket const* WorldPackets::Guild::QueryGuildInfoResponse::Write() { _worldPacket << GuildGuid; _worldPacket.WriteBit(Info.is_initialized()); + _worldPacket.FlushBits(); if (Info) { @@ -48,13 +49,16 @@ WorldPacket const* WorldPackets::Guild::QueryGuildInfoResponse::Write() _worldPacket << uint32(rank.RankOrder); _worldPacket.WriteBits(rank.RankName.size(), 7); + _worldPacket.FlushBits(); + _worldPacket.WriteString(rank.RankName); } _worldPacket.WriteBits(Info->GuildName.size(), 7); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Info->GuildName); } - _worldPacket.FlushBits(); return &_worldPacket; } @@ -69,7 +73,6 @@ WorldPacket const* WorldPackets::Guild::GuildRoster::Write() for (GuildRosterMemberData const& member : MemberData) _worldPacket << member; - _worldPacket.ResetBitPos(); _worldPacket.WriteBits(WelcomeText.length(), 10); _worldPacket.WriteBits(InfoText.length(), 10); _worldPacket.FlushBits(); @@ -798,10 +801,10 @@ WorldPacket const* WorldPackets::Guild::GuildChallengeUpdate::Write() void WorldPackets::Guild::SaveGuildEmblem::Read() { _worldPacket >> Vendor; - _worldPacket >> BStyle; _worldPacket >> EStyle; - _worldPacket >> BColor; _worldPacket >> EColor; + _worldPacket >> BStyle; + _worldPacket >> BColor; _worldPacket >> Bg; } diff --git a/src/server/game/Server/Packets/InstancePackets.cpp b/src/server/game/Server/Packets/InstancePackets.cpp new file mode 100644 index 00000000000..7cf46454533 --- /dev/null +++ b/src/server/game/Server/Packets/InstancePackets.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "InstancePackets.h" + +WorldPacket const* WorldPackets::Instance::UpdateLastInstance::Write() +{ + _worldPacket << uint32(MapID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Instance::UpdateInstanceOwnership::Write() +{ + _worldPacket << int32(IOwnInstance); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Instance::InstanceInfo::Write() +{ + _worldPacket << int32(LockList.size()); + + for (InstanceLockInfos const& lockInfos : LockList) + _worldPacket << lockInfos; + + return &_worldPacket; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Instance::InstanceLockInfos const& lockInfos) +{ + data << lockInfos.MapID; + data << lockInfos.DifficultyID; + data << lockInfos.InstanceID; + data << lockInfos.TimeRemaining; + data << lockInfos.CompletedMask; + + data.WriteBit(lockInfos.Locked); + data.WriteBit(lockInfos.Extended); + + data.FlushBits(); + + return data; +} + +WorldPacket const* WorldPackets::Instance::InstanceReset::Write() +{ + _worldPacket << uint32(MapID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Instance::InstanceResetFailed::Write() +{ + _worldPacket << uint32(MapID); + _worldPacket.WriteBits(ResetFailedReason, 2); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/InstancePackets.h b/src/server/game/Server/Packets/InstancePackets.h new file mode 100644 index 00000000000..bfc14dddc5b --- /dev/null +++ b/src/server/game/Server/Packets/InstancePackets.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef InstancePackets_h__ +#define InstancePackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace Instance + { + class UpdateLastInstance final : public ServerPacket + { + public: + UpdateLastInstance() : ServerPacket(SMSG_UPDATE_LAST_INSTANCE, 4) { } + + WorldPacket const* Write() override; + + uint32 MapID = 0; + }; + + // This packet is no longer sent - it is only here for documentation purposes + class UpdateInstanceOwnership final : public ServerPacket + { + public: + UpdateInstanceOwnership() : ServerPacket(SMSG_UPDATE_INSTANCE_OWNERSHIP, 4) { } + + WorldPacket const* Write() override; + + int32 IOwnInstance = 0; // Used to control whether "Reset all instances" button appears on the UI - Script_CanShowResetInstances() + // but it has been deperecated in favor of simply checking group leader, being inside an instance or using dungeon finder + }; + + struct InstanceLockInfos + { + uint64 InstanceID = 0u; + uint32 MapID = 0u; + uint32 DifficultyID = 0u; + int32 TimeRemaining = 0; + uint32 CompletedMask = 0u; + + bool Locked = false; + bool Extended = false; + }; + + class InstanceInfo final : public ServerPacket + { + public: + InstanceInfo() : ServerPacket(SMSG_INSTANCE_INFO, 4) { } + + WorldPacket const* Write() override; + + std::vector<InstanceLockInfos> LockList; + }; + + class ResetInstances final : public ClientPacket + { + public: + ResetInstances(WorldPacket&& packet) : ClientPacket(CMSG_RESET_INSTANCES, std::move(packet)) { } + + void Read() override { } + }; + + class InstanceReset final : public ServerPacket + { + public: + InstanceReset() : ServerPacket(SMSG_INSTANCE_RESET, 4) { } + + WorldPacket const* Write() override; + + uint32 MapID = 0; + }; + + class InstanceResetFailed final : public ServerPacket + { + public: + InstanceResetFailed() : ServerPacket(SMSG_INSTANCE_RESET_FAILED, 4 + 4) { } + + WorldPacket const* Write() override; + + uint32 MapID = 0; + uint8 ResetFailedReason = 0; + }; + + class ResetFailedNotify final : public ServerPacket + { + public: + ResetFailedNotify() : ServerPacket(SMSG_RESET_FAILED_NOTIFY, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Instance::InstanceLockInfos const& lockInfos); + +#endif // InstancePackets_h__ diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index 3feea2cdc98..8b0bec535b3 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -369,3 +369,26 @@ void WorldPackets::Item::WrapItem::Read() { _worldPacket >> Inv; } + +void WorldPackets::Item::CancelTempEnchantment::Read() +{ + _worldPacket >> Slot; +} + +WorldPacket const* WorldPackets::Item::ItemCooldown::Write() +{ + _worldPacket << ItemGuid; + _worldPacket << uint32(SpellID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Item::ItemEnchantTimeUpdate::Write() +{ + _worldPacket << ItemGuid; + _worldPacket << uint32(DurationLeft); + _worldPacket << uint32(Slot); + _worldPacket << OwnerGuid; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index d37df357513..e73f42bcaf2 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -353,6 +353,40 @@ namespace WorldPackets InvUpdate Inv; }; + class CancelTempEnchantment final : public ClientPacket + { + public: + CancelTempEnchantment(WorldPacket&& packet) : ClientPacket(CMSG_CANCEL_TEMP_ENCHANTMENT, std::move(packet)) { } + + void Read() override; + + int32 Slot = 0; + }; + + class ItemCooldown final : public ServerPacket + { + public: + ItemCooldown() : ServerPacket(SMSG_ITEM_COOLDOWN, 20) { } + + WorldPacket const* Write() override; + + ObjectGuid ItemGuid; + uint32 SpellID = 0; + }; + + class ItemEnchantTimeUpdate final : public ServerPacket + { + public: + ItemEnchantTimeUpdate() : ServerPacket(SMSG_ITEM_ENCHANT_TIME_UPDATE, 40) { } + + WorldPacket const* Write() override; + + ObjectGuid OwnerGuid; + ObjectGuid ItemGuid; + uint32 DurationLeft = 0; + uint32 Slot = 0; + }; + ByteBuffer& operator>>(ByteBuffer& data, InvUpdate& invUpdate); } } diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index 40dde52700b..bbd3fcb2ba7 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -439,3 +439,84 @@ WorldPacket const* WorldPackets::Misc::PlaySound::Write() return &_worldPacket; } + +void WorldPackets::Misc::FarSight::Read() +{ + Enable = _worldPacket.ReadBit(); +} + +WorldPacket const* WorldPackets::Misc::Dismount::Write() +{ + _worldPacket << Guid; + + return &_worldPacket; +} + +void WorldPackets::Misc::SaveCUFProfiles::Read() +{ + uint32 count; + _worldPacket >> count; + + for (uint8 i = 0; i < count && i < MAX_CUF_PROFILES; i++) + { + std::unique_ptr<CUFProfile> cufProfile = Trinity::make_unique<CUFProfile>(); + + uint8 strLen = _worldPacket.ReadBits(7); + + // Bool Options + for (uint8 option = 0; option < CUF_BOOL_OPTIONS_COUNT; option++) + cufProfile->BoolOptions.set(option, _worldPacket.ReadBit()); + + // Other Options + _worldPacket >> cufProfile->FrameHeight; + _worldPacket >> cufProfile->FrameWidth; + + _worldPacket >> cufProfile->SortBy; + _worldPacket >> cufProfile->HealthText; + + _worldPacket >> cufProfile->TopPoint; + _worldPacket >> cufProfile->BottomPoint; + _worldPacket >> cufProfile->LeftPoint; + + _worldPacket >> cufProfile->TopOffset; + _worldPacket >> cufProfile->BottomOffset; + _worldPacket >> cufProfile->LeftOffset; + + cufProfile->ProfileName = _worldPacket.ReadString(strLen); + + CUFProfiles.push_back(std::move(cufProfile)); + } +} + +WorldPacket const* WorldPackets::Misc::LoadCUFProfiles::Write() +{ + _worldPacket << uint32(CUFProfiles.size()); + + for (CUFProfile const* cufProfile : CUFProfiles) + { + _worldPacket.WriteBits(cufProfile->ProfileName.size(), 7); + + // Bool Options + for (uint8 option = 0; option < CUF_BOOL_OPTIONS_COUNT; option++) + _worldPacket.WriteBit(cufProfile->BoolOptions[option]); + + // Other Options + _worldPacket << cufProfile->FrameHeight; + _worldPacket << cufProfile->FrameWidth; + + _worldPacket << cufProfile->SortBy; + _worldPacket << cufProfile->HealthText; + + _worldPacket << cufProfile->TopPoint; + _worldPacket << cufProfile->BottomPoint; + _worldPacket << cufProfile->LeftPoint; + + _worldPacket << cufProfile->TopOffset; + _worldPacket << cufProfile->BottomOffset; + _worldPacket << cufProfile->LeftOffset; + + _worldPacket.WriteString(cufProfile->ProfileName); + } + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index 5673680afe6..93bac0d208b 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -24,6 +24,7 @@ #include "G3D/Vector3.h" #include "Object.h" #include "Unit.h" +#include "Player.h" #include "Weather.h" namespace WorldPackets @@ -622,6 +623,46 @@ namespace WorldPackets void Read() override { } }; + + class FarSight final : public ClientPacket + { + public: + FarSight(WorldPacket&& packet) : ClientPacket(CMSG_FAR_SIGHT, std::move(packet)) { } + + void Read() override; + + bool Enable = false; + }; + + class Dismount final : public ServerPacket + { + public: + Dismount() : ServerPacket(SMSG_DISMOUNT, 16) { } + + WorldPacket const* Write() override; + + ObjectGuid Guid; + }; + + class SaveCUFProfiles final : public ClientPacket + { + public: + SaveCUFProfiles(WorldPacket&& packet) : ClientPacket(CMSG_SAVE_CUF_PROFILES, std::move(packet)) { } + + void Read() override; + + std::vector<std::unique_ptr<CUFProfile>> CUFProfiles; + }; + + class LoadCUFProfiles final : public ServerPacket + { + public: + LoadCUFProfiles() : ServerPacket(SMSG_LOAD_CUF_PROFILES, 20) { } + + WorldPacket const* Write() override; + + std::vector<CUFProfile const*> CUFProfiles; + }; } } diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp index f0db56302f6..14fb2ecb33c 100644 --- a/src/server/game/Server/Packets/MovementPackets.cpp +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -198,9 +198,9 @@ ByteBuffer& WorldPackets::operator<<(ByteBuffer& data, Movement::MonsterSplineFi data << monsterSplineFilter.BaseSpeed; data << monsterSplineFilter.StartOffset; data << monsterSplineFilter.DistToPrevFilterKey; + data << monsterSplineFilter.AddedToStart; for (WorldPackets::Movement::MonsterSplineFilterKey const& filterKey : monsterSplineFilter.FilterKeys) data << filterKey; - data << monsterSplineFilter.AddedToStart; data.WriteBits(monsterSplineFilter.FilterFlags, 2); data.FlushBits(); diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h index 6803bdf3b95..d4fb41cf330 100644 --- a/src/server/game/Server/Packets/MovementPackets.h +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -398,7 +398,7 @@ namespace WorldPackets void Read() override; ObjectGuid MoverGUID; - uint32 TimeSkipped; + uint32 TimeSkipped = 0; }; } diff --git a/src/server/game/Server/Packets/NPCPackets.cpp b/src/server/game/Server/Packets/NPCPackets.cpp index 4e44f07fd01..a6c74459bf5 100644 --- a/src/server/game/Server/Packets/NPCPackets.cpp +++ b/src/server/game/Server/Packets/NPCPackets.cpp @@ -175,3 +175,19 @@ WorldPacket const* WorldPackets::NPC::SpiritHealerConfirm::Write() return &_worldPacket; } + +void WorldPackets::NPC::TrainerBuySpell::Read() +{ + _worldPacket >> TrainerGUID; + _worldPacket >> TrainerID; + _worldPacket >> SpellID; +} + +WorldPacket const* WorldPackets::NPC::TrainerBuyFailed::Write() +{ + _worldPacket << TrainerGUID; + _worldPacket << SpellID; + _worldPacket << TrainerFailedReason; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/NPCPackets.h b/src/server/game/Server/Packets/NPCPackets.h index ec23c51a206..990ef897986 100644 --- a/src/server/game/Server/Packets/NPCPackets.h +++ b/src/server/game/Server/Packets/NPCPackets.h @@ -216,6 +216,30 @@ namespace WorldPackets ObjectGuid Unit; }; + + class TrainerBuySpell final : public ClientPacket + { + public: + TrainerBuySpell(WorldPacket&& packet) : ClientPacket(CMSG_TRAINER_BUY_SPELL, std::move(packet)) { } + + void Read() override; + + ObjectGuid TrainerGUID; + int32 TrainerID = 0; + int32 SpellID = 0; + }; + + class TrainerBuyFailed final : public ServerPacket + { + public: + TrainerBuyFailed() : ServerPacket(SMSG_TRAINER_BUY_FAILED, 16 + 4 + 4) { } + + WorldPacket const* Write() override; + + ObjectGuid TrainerGUID; + int32 SpellID = 0; + int32 TrainerFailedReason = 0; + }; } } diff --git a/src/server/game/Server/Packets/PartyPackets.cpp b/src/server/game/Server/Packets/PartyPackets.cpp new file mode 100644 index 00000000000..f5cbfd7f5c2 --- /dev/null +++ b/src/server/game/Server/Packets/PartyPackets.cpp @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "PartyPackets.h" + +#include "Player.h" +#include "Pet.h" +#include "Vehicle.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "ObjectMgr.h" + +WorldPacket const* WorldPackets::Party::PartyCommandResult::Write() +{ + _worldPacket.WriteBits(Name.size(), 9); + + _worldPacket.WriteBits(Command, 4); + _worldPacket.WriteBits(Result, 6); + + _worldPacket << ResultData; + _worldPacket << ResultGUID; + _worldPacket.WriteString(Name); + + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Party::PartyInviteClient::Read() +{ + uint32 targetNameLen, targetRealmLen; + + _worldPacket >> PartyIndex; + _worldPacket >> ProposedRoles; + _worldPacket >> TargetGUID; + _worldPacket >> TargetCfgRealmID; + + targetNameLen = _worldPacket.ReadBits(9); + targetRealmLen = _worldPacket.ReadBits(9); + + TargetName = _worldPacket.ReadString(targetNameLen); + TargetRealm = _worldPacket.ReadString(targetRealmLen); +} + +WorldPacket const* WorldPackets::Party::PartyInvite::Write() +{ + // Order guessed + _worldPacket.WriteBit(CanAccept); + _worldPacket.WriteBit(MightCRZYou); + _worldPacket.WriteBit(MustBeBNetFriend); + _worldPacket.WriteBit(AllowMultipleRoles); + _worldPacket.WriteBit(IsXRealm); + + _worldPacket.WriteBits(InviterName.size(), 6); + + _worldPacket << InviterGUID; + _worldPacket << InviterBNetAccountId; + + _worldPacket << InviterVirtualRealmAddress; + _worldPacket << Unk1; + + _worldPacket.WriteBit(IsLocal); + _worldPacket.WriteBit(Unk2); + + _worldPacket.WriteBits(InviterRealmNameActual.size(), 8); + _worldPacket.WriteBits(InviterRealmNameNormalized.size(), 8); + _worldPacket.WriteString(InviterRealmNameActual); + _worldPacket.WriteString(InviterRealmNameNormalized); + + _worldPacket << ProposedRoles; + _worldPacket << int32(LfgSlots.size()); + _worldPacket << LfgCompletedMask; + + _worldPacket.WriteString(InviterName); + + for (int32 LfgSlot : LfgSlots) + _worldPacket << LfgSlot; + + return &_worldPacket; +} + +void WorldPackets::Party::PartyInvite::Initialize(Player* const inviter, int32 proposedRoles, bool canAccept) +{ + CanAccept = canAccept; + + InviterName = inviter->GetName(); + InviterGUID = inviter->GetGUID(); + InviterBNetAccountId = inviter->GetSession()->GetAccountGUID(); + + ProposedRoles = proposedRoles; + + std::string realmName = sObjectMgr->GetRealmName(realmHandle.Index); + + InviterVirtualRealmAddress = GetVirtualRealmAddress(); + InviterRealmNameActual = realmName; + InviterRealmNameNormalized = realmName; +} + +void WorldPackets::Party::PartyInviteResponse::Read() +{ + _worldPacket >> PartyIndex; + + Accept = _worldPacket.ReadBit(); + + bool hasRolesDesired = _worldPacket.ReadBit(); + if (hasRolesDesired) + { + RolesDesired = boost::in_place(); + _worldPacket >> *RolesDesired; + } +} + +void WorldPackets::Party::PartyUninvite::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; + + uint8 reasonLen = _worldPacket.ReadBits(8); + Reason = _worldPacket.ReadString(reasonLen); +} + +WorldPacket const* WorldPackets::Party::GroupDecline::Write() +{ + _worldPacket.WriteBits(Name.length(), 9); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Name); + + return &_worldPacket; +} + +void WorldPackets::Party::RequestPartyMemberStats::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; +} + +WorldPacket const* WorldPackets::Party::PartyMemberStats::Write() +{ + _worldPacket.WriteBit(ForEnemy); + + _worldPacket << MemberStats; + + return &_worldPacket; +} + +void WorldPackets::Party::SetPartyLeader::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; +} + +void WorldPackets::Party::SetRole::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> TargetGUID; + _worldPacket >> Role; +} + +WorldPacket const* WorldPackets::Party::RoleChangedInform::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << From; + _worldPacket << ChangedUnit; + _worldPacket << OldRole; + _worldPacket << NewRole; + + return &_worldPacket; +} + +void WorldPackets::Party::LeaveGroup::Read() +{ + _worldPacket >> PartyIndex; +} + +void WorldPackets::Party::SetLootMethod::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> LootMethod; + _worldPacket >> LootMasterGUID; + _worldPacket >> LootThreshold; +} + +void WorldPackets::Party::MinimapPingClient::Read() +{ + _worldPacket >> PositionX; + _worldPacket >> PositionY; + _worldPacket >> PartyIndex; +} + +WorldPacket const* WorldPackets::Party::MinimapPing::Write() +{ + _worldPacket << Sender; + _worldPacket << PositionX; + _worldPacket << PositionY; + + return &_worldPacket; +} + +void WorldPackets::Party::UpdateRaidTarget::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> Target; + _worldPacket >> Symbol; +} + +WorldPacket const* WorldPackets::Party::SendRaidTargetUpdateSingle::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << Symbol; + _worldPacket << Target; + _worldPacket << ChangedBy; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::SendRaidTargetUpdateAll::Write() +{ + _worldPacket << PartyIndex; + + _worldPacket << int32(TargetIcons.size()); + + std::map<uint8, ObjectGuid>::const_iterator itr; + for (itr = TargetIcons.begin(); itr != TargetIcons.end(); itr++) + { + _worldPacket << itr->second; + _worldPacket << itr->first; + } + + return &_worldPacket; +} + +void WorldPackets::Party::ConvertRaid::Read() +{ + Raid = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::RequestPartyJoinUpdates::Read() +{ + _worldPacket >> PartyIndex; +} + +void WorldPackets::Party::SetAssistantLeader::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> Target; + Apply = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::DoReadyCheck::Read() +{ + _worldPacket >> PartyIndex; +} + +WorldPacket const* WorldPackets::Party::ReadyCheckStarted::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << PartyGUID; + _worldPacket << InitiatorGUID; + _worldPacket << Duration; + + return &_worldPacket; +} + +void WorldPackets::Party::ReadyCheckResponseClient::Read() +{ + _worldPacket >> PartyIndex; + IsReady = _worldPacket.ReadBit(); +} + +WorldPacket const* WorldPackets::Party::ReadyCheckResponse::Write() +{ + _worldPacket << PartyGUID; + _worldPacket << Player; + + _worldPacket.WriteBit(IsReady); + + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::ReadyCheckCompleted::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << PartyGUID; + + return &_worldPacket; +} + +void WorldPackets::Party::OptOutOfLoot::Read() +{ + PassOnLoot = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::InitiateRolePoll::Read() +{ + _worldPacket >> PartyIndex; +} + +WorldPacket const* WorldPackets::Party::RolePollInform::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << From; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::GroupNewLeader::Write() +{ + _worldPacket << PartyIndex; + _worldPacket.WriteBits(Name.size(), 6); + _worldPacket.WriteString(Name); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Party::PartyUpdate::Write() +{ + _worldPacket << PartyType; + _worldPacket << PartyIndex; + _worldPacket << PartyFlags; + + _worldPacket << MyIndex; + _worldPacket << PartyGUID; + _worldPacket << SequenceNum; + _worldPacket << LeaderGUID; + + _worldPacket << PlayerList; + + _worldPacket.WriteBit(LfgInfos.is_initialized()); + _worldPacket.WriteBit(LootSettings.is_initialized()); + _worldPacket.WriteBit(DifficultySettings.is_initialized()); + + _worldPacket.FlushBits(); + + if (LfgInfos.is_initialized()) + _worldPacket << *LfgInfos; + + if (LootSettings.is_initialized()) + _worldPacket << *LootSettings; + + if (DifficultySettings.is_initialized()) + _worldPacket << *DifficultySettings; + + return &_worldPacket; +} + +void WorldPackets::Party::SetEveryoneIsAssistant::Read() +{ + _worldPacket >> PartyIndex; + EveryoneIsAssistant = _worldPacket.ReadBit(); +} + +void WorldPackets::Party::ChangeSubGroup::Read() +{ + _worldPacket >> TargetGUID; + _worldPacket >> PartyIndex; + _worldPacket >> NewSubGroup; +} + +void WorldPackets::Party::SwapSubGroups::Read() +{ + _worldPacket >> PartyIndex; + _worldPacket >> FirstTarget; + _worldPacket >> SecondTarget; +} + +void WorldPackets::Party::ClearRaidMarker::Read() +{ + _worldPacket >> MarkerId; +} + +WorldPacket const* WorldPackets::Party::RaidMarkersChanged::Write() +{ + _worldPacket << PartyIndex; + _worldPacket << ActiveMarkers; + + _worldPacket.WriteBits(RaidMarkers.size(), 4); + _worldPacket.FlushBits(); + + for (RaidMarker* raidMarker : RaidMarkers) + { + _worldPacket << raidMarker->TransportGUID; + _worldPacket << raidMarker->Location.GetMapId(); + _worldPacket << raidMarker->Location.PositionXYZStream(); + } + + return &_worldPacket; +} + +void WorldPackets::Party::PartyMemberStats::Initialize(Player const* player) +{ + ForEnemy = false; + + MemberStats.GUID = player->GetGUID(); + + // Status + MemberStats.Status = MEMBER_STATUS_ONLINE; + + if (player->IsPvP()) + MemberStats.Status |= MEMBER_STATUS_PVP; + + if (!player->IsAlive()) + { + if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) + MemberStats.Status |= MEMBER_STATUS_GHOST; + else + MemberStats.Status |= MEMBER_STATUS_DEAD; + } + + if (player->IsFFAPvP()) + MemberStats.Status |= MEMBER_STATUS_PVP_FFA; + + if (player->isAFK()) + MemberStats.Status |= MEMBER_STATUS_AFK; + + if (player->isDND()) + MemberStats.Status |= MEMBER_STATUS_DND; + + // Level + MemberStats.Level = player->getLevel(); + + // Health + MemberStats.CurrentHealth = player->GetHealth(); + MemberStats.MaxHealth = player->GetMaxHealth(); + + // Power + MemberStats.PowerType = player->getPowerType(); + MemberStats.CurrentPower = player->GetPower(player->getPowerType()); + MemberStats.MaxPower = player->GetMaxPower(player->getPowerType()); + + // Position + MemberStats.ZoneID = player->GetZoneId(); + MemberStats.PositionX = int16(player->GetPositionX()); + MemberStats.PositionY = int16(player->GetPositionY()); + MemberStats.PositionZ = int16(player->GetPositionZ()); + + // Unk + MemberStats.Unk322 = 0; // Always 0 + MemberStats.Unk704[0] = 1; // Always 1 + MemberStats.Unk704[1] = 0; // Always 0 + MemberStats.Unk200000 = 0; // Always 0 + + MemberStats.Unk2000000 = 0; + MemberStats.Unk4000000 = 0; + + // Vehicle + if (player->GetVehicle() && player->GetVehicle()->GetVehicleInfo()) + MemberStats.VehicleSeat = player->GetVehicle()->GetVehicleInfo()->SeatID[player->m_movementInfo.transport.seat]; + + // Auras + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication const* aurApp = player->GetVisibleAura(i)) + { + WorldPackets::Party::GroupAura aura; + + aura.SpellId = aurApp->GetBase()->GetId(); + aura.EffectMask = aurApp->GetEffectMask(); + aura.Scalings = aurApp->GetFlags(); // ?? + + if (aurApp->GetFlags() & AFLAG_SCALABLE) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + float scale = 0.f; + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + scale = float(eff->GetAmount()); + aura.EffectScales.push_back(scale); + } + } + + MemberStats.AuraList.push_back(aura); + } + } + + // Phases + std::set<uint32> const& phases = player->GetPhases(); + MemberStats.Phases.PhaseShiftFlags = 0x08 | (phases.size() ? 0x10 : 0); + MemberStats.Phases.PersonalGUID = ObjectGuid::Empty; + for (uint32 phaseId : phases) + { + WorldPackets::Party::GroupPhase phase; + phase.Id = phaseId; + phase.Flags = 1; + MemberStats.Phases.List.push_back(phase); + } + + // Pet + if (player->GetPet()) + { + Pet* pet = player->GetPet(); + + MemberStats.PetStats = boost::in_place(); + + MemberStats.PetStats->GUID = pet->GetGUID(); + MemberStats.PetStats->Name = pet->GetName(); + MemberStats.PetStats->ModelId = pet->GetDisplayId(); + + MemberStats.PetStats->CurrentHealth = pet->GetHealth(); + MemberStats.PetStats->MaxHealth = pet->GetMaxHealth(); + + for (uint8 i = 0; i < MAX_AURAS; ++i) + { + if (AuraApplication const* aurApp = pet->GetVisibleAura(i)) + { + WorldPackets::Party::GroupAura aura; + + aura.SpellId = aurApp->GetBase()->GetId(); + aura.EffectMask = aurApp->GetEffectMask(); + aura.Scalings = aurApp->GetFlags(); // ?? + + if (aurApp->GetFlags() & AFLAG_SCALABLE) + { + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + float scale = 0.f; + if (AuraEffect const* eff = aurApp->GetBase()->GetEffect(i)) + scale = float(eff->GetAmount()); + aura.EffectScales.push_back(scale); + } + } + + MemberStats.PetStats->AuraList.push_back(aura); + } + } + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhase const& phase) +{ + data << phase.Flags; + data << phase.Id; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhases const& phases) +{ + data << phases.PhaseShiftFlags; + data << int32(phases.List.size()); + data << phases.PersonalGUID; + + for (WorldPackets::Party::GroupPhase const& phase : phases.List) + data << phase; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupAura const& aura) +{ + data << aura.SpellId; + data << aura.Scalings; + data << aura.EffectMask; + + data << int32(aura.EffectScales.size()); + for (float scale : aura.EffectScales) + data << scale; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupAura> const& auraList) +{ + data << int32(auraList.size()); + for (WorldPackets::Party::GroupAura const& aura : auraList) + data << aura; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPetStats const& petStats) +{ + data << petStats.GUID; + + data << petStats.ModelId; + + data << petStats.CurrentHealth; + data << petStats.MaxHealth; + + data << petStats.AuraList; + + data.WriteBits(petStats.Name.size(), 8); + data.FlushBits(); + data.WriteString(petStats.Name); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupMemberStats const& memberStats) +{ + data << memberStats.GUID; + + for (uint8 i = 0; i < 2; i++) + data << memberStats.Unk704[i]; + + data << memberStats.Status; + + data << memberStats.PowerType; + + data << memberStats.Unk322; + + data << memberStats.CurrentHealth; + data << memberStats.MaxHealth; + + data << memberStats.CurrentPower; + data << memberStats.MaxPower; + + data << memberStats.Level; + + data << memberStats.Unk200000; + + data << memberStats.ZoneID; + + data << memberStats.Unk2000000; + data << memberStats.Unk4000000; + + data << memberStats.PositionX; + data << memberStats.PositionY; + data << memberStats.PositionZ; + + data << memberStats.VehicleSeat; + + data << int32(memberStats.AuraList.size()); + + data << memberStats.Phases; + + for (WorldPackets::Party::GroupAura const& aura : memberStats.AuraList) + data << aura; + + data.WriteBit(memberStats.PetStats.is_initialized()); + data.FlushBits(); + + if (memberStats.PetStats.is_initialized()) + data << *memberStats.PetStats; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupPlayerInfos> const& playerList) +{ + data << int32(playerList.size()); + + for (WorldPackets::Party::GroupPlayerInfos const& playerInfos : playerList) + data << playerInfos; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPlayerInfos const& playerInfos) +{ + data.WriteBits(playerInfos.Name.size(), 6); + data.FlushBits(); + + data << playerInfos.GUID; + data << playerInfos.Status; + data << playerInfos.Subgroup; + data << playerInfos.Flags; + data << playerInfos.RolesAssigned; + data << playerInfos.Class; + + data.WriteString(playerInfos.Name); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLfgInfos const& lfgInfos) +{ + data << lfgInfos.MyFlags; + data << lfgInfos.Slot; + data << lfgInfos.MyRandomSlot; + data << lfgInfos.MyPartialClear; + data << lfgInfos.MyGearDiff; + data << lfgInfos.MyStrangerCount; + data << lfgInfos.MyKickVoteCount; + data << lfgInfos.BootCount; + + data.WriteBit(lfgInfos.Aborted); + data.WriteBit(lfgInfos.MyFirstReward); + data.FlushBits(); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLootSettings const& lootSettings) +{ + data << lootSettings.Method; + data << lootSettings.LootMaster; + data << lootSettings.Threshold; + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupDifficultySettings const& difficultySettings) +{ + data << difficultySettings.DungeonDifficultyID; + data << difficultySettings.RaidDifficultyID; + data << difficultySettings.LegacyRaidDifficultyID; + + return data; +} diff --git a/src/server/game/Server/Packets/PartyPackets.h b/src/server/game/Server/Packets/PartyPackets.h new file mode 100644 index 00000000000..ed3eed60ef4 --- /dev/null +++ b/src/server/game/Server/Packets/PartyPackets.h @@ -0,0 +1,616 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PartyPackets_h__ +#define PartyPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" +#include "Group.h" + +namespace WorldPackets +{ + namespace Party + { + class PartyCommandResult final : public ServerPacket + { + public: + PartyCommandResult() : ServerPacket(SMSG_PARTY_COMMAND_RESULT, 23) { } + + WorldPacket const* Write() override; + + std::string Name; + uint8 Command = 0u; + uint8 Result = 0u; + uint32 ResultData = 0u; + ObjectGuid ResultGUID; + }; + + class PartyInviteClient final : public ClientPacket + { + public: + PartyInviteClient(WorldPacket&& packet) : ClientPacket(CMSG_PARTY_INVITE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + int32 ProposedRoles = 0; + int32 TargetCfgRealmID = 0; + std::string TargetName; + std::string TargetRealm; + ObjectGuid TargetGUID; + }; + + class PartyInvite final : public ServerPacket + { + public: + PartyInvite() : ServerPacket(SMSG_PARTY_INVITE, 55) { } + + WorldPacket const* Write() override; + void Initialize(Player* const inviter, int32 proposedRoles, bool canAccept); + + bool MightCRZYou = false; + bool MustBeBNetFriend = false; + bool AllowMultipleRoles = false; + bool Unk2 = false; + int16 Unk1 = 0; + + bool CanAccept = false; + + // Inviter + ObjectGuid InviterGUID; + ObjectGuid InviterBNetAccountId; + std::string InviterName; + + // Realm + bool IsXRealm = false; + bool IsLocal = true; + uint32 InviterVirtualRealmAddress = 0u; + std::string InviterRealmNameActual; + std::string InviterRealmNameNormalized; + + // Lfg + int32 ProposedRoles = 0; + int32 LfgCompletedMask = 0; + std::vector<int32> LfgSlots; + }; + + class PartyInviteResponse final : public ClientPacket + { + public: + PartyInviteResponse(WorldPacket&& packet) : ClientPacket(CMSG_PARTY_INVITE_RESPONSE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + bool Accept = false; + Optional<int32> RolesDesired; + }; + + class PartyUninvite final : public ClientPacket + { + public: + PartyUninvite(WorldPacket&& packet) : ClientPacket(CMSG_PARTY_UNINVITE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + std::string Reason; + }; + + class GroupDecline final : public ServerPacket + { + public: + GroupDecline(std::string const& name) : ServerPacket(SMSG_GROUP_DECLINE, 2 + name.size()), Name(name) { } + + WorldPacket const* Write() override; + + std::string Name; + }; + + class RequestPartyMemberStats final : public ClientPacket + { + public: + RequestPartyMemberStats(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PARTY_MEMBER_STATS, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + }; + + struct GroupPhase + { + uint16 Flags = 0u; + uint16 Id = 0u; + }; + + struct GroupPhases + { + int32 PhaseShiftFlags = 0; + ObjectGuid PersonalGUID; + std::vector<GroupPhase> List; + }; + + struct GroupAura + { + uint32 SpellId = 0u; + uint8 Scalings = 0; + uint32 EffectMask = 0u; + std::vector<float> EffectScales; + }; + + struct GroupPetStats + { + ObjectGuid GUID; + std::string Name; + int16 ModelId = 0; + + int32 CurrentHealth = 0; + int32 MaxHealth = 0; + + std::vector<GroupAura> AuraList; + }; + + struct GroupMemberStats + { + ObjectGuid GUID; + int16 Level = 0; + int16 Status = 0; + + int32 CurrentHealth = 0; + int32 MaxHealth; + + uint8 PowerType = 0u; + int16 CurrentPower = 0; + int16 MaxPower = 0; + + int16 ZoneID = 0; + int16 PositionX = 0; + int16 PositionY = 0; + int16 PositionZ = 0; + + int32 VehicleSeat = 0; + + GroupPhases Phases; + std::vector<GroupAura> AuraList; + Optional<GroupPetStats> PetStats; + + int16 Unk322 = 0; + int16 Unk200000 = 0; + int16 Unk2000000 = 0; + int32 Unk4000000 = 0; + int8 Unk704[2]; + }; + + class PartyMemberStats final : public ServerPacket + { + public: + PartyMemberStats() : ServerPacket(SMSG_PARTY_MEMBER_STATE, 80) { } + + WorldPacket const* Write() override; + void Initialize(Player const* player); + + GroupMemberStats MemberStats; + bool ForEnemy = false; + }; + + class SetPartyLeader final : public ClientPacket + { + public: + SetPartyLeader(WorldPacket&& packet) : ClientPacket(CMSG_SET_PARTY_LEADER, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + }; + + class SetRole final : public ClientPacket + { + public: + SetRole(WorldPacket&& packet) : ClientPacket(CMSG_SET_ROLE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid TargetGUID; + int32 Role = 0; + }; + + class RoleChangedInform final : public ServerPacket + { + public: + RoleChangedInform() : ServerPacket(SMSG_ROLE_CHANGED_INFORM, 41) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid From; + ObjectGuid ChangedUnit; + int32 OldRole = 0; + int32 NewRole = 0; + }; + + class LeaveGroup final : public ClientPacket + { + public: + LeaveGroup(WorldPacket&& packet) : ClientPacket(CMSG_LEAVE_GROUP, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class SetLootMethod final : public ClientPacket + { + public: + SetLootMethod(WorldPacket&& packet) : ClientPacket(CMSG_SET_LOOT_METHOD, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid LootMasterGUID; + uint8 LootMethod = 0u; + uint32 LootThreshold = 0u; + }; + + class MinimapPingClient final : public ClientPacket + { + public: + MinimapPingClient(WorldPacket&& packet) : ClientPacket(CMSG_MINIMAP_PING, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + float PositionX = 0.f; + float PositionY = 0.f; + }; + + class MinimapPing final : public ServerPacket + { + public: + MinimapPing() : ServerPacket(SMSG_MINIMAP_PING, 24) { } + + WorldPacket const* Write() override; + + ObjectGuid Sender; + float PositionX = 0.f; + float PositionY = 0.f; + }; + + class UpdateRaidTarget final : public ClientPacket + { + public: + UpdateRaidTarget(WorldPacket&& packet) : ClientPacket(CMSG_UPDATE_RAID_TARGET, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + ObjectGuid Target; + int8 Symbol = 0; + }; + + class SendRaidTargetUpdateSingle final : public ServerPacket + { + public: + SendRaidTargetUpdateSingle() : ServerPacket(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, 34) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid Target; + ObjectGuid ChangedBy; + int8 Symbol = 0; + }; + + class SendRaidTargetUpdateAll final : public ServerPacket + { + public: + SendRaidTargetUpdateAll() : ServerPacket(SMSG_SEND_RAID_TARGET_UPDATE_ALL, 1 + TARGET_ICONS_COUNT * (1 + 16)) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + std::map<uint8, ObjectGuid> TargetIcons; + }; + + class ConvertRaid final : public ClientPacket + { + public: + ConvertRaid(WorldPacket&& packet) : ClientPacket(CMSG_CONVERT_RAID, std::move(packet)) { } + + void Read() override; + + bool Raid = false; + }; + + class RequestPartyJoinUpdates final : public ClientPacket + { + public: + RequestPartyJoinUpdates(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_PARTY_JOIN_UPDATES, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class SetAssistantLeader final : public ClientPacket + { + public: + SetAssistantLeader(WorldPacket&& packet) : ClientPacket(CMSG_SET_ASSISTANT_LEADER, std::move(packet)) { } + + void Read() override; + + ObjectGuid Target; + int8 PartyIndex = 0; + bool Apply = false; + }; + + class DoReadyCheck final : public ClientPacket + { + public: + DoReadyCheck(WorldPacket&& packet) : ClientPacket(CMSG_DO_READY_CHECK, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class ReadyCheckStarted final : public ServerPacket + { + public: + ReadyCheckStarted() : ServerPacket(SMSG_READY_CHECK_STARTED, 37) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid PartyGUID; + ObjectGuid InitiatorGUID; + uint32 Duration = 0u; + }; + + class ReadyCheckResponseClient final : public ClientPacket + { + public: + ReadyCheckResponseClient(WorldPacket&& packet) : ClientPacket(CMSG_READY_CHECK_RESPONSE, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + bool IsReady = false; + }; + + class ReadyCheckResponse final : public ServerPacket + { + public: + ReadyCheckResponse() : ServerPacket(SMSG_READY_CHECK_RESPONSE, 19) { } + + WorldPacket const* Write() override; + + ObjectGuid PartyGUID; + ObjectGuid Player; + bool IsReady = false; + }; + + class ReadyCheckCompleted final : public ServerPacket + { + public: + ReadyCheckCompleted() : ServerPacket(SMSG_READY_CHECK_COMPLETED, 17) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid PartyGUID; + }; + + class RequestRaidInfo final : public ClientPacket + { + public: + RequestRaidInfo(WorldPacket&& packet) : ClientPacket(CMSG_REQUEST_RAID_INFO, std::move(packet)) { } + + void Read() override { } + }; + + class OptOutOfLoot final : public ClientPacket + { + public: + OptOutOfLoot(WorldPacket&& packet) : ClientPacket(CMSG_OPT_OUT_OF_LOOT, std::move(packet)) { } + + void Read() override; + + bool PassOnLoot = false; + }; + + class InitiateRolePoll final : public ClientPacket + { + public: + InitiateRolePoll(WorldPacket&& packet) : ClientPacket(CMSG_INITIATE_ROLE_POLL, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + }; + + class RolePollInform final : public ServerPacket + { + public: + RolePollInform() : ServerPacket(SMSG_ROLE_POLL_INFORM, 17) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + ObjectGuid From; + }; + + class GroupNewLeader final : public ServerPacket + { + public: + GroupNewLeader() : ServerPacket(SMSG_GROUP_NEW_LEADER, 14) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + std::string Name; + }; + + struct GroupPlayerInfos + { + ObjectGuid GUID; + std::string Name; + uint8 Class = 0; + + uint8 Status = 0u; + uint8 Subgroup = 0u; + uint8 Flags = 0u; + uint8 RolesAssigned = 0u; + }; + + struct GroupLfgInfos + { + int32 Slot = 0u; + int8 BootCount = 0; + + bool Aborted = false; + + int32 MyRandomSlot = 0; + uint8 MyFlags = 0u; + uint8 MyPartialClear = 0u; + float MyGearDiff = 0.f; + + int8 MyStrangerCount = 0; + int8 MyKickVoteCount = 0; + + bool MyFirstReward = false; + }; + + struct GroupLootSettings + { + uint8 Method = 0u; + ObjectGuid LootMaster; + uint8 Threshold = 0u; + }; + + struct GroupDifficultySettings + { + uint32 DungeonDifficultyID = 0u; + uint32 RaidDifficultyID = 0u; + uint32 LegacyRaidDifficultyID = 0u; + }; + + class PartyUpdate final : public ServerPacket + { + public: + PartyUpdate() : ServerPacket(SMSG_PARTY_UPDATE, 200) { } + + WorldPacket const* Write() override; + + int8 PartyFlags = 0; + int8 PartyIndex = 0; + int8 PartyType = 0; + + ObjectGuid PartyGUID; + ObjectGuid LeaderGUID; + + int32 MyIndex = 0; + int32 SequenceNum = 0; + + std::vector<GroupPlayerInfos> PlayerList; + + Optional<GroupLfgInfos> LfgInfos; + Optional<GroupLootSettings> LootSettings; + Optional<GroupDifficultySettings> DifficultySettings; + }; + + class SetEveryoneIsAssistant final : public ClientPacket + { + public: + SetEveryoneIsAssistant(WorldPacket&& packet) : ClientPacket(CMSG_SET_EVERYONE_IS_ASSISTANT, std::move(packet)) { } + + void Read() override; + + int8 PartyIndex = 0; + bool EveryoneIsAssistant = false; + }; + + class ChangeSubGroup final : public ClientPacket + { + public: + ChangeSubGroup(WorldPacket&& packet) : ClientPacket(CMSG_CHANGE_SUB_GROUP, std::move(packet)) { } + + void Read() override; + + ObjectGuid TargetGUID; + int8 PartyIndex = 0; + uint8 NewSubGroup = 0u; + }; + + class SwapSubGroups final : public ClientPacket + { + public: + SwapSubGroups(WorldPacket&& packet) : ClientPacket(CMSG_SWAP_SUB_GROUPS, std::move(packet)) { } + + void Read() override; + + ObjectGuid FirstTarget; + ObjectGuid SecondTarget; + int8 PartyIndex = 0; + }; + + class ClearRaidMarker final : public ClientPacket + { + public: + ClearRaidMarker(WorldPacket&& packet) : ClientPacket(CMSG_CLEAR_RAID_MARKER, std::move(packet)) { } + + void Read() override; + + uint8 MarkerId = 0u; + }; + + class RaidMarkersChanged final : public ServerPacket + { + public: + RaidMarkersChanged() : ServerPacket(SMSG_RAID_MARKERS_CHANGED, 6) { } + + WorldPacket const* Write() override; + + int8 PartyIndex = 0; + uint32 ActiveMarkers = 0u; + + std::vector<RaidMarker*> RaidMarkers; + }; + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhase const& phase); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPhases const& phases); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupAura const& aura); +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupAura> const& auraList); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPetStats const& petStats); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupMemberStats const& memberStats); + +ByteBuffer& operator<<(ByteBuffer& data, std::vector<WorldPackets::Party::GroupPlayerInfos> const& playerList); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupPlayerInfos const& playerInfos); + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLfgInfos const& lfgInfos); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupLootSettings const& lootSettings); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Party::GroupDifficultySettings const& difficultySettings); + +#endif // PartyPackets_h__ diff --git a/src/server/game/Server/Packets/QueryPackets.cpp b/src/server/game/Server/Packets/QueryPackets.cpp index 2325c5efac0..f7806a9e588 100644 --- a/src/server/game/Server/Packets/QueryPackets.cpp +++ b/src/server/game/Server/Packets/QueryPackets.cpp @@ -176,8 +176,6 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Query::PlayerGuidLookupDa data << uint8(lookupData.Level); data.WriteString(lookupData.Name); - data.FlushBits(); - return data; } @@ -210,6 +208,8 @@ WorldPacket const* WorldPackets::Query::QueryPageTextResponse::Write() _worldPacket << Info.ID; _worldPacket << Info.NextPageID; _worldPacket.WriteBits(Info.Text.length(), 12); + _worldPacket.FlushBits(); + _worldPacket.WriteString(Info.Text); } @@ -290,6 +290,7 @@ WorldPacket const* WorldPackets::Query::QueryGameObjectResponse::Write() { _worldPacket << GameObjectID; _worldPacket.WriteBit(Allow); + _worldPacket.FlushBits(); if (Allow) { @@ -464,3 +465,27 @@ WorldPacket const* WorldPackets::Query::QueryPetNameResponse::Write() return &_worldPacket; } + +void WorldPackets::Query::ItemTextQuery::Read() +{ + _worldPacket >> Id; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Query::ItemTextCache const& itemTextCache) +{ + data.WriteBits(itemTextCache.Text.length(), 13); + data.FlushBits(); + + data.WriteString(itemTextCache.Text); + + return data; +} + +WorldPacket const* WorldPackets::Query::QueryItemTextResponse::Write() +{ + _worldPacket.WriteBit(Valid); + _worldPacket << Id; + _worldPacket << Item; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/QueryPackets.h b/src/server/game/Server/Packets/QueryPackets.h index a5d7e5de8c4..88bf5a887f6 100644 --- a/src/server/game/Server/Packets/QueryPackets.h +++ b/src/server/game/Server/Packets/QueryPackets.h @@ -418,6 +418,33 @@ namespace WorldPackets uint32 Timestamp = 0; std::string Name; }; + + class ItemTextQuery final : public ClientPacket + { + public: + ItemTextQuery(WorldPacket&& packet) : ClientPacket(CMSG_ITEM_TEXT_QUERY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Id; + }; + + struct ItemTextCache + { + std::string Text; + }; + + class QueryItemTextResponse final : public ServerPacket + { + public: + QueryItemTextResponse() : ServerPacket(SMSG_QUERY_ITEM_TEXT_RESPONSE) { } + + WorldPacket const* Write() override; + + ObjectGuid Id; + bool Valid = false; + ItemTextCache Item; + }; } } diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp index 5a5320a4e2f..d792783cf9a 100644 --- a/src/server/game/Server/Packets/QuestPackets.cpp +++ b/src/server/game/Server/Packets/QuestPackets.cpp @@ -72,7 +72,7 @@ WorldPacket const* WorldPackets::Quest::QueryQuestInfoResponse::Write() _worldPacket << Info.SuggestedGroupNum; _worldPacket << Info.RewardNextQuest; _worldPacket << Info.RewardXPDifficulty; - _worldPacket << Info.Float10; // Unk + _worldPacket << Info.RewardXPMultiplier; _worldPacket << Info.RewardMoney; _worldPacket << Info.RewardMoneyDifficulty; _worldPacket << Info.Float13; // Unk @@ -149,10 +149,12 @@ WorldPacket const* WorldPackets::Quest::QueryQuestInfoResponse::Write() _worldPacket << questObjective.UnkFloat; _worldPacket << int32(questObjective.VisualEffects.size()); - for (auto& visualEffect : questObjective.VisualEffects) + for (int32 visualEffect : questObjective.VisualEffects) _worldPacket << visualEffect; _worldPacket.WriteBits(questObjective.Description.size(), 8); + _worldPacket.FlushBits(); + _worldPacket.WriteString(questObjective.Description); } @@ -165,6 +167,7 @@ WorldPacket const* WorldPackets::Quest::QueryQuestInfoResponse::Write() _worldPacket.WriteBits(Info.PortraitTurnInText.size(), 10); _worldPacket.WriteBits(Info.PortraitTurnInName.size(), 8); _worldPacket.WriteBits(Info.QuestCompletionLog.size(), 11); + _worldPacket.FlushBits(); _worldPacket.WriteString(Info.LogTitle); _worldPacket.WriteString(Info.LogDescription); @@ -277,6 +280,7 @@ WorldPacket const* WorldPackets::Quest::QuestGiverOfferRewardMessage::Write() _worldPacket.WriteBits(PortraitGiverName.size(), 8); _worldPacket.WriteBits(PortraitGiverText.size(), 10); _worldPacket.WriteBits(PortraitTurnInName.size(), 8); + _worldPacket.FlushBits(); _worldPacket.WriteString(QuestTitle); _worldPacket.WriteString(RewardText); @@ -362,6 +366,7 @@ WorldPacket const* WorldPackets::Quest::QuestGiverQuestDetails::Write() _worldPacket.WriteBit(DisplayPopup); _worldPacket.WriteBit(StartCheat); _worldPacket.WriteBit(AutoLaunched); + _worldPacket.FlushBits(); _worldPacket.WriteString(QuestTitle); _worldPacket.WriteString(DescriptionText); @@ -406,6 +411,7 @@ WorldPacket const* WorldPackets::Quest::QuestGiverRequestItems::Write() _worldPacket.WriteBits(QuestTitle.size(), 9); _worldPacket.WriteBits(CompletionText.size(), 12); + _worldPacket.FlushBits(); _worldPacket.WriteString(QuestTitle); _worldPacket.WriteString(CompletionText); @@ -477,6 +483,8 @@ WorldPacket const* WorldPackets::Quest::QuestConfirmAcceptResponse::Write() _worldPacket << InitiatedBy; _worldPacket.WriteBits(QuestTitle.size(), 10); + _worldPacket.FlushBits(); + _worldPacket.WriteString(QuestTitle); return &_worldPacket; diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index a83bcc219be..b2d7269ebb0 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -116,6 +116,7 @@ namespace WorldPackets int32 SuggestedGroupNum = 0; int32 RewardNextQuest = 0; // client will request this quest from NPC, if not 0 int32 RewardXPDifficulty = 0; // used for calculating rewarded experience + float RewardXPMultiplier = 1.0f; int32 RewardMoney = 0; // reward money (below max lvl) int32 RewardMoneyDifficulty = 0; // used in XP calculation at client int32 RewardBonusMoney = 0; @@ -163,8 +164,6 @@ namespace WorldPackets int32 RewardCurrencyID[QUEST_REWARD_CURRENCY_COUNT] = {}; int32 RewardCurrencyQty[QUEST_REWARD_CURRENCY_COUNT] = {}; - // Non JAM data - float Float10 = 1.0f; float Float13 = 1.0f; int32 AllowableRaces = -1; }; diff --git a/src/server/game/Server/Packets/ReferAFriendPackets.cpp b/src/server/game/Server/Packets/ReferAFriendPackets.cpp index 0f3211936f6..8bc017223f8 100644 --- a/src/server/game/Server/Packets/ReferAFriendPackets.cpp +++ b/src/server/game/Server/Packets/ReferAFriendPackets.cpp @@ -30,6 +30,7 @@ void WorldPackets::RaF::GrantLevel::Read() WorldPacket const* WorldPackets::RaF::ProposeLevelGrant::Write() { _worldPacket << Sender; + return &_worldPacket; } @@ -39,6 +40,8 @@ WorldPacket const* WorldPackets::RaF::ReferAFriendFailure::Write() // Client uses this string only if Reason == ERR_REFER_A_FRIEND_NOT_IN_GROUP || Reason == ERR_REFER_A_FRIEND_SUMMON_OFFLINE_S // but always reads it from packet _worldPacket.WriteBits(Str.length(), 6); + _worldPacket.FlushBits(); _worldPacket.WriteString(Str); + return &_worldPacket; } diff --git a/src/server/game/Server/Packets/SystemPackets.cpp b/src/server/game/Server/Packets/SystemPackets.cpp index 365dc742e85..b03994aebab 100644 --- a/src/server/game/Server/Packets/SystemPackets.cpp +++ b/src/server/game/Server/Packets/SystemPackets.cpp @@ -121,6 +121,8 @@ WorldPacket const* WorldPackets::System::SetTimeZoneInformation::Write() { _worldPacket.WriteBits(ServerTimeTZ.length(), 7); _worldPacket.WriteBits(GameTimeTZ.length(), 7); + _worldPacket.FlushBits(); + _worldPacket.WriteString(ServerTimeTZ); _worldPacket.WriteString(GameTimeTZ); diff --git a/src/server/game/Server/Packets/TicketPackets.cpp b/src/server/game/Server/Packets/TicketPackets.cpp index 80a6dad3bd2..cdbeea53e32 100644 --- a/src/server/game/Server/Packets/TicketPackets.cpp +++ b/src/server/game/Server/Packets/TicketPackets.cpp @@ -70,6 +70,7 @@ WorldPacket const* WorldPackets::Ticket::GMTicketGetTicketResponse::Write() { _worldPacket << Result; _worldPacket.WriteBit(Info.is_initialized()); + _worldPacket.FlushBits(); if (Info) { @@ -84,12 +85,12 @@ WorldPacket const* WorldPackets::Ticket::GMTicketGetTicketResponse::Write() _worldPacket.WriteBits(Info->TicketDescription.size(), 11); _worldPacket.WriteBits(Info->WaitTimeOverrideMessage.size(), 10); + _worldPacket.FlushBits(); _worldPacket.WriteString(Info->TicketDescription); _worldPacket.WriteString(Info->WaitTimeOverrideMessage); } - _worldPacket.FlushBits(); return &_worldPacket; } diff --git a/src/server/game/Server/Packets/WhoPackets.cpp b/src/server/game/Server/Packets/WhoPackets.cpp index 99ce0805e8b..632aeba0e12 100644 --- a/src/server/game/Server/Packets/WhoPackets.cpp +++ b/src/server/game/Server/Packets/WhoPackets.cpp @@ -25,9 +25,10 @@ void WorldPackets::Who::WhoIsRequest::Read() WorldPacket const* WorldPackets::Who::WhoIsResponse::Write() { _worldPacket.WriteBits(AccountName.length(), 11); - _worldPacket.WriteString(AccountName); _worldPacket.FlushBits(); + _worldPacket.WriteString(AccountName); + return &_worldPacket; } @@ -102,10 +103,10 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Who::WhoEntry const& entr data.WriteBits(entry.GuildName.length(), 7); data.WriteBit(entry.IsGM); - data.WriteString(entry.GuildName); - data.FlushBits(); + data.WriteString(entry.GuildName); + return data; } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 2886b079c93..45071d14cd4 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -23,16 +23,19 @@ #include "Packets/BankPackets.h" #include "Packets/BattlegroundPackets.h" #include "Packets/BlackMarketPackets.h" -#include "Packets/CharacterPackets.h" #include "Packets/ChannelPackets.h" +#include "Packets/CharacterPackets.h" #include "Packets/ChatPackets.h" #include "Packets/ClientConfigPackets.h" #include "Packets/CombatPackets.h" #include "Packets/DuelPackets.h" #include "Packets/EquipmentSetPackets.h" #include "Packets/GameObjectPackets.h" +#include "Packets/GarrisonPackets.h" #include "Packets/GuildPackets.h" +#include "Packets/PartyPackets.h" #include "Packets/InspectPackets.h" +#include "Packets/InstancePackets.h" #include "Packets/ItemPackets.h" #include "Packets/LootPackets.h" #include "Packets/MailPackets.h" @@ -47,9 +50,9 @@ #include "Packets/ScenePackets.h" #include "Packets/SocialPackets.h" #include "Packets/TalentPackets.h" +#include "Packets/TicketPackets.h" #include "Packets/TokenPackets.h" #include "Packets/TradePackets.h" -#include "Packets/TicketPackets.h" #include "Packets/VehiclePackets.h" #include "Packets/VoidStoragePackets.h" #include "Packets/WhoPackets.h" @@ -249,7 +252,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_CANCEL_MOD_SPEED_NO_CONTROL_AURAS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CANCEL_MOUNT_AURA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::CancelMountAura, &WorldSession::HandleCancelMountAuraOpcode); DEFINE_HANDLER(CMSG_CANCEL_QUEUED_SPELL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CANCEL_TEMP_ENCHANTMENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCancelTempEnchantmentOpcode); + DEFINE_HANDLER(CMSG_CANCEL_TEMP_ENCHANTMENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::CancelTempEnchantment, &WorldSession::HandleCancelTempEnchantmentOpcode); DEFINE_HANDLER(CMSG_CANCEL_TRADE, STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, PROCESS_THREADUNSAFE, WorldPackets::Trade::CancelTrade, &WorldSession::HandleCancelTradeOpcode); DEFINE_HANDLER(CMSG_CAN_DUEL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Duel::CanDuel, &WorldSession::HandleCanDuel); DEFINE_HANDLER(CMSG_CAST_SPELL, STATUS_LOGGEDIN, PROCESS_THREADSAFE, WorldPackets::Spells::CastSpell, &WorldSession::HandleCastSpellOpcode); @@ -257,7 +260,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_CHALLENGE_MODE_REQUEST_MAP_STATS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHANGE_BAG_SLOT_FLAG, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHANGE_MONUMENT_APPEARANCE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHANGE_SUB_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupChangeSubGroupOpcode ); + DEFINE_HANDLER(CMSG_CHANGE_SUB_GROUP, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ChangeSubGroup, &WorldSession::HandleChangeSubGroupOpcode); DEFINE_HANDLER(CMSG_CHARACTER_RENAME_REQUEST, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharacterRenameRequest, &WorldSession::HandleCharRenameOpcode); DEFINE_HANDLER(CMSG_CHAR_CUSTOMIZE, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharCustomize, &WorldSession::HandleCharCustomizeOpcode); DEFINE_HANDLER(CMSG_CHAR_DELETE, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CharDelete, &WorldSession::HandleCharDeleteOpcode); @@ -306,14 +309,14 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_CHAT_MESSAGE_SAY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); DEFINE_HANDLER(CMSG_CHAT_MESSAGE_WHISPER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessageWhisper, &WorldSession::HandleChatMessageWhisperOpcode); DEFINE_HANDLER(CMSG_CHAT_MESSAGE_YELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatMessage, &WorldSession::HandleChatMessageOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_REGISTER_ADDON_PREFIXES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAddonRegisteredPrefixesOpcode); + DEFINE_HANDLER(CMSG_CHAT_REGISTER_ADDON_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatRegisterAddonPrefixes, &WorldSession::HandleAddonRegisteredPrefixesOpcode); DEFINE_HANDLER(CMSG_CHAT_REPORT_FILTERED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_REPORT_IGNORED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleChatIgnoredOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUnregisterAddonPrefixesOpcode); + DEFINE_HANDLER(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::ChatUnregisterAllAddonPrefixes, &WorldSession::HandleUnregisterAllAddonPrefixesOpcode); DEFINE_HANDLER(CMSG_CHECK_RAF_EMAIL_ENABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHECK_WOW_TOKEN_VETERAN_ELIGIBILITY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_CHOICE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_CLEAR_RAID_MARKER, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_CLEAR_RAID_MARKER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::ClearRaidMarker, &WorldSession::HandleClearRaidMarker); DEFINE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::ClearTradeItem, &WorldSession::HandleClearTradeItemOpcode); DEFINE_HANDLER(CMSG_CLIENT_PORT_GRAVEYARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::PortGraveyard, &WorldSession::HandlePortGraveyard); DEFINE_HANDLER(CMSG_CLOSE_INTERACTION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -329,7 +332,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_COMPLETE_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_CONFIRM_RESPEC_WIPE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleConfirmRespecWipeOpcode ); DEFINE_HANDLER(CMSG_CONNECT_TO_FAILED, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); - DEFINE_OPCODE_HANDLER_OLD(CMSG_CONVERT_RAID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupRaidConvertOpcode ); + DEFINE_HANDLER(CMSG_CONVERT_RAID, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ConvertRaid, &WorldSession::HandleConvertRaidOpcode); DEFINE_HANDLER(CMSG_CREATE_CHARACTER, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::CreateCharacter, &WorldSession::HandleCharCreateOpcode); DEFINE_HANDLER(CMSG_CREATE_SHIPMENT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_DB_QUERY_BULK, STATUS_AUTHED, PROCESS_INPLACE, WorldPackets::Query::DBQueryBulk, &WorldSession::HandleDBQueryBulk); @@ -355,7 +358,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_DISCARDED_TIME_SYNC_ACKS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_DISMISS_CRITTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleDismissCritter ); DEFINE_HANDLER(CMSG_DO_MASTER_LOOT_ROLL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_DO_READY_CHECK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidReadyCheckOpcode ); + DEFINE_HANDLER(CMSG_DO_READY_CHECK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::DoReadyCheck, &WorldSession::HandleDoReadyCheckOpcode); DEFINE_HANDLER(CMSG_DUEL_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Duel::DuelResponse, &WorldSession::HandleDuelResponseOpcode); DEFINE_HANDLER(CMSG_EJECT_PASSENGER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::EjectPassenger, &WorldSession::HandleEjectPassenger); DEFINE_HANDLER(CMSG_EMOTE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Chat::EmoteClient, &WorldSession::HandleEmoteOpcode); @@ -364,21 +367,21 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_ENGINE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_ENUM_CHARACTERS, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::EnumCharacters, &WorldSession::HandleCharEnumOpcode); DEFINE_HANDLER(CMSG_ENUM_CHARACTERS_DELETED_BY_CLIENT, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::EnumCharacters, &WorldSession::HandleCharUndeleteEnumOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_FAR_SIGHT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleFarSightOpcode ); + DEFINE_HANDLER(CMSG_FAR_SIGHT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::FarSight, &WorldSession::HandleFarSightOpcode); DEFINE_HANDLER(CMSG_GAME_OBJ_REPORT_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::GameObject::GameObjReportUse, &WorldSession::HandleGameobjectReportUse); DEFINE_HANDLER(CMSG_GAME_OBJ_USE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::GameObject::GameObjUse, &WorldSession::HandleGameObjectUseOpcode); DEFINE_HANDLER(CMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_CANCEL_CONSTRUCTION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_CANCEL_CONSTRUCTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonCancelConstruction, &WorldSession::HandleGarrisonCancelConstruction); DEFINE_HANDLER(CMSG_GARRISON_CHECK_UPGRADEABLE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_COMPLETE_MISSION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_GENERATE_RECRUITS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_GET_BUILDING_LANDMARKS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_GET_BUILDING_LANDMARKS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonGetBuildingLandmarks, &WorldSession::HandleGarrisonGetBuildingLandmarks); DEFINE_HANDLER(CMSG_GARRISON_MISSION_BONUS_ROLL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_PURCHASE_BUILDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_PURCHASE_BUILDING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonPurchaseBuilding, &WorldSession::HandleGarrisonPurchaseBuilding); DEFINE_HANDLER(CMSG_GARRISON_RECRUIT_FOLLOWER, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_REMOVE_FOLLOWER, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_REMOVE_FOLLOWER_FROM_BUILDING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData, &WorldSession::HandleGarrisonRequestBlueprintAndSpecializationData); DEFINE_HANDLER(CMSG_GARRISON_REQUEST_LANDING_PAGE_SHIPMENT_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_REQUEST_SHIPMENT_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GARRISON_SET_BUILDING_ACTIVE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -389,7 +392,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_GARRISON_SWAP_BUILDINGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_GENERATE_RANDOM_CHARACTER_NAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::GenerateRandomCharacterName, &WorldSession::HandleRandomizeCharNameOpcode); DEFINE_HANDLER(CMSG_GET_CHALLENGE_MODE_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_GET_GARRISON_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_GET_GARRISON_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Garrison::GetGarrisonInfo, &WorldSession::HandleGetGarrisonInfo); DEFINE_HANDLER(CMSG_GET_ITEM_PURCHASE_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::GetItemPurchaseData, &WorldSession::HandleGetItemPurchaseData); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MIRROR_IMAGE_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest ); DEFINE_HANDLER(CMSG_GET_PVP_OPTIONS_ENABLED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Battleground::GetPVPOptionsEnabled, &WorldSession::HandleGetPVPOptionsEnabled); @@ -456,20 +459,20 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_HEARTH_AND_RESURRECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Battleground::HearthAndResurrect, &WorldSession::HandleHearthAndResurrect); DEFINE_HANDLER(CMSG_IGNORE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::IgnoreTrade, &WorldSession::HandleIgnoreTradeOpcode); DEFINE_HANDLER(CMSG_INCREASE_CAST_TIME_FOR_SPELL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_INITIATE_ROLE_POLL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRolePollBeginOpcode); + DEFINE_HANDLER(CMSG_INITIATE_ROLE_POLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::InitiateRolePoll, &WorldSession::HandleInitiateRolePoll); DEFINE_HANDLER(CMSG_INITIATE_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::InitiateTrade, &WorldSession::HandleInitiateTradeOpcode); DEFINE_HANDLER(CMSG_INSPECT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::Inspect, &WorldSession::HandleInspectOpcode); DEFINE_HANDLER(CMSG_INSPECT_PVP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::InspectPVPRequest, &WorldSession::HandleInspectPVP); DEFINE_OPCODE_HANDLER_OLD(CMSG_INSTANCE_LOCK_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleInstanceLockResponse); DEFINE_OPCODE_HANDLER_OLD(CMSG_ITEM_PURCHASE_REFUND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleItemRefund ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_ITEM_TEXT_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleItemTextQuery ); + DEFINE_HANDLER(CMSG_ITEM_TEXT_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::ItemTextQuery, &WorldSession::HandleItemTextQuery); DEFINE_HANDLER(CMSG_JOIN_PET_BATTLE_QUEUE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_JOIN_RATED_BATTLEGROUND, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_KEEP_ALIVE, STATUS_NEVER, PROCESS_INPLACE, WorldPacket, &WorldSession::Handle_EarlyProccess); DEFINE_HANDLER(CMSG_KEYBOUND_OVERRIDE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LEARN_PET_SPECIALIZATION_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LEARN_TALENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Talent::LearnTalents, &WorldSession::HandleLearnTalentsOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_LEAVE_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupDisbandOpcode ); + DEFINE_HANDLER(CMSG_LEAVE_GROUP, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::LeaveGroup, &WorldSession::HandleLeaveGroupOpcode); DEFINE_HANDLER(CMSG_LEAVE_PET_BATTLE_QUEUE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LFG_LIST_APPLY_TO_GROUP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_LFG_LIST_CANCEL_APPLICATION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -512,7 +515,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_MAIL_TAKE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeItem, &WorldSession::HandleMailTakeItem); DEFINE_HANDLER(CMSG_MAIL_TAKE_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeMoney, &WorldSession::HandleMailTakeMoney); DEFINE_OPCODE_HANDLER_OLD(CMSG_MASTER_LOOT_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMasterGiveOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MINIMAP_PING, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMinimapPingOpcode ); + DEFINE_HANDLER(CMSG_MINIMAP_PING, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::MinimapPingClient, &WorldSession::HandleMinimapPingOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateProjectilePosition ); DEFINE_HANDLER(CMSG_MOUNT_SET_FAVORITE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_MOUNT_SPECIAL_ANIM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMountSpecialAnimOpcode ); @@ -588,10 +591,10 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_OPEN_MISSION_NPC, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_OPEN_SHIPMENT_NPC, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_OPT_OUT_OF_LOOT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleOptOutOfLootOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PARTY_INVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PARTY_INVITE_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupInviteResponseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_PARTY_UNINVITE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupUninviteOpcode ); + DEFINE_HANDLER(CMSG_OPT_OUT_OF_LOOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::OptOutOfLoot, &WorldSession::HandleOptOutOfLootOpcode); + DEFINE_HANDLER(CMSG_PARTY_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::PartyInviteClient, &WorldSession::HandlePartyInviteOpcode); + DEFINE_HANDLER(CMSG_PARTY_INVITE_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::PartyInviteResponse, &WorldSession::HandlePartyInviteResponseOpcode); + DEFINE_HANDLER(CMSG_PARTY_UNINVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::PartyUninvite, &WorldSession::HandlePartyUninviteOpcode); DEFINE_HANDLER(CMSG_PETITION_BUY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionBuy, &WorldSession::HandlePetitionBuy); DEFINE_HANDLER(CMSG_PETITION_RENAME_GUILD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionRenameGuild, &WorldSession::HandlePetitionRenameGuild); DEFINE_HANDLER(CMSG_PETITION_SHOW_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::PetitionShowList, &WorldSession::HandlePetitionShowList); @@ -653,7 +656,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_PUSH_RESULT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPushResult ); DEFINE_HANDLER(CMSG_QUEUED_MESSAGES_END, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_RANDOM_ROLL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::RandomRollClient, &WorldSession::HandleRandomRollOpcode); - DEFINE_HANDLER(CMSG_READY_CHECK_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_READY_CHECK_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::ReadyCheckResponseClient, &WorldSession::HandleReadyCheckResponseOpcode); DEFINE_HANDLER(CMSG_READ_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::ReadItem, &WorldSession::HandleReadItem); DEFINE_HANDLER(CMSG_RECLAIM_CORPSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::ReclaimCorpse, &WorldSession::HandleReclaimCorpse); DEFINE_HANDLER(CMSG_RECRUIT_A_FRIEND, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -674,12 +677,12 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_GUILD_REWARDS_LIST, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Guild::RequestGuildRewardsList, &WorldSession::HandleRequestGuildRewardsList); DEFINE_HANDLER(CMSG_REQUEST_HONOR_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::RequestHonorStats, &WorldSession::HandleRequestHonorStatsOpcode); DEFINE_HANDLER(CMSG_REQUEST_LFG_LIST_BLACKLIST, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PARTY_JOIN_UPDATES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGroupRequestJoinUpdates); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPartyMemberStatsOpcode); + DEFINE_HANDLER(CMSG_REQUEST_PARTY_JOIN_UPDATES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyJoinUpdates, &WorldSession::HandleRequestPartyJoinUpdates); + DEFINE_HANDLER(CMSG_REQUEST_PARTY_MEMBER_STATS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestPartyMemberStats, &WorldSession::HandleRequestPartyMemberStatsOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PET_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestPetInfoOpcode ); DEFINE_HANDLER(CMSG_REQUEST_PLAYED_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::RequestPlayedTime, &WorldSession::HandlePlayedTime); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_PVP_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleRequestPvpReward ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_RAID_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRaidInfoOpcode ); + DEFINE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::RequestRaidInfo, &WorldSession::HandleRequestRaidInfoOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_RATED_BATTLEFIELD_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRatedBattlefieldInfo); DEFINE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_REQUEST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); @@ -689,11 +692,11 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_REQUEST_VEHICLE_SWITCH_SEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RequestVehicleSwitchSeat, &WorldSession::HandleRequestVehicleSwitchSeat); DEFINE_HANDLER(CMSG_REQUEST_WOW_TOKEN_MARKET_PRICE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Token::RequestWowTokenMarketPrice, &WorldSession::HandleRequestWowTokenMarketPrice); DEFINE_HANDLER(CMSG_RESET_CHALLENGE_MODE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_RESET_INSTANCES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleResetInstancesOpcode ); + DEFINE_HANDLER(CMSG_RESET_INSTANCES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Instance::ResetInstances, &WorldSession::HandleResetInstancesOpcode); DEFINE_HANDLER(CMSG_RESURRECT_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::ResurrectResponse, &WorldSession::HandleResurrectResponse); DEFINE_HANDLER(CMSG_REVERT_MONUMENT_APPEARANCE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_RIDE_VEHICLE_INTERACT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Vehicle::RideVehicleInteract, &WorldSession::HandleRideVehicleInteract); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SAVE_CUF_PROFILES, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleSaveCUFProfiles ); + DEFINE_HANDLER(CMSG_SAVE_CUF_PROFILES, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Misc::SaveCUFProfiles, &WorldSession::HandleSaveCUFProfiles); DEFINE_HANDLER(CMSG_SAVE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::SaveEquipmentSet, &WorldSession::HandleEquipmentSetSave); DEFINE_HANDLER(CMSG_SAVE_GUILD_EMBLEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Guild::SaveGuildEmblem, &WorldSession::HandleSaveGuildEmblem); DEFINE_HANDLER(CMSG_SCENE_PLAYBACK_CANCELED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Scenes::ScenePlaybackCanceled, &WorldSession::HandleScenePlaybackCanceled); @@ -714,7 +717,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Movement::SetActiveMover, &WorldSession::HandleSetActiveMoverOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ACTIVE_VOICE_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveVoiceChannel ); DEFINE_HANDLER(CMSG_SET_ADVANCED_COMBAT_LOGGING, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ASSISTANT_LEADER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupAssistantLeaderOpcode); + DEFINE_HANDLER(CMSG_SET_ASSISTANT_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetAssistantLeader, &WorldSession::HandleSetAssistantLeaderOpcode); DEFINE_HANDLER(CMSG_SET_BACKPACK_AUTOSORT_DISABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_BANK_AUTOSORT_DISABLED, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_BANK_BAG_SLOT_FLAG, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -722,22 +725,22 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SET_CURRENCY_FLAGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_DIFFICULTY_ID, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_DUNGEON_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetDungeonDifficulty, &WorldSession::HandleSetDungeonDifficultyOpcode); - DEFINE_HANDLER(CMSG_SET_EVERYONE_IS_ASSISTANT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_SET_EVERYONE_IS_ASSISTANT, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetEveryoneIsAssistant, &WorldSession::HandleSetEveryoneIsAssistant); DEFINE_HANDLER(CMSG_SET_FACTION_AT_WAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetFactionAtWar, &WorldSession::HandleSetFactionAtWar); DEFINE_HANDLER(CMSG_SET_FACTION_INACTIVE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetFactionInactive, &WorldSession::HandleSetFactionInactiveOpcode); DEFINE_HANDLER(CMSG_SET_FACTION_NOT_AT_WAR, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Character::SetFactionNotAtWar, &WorldSession::HandleSetFactionNotAtWar); DEFINE_HANDLER(CMSG_SET_INSERT_ITEMS_LEFT_TO_RIGHT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_LFG_BONUS_FACTION_ID, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_LOOT_METHOD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLootMethodOpcode ); + DEFINE_HANDLER(CMSG_SET_LOOT_METHOD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::SetLootMethod, &WorldSession::HandleSetLootMethodOpcode); DEFINE_HANDLER(CMSG_SET_LOOT_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PARTY_ASSIGNMENT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyAssignmentOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PARTY_LEADER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSetLeaderOpcode ); + DEFINE_HANDLER(CMSG_SET_PARTY_LEADER, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetPartyLeader, &WorldSession::HandleSetPartyLeaderOpcode); DEFINE_HANDLER(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames ); DEFINE_HANDLER(CMSG_SET_PREFERRED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_PVP, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SET_RAID_DIFFICULTY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetRaidDifficulty, &WorldSession::HandleSetRaidDifficultyOpcode); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_ROLE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSetRolesOpcode ); + DEFINE_HANDLER(CMSG_SET_ROLE, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SetRole, &WorldSession::HandleSetRoleOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_SAVED_INSTANCE_EXTEND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetSavedInstanceExtend ); DEFINE_HANDLER(CMSG_SET_SELECTION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Misc::SetSelection, &WorldSession::HandleSetSelectionOpcode); DEFINE_HANDLER(CMSG_SET_SHEATHED, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Combat::SetSheathed, &WorldSession::HandleSetSheathedOpcode); @@ -773,7 +776,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapInvItem, &WorldSession::HandleSwapInvItemOpcode); DEFINE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SwapItem, &WorldSession::HandleSwapItem); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_SUB_GROUPS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleGroupSwapSubGroupOpcode ); + DEFINE_HANDLER(CMSG_SWAP_SUB_GROUPS, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::Party::SwapSubGroups, &WorldSession::HandleSwapSubGroupsOpcode); DEFINE_HANDLER(CMSG_SWAP_VOID_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::VoidStorage::SwapVoidItem, &WorldSession::HandleVoidSwapItem); DEFINE_HANDLER(CMSG_TABARD_VENDOR_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTabardVendorActivateOpcode); DEFINE_HANDLER(CMSG_TALK_TO_GOSSIP, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleGossipHelloOpcode); @@ -789,7 +792,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_TOGGLE_PVP, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTogglePvP ); DEFINE_OPCODE_HANDLER_OLD(CMSG_TOTEM_DESTROYED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTotemDestroyed ); DEFINE_HANDLER(CMSG_TOY_SET_FAVORITE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_OPCODE_HANDLER_OLD(CMSG_TRAINER_BUY_SPELL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTrainerBuySpellOpcode ); + DEFINE_HANDLER(CMSG_TRAINER_BUY_SPELL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::TrainerBuySpell, &WorldSession::HandleTrainerBuySpellOpcode); DEFINE_HANDLER(CMSG_TRAINER_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleTrainerListOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_TRANSMOGRIFY_ITEMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogrifyItems ); DEFINE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Petition::TurnInPetition, &WorldSession::HandleTurnInPetition); @@ -807,7 +810,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::ClientConfig::UserClientUpdateAccountData, &WorldSession::HandleUpdateAccountData); DEFINE_HANDLER(CMSG_UPDATE_CLIENT_SETTINGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_UPDATE_RAID_TARGET, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRaidTargetUpdateOpcode ); + DEFINE_HANDLER(CMSG_UPDATE_RAID_TARGET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Party::UpdateRaidTarget, &WorldSession::HandleUpdateRaidTargetOpcode); DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_AUCTIONABLE_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Token::UpdateListedAuctionableTokens, &WorldSession::HandleUpdateListedAuctionableTokens); DEFINE_HANDLER(CMSG_UPDATE_WOW_TOKEN_COUNT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_UPGRADE_GARRISON, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); @@ -988,7 +991,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHALLENGE_MODE_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANGE_PLAYER_DIFFICULTY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_LIST, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_JOINED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY_LEFT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -998,8 +1001,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_UPGRADE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_UPGRADE_SPELL_TIER_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_UPGRADE_STARTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_FACTION_CHANGE_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_AUTO_RESPONDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1011,7 +1014,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_PLAYER_NOTFOUND, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RECONNECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_RESTRICTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAT_SERVER_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHEAT_IGNORE_DIMISHING_RETURNS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHECK_WARGAME_ENTRY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHUNKED_PACKET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1058,7 +1061,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DIFFERENT_INSTANCE_FROM_PARTY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISENCHANT_CREDIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPEL_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_GAME_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1081,7 +1084,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENCOUNTER_END, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENCOUNTER_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENUM_CHARACTERS_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTAL_DAMAGE_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTAL_DAMAGE_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_ID, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPECTED_SPAM_RECORDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPLORATION_EXPERIENCE, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1107,51 +1110,51 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_SPEED_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_TIME_SET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GAME_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_ACTIVATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_LANDMARKS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_SET_ACTIVE_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_CREATE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_DELETE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL2, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_XP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_IS_UPGRADEABLE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LANDINGPAGE_SHIPMENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_BLUEPRINT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_FOLLOWERS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_MISSIONS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_MISSION_BONUS_ROLL_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_NUM_FOLLOWER_ACTIVATIONS_REMAINING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_ARCHITECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_MISSION_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLACE_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_LAST_USED_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_USED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUITMENT_FOLLOWERS_GENERATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUIT_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOTE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_FROM_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_START_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UNLEARN_BLUEPRINT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UPGRADE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_FOLLOWER_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ADD_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_ASSIGN_FOLLOWER_TO_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_ACTIVATED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_LANDMARKS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_BUILDING_SET_ACTIVE_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_COMPLETE_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_CREATE_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_DELETE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_ITEM_LEVEL2, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_FOLLOWER_CHANGED_XP, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_IS_UPGRADEABLE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LANDINGPAGE_SHIPMENTS, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_BLUEPRINT_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LEARN_SPECIALIZATION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_FOLLOWERS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_LIST_MISSIONS_CHEAT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_MISSION_BONUS_ROLL_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_NUM_FOLLOWER_ACTIVATIONS_REMAINING, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_ARCHITECT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_MISSION_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_OPEN_TRADESKILL_NPC, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLACE_BUILDING_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_PLACED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_PLOT_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_LAST_USED_TIME, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECALL_PORTAL_USED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUITMENT_FOLLOWERS_GENERATED, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_RECRUIT_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOTE_INFO, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_FROM_BUILDING_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REMOVE_FOLLOWER_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_REQUEST_BLUEPRINT_AND_SPECIALIZATION_DATA_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_START_MISSION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UNLEARN_BLUEPRINT_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_UPGRADE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GENERATE_RANDOM_CHARACTER_NAME_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_DISPLAYED_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_GARRISON_INFO_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENTS_OF_TYPE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENT_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_DISPLAYED_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_GARRISON_INFO_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENTS_OF_TYPE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SHIPMENT_INFO_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_TROPHY_LIST_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_REQUEST_PLAYER_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GM_TICKET_CASE_STATUS, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1167,10 +1170,10 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GOSSIP_POI, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_ACTION_THROTTLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_NEW_LEADER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DECLINE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_DESTROYED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_NEW_LEADER, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_GROUP_UNINVITE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_DELETED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_EARNED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_GUILD_ACHIEVEMENT_MEMBERS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1246,21 +1249,21 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_TIMER_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_GROUP_SIZE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_RESET_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_SAVE_CREATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALIDATE_PLAYER, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVALID_PROMOTION_CODE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_INVENTORY_CHANGE_FAILURE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_IS_QUEST_COMPLETE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_COOLDOWN, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_ENCHANT_TIME_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_EXPIRE_PURCHASE_REFUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PURCHASE_REFUND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARN_TALENT_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1296,7 +1299,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_ACCOUNT_RESTORE_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_CHARACTER_COPY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LIVE_REGION_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_CUF_PROFILES, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_EQUIPMENT_SET, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOAD_SELECTED_TROPHY_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOGIN_SET_TIME_SPEED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1325,7 +1328,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAP_OBJ_EVENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MASTER_LOOT_CANDIDATE_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MESSAGE_BOX, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MINIMAP_PING, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRROR_IMAGE_COMPONENTED_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MIRROR_IMAGE_CREATURE_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MISSILE_CANCEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1420,7 +1423,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MONEY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_RECEIVED_MAIL, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ON_MONSTER_MOVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_CONTAINER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1429,14 +1432,14 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_SHIPMENT_NPC_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OVERRIDE_LIGHT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAGE_TEXT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_INVITE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_COMMAND_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_INVITE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_KILL_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_MEMBER_STATE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PARTY_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PAUSE_MIRROR_TIMER, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PENDING_RAID_LOCK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_ALREADY_SIGNED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_ALREADY_SIGNED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_RENAME_GUILD_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SHOW_LIST, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PETITION_SHOW_SIGNATURES, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1495,7 +1498,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PRINT_NOTIFICATION, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROC_RESIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PROPOSE_LEVEL_GRANT, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_LOG_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_OPTIONS_ENABLED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_SEASON, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1504,7 +1507,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_GAME_OBJECT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_GARRISON_CREATURE_NAME_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_GUILD_INFO_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_ITEM_TEXT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_ITEM_TEXT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_NPC_TEXT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_PAGE_TEXT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_PETITION_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1537,12 +1540,12 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_DIFFICULTY_SET, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_GROUP_ONLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_MARKERS_CHANGED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RANDOM_ROLL, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RATED_BATTLEFIELD_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_COMPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_STARTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_COMPLETED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_READY_CHECK_STARTED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_RESULT_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_READ_ITEM_RESULT_OK, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1561,7 +1564,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_REQUEST_WOW_TOKEN_MARKET_PRICE_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESEARCH_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_COMPRESSION_CONTEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_RANGED_COMBAT_TIMER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_WEEKLY_CURRENCY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPEC_WIPE_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1571,9 +1574,9 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHANGED_INFORM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHANGED_INFORM, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHOSEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_INFORM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_INFORM, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RUNE_REGEN_DEBUG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_BOOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_COMPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1592,8 +1595,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SELL_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_ITEM_PASSIVES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_KNOWN_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_ALL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_ALL, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_CHARGES, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_HISTORY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_UNLEARN_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1625,7 +1628,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_SPELL_CHARGES, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_SPELL_CHARGES, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_TASK_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_TIME_ZONE_INFORMATION, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_VEHICLE_REC_ID, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1643,19 +1646,19 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_DAMAGE_SHIELD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_DELAYED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_DISPELL_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_ENERGIZE_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_ENERGIZE_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_EXECUTE_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILED_OTHER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_FAILURE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_GO, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_HEAL_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_INSTAKILL_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_INTERRUPT_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_INSTAKILL_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_INTERRUPT_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_MISS_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_MULTISTRIKE_EFFECT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_NON_MELEE_DAMAGE_LOG, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_OR_DAMAGE_IMMUNE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_PERIODIC_AURA_LOG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_PERIODIC_AURA_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_START, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPELL_UPDATE_CHAIN_TARGETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPIRIT_HEALER_CONFIRM, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1691,8 +1694,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_TOTEM_MOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_STATUS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRADE_UPDATED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_BUY_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAINER_LIST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_PENDING, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_CINEMATIC, STATUS_NEVER, CONNECTION_TYPE_REALM); @@ -1709,17 +1712,17 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_CHARACTER_FLAGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_DUNGEON_ENCOUNTER_FOR_LOOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_EXPANSION_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_OWNERSHIP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_INSTANCE_OWNERSHIP, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_OBJECT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_TALENT_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_TASK_PROGRESS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WEEKLY_SPELL_USAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WORLD_STATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WOW_TOKEN_AUCTIONABLE_LIST_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_ADD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_REMOVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_ADD, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_REMOVE, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_USE_EQUIPMENT_SET_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_VENDOR_INVENTORY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_VIGNETTE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index db4ec66ea00..650e100f514 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -322,6 +322,10 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (IsConnectionIdle()) m_Socket[CONNECTION_TYPE_REALM]->CloseSocket(); + if (updater.ProcessUnsafe()) + while (_player && _player->IsBeingTeleportedSeamlessly()) + HandleMoveWorldportAckOpcode(); + ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; @@ -453,7 +457,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) //check if we are safe to proceed with logout //logout procedure should happen only in World::UpdateSessions() method!!! - if (updater.ProcessLogout()) + if (updater.ProcessUnsafe()) { time_t currTime = time(NULL); ///- If necessary, log the player out @@ -909,31 +913,23 @@ bool WorldSession::IsAddonRegistered(const std::string& prefix) const return itr != _registeredAddonPrefixes.end(); } -void WorldSession::HandleUnregisterAddonPrefixesOpcode(WorldPacket& /*recvPacket*/) // empty packet +void WorldSession::HandleUnregisterAllAddonPrefixesOpcode(WorldPackets::Chat::ChatUnregisterAllAddonPrefixes& /*packet*/) // empty packet { _registeredAddonPrefixes.clear(); } -void WorldSession::HandleAddonRegisteredPrefixesOpcode(WorldPacket& recvPacket) +void WorldSession::HandleAddonRegisteredPrefixesOpcode(WorldPackets::Chat::ChatRegisterAddonPrefixes& packet) { - // This is always sent after CMSG_UNREGISTER_ALL_ADDON_PREFIXES + // This is always sent after CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES - uint32 count = recvPacket.ReadBits(25); - - if (count > REGISTERED_ADDON_PREFIX_SOFTCAP) + if (packet.Prefixes.size() > REGISTERED_ADDON_PREFIX_SOFTCAP) { // if we have hit the softcap (64) nothing should be filtered _filterAddonMessages = false; - recvPacket.rfinish(); return; } - std::vector<uint8> lengths(count); - for (uint32 i = 0; i < count; ++i) - lengths[i] = recvPacket.ReadBits(5); - - for (uint32 i = 0; i < count; ++i) - _registeredAddonPrefixes.push_back(recvPacket.ReadString(lengths[i])); + _registeredAddonPrefixes.insert(_registeredAddonPrefixes.end(), packet.Prefixes.begin(), packet.Prefixes.end()); if (_registeredAddonPrefixes.size() > REGISTERED_ADDON_PREFIX_SOFTCAP) // shouldn't happen { diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 631f87aeb11..d0242b86440 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -186,6 +186,8 @@ namespace WorldPackets class ChatMessageEmote; class CTextEmote; class EmoteClient; + class ChatRegisterAddonPrefixes; + class ChatUnregisterAllAddonPrefixes; } namespace Combat @@ -214,6 +216,15 @@ namespace WorldPackets class GameObjUse; } + namespace Garrison + { + class GetGarrisonInfo; + class GarrisonPurchaseBuilding; + class GarrisonCancelConstruction; + class GarrisonRequestBlueprintAndSpecializationData; + class GarrisonGetBuildingLandmarks; + } + namespace Guild { class QueryGuildInfo; @@ -266,6 +277,12 @@ namespace WorldPackets class RequestHonorStats; } + namespace Instance + { + class InstanceInfo; + class ResetInstances; + } + namespace Item { class AutoEquipItem; @@ -282,6 +299,7 @@ namespace WorldPackets class SwapInvItem; class SwapItem; class WrapItem; + class CancelTempEnchantment; } namespace Loot @@ -327,6 +345,9 @@ namespace WorldPackets class ObjectUpdateRescued; class CompleteCinematic; class NextCinematicCamera; + class FarSight; + class LoadCUFProfiles; + class SaveCUFProfiles; } namespace Movement @@ -346,6 +367,48 @@ namespace WorldPackets class Hello; class GossipSelectOption; class SpiritHealerActivate; + class TrainerBuySpell; + } + + namespace Party + { + class PartyCommandResult; + class PartyInviteClient; + class PartyInvite; + class PartyInviteResponse; + class PartyUninvite; + class GroupDecline; + class RequestPartyMemberStats; + class PartyMemberStats; + class SetPartyLeader; + class SetRole; + class RoleChangedInform; + class SetLootMethod; + class LeaveGroup; + class MinimapPingClient; + class MinimapPing; + class UpdateRaidTarget; + class SendRaidTargetUpdateSingle; + class SendRaidTargetUpdateAll; + class ConvertRaid; + class RequestPartyJoinUpdates; + class SetAssistantLeader; + class DoReadyCheck; + class ReadyCheckStarted; + class ReadyCheckResponseClient; + class ReadyCheckResponse; + class ReadyCheckCompleted; + class RequestRaidInfo; + class OptOutOfLoot; + class InitiateRolePoll; + class RolePollInform; + class GroupNewLeader; + class PartyUpdate; + class SetEveryoneIsAssistant; + class ChangeSubGroup; + class SwapSubGroups; + class RaidMarkersChanged; + class ClearRaidMarker; } namespace Petition @@ -375,6 +438,7 @@ namespace WorldPackets class QueryPetName; class QuestPOIQuery; class QueryQuestCompletionNPCs; + class ItemTextQuery; } namespace Quest @@ -635,8 +699,8 @@ public: explicit PacketFilter(WorldSession* pSession) : m_pSession(pSession) { } virtual ~PacketFilter() { } - virtual bool Process(WorldPacket* /*packet*/) { return true; } - virtual bool ProcessLogout() const { return true; } + virtual bool Process(WorldPacket* /*packet*/) = 0; + virtual bool ProcessUnsafe() const { return false; } protected: WorldSession* const m_pSession; @@ -653,9 +717,7 @@ public: explicit MapSessionFilter(WorldSession* pSession) : PacketFilter(pSession) { } ~MapSessionFilter() { } - virtual bool Process(WorldPacket* packet) override; - //in Map::Update() we do not process player logout! - virtual bool ProcessLogout() const override { return false; } + bool Process(WorldPacket* packet) override; }; //class used to filer only thread-unsafe packets from queue @@ -666,7 +728,8 @@ public: explicit WorldSessionFilter(WorldSession* pSession) : PacketFilter(pSession) { } ~WorldSessionFilter() { } - virtual bool Process(WorldPacket* packet) override; + bool Process(WorldPacket* packet) override; + bool ProcessUnsafe() const override { return true; } }; struct PacketCounter @@ -843,8 +906,6 @@ class WorldSession void SendNotInArenaTeamPacket(uint8 type); void SendPetitionShowList(ObjectGuid guid); - void BuildPartyMemberStatsChangedPacket(Player* player, WorldPacket* data); - void DoLootRelease(ObjectGuid lguid); // Account mute time @@ -1039,28 +1100,31 @@ class WorldSession void HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeSkipped& moveTimeSkipped); void HandleMovementAckMessage(WorldPackets::Movement::MovementAckMessage& movementAck); - void HandleRequestRaidInfoOpcode(WorldPacket& recvData); + void HandleRequestRaidInfoOpcode(WorldPackets::Party::RequestRaidInfo& packet); - void HandleGroupInviteOpcode(WorldPacket& recvPacket); + void HandlePartyInviteOpcode(WorldPackets::Party::PartyInviteClient& packet); //void HandleGroupCancelOpcode(WorldPacket& recvPacket); - void HandleGroupInviteResponseOpcode(WorldPacket& recvPacket); - void HandleGroupUninviteOpcode(WorldPacket& recvPacket); - void HandleGroupSetLeaderOpcode(WorldPacket& recvPacket); - void HandleGroupSetRolesOpcode(WorldPacket& recvData); - void HandleGroupDisbandOpcode(WorldPacket& recvPacket); - void HandleOptOutOfLootOpcode(WorldPacket& recvData); - void HandleLootMethodOpcode(WorldPacket& recvPacket); + void HandlePartyInviteResponseOpcode(WorldPackets::Party::PartyInviteResponse& packet); + void HandlePartyUninviteOpcode(WorldPackets::Party::PartyUninvite& packet); + void HandleSetPartyLeaderOpcode(WorldPackets::Party::SetPartyLeader& packet); + void HandleSetRoleOpcode(WorldPackets::Party::SetRole& packet); + void HandleLeaveGroupOpcode(WorldPackets::Party::LeaveGroup& packet); + void HandleOptOutOfLootOpcode(WorldPackets::Party::OptOutOfLoot& packet); + void HandleSetLootMethodOpcode(WorldPackets::Party::SetLootMethod& packet); void HandleLootRoll(WorldPackets::Loot::LootRoll& packet); - void HandleRequestPartyMemberStatsOpcode(WorldPacket& recvData); - void HandleRaidTargetUpdateOpcode(WorldPacket& recvData); - void HandleRaidReadyCheckOpcode(WorldPacket& recvData); - void HandleGroupRaidConvertOpcode(WorldPacket& recvData); - void HandleGroupRequestJoinUpdates(WorldPacket& recvData); - void HandleGroupChangeSubGroupOpcode(WorldPacket& recvData); - void HandleGroupSwapSubGroupOpcode(WorldPacket& recvData); - void HandleGroupAssistantLeaderOpcode(WorldPacket& recvData); + void HandleRequestPartyMemberStatsOpcode(WorldPackets::Party::RequestPartyMemberStats& packet); + void HandleUpdateRaidTargetOpcode(WorldPackets::Party::UpdateRaidTarget& packet); + void HandleDoReadyCheckOpcode(WorldPackets::Party::DoReadyCheck& packet); + void HandleReadyCheckResponseOpcode(WorldPackets::Party::ReadyCheckResponseClient& packet); + void HandleConvertRaidOpcode(WorldPackets::Party::ConvertRaid& packet); + void HandleRequestPartyJoinUpdates(WorldPackets::Party::RequestPartyJoinUpdates& packet); + void HandleChangeSubGroupOpcode(WorldPackets::Party::ChangeSubGroup& packet); + void HandleSwapSubGroupsOpcode(WorldPackets::Party::SwapSubGroups& packet); + void HandleSetAssistantLeaderOpcode(WorldPackets::Party::SetAssistantLeader& packet); void HandlePartyAssignmentOpcode(WorldPacket& recvData); - void HandleRolePollBeginOpcode(WorldPacket& recvData); + void HandleInitiateRolePoll(WorldPackets::Party::InitiateRolePoll& packet); + void HandleSetEveryoneIsAssistant(WorldPackets::Party::SetEveryoneIsAssistant& packet); + void HandleClearRaidMarker(WorldPackets::Party::ClearRaidMarker& packet); void HandleDeclinePetition(WorldPackets::Petition::DeclinePetition& packet); void HandleOfferPetition(WorldPackets::Petition::OfferPetition& packet); @@ -1119,7 +1183,7 @@ class WorldSession void HandleTabardVendorActivateOpcode(WorldPackets::NPC::Hello& packet); void HandleBankerActivateOpcode(WorldPackets::NPC::Hello& packet); void HandleTrainerListOpcode(WorldPackets::NPC::Hello& packet); - void HandleTrainerBuySpellOpcode(WorldPacket& recvPacket); + void HandleTrainerBuySpellOpcode(WorldPackets::NPC::TrainerBuySpell& packet); void HandlePetitionShowList(WorldPackets::Petition::PetitionShowList& packet); void HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet); void HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelectOption& packet); @@ -1135,7 +1199,7 @@ class WorldSession void HandleStableRevivePet(WorldPacket& recvPacket); void HandleStableSwapPet(WorldPacket& recvPacket); void HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId); - void SendTrainerBuyFailed(ObjectGuid guid, uint32 spellId, uint32 reason); + void SendTrainerBuyFailed(ObjectGuid trainerGUID, uint32 spellID, int32 trainerFailedReason); void HandleCanDuel(WorldPackets::Duel::CanDuel& packet); void HandleDuelResponseOpcode(WorldPackets::Duel::DuelResponse& duelResponse); @@ -1179,7 +1243,7 @@ class WorldSession void HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead& packet); void HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender& packet); void HandleMailDelete(WorldPackets::Mail::MailDelete& packet); - void HandleItemTextQuery(WorldPacket& recvData); + void HandleItemTextQuery(WorldPackets::Query::ItemTextQuery& itemTextQuery); void HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem& packet); void HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime& packet); void HandleCancelChanneling(WorldPacket& recvData); @@ -1190,7 +1254,6 @@ class WorldSession void HandleDestroyItemOpcode(WorldPackets::Item::DestroyItem& destroyItem); void HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& autoEquipItem); void HandleSellItemOpcode(WorldPackets::Item::SellItem& packet); - void HandleBuyItemInSlotOpcode(WorldPacket& recvPacket); void HandleBuyItemOpcode(WorldPackets::Item::BuyItem& packet); void HandleListInventoryOpcode(WorldPackets::NPC::Hello& packet); void HandleAutoStoreBagItemOpcode(WorldPackets::Item::AutoStoreBagItem& packet); @@ -1252,8 +1315,8 @@ class WorldSession void HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet); void HandleChatIgnoredOpcode(WorldPacket& recvPacket); - void HandleUnregisterAddonPrefixesOpcode(WorldPacket& recvPacket); - void HandleAddonRegisteredPrefixesOpcode(WorldPacket& recvPacket); + void HandleUnregisterAllAddonPrefixesOpcode(WorldPackets::Chat::ChatUnregisterAllAddonPrefixes& packet); + void HandleAddonRegisteredPrefixesOpcode(WorldPackets::Chat::ChatRegisterAddonPrefixes& packet); void HandleReclaimCorpse(WorldPackets::Misc::ReclaimCorpse& packet); void HandleQueryCorpseLocation(WorldPackets::Query::QueryCorpseLocationFromClient& packet); @@ -1326,9 +1389,9 @@ class WorldSession void HandleWardenDataOpcode(WorldPacket& recvData); void HandleWorldTeleportOpcode(WorldPacket& recvData); - void HandleMinimapPingOpcode(WorldPacket& recvData); + void HandleMinimapPingOpcode(WorldPackets::Party::MinimapPingClient& packet); void HandleRandomRollOpcode(WorldPackets::Misc::RandomRollClient& packet); - void HandleFarSightOpcode(WorldPacket& recvData); + void HandleFarSightOpcode(WorldPackets::Misc::FarSight& packet); void HandleSetDungeonDifficultyOpcode(WorldPackets::Misc::SetDungeonDifficulty& setDungeonDifficulty); void HandleSetRaidDifficultyOpcode(WorldPackets::Misc::SetRaidDifficulty& setRaidDifficulty); void HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData); @@ -1336,7 +1399,7 @@ class WorldSession void HandleRealmSplitOpcode(WorldPacket& recvData); void HandleTimeSyncResponse(WorldPackets::Misc::TimeSyncResponse& packet); void HandleWhoIsOpcode(WorldPackets::Who::WhoIsRequest& packet); - void HandleResetInstancesOpcode(WorldPacket& recvData); + void HandleResetInstancesOpcode(WorldPackets::Instance::ResetInstances& packet); void HandleInstanceLockResponse(WorldPacket& recvPacket); // Looking for Dungeon/Raid @@ -1374,7 +1437,7 @@ class WorldSession // Socket gem void HandleSocketOpcode(WorldPacket& recvData); - void HandleCancelTempEnchantmentOpcode(WorldPacket& recvData); + void HandleCancelTempEnchantmentOpcode(WorldPackets::Item::CancelTempEnchantment& cancelTempEnchantment); void HandleGetItemPurchaseData(WorldPackets::Item::GetItemPurchaseData& packet); void HandleItemRefund(WorldPacket& recvData); @@ -1459,9 +1522,16 @@ class WorldSession void HandleRequestWowTokenMarketPrice(WorldPackets::Token::RequestWowTokenMarketPrice& requestWowTokenMarketPrice); // Compact Unit Frames (4.x) - void HandleSaveCUFProfiles(WorldPacket& recvPacket); + void HandleSaveCUFProfiles(WorldPackets::Misc::SaveCUFProfiles& packet); void SendLoadCUFProfiles(); + // Garrison + void HandleGetGarrisonInfo(WorldPackets::Garrison::GetGarrisonInfo& getGarrisonInfo); + void HandleGarrisonPurchaseBuilding(WorldPackets::Garrison::GarrisonPurchaseBuilding& garrisonPurchaseBuilding); + void HandleGarrisonCancelConstruction(WorldPackets::Garrison::GarrisonCancelConstruction& garrisonCancelConstruction); + void HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& garrisonRequestBlueprintAndSpecializationData); + void HandleGarrisonGetBuildingLandmarks(WorldPackets::Garrison::GarrisonGetBuildingLandmarks& garrisonGetBuildingLandmarks); + private: void InitializeQueryCallbackParameters(); void ProcessQueryCallbacks(); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index e4b98f1c54b..bc1306d73e1 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -44,8 +44,8 @@ struct CompressedWorldPacket using boost::asio::ip::tcp; std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT"); - std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER"); +uint32 const WorldSocket::MinSizeForCompression = 0x400; uint32 const SizeOfClientHeader[2][2] = { @@ -54,7 +54,6 @@ uint32 const SizeOfClientHeader[2][2] = }; uint32 const SizeOfServerHeader[2] = { sizeof(uint16) + sizeof(uint32), sizeof(uint32) }; - WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), _type(CONNECTION_TYPE_REALM), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _compressionStream(nullptr), _initialized(false) @@ -375,7 +374,7 @@ void WorldSocket::SendPacket(WorldPacket const& packet) uint32 packetSize = packet.size(); uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; - if (packetSize > 0x400) + if (packetSize > MinSizeForCompression && _authCrypt.IsInitialized()) packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); std::unique_lock<std::mutex> guard(_writeLock); @@ -403,7 +402,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& uint8* headerPos = buffer.GetWritePointer(); buffer.WriteCompleted(sizeOfHeader); - if (packetSize > 0x400) + if (packetSize > MinSizeForCompression && _authCrypt.IsInitialized()) { CompressedWorldPacket cmp; cmp.UncompressedSize = packetSize + 4; @@ -451,7 +450,7 @@ uint32 WorldSocket::CompressPacket(uint8* buffer, WorldPacket const& packet) _compressionStream->next_in = (Bytef*)&opcode; _compressionStream->avail_in = sizeof(uint32); - int32 z_res = deflate(_compressionStream, Z_BLOCK); + int32 z_res = deflate(_compressionStream, Z_NO_FLUSH); if (z_res != Z_OK) { TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index e42a310f470..b82029f88d5 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -69,8 +69,8 @@ union ClientPktHeader class WorldSocket : public Socket<WorldSocket> { static std::string const ServerConnectionInitialize; - static std::string const ClientConnectionInitialize; + static uint32 const MinSizeForCompression; public: WorldSocket(tcp::socket&& socket); diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 7e60ac9b5da..497b416ded1 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -461,7 +461,7 @@ enum AuraType SPELL_AURA_401 = 401, SPELL_AURA_402 = 402, SPELL_AURA_403 = 403, - SPELL_AURA_404 = 404, + SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT = 404, SPELL_AURA_405 = 405, SPELL_AURA_406 = 406, SPELL_AURA_MOD_FEAR_2 = 407, // NYI @@ -476,7 +476,7 @@ enum AuraType SPELL_AURA_416 = 416, SPELL_AURA_417 = 417, SPELL_AURA_418 = 418, - SPELL_AURA_419 = 419, + SPELL_AURA_MOD_BASE_MANA_PCT = 419, SPELL_AURA_MOD_BATTLE_PET_XP_PCT = 420, // NYI SPELL_AURA_421 = 421, SPELL_AURA_422 = 422, @@ -523,8 +523,8 @@ enum AuraType SPELL_AURA_CONVER_CRIT_RATING_PCT_TO_PARRY_RATING = 463, // NYI SPELL_AURA_464 = 464, SPELL_AURA_465 = 465, - SPELL_AURA_466 = 466, - SPELL_AURA_467 = 467, + SPELL_AURA_MOD_BONUS_ARMOR_PCT = 466, // Affects bonus armor gain from all sources except base stats + SPELL_AURA_MOD_STAT_BONUS_PCT = 467, // Affects stat gain from all sources except base stats SPELL_AURA_468 = 468, SPELL_AURA_469 = 469, SPELL_AURA_471 = 471, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a3b0c4788e7..b5f154e6fe1 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -426,7 +426,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //363 SPELL_AURA_MOD_NEXT_SPELL &AuraEffect::HandleUnused, //364 unused (4.3.4) &AuraEffect::HandleNULL, //365 SPELL_AURA_MAX_FAR_CLIP_PLANE - &AuraEffect::HandleNULL, //366 SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT + &AuraEffect::HandleOverrideSpellPowerByAttackPower, //366 SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT &AuraEffect::HandleNULL, //367 SPELL_AURA_367 &AuraEffect::HandleUnused, //368 unused (4.3.4) &AuraEffect::HandleNULL, //369 SPELL_AURA_ENABLE_POWER_BAR_TIMER @@ -464,7 +464,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //401 &AuraEffect::HandleNULL, //402 &AuraEffect::HandleNULL, //403 - &AuraEffect::HandleNULL, //404 + &AuraEffect::HandleOverrideAttackPowerBySpellPower, //404 SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT &AuraEffect::HandleNULL, //405 &AuraEffect::HandleNULL, //406 &AuraEffect::HandleNULL, //407 SPELL_AURA_MOD_FEAR_2 @@ -479,7 +479,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //416 &AuraEffect::HandleNULL, //417 &AuraEffect::HandleNULL, //418 - &AuraEffect::HandleNULL, //419 + &AuraEffect::HandleAuraModIncreaseBaseManaPercent, //419 SPELL_AURA_MOD_BASE_MANA_PCT &AuraEffect::HandleNULL, //420 SPELL_AURA_MOD_BATTLE_PET_XP_PCT &AuraEffect::HandleNULL, //421 &AuraEffect::HandleNULL, //422 @@ -526,8 +526,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //463 SPELL_AURA_CRIT_RATING_AFFECTS_PARRY used by Riposte &AuraEffect::HandleNULL, //464 &AuraEffect::HandleNULL, //465 - &AuraEffect::HandleNULL, //466 - &AuraEffect::HandleNULL, //467 + &AuraEffect::HandleNULL, //466 SPELL_AURA_MOD_BONUS_ARMOR_PCT + &AuraEffect::HandleModStatBonusPercent, //467 SPELL_AURA_MOD_STAT_BONUS_PCT &AuraEffect::HandleNULL, //468 &AuraEffect::HandleNULL, //469 &AuraEffect::HandleNULL, //470 @@ -3982,6 +3982,59 @@ void AuraEffect::HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mod target->ToPlayer()->UpdateExpertise(OFF_ATTACK); } +void AuraEffect::HandleModStatBonusPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + Unit* target = aurApp->GetTarget(); + + if (GetMiscValue() < -1 || GetMiscValue() > 4) + { + TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_STAT_BONUS_PCT not valid"); + return; + } + + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) + { + if (GetMiscValue() == i || GetMiscValue() == -1) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT_EXCLUDE_CREATE, float(m_amount), apply); + target->ApplyStatPercentBuffMod(Stats(i), float(m_amount), apply); + } + } +} + +void AuraEffect::HandleOverrideSpellPowerByAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; + + target->ApplyModSignedFloatValue(PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT, float(m_amount), apply); + target->UpdateSpellDamageAndHealingBonus(); +} + +void AuraEffect::HandleOverrideAttackPowerBySpellPower(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; + + target->ApplyModSignedFloatValue(PLAYER_FIELD_OVERRIDE_AP_BY_SPELL_POWER_PERCENT, float(m_amount), apply); + target->UpdateAttackPowerAndDamage(); +} + /********************************/ /*** HEAL & ENERGIZE ***/ /********************************/ @@ -4141,6 +4194,14 @@ void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurA target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply); } +void AuraEffect::HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + aurApp->GetTarget()->HandleStatModifier(UNIT_MOD_MANA, BASE_PCT, float(GetAmount()), apply); +} + /********************************/ /*** FIGHT ***/ /********************************/ diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index e8431e202ba..91cf75dbe87 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -234,6 +234,9 @@ class AuraEffect void HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModResistenceOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleModStatBonusPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleOverrideSpellPowerByAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleOverrideAttackPowerBySpellPower(AuraApplication const* aurApp, uint8 mode, bool apply) const; // heal and energize void HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const; @@ -244,6 +247,7 @@ class AuraEffect void HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModIncreaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; // fight void HandleAuraModParryPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraModDodgePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e8da248160b..cb0f34c162b 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -857,12 +857,14 @@ void Spell::SelectSpellTargets() // Do not check for selfcast if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID()) { - m_UniqueTargetInfo.erase(ihit++); - continue; + ihit = m_UniqueTargetInfo.erase(ihit); + continue; } } + ++ihit; } + if (checkLvl && m_UniqueTargetInfo.empty()) { SendCastResult(SPELL_FAILED_LOWLEVEL); @@ -2298,7 +2300,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) target->processed = true; // Target checked in apply effects procedure // Get mask of effects for target - uint8 mask = target->effectMask; + uint32 mask = target->effectMask; Unit* unit = m_caster->GetGUID() == target->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target->targetGUID); if (!unit && target->targetGUID.IsPlayer()) // only players may be targeted across maps @@ -2326,6 +2328,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) return; } + if (!unit) + return; + if (unit->IsAlive() != target->alive) return; @@ -2850,8 +2855,8 @@ bool Spell::UpdateChanneledTargetList() if (m_channelTargetEffectMask == 0) return true; - uint8 channelTargetEffectMask = m_channelTargetEffectMask; - uint8 channelAuraMask = 0; + uint32 channelTargetEffectMask = m_channelTargetEffectMask; + uint32 channelAuraMask = 0; for (SpellEffectInfo const* effect : GetEffects()) if (effect && effect->Effect == SPELL_EFFECT_APPLY_AURA) channelAuraMask |= 1 << effect->EffectIndex; @@ -2866,7 +2871,7 @@ bool Spell::UpdateChanneledTargetList() modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this); } - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { if (ihit->missCondition == SPELL_MISS_NONE && (channelTargetEffectMask & ihit->effectMask)) { @@ -3359,10 +3364,10 @@ void Spell::handle_immediate() // process immediate effects (items, ground, etc.) also initialize some variables _handle_immediate_phase(); - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); - for (std::vector<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) + for (std::vector<GOTargetInfo>::iterator ihit = m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); FinishTargetProcessing(); @@ -3402,7 +3407,7 @@ uint64 Spell::handle_delayed(uint64 t_offset) bool single_missile = (m_targets.HasDst()); // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases) - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { if (ihit->processed == false) { @@ -3417,7 +3422,7 @@ uint64 Spell::handle_delayed(uint64 t_offset) } // now recheck gameobject targeting correctness - for (std::vector<GOTargetInfo>::iterator ighit= m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end(); ++ighit) + for (std::vector<GOTargetInfo>::iterator ighit = m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end(); ++ighit) { if (ighit->processed == false) { @@ -3475,7 +3480,7 @@ void Spell::_handle_immediate_phase() } // process items - for (std::vector<ItemTargetInfo>::iterator ihit= m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit) + for (std::vector<ItemTargetInfo>::iterator ihit = m_UniqueItemInfo.begin(); ihit != m_UniqueItemInfo.end(); ++ihit) DoAllEffectOnTarget(&(*ihit)); if (!m_originalCaster) @@ -4145,47 +4150,13 @@ void Spell::ExecuteLogEffectExtraAttacks(uint8 effIndex, Unit* victim, uint32 nu void Spell::ExecuteLogEffectInterruptCast(uint8 /*effIndex*/, Unit* victim, uint32 spellId) { - ObjectGuid casterGuid = m_caster->GetGUID(); - ObjectGuid targetGuid = victim->GetGUID(); - - WorldPacket data(SMSG_SPELL_INTERRUPT_LOG, 8 + 8 + 4 + 4); - data.WriteBit(targetGuid[4]); - data.WriteBit(casterGuid[5]); - data.WriteBit(casterGuid[6]); - data.WriteBit(casterGuid[1]); - data.WriteBit(casterGuid[3]); - data.WriteBit(casterGuid[0]); - data.WriteBit(targetGuid[3]); - data.WriteBit(targetGuid[5]); - data.WriteBit(targetGuid[1]); - data.WriteBit(casterGuid[4]); - data.WriteBit(casterGuid[7]); - data.WriteBit(targetGuid[7]); - data.WriteBit(targetGuid[6]); - data.WriteBit(targetGuid[2]); - data.WriteBit(casterGuid[2]); - data.WriteBit(targetGuid[0]); - - data.WriteByteSeq(casterGuid[7]); - data.WriteByteSeq(casterGuid[6]); - data.WriteByteSeq(casterGuid[3]); - data.WriteByteSeq(casterGuid[2]); - data.WriteByteSeq(targetGuid[3]); - data.WriteByteSeq(targetGuid[6]); - data.WriteByteSeq(targetGuid[2]); - data.WriteByteSeq(targetGuid[4]); - data.WriteByteSeq(targetGuid[7]); - data.WriteByteSeq(targetGuid[0]); - data.WriteByteSeq(casterGuid[4]); - data << uint32(m_spellInfo->Id); - data.WriteByteSeq(targetGuid[1]); - data.WriteByteSeq(casterGuid[0]); - data.WriteByteSeq(casterGuid[5]); - data.WriteByteSeq(casterGuid[1]); - data << uint32(spellId); - data.WriteByteSeq(targetGuid[5]); + WorldPackets::CombatLog::SpellInterruptLog data; + data.Caster = m_caster->GetGUID(); + data.Victim = victim->GetGUID(); + data.InterruptedSpellID = m_spellInfo->Id; + data.SpellID = spellId; - m_caster->SendMessageToSet(&data, true); + m_caster->SendMessageToSet(data.Write(), true); } void Spell::ExecuteLogEffectDurabilityDamage(uint8 effIndex, Unit* victim, int32 itemId, int32 amount) @@ -4313,7 +4284,7 @@ void Spell::SendResurrectRequest(Player* target) // for player resurrections the name is looked up by guid std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER ? "" : m_caster->GetNameForLocaleIdx(target->GetSession()->GetSessionDbLocaleIndex())); - + WorldPackets::Spells::ResurrectRequest resurrectRequest; resurrectRequest.ResurrectOffererGUID = m_caster->GetGUID(); resurrectRequest.ResurrectOffererVirtualRealmAddress = GetVirtualRealmAddress(); @@ -4585,7 +4556,7 @@ void Spell::TakeReagents() ItemTemplate const* castItemTemplate = m_CastItem ? m_CastItem->GetTemplate() : NULL; // do not take reagents for these item casts - if (castItemTemplate && castItemTemplate->GetFlags() & ITEM_PROTO_FLAG_TRIGGERED_CAST) + if (castItemTemplate && castItemTemplate->GetFlags() & ITEM_FLAG_TRIGGERED_CAST) return; Player* p_caster = m_caster->ToPlayer(); @@ -5815,7 +5786,7 @@ bool Spell::CanAutoCast(Unit* target) { SelectSpellTargets(); //check if among target units, our WANTED target is as well (->only self cast spells return false) - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) if (ihit->targetGUID == targetguid) return true; } @@ -6016,7 +5987,7 @@ SpellCastResult Spell::CheckItems() } // do not take reagents for these item casts - if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_TRIGGERED_CAST)) + if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_TRIGGERED_CAST)) { bool checkReagents = !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST) && !player->CanNoReagentCast(m_spellInfo); // Not own traded item (in trader trade slot) requires reagents even if triggered spell @@ -6143,7 +6114,7 @@ SpellCastResult Spell::CheckItems() if (m_targets.GetItemTarget()->GetOwner() != m_caster) return SPELL_FAILED_NOT_TRADEABLE; // do not allow to enchant vellum from scroll made by vellum-prevent exploit - if (m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_TRIGGERED_CAST) + if (m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_TRIGGERED_CAST) return SPELL_FAILED_TOTEM_CATEGORY; ItemPosCountVec dest; InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, effect->ItemType, 1); @@ -6266,7 +6237,7 @@ SpellCastResult Spell::CheckItems() if (!m_targets.GetItemTarget()) return SPELL_FAILED_CANT_BE_PROSPECTED; //ensure item is a prospectable ore - if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_PROSPECTABLE)) + if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_FLAG_PROSPECTABLE)) return SPELL_FAILED_CANT_BE_PROSPECTED; //prevent prospecting in trade slot if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID()) @@ -6289,7 +6260,7 @@ SpellCastResult Spell::CheckItems() if (!m_targets.GetItemTarget()) return SPELL_FAILED_CANT_BE_MILLED; //ensure item is a millable herb - if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_MILLABLE)) + if (!(m_targets.GetItemTarget()->GetTemplate()->GetFlags() & ITEM_FLAG_MILLABLE)) return SPELL_FAILED_CANT_BE_MILLED; //prevent milling in trade slot if (m_targets.GetItemTarget()->GetOwnerGUID() != m_caster->GetGUID()) @@ -6832,7 +6803,7 @@ void Spell::HandleLaunchPhase() if (effect && (m_applyMultiplierMask & (1 << effect->EffectIndex))) multiplier[effect->EffectIndex] = effect->CalcDamageMultiplier(m_originalCaster, this); - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { TargetInfo& target = *ihit; @@ -7502,7 +7473,7 @@ bool WorldObjectSpellConeTargetCheck::operator()(WorldObject* target) } else if (_spellInfo->HasAttribute(SPELL_ATTR0_CU_CONE_LINE)) { - if (!_caster->HasInLine(target, _caster->GetObjectSize())) + if (!_caster->HasInLine(target, _caster->GetObjectSize() + target->GetObjectSize())) return false; } else @@ -7519,7 +7490,7 @@ WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Po bool WorldObjectSpellTrajTargetCheck::operator()(WorldObject* target) { // return all targets on missile trajectory (0 - size of a missile) - if (!_caster->HasInLine(target, 0)) + if (!_caster->HasInLine(target, target->GetObjectSize())) return false; return WorldObjectSpellAreaTargetCheck::operator ()(target); } diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index ddf6cb055ae..ec716a0e03d 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -338,6 +338,7 @@ class Spell void EffectApplyGlyph(SpellEffIndex effIndex); void EffectEnchantHeldItem(SpellEffIndex effIndex); void EffectSummonObject(SpellEffIndex effIndex); + void EffectChangeRaidMarker(SpellEffIndex effIndex); void EffectResurrect(SpellEffIndex effIndex); void EffectParry(SpellEffIndex effIndex); void EffectBlock(SpellEffIndex effIndex); @@ -405,6 +406,9 @@ class Spell void EffectCreateAreaTrigger(SpellEffIndex effIndex); void EffectRemoveTalent(SpellEffIndex effIndex); void EffectDestroyItem(SpellEffIndex effIndex); + void EffectLearnGarrisonBuilding(SpellEffIndex effIndex); + void EffectCreateGarrison(SpellEffIndex effIndex); + void EffectAddGarrisonFollower(SpellEffIndex effIndex); typedef std::set<Aura*> UsedSpellMods; @@ -669,7 +673,7 @@ class Spell uint64 timeDelay; SpellMissInfo missCondition:8; SpellMissInfo reflectResult:8; - uint32 effectMask:32; + uint32 effectMask; bool processed:1; bool alive:1; bool crit:1; @@ -683,8 +687,8 @@ class Spell { ObjectGuid targetGUID; uint64 timeDelay; - uint32 effectMask:32; - bool processed:1; + uint32 effectMask; + bool processed; }; std::vector<GOTargetInfo> m_UniqueGOTargetInfo; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 372ff5faba8..36e544de3bd 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -67,6 +67,8 @@ #include "GuildMgr.h" #include "ReputationMgr.h" #include "AreaTrigger.h" +#include "Garrison.h" +#include "CombatLogPackets.h" #include "DuelPackets.h" #include "MiscPackets.h" #include "SpellPackets.h" @@ -179,7 +181,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION &Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 &Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 - &Spell::EffectSummonObject, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 + &Spell::EffectChangeRaidMarker, //106 SPELL_EFFECT_CHANGE_RAID_MARKER &Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 &Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC &Spell::EffectResurrectPet, //109 SPELL_EFFECT_RESURRECT_PET @@ -240,7 +242,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA &Spell::EffectDamageFromMaxHealthPCT, //165 SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT &Spell::EffectGiveCurrency, //166 SPELL_EFFECT_GIVE_CURRENCY - &Spell::EffectNULL, //167 SPELL_EFFECT_167 + &Spell::EffectNULL, //167 SPELL_EFFECT_UPDATE_PLAYER_PHASE &Spell::EffectNULL, //168 SPELL_EFFECT_ALLOW_CONTROL_PET &Spell::EffectDestroyItem, //169 SPELL_EFFECT_DESTROY_ITEM &Spell::EffectNULL, //170 SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES @@ -265,8 +267,8 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //189 SPELL_EFFECT_LOOT &Spell::EffectNULL, //190 SPELL_EFFECT_190 &Spell::EffectNULL, //191 SPELL_EFFECT_TELEPORT_TO_DIGSITE - &Spell::EffectNULL, //192 SPELL_EFFECT_192 - &Spell::EffectNULL, //193 SPELL_EFFECT_193 + &Spell::EffectNULL, //192 SPELL_EFFECT_UNCAGE_BATTLEPET + &Spell::EffectNULL, //193 SPELL_EFFECT_START_PET_BATTLE &Spell::EffectNULL, //194 SPELL_EFFECT_194 &Spell::EffectNULL, //195 SPELL_EFFECT_195 &Spell::EffectNULL, //196 SPELL_EFFECT_196 @@ -277,53 +279,53 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //201 SPELL_EFFECT_ENABLE_BATTLE_PETS &Spell::EffectNULL, //202 SPELL_EFFECT_202 &Spell::EffectNULL, //203 SPELL_EFFECT_203 - &Spell::EffectNULL, //204 SPELL_EFFECT_204 - &Spell::EffectNULL, //205 SPELL_EFFECT_205 + &Spell::EffectNULL, //204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY + &Spell::EffectNULL, //205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE &Spell::EffectNULL, //206 SPELL_EFFECT_206 - &Spell::EffectNULL, //207 SPELL_EFFECT_207 + &Spell::EffectNULL, //207 SPELL_EFFECT_LAUNCH_QUEST_TASK &Spell::EffectNULL, //208 SPELL_EFFECT_208 &Spell::EffectNULL, //209 SPELL_EFFECT_209 - &Spell::EffectNULL, //210 SPELL_EFFECT_210 - &Spell::EffectNULL, //211 SPELL_EFFECT_211 + &Spell::EffectLearnGarrisonBuilding, //210 SPELL_EFFECT_LEARN_GARRISON_BUILDING + &Spell::EffectNULL, //211 SPELL_EFFECT_LEARN_GARRISON_SPECIALIZATION &Spell::EffectNULL, //212 SPELL_EFFECT_212 &Spell::EffectNULL, //213 SPELL_EFFECT_213 - &Spell::EffectNULL, //214 SPELL_EFFECT_214 - &Spell::EffectNULL, //215 SPELL_EFFECT_215 - &Spell::EffectNULL, //216 SPELL_EFFECT_216 - &Spell::EffectNULL, //217 SPELL_EFFECT_217 + &Spell::EffectCreateGarrison, //214 SPELL_EFFECT_CREATE_GARRISON + &Spell::EffectNULL, //215 SPELL_EFFECT_UPGRADE_CHARACTER_SPELLS + &Spell::EffectNULL, //216 SPELL_EFFECT_CREATE_SHIPMENT + &Spell::EffectNULL, //217 SPELL_EFFECT_UPGRADE_GARRISON &Spell::EffectNULL, //218 SPELL_EFFECT_218 &Spell::EffectNULL, //219 SPELL_EFFECT_219 - &Spell::EffectNULL, //220 SPELL_EFFECT_220 + &Spell::EffectAddGarrisonFollower, //220 SPELL_EFFECT_ADD_GARRISON_FOLLOWER &Spell::EffectNULL, //221 SPELL_EFFECT_221 - &Spell::EffectNULL, //222 SPELL_EFFECT_222 - &Spell::EffectNULL, //223 SPELL_EFFECT_223 - &Spell::EffectNULL, //224 SPELL_EFFECT_224 - &Spell::EffectNULL, //225 SPELL_EFFECT_225 + &Spell::EffectNULL, //222 SPELL_EFFECT_CREATE_HEIRLOOM_ITEM + &Spell::EffectNULL, //223 SPELL_EFFECT_CHANGE_ITEM_BONUSES + &Spell::EffectNULL, //224 SPELL_EFFECT_ACTIVATE_GARRISON_BUILDING + &Spell::EffectNULL, //225 SPELL_EFFECT_GRANT_BATTLEPET_LEVEL &Spell::EffectNULL, //226 SPELL_EFFECT_226 &Spell::EffectNULL, //227 SPELL_EFFECT_227 &Spell::EffectNULL, //228 SPELL_EFFECT_228 - &Spell::EffectNULL, //229 SPELL_EFFECT_229 - &Spell::EffectNULL, //230 SPELL_EFFECT_230 - &Spell::EffectNULL, //231 SPELL_EFFECT_231 - &Spell::EffectNULL, //232 SPELL_EFFECT_232 - &Spell::EffectNULL, //233 SPELL_EFFECT_233 + &Spell::EffectNULL, //229 SPELL_EFFECT_SET_FOLLOWER_QUALITY + &Spell::EffectNULL, //230 SPELL_EFFECT_INCREASE_FOLLOWER_ITEM_LEVEL + &Spell::EffectNULL, //231 SPELL_EFFECT_INCREASE_FOLLOWER_EXPERIENCE + &Spell::EffectNULL, //232 SPELL_EFFECT_REMOVE_PHASE + &Spell::EffectNULL, //233 SPELL_EFFECT_RANDOMIZE_FOLLOWER_ABILITIES &Spell::EffectNULL, //234 SPELL_EFFECT_234 &Spell::EffectNULL, //235 SPELL_EFFECT_235 - &Spell::EffectNULL, //236 SPELL_EFFECT_236 - &Spell::EffectNULL, //237 SPELL_EFFECT_237 - &Spell::EffectNULL, //238 SPELL_EFFECT_238 - &Spell::EffectNULL, //239 SPELL_EFFECT_239 + &Spell::EffectNULL, //236 SPELL_EFFECT_GIVE_EXPERIENCE + &Spell::EffectNULL, //237 SPELL_EFFECT_GIVE_RESTED_EXPERIENCE_BONUS + &Spell::EffectNULL, //238 SPELL_EFFECT_INCREASE_SKILL + &Spell::EffectNULL, //239 SPELL_EFFECT_END_GARRISON_BUILDING_CONSTRUCTION &Spell::EffectNULL, //240 SPELL_EFFECT_240 &Spell::EffectNULL, //241 SPELL_EFFECT_241 &Spell::EffectNULL, //242 SPELL_EFFECT_242 - &Spell::EffectNULL, //243 SPELL_EFFECT_243 - &Spell::EffectNULL, //244 SPELL_EFFECT_244 - &Spell::EffectNULL, //244 SPELL_EFFECT_245 - &Spell::EffectNULL, //244 SPELL_EFFECT_246 - &Spell::EffectNULL, //244 SPELL_EFFECT_247 - &Spell::EffectNULL, //244 SPELL_EFFECT_248 - &Spell::EffectNULL, //244 SPELL_EFFECT_249 - &Spell::EffectNULL, //244 SPELL_EFFECT_250 + &Spell::EffectNULL, //243 SPELL_EFFECT_APPLY_ENCHANT_ILLUSION + &Spell::EffectNULL, //244 SPELL_EFFECT_LEARN_FOLLOWER_ABILITY + &Spell::EffectNULL, //245 SPELL_EFFECT_UPGRADE_HEIRLOOM + &Spell::EffectNULL, //246 SPELL_EFFECT_FINISH_GARRISON_MISSION + &Spell::EffectNULL, //247 SPELL_EFFECT_ADD_GARRISON_MISSION + &Spell::EffectNULL, //248 SPELL_EFFECT_FINISH_SHIPMENT + &Spell::EffectNULL, //249 SPELL_EFFECT_249 + &Spell::EffectNULL, //250 SPELL_EFFECT_TAKE_SCREENSHOT }; void Spell::EffectNULL(SpellEffIndex /*effIndex*/) @@ -377,11 +379,12 @@ void Spell::EffectInstaKill(SpellEffIndex /*effIndex*/) if (m_caster == unitTarget) // prevent interrupt message finish(); - WorldPacket data(SMSG_SPELL_INSTAKILL_LOG, 8+8+4); - data << m_caster->GetGUID(); - data << unitTarget->GetGUID(); - data << uint32(m_spellInfo->Id); - m_caster->SendMessageToSet(&data, true); + WorldPackets::CombatLog::SpellInstakillLog data; + data.Target = unitTarget->GetGUID(); + data.Caster = m_caster->GetGUID(); + data.SpellID = m_spellInfo->Id; + + m_caster->SendMessageToSet(data.Write(), true); m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } @@ -420,7 +423,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_SHARE_DAMAGE)) { uint32 count = 0; - for (std::vector<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) if (ihit->effectMask & (1<<effIndex)) ++count; @@ -431,7 +434,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) { // Consumption case 28865: - damage = (((InstanceMap*)m_caster->GetMap())->GetDifficultyID() == DIFFICULTY_NONE ? 2750 : 4250); + damage = (m_caster->GetMap()->GetDifficultyID() == DIFFICULTY_NONE ? 2750 : 4250); break; // percent from health with min case 25599: // Thundercrash @@ -1907,7 +1910,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) if (gameObjTarget) SendLoot(guid, LOOT_SKINNING); else if (itemTarget) - itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_UNLOCKED); + itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); // not allow use skill grow at item base open if (!m_CastItem && skillId != SKILL_NONE) @@ -2166,7 +2169,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) return; summon->SelectLevel(); // some summoned creaters have different from 1 DB data for level/hp - summon->SetUInt32Value(UNIT_NPC_FLAGS, summon->GetCreatureTemplate()->npcflag); + summon->SetUInt64Value(UNIT_NPC_FLAGS, summon->GetCreatureTemplate()->npcflag); summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC); @@ -2544,7 +2547,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) else { // do not increase skill if vellum used - if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_TRIGGERED_CAST)) + if (!(m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_TRIGGERED_CAST)) player->UpdateCraftSkill(m_spellInfo->Id); uint32 enchant_id = effectInfo->MiscValue; @@ -2922,7 +2925,7 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/) unitTarget->ToCreature()->AI()->AttackStart(m_caster); } -void Spell::EffectWeaponDmg(SpellEffIndex /*effIndex*/) +void Spell::EffectWeaponDmg(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET) return; @@ -2933,8 +2936,9 @@ void Spell::EffectWeaponDmg(SpellEffIndex /*effIndex*/) // multiple weapon dmg effect workaround // execute only the last weapon damage // and handle all effects at once - for (SpellEffectInfo const* effect : GetEffects()) + for (uint8 index = effIndex + 1; index < MAX_SPELL_EFFECTS; ++index) { + SpellEffectInfo const* effect = GetEffect(index); if (!effect) continue; switch (effect->Effect) @@ -4646,6 +4650,25 @@ void Spell::EffectPullTowards(SpellEffIndex /*effIndex*/) unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); } +void Spell::EffectChangeRaidMarker(SpellEffIndex /*effIndex*/) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) + return; + + Player* player = m_caster->ToPlayer(); + if (!player || !m_targets.HasDst()) + return; + + Group* group = player->GetGroup(); + if (!group || (group->isRaidGroup() && !group->IsLeader(player->GetGUID()) && !group->IsAssistant(player->GetGUID()))) + return; + + float x, y, z; + destTarget->GetPosition(x, y, z); + + group->AddRaidMarker(damage, player->GetMapId(), x, y, z); +} + void Spell::EffectDispelMechanic(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) @@ -4981,7 +5004,7 @@ void Spell::EffectProspecting(SpellEffIndex /*effIndex*/) if (!player) return; - if (!itemTarget || !(itemTarget->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_PROSPECTABLE)) + if (!itemTarget || !(itemTarget->GetTemplate()->GetFlags() & ITEM_FLAG_PROSPECTABLE)) return; if (itemTarget->GetCount() < 5) @@ -5006,7 +5029,7 @@ void Spell::EffectMilling(SpellEffIndex /*effIndex*/) if (!player) return; - if (!itemTarget || !(itemTarget->GetTemplate()->GetFlags() & ITEM_PROTO_FLAG_MILLABLE)) + if (!itemTarget || !(itemTarget->GetTemplate()->GetFlags() & ITEM_FLAG_MILLABLE)) return; if (itemTarget->GetCount() < 5) @@ -5801,3 +5824,38 @@ void Spell::EffectDestroyItem(SpellEffIndex effIndex) if (Item* item = player->GetItemByEntry(itemId)) player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); } + +void Spell::EffectLearnGarrisonBuilding(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (Garrison* garrison = unitTarget->ToPlayer()->GetGarrison()) + garrison->LearnBlueprint(GetEffect(effIndex)->MiscValue); +} + +void Spell::EffectCreateGarrison(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->CreateGarrison(GetEffect(effIndex)->MiscValue); +} + +void Spell::EffectAddGarrisonFollower(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (Garrison* garrison = unitTarget->ToPlayer()->GetGarrison()) + garrison->AddFollower(GetEffect(effIndex)->MiscValue); +} diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 4db7091f971..6560309527c 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -806,7 +806,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 103 SPELL_EFFECT_REPUTATION {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1 {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2 - {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3 + {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 106 SPELL_EFFECT_CHANGE_RAID_MARKER {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4 {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 108 SPELL_EFFECT_DISPEL_MECHANIC {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_DEST}, // 109 SPELL_EFFECT_SUMMON_DEAD_PET @@ -1822,6 +1822,7 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a if (!player->CanFlyInZone(map_id, zone_id)) return SPELL_FAILED_INCORRECT_AREA; } + break; } case SPELL_AURA_MOUNTED: { @@ -1958,7 +1959,7 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta } // not allow casting on flying player - if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT)) + if (unitTarget->HasUnitState(UNIT_STATE_IN_FLIGHT) && !(AttributesCu & SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET)) return SPELL_FAILED_BAD_TARGETS; /* TARGET_UNIT_MASTER gets blocked here for passengers, because the whole idea of this check is to @@ -2577,6 +2578,8 @@ std::vector<SpellInfo::CostData> SpellInfo::CalcPowerCost(Unit const* caster, Sp powerCost += int32(CalculatePct(caster->GetMaxHealth(), power->ManaCostPercentage)); break; case POWER_MANA: + powerCost += int32(CalculatePct(caster->GetCreateMana(), power->ManaCostPercentage)); + break; case POWER_RAGE: case POWER_FOCUS: case POWER_ENERGY: @@ -2635,7 +2638,7 @@ std::vector<SpellInfo::CostData> SpellInfo::CalcPowerCost(Unit const* caster, Sp modOwner->ApplySpellMod(Id, SPELLMOD_SPELL_COST2, powerCost); } - if (!caster->IsControlledByPlayer()) + if (!caster->IsControlledByPlayer() && G3D::fuzzyEq(power->ManaCostPercentage, 0.0f)) { if (Attributes & SPELL_ATTR0_LEVEL_DAMAGE_CALCULATION) { @@ -2693,7 +2696,7 @@ std::vector<SpellInfo::CostData> SpellInfo::CalcPowerCost(Unit const* caster, Sp } }; - if (_hasPowerDifficultyData) // optimization - use static data for 99.5% cases (4753 of 4772 in build 6.1.0.19702) + if (!_hasPowerDifficultyData) // optimization - use static data for 99.5% cases (4753 of 4772 in build 6.1.0.19702) collector(PowerCosts); else collector(sDB2Manager.GetSpellPowers(Id, caster->GetMap()->GetDifficultyID())); diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 62381372657..6d1d787e303 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -197,6 +197,7 @@ enum SpellCustomAttributes SPELL_ATTR0_CU_IGNORE_ARMOR = 0x00008000, SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000, SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000, + SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000, SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2 }; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 2f74218ba7b..4f73eee601f 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3030,6 +3030,10 @@ void SpellMgr::LoadSpellInfoCorrections() switch (spellInfo->Id) { + case 63026: // Summon Aspirant Test NPC (HACK: Target shouldn't be changed) + case 63137: // Summon Valiant Test (HACK: Target shouldn't be changed; summon position should be untied from spell destination) + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB); + break; case 42436: // Drink! (Brewfest) const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY); break; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 33773a57631..4fd8b5d8bf6 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -64,9 +64,9 @@ _SpellScript::EffectHook::EffectHook(uint8 _effIndex) effIndex = _effIndex; } -uint8 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellInfo const* spellEntry) +uint32 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellInfo const* spellEntry) { - uint8 mask = 0; + uint32 mask = 0; if ((effIndex == EFFECT_ALL) || (effIndex == EFFECT_FIRST_FOUND)) { for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -74,13 +74,13 @@ uint8 _SpellScript::EffectHook::GetAffectedEffectsMask(SpellInfo const* spellEnt if ((effIndex == EFFECT_FIRST_FOUND) && mask) return mask; if (CheckEffect(spellEntry, i)) - mask |= (uint8)1<<i; + mask |= 1 << i; } } else { if (CheckEffect(spellEntry, effIndex)) - mask |= (uint8)1<<effIndex; + mask |= 1 << effIndex; } return mask; } diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index fb9e1ed3937..f9a2f1ec847 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -74,7 +74,7 @@ class _SpellScript EffectHook(uint8 _effIndex); virtual ~EffectHook() { } - uint8 GetAffectedEffectsMask(SpellInfo const* spellInfo); + uint32 GetAffectedEffectsMask(SpellInfo const* spellInfo); bool IsEffectAffected(SpellInfo const* spellInfo, uint8 effIndex); virtual bool CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) = 0; std::string EffIndexToString(); diff --git a/src/server/game/Support/SupportMgr.cpp b/src/server/game/Support/SupportMgr.cpp index 90afcfd1511..5afd6fc1d81 100644 --- a/src/server/game/Support/SupportMgr.cpp +++ b/src/server/game/Support/SupportMgr.cpp @@ -38,7 +38,7 @@ std::string Ticket::FormatViewMessageString(ChatHandler& handler, char const* cl { std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); if (closedName) ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, closedName); if (assignedToName) @@ -173,13 +173,12 @@ std::string GmTicket::FormatViewMessageString(ChatHandler& handler, bool detaile std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGE, (secsToTimeString(curTime - _lastModifiedTime, true, false)).c_str()); - std::string name; - if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + if (!_assignedTo.IsEmpty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { @@ -196,7 +195,7 @@ std::string GmTicket::FormatViewMessageString(ChatHandler& handler, const char* { std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); if (szClosedName) ss << handler.PGetParseString(LANG_COMMAND_TICKETCLOSED, szClosedName); if (szAssignedToName) @@ -281,12 +280,11 @@ std::string BugTicket::FormatViewMessageString(ChatHandler& handler, bool detail std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); - std::string name; - if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + if (!_assignedTo.IsEmpty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { @@ -408,12 +406,11 @@ std::string ComplaintTicket::FormatViewMessageString(ChatHandler& handler, bool std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); - std::string name; - if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + if (!_assignedTo.IsEmpty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { @@ -495,12 +492,11 @@ std::string SuggestionTicket::FormatViewMessageString(ChatHandler& handler, bool std::stringstream ss; ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTGUID, _id); - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayer()->GetName().c_str()); + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTNAME, GetPlayerName().c_str()); ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTAGECREATE, (secsToTimeString(curTime - _createTime, true, false)).c_str()); - std::string name; - if (ObjectMgr::GetPlayerNameByGUID(_assignedTo, name)) - ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, name.c_str()); + if (!_assignedTo.IsEmpty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTASSIGNEDTO, GetAssignedToName().c_str()); if (detailed) { diff --git a/src/server/game/Support/SupportMgr.h b/src/server/game/Support/SupportMgr.h index e0adb411aa0..10bd90d4f80 100644 --- a/src/server/game/Support/SupportMgr.h +++ b/src/server/game/Support/SupportMgr.h @@ -93,8 +93,16 @@ public: uint32 GetId() const { return _id; } ObjectGuid GetPlayerGuid() const { return _playerGuid; } - Player* GetPlayer() const { return ObjectAccessor::FindPlayer(_playerGuid); } - Player* GetAssignedPlayer() const { return ObjectAccessor::FindPlayer(_assignedTo); } + Player* GetPlayer() const { return ObjectAccessor::FindConnectedPlayer(_playerGuid); } + std::string GetPlayerName() const + { + std::string name; + if (!_playerGuid.IsEmpty()) + ObjectMgr::GetPlayerNameByGUID(_playerGuid, name); + + return name; + } + Player* GetAssignedPlayer() const { return ObjectAccessor::FindConnectedPlayer(_assignedTo); } ObjectGuid GetAssignedToGUID() const { return _assignedTo; } std::string GetAssignedToName() const { diff --git a/src/server/game/Texts/ChatTextBuilder.h b/src/server/game/Texts/ChatTextBuilder.h index dcee6f08ac3..167680f1cd2 100644 --- a/src/server/game/Texts/ChatTextBuilder.h +++ b/src/server/game/Texts/ChatTextBuilder.h @@ -34,7 +34,7 @@ namespace Trinity { BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(_textId); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? DB2Manager::GetBroadcastTextValue(bct, locale, _source->getGender()) : "", _achievementId, "", locale); + packet.Initialize(_msgType, bct ? Language(bct->Language) : LANG_UNIVERSAL, _source, _target, bct ? DB2Manager::GetBroadcastTextValue(bct, locale, _source->getGender()) : "", _achievementId, "", locale); packet.Write(); data = packet.Move(); } @@ -56,7 +56,7 @@ namespace Trinity void operator()(WorldPacket& data, LocaleConstant locale) { WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, _language, _source, _target, _text, 0, "", locale); + packet.Initialize(_msgType, _language, _source, _target, _text, 0, "", locale); packet.Write(); data = packet.Move(); } diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 281504b9aaf..c1ea235a3e2 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -37,7 +37,7 @@ class CreatureTextBuilder { std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, Language(_language), _source, _target, text, 0, "", locale); + packet.Initialize(_msgType, Language(_language), _source, _target, text, 0, "", locale); packet.Write(); data = packet.Move(); } @@ -62,7 +62,7 @@ class PlayerTextBuilder { std::string const& text = sCreatureTextMgr->GetLocalizedChatString(_source->GetEntry(), _gender, _textGroup, _textId, locale); WorldPackets::Chat::Chat packet; - packet.Initalize(_msgType, Language(_language), _talker, _target, text, 0, "", locale); + packet.Initialize(_msgType, Language(_language), _talker, _target, text, 0, "", locale); packet.Write(); data = packet.Move(); } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 94f13abfb6c..d68da8fbc63 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -38,6 +38,7 @@ #include "DatabaseEnv.h" #include "DisableMgr.h" #include "GameEventMgr.h" +#include "GarrisonMgr.h" #include "GridNotifiersImpl.h" #include "GroupMgr.h" #include "GuildFinderMgr.h" @@ -1520,7 +1521,6 @@ void World::SetInitialWorldSettings() sObjectMgr->LoadGameObjectLocales(); sObjectMgr->LoadQuestTemplateLocale(); sObjectMgr->LoadQuestObjectivesLocale(); - sObjectMgr->LoadQuestGreetings(); sObjectMgr->LoadPageTextLocales(); sObjectMgr->LoadGossipMenuItemsLocales(); sObjectMgr->LoadPointOfInterestLocales(); @@ -1660,6 +1660,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Quests Starters and Enders..."); sObjectMgr->LoadQuestStartersAndEnders(); // must be after quest load + TC_LOG_INFO("server.loading", "Loading Quest Greetings..."); + sObjectMgr->LoadQuestGreetings(); + TC_LOG_INFO("server.loading", "Loading Objects Pooling Data..."); sPoolMgr->LoadFromDB(); @@ -1869,6 +1872,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading client addons..."); AddonMgr::LoadFromDB(); + TC_LOG_INFO("server.loading", "Loading garrison info..."); + sGarrisonMgr.Initialize(); + ///- Handle outdated emails (delete/return) TC_LOG_INFO("server.loading", "Returning old mails..."); sObjectMgr->ReturnOrDeleteOldMails(false); @@ -2121,7 +2127,7 @@ void World::Update(uint32 diff) /// Handle daily quests reset time if (m_gameTime > m_NextDailyQuestReset) { - ResetDailyQuests(); + DailyReset(); m_NextDailyQuestReset += DAY; } @@ -2246,6 +2252,9 @@ void World::Update(uint32 diff) sLFGMgr->Update(diff); RecordTimeDiff("UpdateLFGMgr"); + sGroupMgr->Update(diff); + RecordTimeDiff("GroupMgr"); + // execute callbacks from sql queries that were queued recently ProcessQueryCallbacks(); RecordTimeDiff("ProcessQueryCallbacks"); @@ -2375,7 +2384,7 @@ namespace Trinity while (char* line = ChatHandler::LineFromMessage(text)) { WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); packet.Write(); dataList.emplace_back(new WorldPacket(packet.Move())); } @@ -2441,7 +2450,7 @@ void World::SendGlobalText(const char* text, WorldSession* self) while (char* line = ChatHandler::LineFromMessage(pos)) { WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, line); SendGlobalMessage(packet.Write(), self); } @@ -2475,7 +2484,7 @@ bool World::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession void World::SendZoneText(uint32 zone, const char* text, WorldSession* self, uint32 team) { WorldPackets::Chat::Chat packet; - packet.Initalize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text); + packet.Initialize(CHAT_MSG_SYSTEM, LANG_UNIVERSAL, nullptr, nullptr, text); SendZoneMessage(zone, packet.Write(), self, team); } @@ -2747,7 +2756,7 @@ void World::ShutdownMsg(bool show, Player* player, const std::string& reason) ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME; - SendServerMessage(msgid, str.c_str(), player); + SendServerMessage(msgid, str, player); TC_LOG_DEBUG("misc", "Server is %s in %s", (m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"), str.c_str()); } } @@ -2772,17 +2781,17 @@ void World::ShutdownCancel() } /// Send a server message to the user(s) -void World::SendServerMessage(ServerMessageType type, const char *text, Player* player) +void World::SendServerMessage(ServerMessageType messageID, std::string stringParam /*= ""*/, Player* player /*= NULL*/) { - WorldPacket data(SMSG_CHAT_SERVER_MESSAGE, 50); // guess size - data << uint32(type); - if (type <= SERVER_MSG_STRING) - data << text; + WorldPackets::Chat::ChatServerMessage chatServerMessage; + chatServerMessage.MessageID = int32(messageID); + if (messageID <= SERVER_MSG_STRING) + chatServerMessage.StringParam = stringParam; if (player) - player->GetSession()->SendPacket(&data); + player->GetSession()->SendPacket(chatServerMessage.Write()); else - SendGlobalMessage(&data); + SendGlobalMessage(chatServerMessage.Write()); } void World::UpdateSessions(uint32 diff) @@ -3050,16 +3059,20 @@ void World::InitCurrencyResetTime() sWorld->setWorldState(WS_CURRENCY_RESET_TIME, uint64(m_NextCurrencyReset)); } -void World::ResetDailyQuests() +void World::DailyReset() { TC_LOG_INFO("misc", "Daily quests reset for all characters."); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_DAILY); CharacterDatabase.Execute(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS); + stmt->setUInt32(0, 1); + CharacterDatabase.Execute(stmt); + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) if (itr->second->GetPlayer()) - itr->second->GetPlayer()->ResetDailyQuestStatus(); + itr->second->GetPlayer()->DailyReset(); // change available dailies sPoolMgr->ChangeDailyQuests(); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index b3bebca08e3..b169431f2fd 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -671,7 +671,7 @@ class World void SendWorldText(uint32 string_id, ...); void SendGlobalText(const char* text, WorldSession* self); void SendGMText(uint32 string_id, ...); - void SendServerMessage(ServerMessageType type, const char *text = "", Player* player = NULL); + void SendServerMessage(ServerMessageType messageID, std::string stringParam = "", Player* player = NULL); void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); @@ -805,7 +805,7 @@ class World void InitRandomBGResetTime(); void InitGuildResetTime(); void InitCurrencyResetTime(); - void ResetDailyQuests(); + void DailyReset(); void ResetWeeklyQuests(); void ResetMonthlyQuests(); void ResetRandomBG(); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index ecd98595723..7f1a364fd57 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -485,7 +485,7 @@ public: char const* msg = "testtest"; uint8 type = atoi(args); WorldPackets::Chat::Chat packet; - packet.Initalize(ChatMsg(type), LANG_UNIVERSAL, handler->GetSession()->GetPlayer(), handler->GetSession()->GetPlayer(), msg, 0, "chan"); + packet.Initialize(ChatMsg(type), LANG_UNIVERSAL, handler->GetSession()->GetPlayer(), handler->GetSession()->GetPlayer(), msg, 0, "chan"); handler->GetSession()->SendPacket(packet.Write()); return true; } diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index c12c9b5d43e..53522736718 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -44,6 +44,7 @@ public: { "graveyard", rbac::RBAC_PERM_COMMAND_GO_GRAVEYARD, false, &HandleGoGraveyardCommand, "", NULL }, { "grid", rbac::RBAC_PERM_COMMAND_GO_GRID, false, &HandleGoGridCommand, "", NULL }, { "object", rbac::RBAC_PERM_COMMAND_GO_OBJECT, false, &HandleGoObjectCommand, "", NULL }, + { "quest", rbac::RBAC_PERM_COMMAND_GO_QUEST, false, &HandleGoQuestCommand, "", NULL }, { "taxinode", rbac::RBAC_PERM_COMMAND_GO_TAXINODE, false, &HandleGoTaxinodeCommand, "", NULL }, { "trigger", rbac::RBAC_PERM_COMMAND_GO_TRIGGER, false, &HandleGoTriggerCommand, "", NULL }, { "zonexy", rbac::RBAC_PERM_COMMAND_GO_ZONEXY, false, &HandleGoZoneXYCommand, "", NULL }, @@ -315,6 +316,71 @@ public: return true; } + static bool HandleGoQuestCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + Player* player = handler->GetSession()->GetPlayer(); + + char* id = handler->extractKeyFromLink((char*)args, "Hquest"); + if (!id) + return false; + + uint32 questID = atoi(id); + if (!questID) + return false; + + if (!sObjectMgr->GetQuestTemplate(questID)) + { + handler->PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, questID); + handler->SetSentErrorMessage(true); + return false; + } + + float x, y, z; + uint32 mapId; + + if (QuestPOIVector const* poiData = sObjectMgr->GetQuestPOIVector(questID)) + { + auto data = poiData->front(); + + mapId = data.MapID; + + x = data.points.front().X; + y = data.points.front().Y; + } + else + { + handler->PSendSysMessage(LANG_COMMAND_QUEST_NOTFOUND, questID); + handler->SetSentErrorMessage(true); + return false; + } + + if (!MapManager::IsValidMapCoord(mapId, x, y) || sObjectMgr->IsTransportMap(mapId)) + { + handler->PSendSysMessage(LANG_INVALID_TARGET_COORD, x, y, mapId); + handler->SetSentErrorMessage(true); + return false; + } + + // stop flight if need + if (player->IsInFlight()) + { + player->GetMotionMaster()->MovementExpired(); + player->CleanupAfterTaxiFlight(); + } + // save only in non-flight case + else + player->SaveRecallPosition(); + + Map const* map = sMapMgr->CreateBaseMap(mapId); + z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + + player->TeleportTo(mapId, x, y, z, 0.0f); + return true; + } + static bool HandleGoTaxinodeCommand(ChatHandler* handler, char const* args) { Player* player = handler->GetSession()->GetPlayer(); @@ -448,7 +514,7 @@ public: if (map->Instanceable()) { - handler->PSendSysMessage(LANG_INVALID_ZONE_MAP, areaEntry->ID, areaEntry->ZoneName, map->GetId(), map->GetMapName()); + handler->PSendSysMessage(LANG_INVALID_ZONE_MAP, areaEntry->ID, areaEntry->AreaName_lang, map->GetId(), map->GetMapName()); handler->SetSentErrorMessage(true); return false; } diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index ef52f6ebd95..ad877bdefb4 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -168,6 +168,8 @@ public: // fill the gameobject data and save to the db object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMask()); + guidLow = object->GetSpawnId(); + // delete the old object and do a clean load from DB with a fresh new GameObject instance. // this is required to avoid weird behavior and memory leaks delete object; @@ -431,14 +433,14 @@ public: } object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o); + object->RelocateStationaryPosition(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o); object->UpdateRotationFields(); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); object->SaveToDB(); - object->Refresh(); - handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetGUID().GetCounter(), object->GetGOInfo()->name.c_str(), object->GetGUID().ToString().c_str(), o); + handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetGUID().ToString().c_str(), o); return true; } @@ -472,21 +474,20 @@ public: char* toY = strtok(NULL, " "); char* toZ = strtok(NULL, " "); + float x, y, z; if (!toX) { Player* player = handler->GetSession()->GetPlayer(); - object->Relocate(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), object->GetOrientation()); - object->DestroyForNearbyPlayers(); - object->UpdateObjectVisibility(); + player->GetPosition(x, y, z); } else { if (!toY || !toZ) return false; - float x = (float)atof(toX); - float y = (float)atof(toY); - float z = (float)atof(toZ); + x = (float)atof(toX); + y = (float)atof(toY); + z = (float)atof(toZ); if (!MapManager::IsValidMapCoord(object->GetMapId(), x, y, z)) { @@ -494,16 +495,15 @@ public: handler->SetSentErrorMessage(true); return false; } - - object->Relocate(x, y, z, object->GetOrientation()); - object->DestroyForNearbyPlayers(); - object->UpdateObjectVisibility(); } + object->DestroyForNearbyPlayers(); + object->RelocateStationaryPosition(x, y, z, object->GetOrientation()); + object->GetMap()->GameObjectRelocation(object, x, y, z, object->GetOrientation()); + object->SaveToDB(); - object->Refresh(); - handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetGUID().GetCounter(), object->GetGOInfo()->name.c_str(), object->GetGUID().ToString().c_str()); + handler->PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, object->GetSpawnId(), object->GetGOInfo()->name.c_str(), object->GetGUID().ToString().c_str()); return true; } diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index ae7b2039e81..5e5694ba23a 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -354,7 +354,7 @@ public: { AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID); if (zone) - zoneName = zone->ZoneName; + zoneName = zone->AreaName_lang; } } else diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index d8f98e90275..4d1d484cb2f 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -106,7 +106,7 @@ public: AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(areaflag); if (areaEntry) { - std::string name = areaEntry->ZoneName; + std::string name = areaEntry->AreaName_lang; if (name.empty()) continue; diff --git a/src/server/scripts/Commands/cs_message.cpp b/src/server/scripts/Commands/cs_message.cpp index 519ae1e1f97..be3a027277c 100644 --- a/src/server/scripts/Commands/cs_message.cpp +++ b/src/server/scripts/Commands/cs_message.cpp @@ -134,9 +134,9 @@ public: if (!*args) return false; - char buff[2048]; - sprintf(buff, handler->GetTrinityString(LANG_SYSTEMMESSAGE), args); - sWorld->SendServerMessage(SERVER_MSG_STRING, buff); + std::string str = handler->PGetParseString(LANG_SYSTEMMESSAGE, args); + + sWorld->SendServerMessage(SERVER_MSG_STRING, str); return true; } // announce to logged in GMs diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 9e537e42d20..b9765223add 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -236,8 +236,8 @@ public: handler->PSendSysMessage(LANG_MAP_POSITION, mapId, (mapEntry ? mapEntry->MapName_lang : unknown), - zoneId, (zoneEntry ? zoneEntry->ZoneName : unknown), - areaId, (areaEntry ? areaEntry->ZoneName : unknown), + zoneId, (zoneEntry ? zoneEntry->AreaName_lang : unknown), + areaId, (areaEntry ? areaEntry->AreaName_lang : unknown), object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation()); handler->PSendSysMessage(LANG_GRID_POSITION, @@ -1465,7 +1465,7 @@ public: * Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER * ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM) * ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned) - * ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted) + * ** Muted: (Reason, Time, By) - IV. LANG_PINFO_MUTED (if muted) * * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT * * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN * * Uses OS: %s - Latency: %u ms - VII. LANG_PINFO_ACC_OS @@ -1716,7 +1716,7 @@ public: // Output IV. LANG_PINFO_MUTED if mute is applied if (muteTime > 0) - handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str()); + handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str()); // Output V. LANG_PINFO_ACC_ACCOUNT handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security); @@ -1762,11 +1762,11 @@ public: AreaTableEntry const* area = GetAreaEntryByAreaID(areaId); if (area) { - areaName = area->ZoneName; + areaName = area->AreaName_lang; AreaTableEntry const* zone = GetAreaEntryByAreaID(area->ParentAreaID); if (zone) - zoneName = zone->ZoneName; + zoneName = zone->AreaName_lang; } if (target) diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 48a514fd0db..3bcb6862b7f 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -313,7 +313,7 @@ public: { uint32 factionid = target->getFaction(); uint32 flag = target->GetUInt32Value(UNIT_FIELD_FLAGS); - uint32 npcflag = target->GetUInt32Value(UNIT_NPC_FLAGS); + uint64 npcflag = target->GetUInt64Value(UNIT_NPC_FLAGS); uint32 dyflag = target->GetUInt32Value(OBJECT_DYNAMIC_FLAGS); handler->PSendSysMessage(LANG_CURRENT_FACTION, target->GetGUID().ToString().c_str(), factionid, flag, npcflag, dyflag); return true; @@ -330,11 +330,11 @@ public: char* pnpcflag = strtok(NULL, " "); - uint32 npcflag; + uint64 npcflag; if (!pnpcflag) - npcflag = target->GetUInt32Value(UNIT_NPC_FLAGS); + npcflag = target->GetUInt64Value(UNIT_NPC_FLAGS); else - npcflag = atoi(pnpcflag); + npcflag = std::strtoull(pnpcflag, nullptr, 10); char* pdyflag = strtok(NULL, " "); @@ -355,7 +355,7 @@ public: target->setFaction(factionid); target->SetUInt32Value(UNIT_FIELD_FLAGS, flag); - target->SetUInt32Value(UNIT_NPC_FLAGS, npcflag); + target->SetUInt64Value(UNIT_NPC_FLAGS, npcflag); target->SetUInt32Value(OBJECT_DYNAMIC_FLAGS, dyflag); return true; diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 5dc1696057e..2c91a9e6e3e 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -374,28 +374,13 @@ public: ObjectGuid::LowType lowGuid = strtoull(guidStr, nullptr, 10); - Creature* creature = NULL; - - /* FIXME: impossible without entry - if (lowguid) - creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT)); - */ - // attempt check creature existence by DB data - if (!creature) - { - CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid); - if (!data) - { - handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid); - handler->SetSentErrorMessage(true); - return false; - } - } - else + CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid); + if (!data) { - // obtain real GUID for DB operations - lowGuid = creature->GetSpawnId(); + handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowGuid); + handler->SetSentErrorMessage(true); + return false; } int wait = waitStr ? atoi(waitStr) : 0; @@ -411,18 +396,6 @@ public: WorldDatabase.Execute(stmt); - if (creature && creature->GetWaypointPath()) - { - creature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE); - creature->GetMotionMaster()->Initialize(); - if (creature->IsAlive()) // dead creature will reset movement generator at respawn - { - creature->setDeathState(JUST_DIED); - creature->Respawn(true); - } - creature->SaveToDB(); - } - handler->SendSysMessage(LANG_WAYPOINT_ADDED); return true; @@ -634,7 +607,7 @@ public: if (!*args) return false; - uint32 npcFlags = (uint32) atoi((char*)args); + uint64 npcFlags = std::strtoull(args, nullptr, 10); Creature* creature = handler->getSelectedCreature(); @@ -645,11 +618,11 @@ public: return false; } - creature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); + creature->SetUInt64Value(UNIT_NPC_FLAGS, npcFlags); PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_NPCFLAG); - stmt->setUInt32(0, npcFlags); + stmt->setUInt64(0, npcFlags); stmt->setUInt32(1, creature->GetEntry()); WorldDatabase.Execute(stmt); @@ -726,7 +699,7 @@ public: CreatureTemplate const* cInfo = target->GetCreatureTemplate(); uint32 faction = target->getFaction(); - uint32 npcflags = target->GetUInt32Value(UNIT_NPC_FLAGS); + uint64 npcflags = target->GetUInt64Value(UNIT_NPC_FLAGS); uint32 mechanicImmuneMask = cInfo->MechanicImmuneMask; uint32 displayid = target->GetDisplayId(); uint32 nativeid = target->GetNativeDisplayId(); @@ -836,34 +809,22 @@ public: lowguid = strtoull(cId, nullptr, 10); - /* FIXME: impossible without entry - if (lowguid) - creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), MAKE_GUID(lowguid, HIGHGUID_UNIT)); - */ - // Attempting creature load from DB data - if (!creature) + CreatureData const* data = sObjectMgr->GetCreatureData(lowguid); + if (!data) { - CreatureData const* data = sObjectMgr->GetCreatureData(lowguid); - if (!data) - { - handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - handler->SetSentErrorMessage(true); - return false; - } + handler->PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + handler->SetSentErrorMessage(true); + return false; + } - uint32 map_id = data->mapid; + uint32 map_id = data->mapid; - if (handler->GetSession()->GetPlayer()->GetMapId() != map_id) - { - handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); - handler->SetSentErrorMessage(true); - return false; - } - } - else + if (handler->GetSession()->GetPlayer()->GetMapId() != map_id) { - lowguid = creature->GetSpawnId(); + handler->PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); + handler->SetSentErrorMessage(true); + return false; } } else diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp index 1d7e1594d05..ca944f7037b 100644 --- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp +++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp @@ -102,7 +102,7 @@ public: } } - virtual void Update(uint32 /*diff*/) // correct order goes form 1-6 + virtual void Update(uint32 /*diff*/) override // correct order goes form 1-6 { switch (State) { diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp index ec2f41cc625..15280bc7848 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp @@ -197,7 +197,7 @@ class boss_archaedas : public CreatureScript DoMeleeAttackIfReady(); } - void JustDied (Unit* /*killer*/) + void JustDied (Unit* /*killer*/) override { instance->SetData(DATA_ANCIENT_DOOR, DONE); // open the vault door instance->SetData(DATA_MINIONS, SPECIAL); // deactivate his minions diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index f1c4c22527b..d261b7a623a 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -25,14 +25,6 @@ #include "ruby_sanctum.h" #include "Player.h" -/* ScriptData -SDName: ruby_sanctum -SDAuthors: Kaelima, Warpten -SD%Complete: 90% -SDComment: Based on Kaelima's initial work (half of it). Corporeality handling is a pure guess, we lack info. -SDCategory: Chamber of Aspects -EndScriptData */ - enum Texts { // Shared @@ -86,6 +78,8 @@ enum Spells // Living Inferno SPELL_BLAZING_AURA = 75885, + SPELL_SPAWN_LIVING_EMBERS = 75880, + SPELL_SUMMON_LIVING_EMBER = 75881, // Halion Controller SPELL_COSMETIC_FIRE_PILLAR = 76006, @@ -142,7 +136,7 @@ enum Events EVENT_CHECK_CORPOREALITY = 14, EVENT_SHADOW_PULSARS_SHOOT = 15, EVENT_TRIGGER_BERSERK = 16, - EVENT_TWILIGHT_MENDING = 17 + EVENT_TWILIGHT_MENDING = 17, }; enum Actions @@ -155,7 +149,13 @@ enum Actions ACTION_MONITOR_CORPOREALITY = 3, // Orb Carrier - ACTION_SHOOT = 4 + ACTION_SHOOT = 4, + + // Living Inferno + ACTION_SUMMON_LIVING_EMBERS = 5, + + // Meteor Flame + ACTION_SUMMON_FLAME = 6 }; enum Phases @@ -173,7 +173,8 @@ enum Misc DATA_MATERIAL_DAMAGE_TAKEN = 2, DATA_STACKS_DISPELLED = 3, DATA_FIGHT_PHASE = 4, - DATA_EVADE_METHOD = 5 + DATA_EVADE_METHOD = 5, + DATA_SPAWNED_FLAMES = 6, }; enum OrbCarrierSeats @@ -702,7 +703,7 @@ class npc_halion_controller : public CreatureScript // The IsInCombat() check is needed because that check should be false when Halion is // not engaged, while it would return true without as UpdateVictim() checks for // combat state. - if (!(_events.IsInPhase(PHASE_INTRO)) && me->IsInCombat() && !UpdateVictim()) + if (!_events.IsInPhase(PHASE_INTRO) && me->IsInCombat() && !UpdateVictim()) { EnterEvadeMode(); return; @@ -893,8 +894,6 @@ class npc_halion_controller : public CreatureScript } }; -typedef npc_halion_controller::npc_halion_controllerAI controllerAI; - class npc_orb_carrier : public CreatureScript { public: @@ -996,7 +995,7 @@ class npc_meteor_strike_initial : public CreatureScript if (!owner) return; - // Let Halion Controller count as summoner + // Let Controller count as summoner if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER))) controller->AI()->JustSummoned(me); @@ -1006,11 +1005,13 @@ class npc_meteor_strike_initial : public CreatureScript if (HalionAI* halionAI = CAST_AI(HalionAI, owner->AI())) { Position const* ownerPos = halionAI->GetMeteorStrikePosition(); + // Adjust randomness between 0 and pi. + float randomAdjustment = frand(static_cast<float>(M_PI / 14), static_cast<float>(13 * M_PI / 14)); float angle[4]; angle[0] = me->GetAngle(ownerPos); - angle[1] = me->GetAngle(ownerPos) - static_cast<float>(M_PI/2); - angle[2] = me->GetAngle(ownerPos) - static_cast<float>(-M_PI/2); - angle[3] = me->GetAngle(ownerPos) - static_cast<float>(M_PI); + angle[1] = angle[0] + randomAdjustment; + angle[2] = angle[0] + static_cast<float>(M_PI); + angle[3] = angle[2] + randomAdjustment; _meteorList.clear(); for (uint8 i = 0; i < 4; i++) @@ -1019,7 +1020,10 @@ class npc_meteor_strike_initial : public CreatureScript me->SetOrientation(angle[i]); Position newPos = me->GetNearPosition(10.0f, 0.0f); // Exact distance if (Creature* meteor = me->SummonCreature(NPC_METEOR_STRIKE_NORTH + i, newPos, TEMPSUMMON_TIMED_DESPAWN, 30000)) + { + meteor->SetOrientation(angle[i]); _meteorList.push_back(meteor); + } } } } @@ -1045,11 +1049,8 @@ class npc_meteor_strike : public CreatureScript struct npc_meteor_strikeAI : public ScriptedAI { npc_meteor_strikeAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()) + _instance(creature->GetInstanceScript()), _spawnCount(0) { - _range = 5.0f; - _spawnCount = 0; - SetCombatMovement(false); } @@ -1070,34 +1071,38 @@ class npc_meteor_strike : public CreatureScript controller->AI()->JustSummoned(me); } - void UpdateAI(uint32 diff) override + void SetData(uint32 dataType, uint32 dataCount) override { - if (_spawnCount > 5) - return; + if (dataType == DATA_SPAWNED_FLAMES) + _spawnCount += dataCount; + } - _events.Update(diff); + uint32 GetData(uint32 dataType) const override + { + if (dataType == DATA_SPAWNED_FLAMES) + return _spawnCount; + return 0; + } + void UpdateAI(uint32 diff) override + { + _events.Update(diff); if (_events.ExecuteEvent() == EVENT_SPAWN_METEOR_FLAME) { - Position pos = me->GetNearPosition( _range, 0.0f); - + Position pos = me->GetNearPosition(5.0f, 0.0f); if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000)) { - if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER))) - controller->AI()->JustSummoned(flame); + flame->SetOrientation(me->GetOrientation()); - flame->CastSpell(flame, SPELL_METEOR_STRIKE_FIRE_AURA_2, true); - ++_spawnCount; + flame->AI()->SetGUID(GetGUID()); + flame->AI()->DoAction(ACTION_SUMMON_FLAME); } - _range += 5.0f; - _events.ScheduleEvent(EVENT_SPAWN_METEOR_FLAME, 800); } } private: InstanceScript* _instance; EventMap _events; - float _range; uint8 _spawnCount; }; @@ -1107,6 +1112,67 @@ class npc_meteor_strike : public CreatureScript } }; +class npc_meteor_strike_flame : public CreatureScript +{ + public: + npc_meteor_strike_flame() : CreatureScript("npc_meteor_strike_flame") { } + + struct npc_meteor_strike_flameAI : public ScriptedAI + { + npc_meteor_strike_flameAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + SetCombatMovement(false); + } + + void SetGUID(ObjectGuid guid, int32 /*id = 0 */) + { + _rootOwnerGuid = guid; + } + + void DoAction(int32 action) override + { + if (action != ACTION_SUMMON_FLAME || _rootOwnerGuid.IsEmpty()) + return; + + me->CastSpell(me, SPELL_METEOR_STRIKE_FIRE_AURA_2, true); + + Creature* meteorStrike = ObjectAccessor::GetCreature(*me, _rootOwnerGuid); + if (!meteorStrike || meteorStrike->AI()->GetData(DATA_SPAWNED_FLAMES) > 5) + return; + + me->SetOrientation(me->GetOrientation() + frand(static_cast<float>(-M_PI / 16), static_cast<float>(M_PI / 16))); + Position pos = me->GetNearPosition(5.0f, 0.0f); + + if (Creature* flame = me->SummonCreature(NPC_METEOR_STRIKE_FLAME, pos, TEMPSUMMON_TIMED_DESPAWN, 25000)) + { + flame->AI()->SetGUID(_rootOwnerGuid); + meteorStrike->AI()->SetData(DATA_SPAWNED_FLAMES, 1); + } + } + + void IsSummonedBy(Unit* /*summoner*/) override + { + // Let Halion Controller count as summoner. + if (Creature* controller = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_HALION_CONTROLLER))) + controller->AI()->JustSummoned(me); + } + + void UpdateAI(uint32 /*diff*/) override { } + void EnterEvadeMode() override { } + + private: + InstanceScript* _instance; + EventMap _events; + ObjectGuid _rootOwnerGuid = ObjectGuid::Empty; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetRubySanctumAI<npc_meteor_strike_flameAI>(creature); + } +}; + class npc_combustion_consumption : public CreatureScript { public: @@ -1119,26 +1185,23 @@ class npc_combustion_consumption : public CreatureScript { SetCombatMovement(false); - switch (me->GetEntry()) + switch (creature->GetEntry()) { case NPC_COMBUSTION: _explosionSpell = SPELL_FIERY_COMBUSTION_EXPLOSION; _damageSpell = SPELL_COMBUSTION_DAMAGE_AURA; - me->SetPhaseMask(0x01, true); + creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x01, true); break; case NPC_CONSUMPTION: _explosionSpell = SPELL_SOUL_CONSUMPTION_EXPLOSION; _damageSpell = SPELL_CONSUMPTION_DAMAGE_AURA; - me->SetPhaseMask(0x20, true); + creature->SetPhaseMask(IsHeroic() ? 0x21 : 0x20, true); break; default: // Should never happen _explosionSpell = 0; _damageSpell = 0; break; } - - if (IsHeroic()) - me->SetPhaseMask(0x01 | 0x20, true); } void IsSummonedBy(Unit* summoner) override @@ -1160,7 +1223,7 @@ class npc_combustion_consumption : public CreatureScript me->CastCustomSpell(SPELL_SCALE_AURA, SPELLVALUE_AURA_STACK, stackAmount, me); DoCast(me, _damageSpell); - int32 damage = 1200 + (stackAmount * 1290); // Needs more researches. + int32 damage = 1200 + (stackAmount * 1290); // Needs more research. summoner->CastCustomSpell(_explosionSpell, SPELLVALUE_BASE_POINT0, damage, summoner); } @@ -1193,6 +1256,10 @@ class npc_living_inferno : public CreatureScript me->SetInCombatWithZone(); me->CastSpell(me, SPELL_BLAZING_AURA, true); + // SMSG_SPELL_GO for the living ember stuff isn't even sent to the client - Blizzard on drugs. + if (me->GetMap()->GetDifficultyID() == DIFFICULTY_25_HC) + me->CastSpell(me, SPELL_SPAWN_LIVING_EMBERS, true); + if (InstanceScript* instance = me->GetInstanceScript()) if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HALION_CONTROLLER))) controller->AI()->JustSummoned(me); @@ -1210,7 +1277,6 @@ class npc_living_inferno : public CreatureScript } }; -//! Need sniff data class npc_living_ember : public CreatureScript { public: @@ -1738,12 +1804,46 @@ class spell_halion_summon_exit_portals : public SpellScriptLoader } }; +class spell_halion_spawn_living_embers : public SpellScriptLoader +{ + public: + spell_halion_spawn_living_embers() : SpellScriptLoader("spell_halion_spawn_living_embers") { } + + class spell_halion_spawn_living_embers_SpellScript : public SpellScript + { + PrepareSpellScript(spell_halion_spawn_living_embers_SpellScript); + + void SelectMeteorFlames(std::list<WorldObject*>& unitList) + { + if (!unitList.empty()) + Trinity::Containers::RandomResizeList(unitList, 10); + } + + void HandleScript(SpellEffIndex /* effIndex */) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_LIVING_EMBER, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_halion_spawn_living_embers_SpellScript::SelectMeteorFlames, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_halion_spawn_living_embers_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_halion_spawn_living_embers_SpellScript(); + } +}; + void AddSC_boss_halion() { new boss_halion(); new boss_twilight_halion(); new npc_halion_controller(); + new npc_meteor_strike_flame(); new npc_meteor_strike_initial(); new npc_meteor_strike(); new npc_combustion_consumption(); @@ -1765,4 +1865,5 @@ void AddSC_boss_halion() new spell_halion_twilight_phasing(); new spell_halion_twilight_cutter(); new spell_halion_clear_debuffs(); + new spell_halion_spawn_living_embers(); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index 0fc4f1a4a8b..7f88a56f22c 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -196,7 +196,7 @@ class instance_halls_of_reflection : public InstanceMapScript } } - uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override + uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override { if (!_teamInInstance) { diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index faa448ef539..51756834e77 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1059,8 +1059,8 @@ class spell_putricide_ooze_eruption_searcher : public SpellScriptLoader { if (GetHitUnit()->HasAura(SPELL_VOLATILE_OOZE_ADHESIVE)) { - GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true); GetHitUnit()->RemoveAurasDueToSpell(SPELL_VOLATILE_OOZE_ADHESIVE, GetCaster()->GetGUID(), 0, AURA_REMOVE_BY_ENEMY_SPELL); + GetCaster()->CastSpell(GetHitUnit(), SPELL_OOZE_ERUPTION, true); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 7bd1dee15ca..423c1049452 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -348,7 +348,7 @@ class boss_sindragosa : public CreatureScript events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1); break; case POINT_AIR_PHASE: - me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL); + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 5, 2, 6), NULL, TRIGGERED_FULL_MASK); me->SetFacingTo(float(M_PI)); events.ScheduleEvent(EVENT_AIR_MOVEMENT_FAR, 1); events.ScheduleEvent(EVENT_FROST_BOMB, 9000); @@ -490,7 +490,7 @@ class boss_sindragosa : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, FrostBeaconSelector(me))) { Talk(EMOTE_WARN_FROZEN_ORB, target); - DoCast(target, SPELL_ICE_TOMB_DUMMY, true); + me->CastCustomSpell(SPELL_ICE_TOMB_TARGET, SPELLVALUE_MAX_TARGETS, 1, nullptr, TRIGGERED_FULL_MASK); } events.ScheduleEvent(EVENT_ICE_TOMB, urand(16000, 23000)); break; @@ -1630,7 +1630,7 @@ void AddSC_boss_sindragosa() new spell_rimefang_icy_blast(); new spell_frostwarden_handler_order_whelp(); new spell_frostwarden_handler_focus_fire(); - new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY); + new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb", SPELL_ICE_TOMB_DUMMY, TRIGGERED_IGNORE_SET_FACING); new spell_trigger_spell_from_caster("spell_sindragosa_ice_tomb_dummy", SPELL_FROST_BEACON); new at_sindragosa_lair(); new achievement_all_you_can_eat(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 8bf8e5ee6fb..091190b6b4e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -524,14 +524,16 @@ enum AreaIds class spell_trigger_spell_from_caster : public SpellScriptLoader { public: - spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId) : SpellScriptLoader(scriptName), _triggerId(triggerId) { } + spell_trigger_spell_from_caster(char const* scriptName, uint32 triggerId, TriggerCastFlags triggerFlags = TRIGGERED_FULL_MASK) + : SpellScriptLoader(scriptName), _triggerId(triggerId), _triggerFlags(triggerFlags) { } class spell_trigger_spell_from_caster_SpellScript : public SpellScript { PrepareSpellScript(spell_trigger_spell_from_caster_SpellScript); public: - spell_trigger_spell_from_caster_SpellScript(uint32 triggerId) : SpellScript(), _triggerId(triggerId) { } + spell_trigger_spell_from_caster_SpellScript(uint32 triggerId, TriggerCastFlags triggerFlags) + : SpellScript(), _triggerId(triggerId), _triggerFlags(triggerFlags) { } bool Validate(SpellInfo const* /*spell*/) override { @@ -542,7 +544,7 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader void HandleTrigger() { - GetCaster()->CastSpell(GetHitUnit(), _triggerId, true); + GetCaster()->CastSpell(GetHitUnit(), _triggerId, _triggerFlags); } void Register() override @@ -551,15 +553,17 @@ class spell_trigger_spell_from_caster : public SpellScriptLoader } uint32 _triggerId; + TriggerCastFlags _triggerFlags; }; SpellScript* GetSpellScript() const override { - return new spell_trigger_spell_from_caster_SpellScript(_triggerId); + return new spell_trigger_spell_from_caster_SpellScript(_triggerId, _triggerFlags); } private: uint32 _triggerId; + TriggerCastFlags _triggerFlags; }; template<class AI> diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index aee14edd0c3..d38d630f775 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -317,7 +317,7 @@ class instance_icecrown_citadel : public InstanceMapScript } // Weekly quest spawn prevention - uint32 GetCreatureEntry(uint32 /*guidLow*/, CreatureData const* data) override + uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override { uint32 entry = data->id; switch (entry) @@ -372,7 +372,7 @@ class instance_icecrown_citadel : public InstanceMapScript return entry; } - uint32 GetGameObjectEntry(uint32 /*guidLow*/, uint32 entry) override + uint32 GetGameObjectEntry(ObjectGuid::LowType /*guidLow*/, uint32 entry) override { switch (entry) { diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 0c79b42f20c..b939c40cabb 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -128,7 +128,6 @@ enum Spells SPELL_ARCANE_BARRAGE_DAMAGE = 63934, // the actual damage - cast by affected player by script spell // Transition /II-III/ - SPELL_SUMMOM_RED_DRAGON_BUDYY = 56070, SPELL_RIDE_RED_DRAGON_BUDDY = 56071, SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST = 58846, // After implicitly hit player targets they will force cast 56070 on self SPELL_DESTROY_PLATFORM_CHANNEL = 58842, diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h index b6a0d3f9b62..d9b921b38a1 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h @@ -80,7 +80,8 @@ enum InstanceSpells SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle SPELL_PORTAL_OPENED = 61236, SPELL_RIDE_RED_DRAGON_TRIGGERED = 56072, - SPELL_IRIS_OPENED = 61012 // visual when starting encounter + SPELL_IRIS_OPENED = 61012, // visual when starting encounter + SPELL_SUMMOM_RED_DRAGON_BUDDY = 56070 }; #endif diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index 79a7c5cb772..11d19d76d80 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -39,6 +39,12 @@ public: SetBossNumber(MAX_ENCOUNTER); } + void OnPlayerEnter(Player* player) override + { + if (GetBossState(DATA_MALYGOS_EVENT) == DONE) + player->CastSpell(player, SPELL_SUMMOM_RED_DRAGON_BUDDY, true); + } + bool SetBossState(uint32 type, EncounterState state) override { if (!InstanceScript::SetBossState(type, state)) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 9ca88f4fdfa..525ecacd39a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -482,40 +482,47 @@ class boss_flame_leviathan : public CreatureScript if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count { if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3 | LOOT_MODE_HARD_MODE_4) && ActiveTowersCount == 4) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_4); - --ActiveTowersCount; - } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2 | LOOT_MODE_HARD_MODE_3) && ActiveTowersCount == 3) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_3); - --ActiveTowersCount; - } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1 | LOOT_MODE_HARD_MODE_2) && ActiveTowersCount == 2) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_2); - --ActiveTowersCount; - } + if (me->HasLootMode(LOOT_MODE_DEFAULT | LOOT_MODE_HARD_MODE_1) && ActiveTowersCount == 1) - { me->RemoveLootMode(LOOT_MODE_HARD_MODE_1); - --ActiveTowersCount; - } } switch (action) { case ACTION_TOWER_OF_STORM_DESTROYED: - towerOfStorms = false; + if (towerOfStorms) + { + towerOfStorms = false; + --ActiveTowersCount; + } break; case ACTION_TOWER_OF_FROST_DESTROYED: - towerOfFrost = false; + if (towerOfFrost) + { + towerOfFrost = false; + --ActiveTowersCount; + } break; case ACTION_TOWER_OF_FLAMES_DESTROYED: - towerOfFlames = false; + if (towerOfFlames) + { + towerOfFlames = false; + --ActiveTowersCount; + } break; case ACTION_TOWER_OF_LIFE_DESTROYED: - towerOfLife = false; + if (towerOfLife) + { + towerOfLife = false; + --ActiveTowersCount; + } break; case ACTION_START_HARD_MODE: // Activate hard-mode enable all towers, apply buffs on leviathan ActiveTowers = true; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp index 134783ccf07..6a1ff6d4eea 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp @@ -903,17 +903,15 @@ class boss_yogg_saron : public CreatureScript DoCast(me, SPELL_KNOCK_AWAY); me->ResetLootMode(); - switch (_instance->GetData(DATA_KEEPERS_COUNT)) - { - case 0: - me->AddLootMode(LOOT_MODE_HARD_MODE_4); - case 1: - me->AddLootMode(LOOT_MODE_HARD_MODE_3); - case 2: - me->AddLootMode(LOOT_MODE_HARD_MODE_2); - case 3: - me->AddLootMode(LOOT_MODE_HARD_MODE_1); - } + uint32 keepersCount = _instance->GetData(DATA_KEEPERS_COUNT); + if (keepersCount == 0) + me->AddLootMode(LOOT_MODE_HARD_MODE_4); + if (keepersCount <= 1) + me->AddLootMode(LOOT_MODE_HARD_MODE_3); + if (keepersCount <= 2) + me->AddLootMode(LOOT_MODE_HARD_MODE_2); + if (keepersCount <= 3) + me->AddLootMode(LOOT_MODE_HARD_MODE_1); } void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 7f29a6621bd..2e426fd77cf 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -25,53 +25,6 @@ #include "CombatAI.h" /*###### -## npc_squire_david -######*/ - -enum SquireDavid -{ - QUEST_THE_ASPIRANT_S_CHALLENGE_H = 13680, - QUEST_THE_ASPIRANT_S_CHALLENGE_A = 13679, - - NPC_ARGENT_VALIANT = 33448, - - GOSSIP_TEXTID_SQUIRE = 14407 -}; - -#define GOSSIP_SQUIRE_ITEM_1 "I am ready to fight!" -#define GOSSIP_SQUIRE_ITEM_2 "How do the Argent Crusader raiders fight?" - -class npc_squire_david : public CreatureScript -{ -public: - npc_squire_david() : CreatureScript("npc_squire_david") { } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_H) == QUEST_STATUS_INCOMPLETE || - player->GetQuestStatus(QUEST_THE_ASPIRANT_S_CHALLENGE_A) == QUEST_STATUS_INCOMPLETE)//We need more info about it. - { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SQUIRE_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - } - - player->SEND_GOSSIP_MENU(GOSSIP_TEXTID_SQUIRE, creature->GetGUID()); - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - player->CLOSE_GOSSIP_MENU(); - creature->SummonCreature(NPC_ARGENT_VALIANT, 8575.451f, 952.472f, 547.554f, 0.38f); - } - return true; - } -}; - -/*###### ## npc_argent_valiant ######*/ @@ -837,7 +790,6 @@ class npc_frostbrood_skytalon : public CreatureScript void AddSC_icecrown() { - new npc_squire_david; new npc_argent_valiant; new npc_guardian_pavilion; new npc_tournament_training_dummy; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h index c2dd71ce7cf..77a7c338118 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h @@ -261,13 +261,13 @@ class OPvPCapturePointNA : public OPvPCapturePoint public: OPvPCapturePointNA(OutdoorPvP* pvp); - bool Update(uint32 diff); + bool Update(uint32 diff) override; - void ChangeState(); + void ChangeState() override; - void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet); + void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& packet) override; - bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go); + bool HandleCustomSpell(Player* player, uint32 spellId, GameObject* go) override; int32 HandleOpenGo(Player* player, GameObject* go) override; diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt index 24658dbc21f..42621b76941 100644 --- a/src/server/scripts/Outland/CMakeLists.txt +++ b/src/server/scripts/Outland/CMakeLists.txt @@ -27,6 +27,7 @@ set(scripts_STAT_SRCS Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp + Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp index fb44a403d86..dfc5f5992a6 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp @@ -108,6 +108,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript void Reset() override { + _Reset(); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); Initialize(); @@ -115,9 +116,8 @@ class boss_grand_warlock_nethekurse : public CreatureScript void JustDied(Unit* /*killer*/) override { + _JustDied(); Talk(SAY_DIE); - - instance->SetBossState(DATA_NETHEKURSE, DONE); } void SetData(uint32 data, uint32 value) override diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp index 7d00cd97126..a950882eddd 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp @@ -160,6 +160,7 @@ class boss_warbringer_omrogg : public CreatureScript void Reset() override { + _Reset(); if (Unit* LeftHead = ObjectAccessor::GetUnit(*me, LeftHeadGUID)) { LeftHead->setDeathState(JUST_DIED); @@ -257,14 +258,14 @@ class boss_warbringer_omrogg : public CreatureScript Creature* LeftHead = ObjectAccessor::GetCreature(*me, LeftHeadGUID); Creature* RightHead = ObjectAccessor::GetCreature(*me, RightHeadGUID); + _JustDied(); + if (!LeftHead || !RightHead) return; LeftHead->AI()->Talk(YELL_DIE_L); RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL); - - instance->SetBossState(DATA_OMROGG, DONE); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index b44ae46c78c..7f2e08b39ca 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -35,7 +35,10 @@ enum Says { SAY_AGGRO = 0, SAY_SLAY = 1, - SAY_DEATH = 2 + SAY_DEATH = 2, + + SAY_CALL_EXECUTIONER_A = 3, + SAY_CALL_EXECUTIONER_H = 4 }; enum Spells @@ -84,10 +87,28 @@ class boss_warchief_kargath_bladefist : public CreatureScript resetcheck_timer = 5000; } + void DoAction(int32 action) override + { + if (action == ACTION_EXECUTIONER_TAUNT) + { + switch (instance->GetData(DATA_TEAM_IN_INSTANCE)) + { + case ALLIANCE: + Talk(SAY_CALL_EXECUTIONER_A); + break; + case HORDE: + Talk(SAY_CALL_EXECUTIONER_H); + break; + default: + break; + } + } + } + void Reset() override { removeAdds(); - + _Reset(); me->SetSpeed(MOVE_RUN, 2); me->SetWalk(false); @@ -96,10 +117,9 @@ class boss_warchief_kargath_bladefist : public CreatureScript void JustDied(Unit* /*killer*/) override { + _JustDied(); Talk(SAY_DEATH); removeAdds(); - - instance->SetBossState(DATA_KARGATH, DONE); } void EnterCombat(Unit* /*who*/) override diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp index c6b08bdada1..a781861d47f 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp @@ -26,6 +26,18 @@ EndScriptData */ #include "ScriptMgr.h" #include "InstanceScript.h" #include "shattered_halls.h" +#include "Player.h" +#include "SpellAuras.h" +#include "CreatureAI.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" + +DoorData const doorData[] = +{ + { GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } +}; class instance_shattered_halls : public InstanceMapScript { @@ -43,6 +55,41 @@ class instance_shattered_halls : public InstanceMapScript { SetHeaders(DataHeader); SetBossNumber(EncounterCount); + LoadDoorData(doorData); + executionTimer = 0; + executed = 0; + _team = 0; + } + + void OnPlayerEnter(Player* player) override + { + Aura* ex = nullptr; + + if (!_team) + _team = player->GetTeam(); + + player->CastSpell(player, SPELL_REMOVE_KARGATH_EXECUTIONER, true); + + if (!executionTimer || executionerGUID.IsEmpty()) + return; + + switch (executed) + { + case 0: + ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_1, player); + break; + case 1: + ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_2, player); + break; + case 2: + ex = player->AddAura(SPELL_KARGATH_EXECUTIONER_3, player); + break; + default: + break; + } + + if (ex) + ex->SetDuration(executionTimer); } void OnGameObjectCreate(GameObject* go) override @@ -50,21 +97,65 @@ class instance_shattered_halls : public InstanceMapScript switch (go->GetEntry()) { case GO_GRAND_WARLOCK_CHAMBER_DOOR_1: - nethekurseDoor1GUID = go->GetGUID(); + case GO_GRAND_WARLOCK_CHAMBER_DOOR_2: + AddDoor(go, true); + default: break; + } + } + + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_GRAND_WARLOCK_CHAMBER_DOOR_1: case GO_GRAND_WARLOCK_CHAMBER_DOOR_2: - nethekurseDoor2GUID = go->GetGUID(); + AddDoor(go, false); + default: break; } } void OnCreatureCreate(Creature* creature) override { + if (!_team) + { + Map::PlayerList const &players = instance->GetPlayers(); + if (!players.isEmpty()) + if (Player* player = players.begin()->GetSource()) + _team = player->GetTeam(); + } + switch (creature->GetEntry()) { case NPC_GRAND_WARLOCK_NETHEKURSE: nethekurseGUID = creature->GetGUID(); break; + case NPC_KARGATH_BLADEFIST: + kargathGUID = creature->GetGUID(); + break; + case NPC_RANDY_WHIZZLESPROCKET: + if (_team == HORDE) + creature->UpdateEntry(NPC_DRISELLA); + break; + case NPC_SHATTERED_EXECUTIONER: + executionTimer = 55 * MINUTE * IN_MILLISECONDS; + DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_1); + executionerGUID = creature->GetGUID(); + SaveToDB(); + break; + case NPC_CAPTAIN_ALINA: + case NPC_CAPTAIN_BONESHATTER: + victimsGUID[0] = creature->GetGUID(); + break; + case NPC_ALLIANCE_VICTIM_1: + case NPC_HORDE_VICTIM_1: + victimsGUID[1] = creature->GetGUID(); + break; + case NPC_ALLIANCE_VICTIM_2: + case NPC_HORDE_VICTIM_2: + victimsGUID[2] = creature->GetGUID(); + break; } } @@ -75,18 +166,18 @@ class instance_shattered_halls : public InstanceMapScript switch (type) { - case DATA_NETHEKURSE: - if (state == IN_PROGRESS) - { - HandleGameObject(nethekurseDoor1GUID, false); - HandleGameObject(nethekurseDoor2GUID, false); - } - else + case DATA_SHATTERED_EXECUTIONER: + if (state == DONE) { - HandleGameObject(nethekurseDoor1GUID, true); - HandleGameObject(nethekurseDoor2GUID, true); + DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER); + executionTimer = 0; + SaveToDB(); } break; + case DATA_KARGATH: + if (Creature* executioner = instance->GetCreature(executionerGUID)) + executioner->AI()->Reset(); // trigger removal of IMMUNE_TO_PC flag + break; case DATA_OMROGG: break; } @@ -99,24 +190,120 @@ class instance_shattered_halls : public InstanceMapScript { case NPC_GRAND_WARLOCK_NETHEKURSE: return nethekurseGUID; - break; - case GO_GRAND_WARLOCK_CHAMBER_DOOR_1: - return nethekurseDoor1GUID; - break; - case GO_GRAND_WARLOCK_CHAMBER_DOOR_2: - return nethekurseDoor2GUID; - break; + case NPC_KARGATH_BLADEFIST: + return kargathGUID; + case NPC_SHATTERED_EXECUTIONER: + return executionerGUID; + case DATA_FIRST_PRISONER: + case DATA_SECOND_PRISONER: + case DATA_THIRD_PRISONER: + return victimsGUID[data - DATA_FIRST_PRISONER]; + default: + return ObjectGuid::Empty; } - return ObjectGuid::Empty; } - protected: + void WriteSaveDataMore(std::ostringstream& data) override + { + if (!instance->IsHeroic()) + return; + + data << uint32(executed) << ' ' + << executionTimer << ' '; + } + + void ReadSaveDataMore(std::istringstream& data) override + { + if (!instance->IsHeroic()) + return; + + uint32 readbuff; + data >> readbuff; + executed = uint8(readbuff); + data >> readbuff; + + if (executed > VictimCount) + { + executed = VictimCount; + executionTimer = 0; + return; + } + + if (!readbuff) + return; + + Creature* executioner = nullptr; + + instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY()); + if (Creature* kargath = instance->GetCreature(kargathGUID)) + if (executionerGUID.IsEmpty()) + executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner); + + if (executioner) + for (uint8 i = executed; i < VictimCount; ++i) + executioner->SummonCreature(executionerVictims[i](GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos()); + + executionTimer = readbuff; + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_PRISONERS_EXECUTED: + return executed; + case DATA_TEAM_IN_INSTANCE: + return _team; + default: + return 0; + } + } + + void Update(uint32 diff) override + { + if (!executionTimer) + return; + + if (executionTimer <= diff) + { + DoCastSpellOnPlayers(SPELL_REMOVE_KARGATH_EXECUTIONER); + switch (++executed) + { + case 1: + DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_2); + executionTimer = 10 * MINUTE * IN_MILLISECONDS; + break; + case 2: + DoCastSpellOnPlayers(SPELL_KARGATH_EXECUTIONER_3); + executionTimer = 15 * MINUTE * IN_MILLISECONDS; + break; + default: + executionTimer = 0; + break; + } + + if (Creature* executioner = instance->GetCreature(executionerGUID)) + executioner->AI()->SetData(DATA_PRISONERS_EXECUTED, executed); + + SaveToDB(); + } + else + executionTimer -= diff; + } + + private: ObjectGuid nethekurseGUID; - ObjectGuid nethekurseDoor1GUID; - ObjectGuid nethekurseDoor2GUID; + ObjectGuid kargathGUID; + ObjectGuid executionerGUID; + ObjectGuid victimsGUID[3]; + + uint8 executed; + uint32 executionTimer; + uint32 _team; }; }; + void AddSC_instance_shattered_halls() { new instance_shattered_halls(); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp new file mode 100644 index 00000000000..d31fa4c4f09 --- /dev/null +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "InstanceScript.h" +#include "Player.h" +#include "SpellAuras.h" +#include "shattered_halls.h" + +class at_nethekurse_exit : public AreaTriggerScript +{ + public: + at_nethekurse_exit() : AreaTriggerScript("at_nethekurse_exit") { }; + + bool OnTrigger(Player* player, AreaTriggerEntry const*, bool /*entered*/) override + { + if (InstanceScript* is = player->GetInstanceScript()) + { + if (is->instance->IsHeroic()) + { + Creature* executioner = nullptr; + + is->instance->LoadGrid(Executioner.GetPositionX(), Executioner.GetPositionY()); + if (Creature* kargath = ObjectAccessor::GetCreature(*player, is->GetGuidData(NPC_KARGATH_BLADEFIST))) + { + if (is->GetGuidData(NPC_SHATTERED_EXECUTIONER).IsEmpty()) + { + executioner = kargath->SummonCreature(NPC_SHATTERED_EXECUTIONER, Executioner); + kargath->AI()->DoAction(ACTION_EXECUTIONER_TAUNT); + } + } + + if (executioner) + for (uint8 i = 0; i < VictimCount; ++i) + executioner->SummonCreature(executionerVictims[i](is->GetData(DATA_TEAM_IN_INSTANCE)), executionerVictims[i].GetPos()); + } + } + + return false; + } +}; + +enum Spells +{ + SPELL_CLEAVE = 15284 +}; + +class boss_shattered_executioner : public CreatureScript +{ + public: + boss_shattered_executioner() : CreatureScript("boss_shattered_executioner") { } + + struct boss_shattered_executionerAI : public BossAI + { + boss_shattered_executionerAI(Creature* creature) : BossAI(creature, DATA_SHATTERED_EXECUTIONER) + { + Initialize(); + }; + + void Initialize() + { + cleaveTimer = 500; + } + + void Reset() override + { + _Reset(); + + // _Reset() resets the loot mode, so we add them again, if any + uint32 prisonersExecuted = instance->GetData(DATA_PRISONERS_EXECUTED); + if (prisonersExecuted == 0) + me->AddLootMode(LOOT_MODE_HARD_MODE_3); + if (prisonersExecuted <= 1) + me->AddLootMode(LOOT_MODE_HARD_MODE_2); + if (prisonersExecuted <= 2) + me->AddLootMode(LOOT_MODE_HARD_MODE_1); + + if (instance->GetBossState(DATA_KARGATH) == DONE) + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + else + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + + Initialize(); + } + + void JustSummoned(Creature*) override { } // avoid despawn of prisoners on death/reset + + void JustDied(Unit*) override + { + _JustDied(); + + if (instance->GetData(DATA_PRISONERS_EXECUTED) > 0) + return; + + Map::PlayerList const &players = instance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + Player* pl = itr->GetSource(); + uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H; + if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE) + pl->CompleteQuest(qId); + } + } + + void SetData(uint32 type, uint32 data) override + { + if (type == DATA_PRISONERS_EXECUTED && data <= 3) + { + if (Creature* victim = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FIRST_PRISONER + data - 1))) + me->Kill(victim); + + if (data == 1) + { + Map::PlayerList const &players = instance->instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + { + Player* pl = itr->GetSource(); + uint32 qId = pl->GetTeam() == ALLIANCE ? QUEST_IMPRISONED_A : QUEST_IMPRISONED_H; + if (pl->GetQuestStatus(qId) == QUEST_STATUS_INCOMPLETE) + pl->FailQuest(qId); + } + } + + switch (data) + { + case 3: + me->RemoveLootMode(LOOT_MODE_HARD_MODE_1); + case 2: + me->RemoveLootMode(LOOT_MODE_HARD_MODE_2); + case 1: + me->RemoveLootMode(LOOT_MODE_HARD_MODE_3); + default: + break; + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + if (cleaveTimer <= diff) + { + DoCast(SPELL_CLEAVE); + cleaveTimer = urand(5000, 7000); + } + else + cleaveTimer -= diff; + + DoMeleeAttackIfReady(); + } + private: + uint32 cleaveTimer; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_shattered_executionerAI>(creature); + } +}; + +class spell_kargath_executioner : public SpellScriptLoader +{ + public: + spell_kargath_executioner() : SpellScriptLoader("spell_kargath_executioner") { } + + class spell_kargath_executioner_AuraScript : public AuraScript + { + PrepareAuraScript(spell_kargath_executioner_AuraScript); + + bool AreaCheck(Unit* target) + { + if (target->GetMap()->GetId() != 540) + return false; + + return true; + } + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void Register() override + { + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_kargath_executioner_AuraScript::AreaCheck); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_kargath_executioner_AuraScript(); + } +}; + +class spell_remove_kargath_executioner : public SpellScriptLoader +{ + public: + spell_remove_kargath_executioner() : SpellScriptLoader("spell_remove_kargath_executioner") { } + + class spell_remove_kargath_executioner_SpellScript : public SpellScript + { + PrepareSpellScript(spell_remove_kargath_executioner_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* target = GetCaster(); + + target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_1); + target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_2); + target->RemoveAurasDueToSpell(SPELL_KARGATH_EXECUTIONER_3); + } + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_remove_kargath_executioner_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_remove_kargath_executioner_SpellScript(); + } +}; + +void AddSC_shattered_halls() +{ + new at_nethekurse_exit(); + new boss_shattered_executioner(); + new spell_kargath_executioner(); + new spell_remove_kargath_executioner(); +} diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h index 90cbbe2a438..894cc9c40a6 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h @@ -21,18 +21,45 @@ #define DataHeader "SH" -uint32 const EncounterCount = 3; +uint32 const EncounterCount = 4; +uint32 const VictimCount = 3; enum DataTypes { - DATA_NETHEKURSE = 1, - DATA_OMROGG = 2, - DATA_KARGATH = 3 + DATA_NETHEKURSE = 0, + DATA_OMROGG = 1, + DATA_KARGATH = 2, + + DATA_SHATTERED_EXECUTIONER = 3, + DATA_PRISONERS_EXECUTED = 4, + + DATA_TEAM_IN_INSTANCE = 5, + + DATA_FIRST_PRISONER, + DATA_SECOND_PRISONER, + DATA_THIRD_PRISONER }; enum CreatureIds { - NPC_GRAND_WARLOCK_NETHEKURSE = 16807 + NPC_GRAND_WARLOCK_NETHEKURSE = 16807, + NPC_KARGATH_BLADEFIST = 16808, + + NPC_SHATTERED_EXECUTIONER = 17301, + + // Alliance Ids + NPC_RANDY_WHIZZLESPROCKET = 17288, + + NPC_CAPTAIN_ALINA = 17290, + NPC_ALLIANCE_VICTIM_1 = 17289, + NPC_ALLIANCE_VICTIM_2 = 17292, + + // Horde Ids + NPC_DRISELLA = 17294, + + NPC_CAPTAIN_BONESHATTER = 17296, + NPC_HORDE_VICTIM_1 = 17295, + NPC_HORDE_VICTIM_2 = 17297 }; enum GameobjectIds @@ -41,4 +68,47 @@ enum GameobjectIds GO_GRAND_WARLOCK_CHAMBER_DOOR_2 = 182540 }; +enum QuestIds +{ + QUEST_IMPRISONED_A = 9524, + QUEST_IMPRISONED_H = 9525 +}; + +enum InstanceSpells +{ + SPELL_KARGATH_EXECUTIONER_1 = 39288, + SPELL_KARGATH_EXECUTIONER_2 = 39289, + SPELL_KARGATH_EXECUTIONER_3 = 39290, + + SPELL_REMOVE_KARGATH_EXECUTIONER = 39291 +}; + +enum Actions +{ + ACTION_EXECUTIONER_TAUNT = 1 +}; + +const Position Executioner = { 152.8524f, -83.63912f, 2.021005f, 0.06981317f }; + +struct FactionSpawnerHelper +{ + FactionSpawnerHelper(uint32 allianceEntry, uint32 hordeEntry, const Position& pos) : _allianceNPC(allianceEntry), _hordeNPC(hordeEntry), _spawnPos(pos) { } + + inline uint32 operator()(uint32 teamID) const { return teamID == ALLIANCE ? _allianceNPC : _hordeNPC; } + inline Position const& GetPos() const { return _spawnPos; } + +private: + const uint32 _allianceNPC; + const uint32 _hordeNPC; + const Position _spawnPos; +}; + +const FactionSpawnerHelper executionerVictims[VictimCount] = +{ + { NPC_CAPTAIN_ALINA, NPC_CAPTAIN_BONESHATTER, { 138.8807f, -84.22707f, 1.992269f, 0.06981317f } }, + { NPC_ALLIANCE_VICTIM_1, NPC_HORDE_VICTIM_1, { 151.2411f, -91.02930f, 2.019741f, 1.57079600f } }, + { NPC_ALLIANCE_VICTIM_2, NPC_HORDE_VICTIM_2, { 151.0459f, -77.51981f, 2.021008f, 4.74729500f } } +}; + + #endif diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index cc825afd3a0..48508aa4790 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -77,12 +77,11 @@ class boss_alar : public CreatureScript public: boss_alar() : CreatureScript("boss_alar") { } - struct boss_alarAI : public ScriptedAI + struct boss_alarAI : public BossAI { - boss_alarAI(Creature* creature) : ScriptedAI(creature) + boss_alarAI(Creature* creature) : BossAI(creature, DATA_ALAR) { Initialize(); - instance = creature->GetInstanceScript(); DefaultMoveSpeedRate = creature->GetSpeedRate(MOVE_RUN); DiveBomb_Timer = 0; MeltArmor_Timer = 0; @@ -105,8 +104,6 @@ class boss_alar : public CreatureScript cur_wp = 4; } - InstanceScript* instance; - WaitEventType WaitEvent; uint32 WaitTimer; @@ -129,9 +126,8 @@ class boss_alar : public CreatureScript void Reset() override { - instance->SetData(DATA_ALAREVENT, NOT_STARTED); - Initialize(); + _Reset(); me->SetDisplayId(me->GetNativeDisplayId()); me->SetSpeed(MOVE_RUN, DefaultMoveSpeedRate); @@ -145,18 +141,11 @@ class boss_alar : public CreatureScript void EnterCombat(Unit* /*who*/) override { - instance->SetData(DATA_ALAREVENT, IN_PROGRESS); - + _EnterCombat(); me->SetDisableGravity(true); // after enterevademode will be set walk movement - DoZoneInCombat(); me->setActive(true); } - void JustDied(Unit* /*killer*/) override - { - instance->SetData(DATA_ALAREVENT, DONE); - } - void JustSummoned(Creature* summon) override { if (summon->GetEntry() == CREATURE_EMBER_OF_ALAR) @@ -508,7 +497,7 @@ class npc_ember_of_alar : public CreatureScript DoCast(me, SPELL_EMBER_BLAST, true); me->SetDisplayId(11686); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - if (instance->GetData(DATA_ALAREVENT) == 2) + if (instance->GetBossState(DATA_ALAR) == IN_PROGRESS) { if (Unit* Alar = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_ALAR))) { diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp index b3324980bd4..c8e3e57ac3b 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp @@ -92,17 +92,13 @@ class boss_high_astromancer_solarian : public CreatureScript { public: - boss_high_astromancer_solarian() - : CreatureScript("boss_high_astromancer_solarian") - { - } + boss_high_astromancer_solarian() : CreatureScript("boss_high_astromancer_solarian") { } - struct boss_high_astromancer_solarianAI : public ScriptedAI + struct boss_high_astromancer_solarianAI : public BossAI { - boss_high_astromancer_solarianAI(Creature* creature) : ScriptedAI(creature), Summons(me) + boss_high_astromancer_solarianAI(Creature* creature) : BossAI(creature, DATA_HIGH_ASTROMANCER_SOLARIAN) { Initialize(); - instance = creature->GetInstanceScript(); defaultarmor = creature->GetArmor(); defaultsize = creature->GetObjectScale(); @@ -126,9 +122,6 @@ class boss_high_astromancer_solarian : public CreatureScript Phase = 1; } - InstanceScript* instance; - SummonList Summons; - uint8 Phase; uint32 ArcaneMissiles_Timer; @@ -152,16 +145,13 @@ class boss_high_astromancer_solarian : public CreatureScript void Reset() override { Initialize(); - - instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, NOT_STARTED); - + _Reset(); me->SetArmor(defaultarmor); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetVisible(true); me->SetObjectScale(defaultsize); me->SetDisplayId(MODEL_HUMAN); - Summons.DespawnAll(); } void KilledUnit(Unit* /*victim*/) override @@ -174,15 +164,13 @@ class boss_high_astromancer_solarian : public CreatureScript me->SetObjectScale(defaultsize); me->SetDisplayId(MODEL_HUMAN); Talk(SAY_DEATH); - instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, DONE); + _JustDied(); } void EnterCombat(Unit* /*who*/) override { Talk(SAY_AGGRO); - DoZoneInCombat(); - - instance->SetData(DATA_HIGHASTROMANCERSOLARIANEVENT, IN_PROGRESS); + _EnterCombat(); } void SummonMinion(uint32 entry, float x, float y, float z) @@ -193,7 +181,7 @@ class boss_high_astromancer_solarian : public CreatureScript if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) Summoned->AI()->AttackStart(target); - Summons.Summon(Summoned); + summons.Summon(Summoned); } } @@ -431,10 +419,7 @@ class npc_solarium_priest : public CreatureScript { public: - npc_solarium_priest() - : CreatureScript("npc_solarium_priest") - { - } + npc_solarium_priest() : CreatureScript("npc_solarium_priest") { } struct npc_solarium_priestAI : public ScriptedAI { @@ -462,9 +447,7 @@ class npc_solarium_priest : public CreatureScript Initialize(); } - void EnterCombat(Unit* /*who*/) override - { - } + void EnterCombat(Unit* /*who*/) override { } void UpdateAI(uint32 diff) override { diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 38ccf33a612..3eae867b86c 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -286,17 +286,13 @@ class boss_kaelthas : public CreatureScript { public: - boss_kaelthas() - : CreatureScript("boss_kaelthas") - { - } - //Kael'thas AI - struct boss_kaelthasAI : public ScriptedAI + boss_kaelthas() : CreatureScript("boss_kaelthas") { } + + struct boss_kaelthasAI : public BossAI { - boss_kaelthasAI(Creature* creature) : ScriptedAI(creature), summons(me) + boss_kaelthasAI(Creature* creature) : BossAI(creature, DATA_KAELTHAS) { Initialize(); - instance = creature->GetInstanceScript(); PhaseSubphase = 0; Phase_Timer = 0; } @@ -320,8 +316,6 @@ class boss_kaelthas : public CreatureScript ChainPyros = false; } - InstanceScript* instance; - uint32 Fireball_Timer; uint32 ArcaneDisruption_Timer; uint32 Phoenix_Timer; @@ -341,8 +335,6 @@ class boss_kaelthas : public CreatureScript bool IsCastingFireball; bool ChainPyros; - SummonList summons; - ObjectGuid m_auiAdvisorGuid[MAX_ADVISORS]; void Reset() override @@ -352,7 +344,7 @@ class boss_kaelthas : public CreatureScript if (me->IsInCombat()) PrepareAdvisors(); - summons.DespawnAll(); + _Reset(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -413,7 +405,6 @@ class boss_kaelthas : public CreatureScript } void MoveInLineOfSight(Unit* who) override - { if (!me->HasUnitState(UNIT_STATE_STUNNED) && me->CanCreatureAttack(who)) { @@ -444,6 +435,8 @@ class boss_kaelthas : public CreatureScript { if (!instance->GetData(DATA_KAELTHASEVENT) && !Phase) StartEvent(); + + instance->SetBossState(DATA_KAELTHAS, IN_PROGRESS); } void KilledUnit(Unit* /*victim*/) override @@ -463,11 +456,6 @@ class boss_kaelthas : public CreatureScript } } - void SummonedCreatureDespawn(Creature* summon) override - { - summons.Despawn(summon); - } - void JustDied(Unit* /*killer*/) override { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -475,8 +463,6 @@ class boss_kaelthas : public CreatureScript Talk(SAY_DEATH); - summons.DespawnAll(); - instance->SetData(DATA_KAELTHASEVENT, 0); for (uint8 i = 0; i < MAX_ADVISORS; ++i) @@ -484,6 +470,7 @@ class boss_kaelthas : public CreatureScript if (Unit* pAdvisor = ObjectAccessor::GetUnit(*me, m_auiAdvisorGuid[i])) pAdvisor->Kill(pAdvisor); } + _JustDied(); } void UpdateAI(uint32 diff) override @@ -1024,10 +1011,8 @@ class boss_thaladred_the_darkener : public CreatureScript { public: - boss_thaladred_the_darkener() - : CreatureScript("boss_thaladred_the_darkener") - { - } + boss_thaladred_the_darkener() : CreatureScript("boss_thaladred_the_darkener") { } + struct boss_thaladred_the_darkenerAI : public advisorbase_ai { boss_thaladred_the_darkenerAI(Creature* creature) : advisorbase_ai(creature) @@ -1130,10 +1115,8 @@ class boss_lord_sanguinar : public CreatureScript { public: - boss_lord_sanguinar() - : CreatureScript("boss_lord_sanguinar") - { - } + boss_lord_sanguinar() : CreatureScript("boss_lord_sanguinar") { } + struct boss_lord_sanguinarAI : public advisorbase_ai { boss_lord_sanguinarAI(Creature* creature) : advisorbase_ai(creature) @@ -1205,10 +1188,8 @@ class boss_grand_astromancer_capernian : public CreatureScript { public: - boss_grand_astromancer_capernian() - : CreatureScript("boss_grand_astromancer_capernian") - { - } + boss_grand_astromancer_capernian() : CreatureScript("boss_grand_astromancer_capernian") { } + struct boss_grand_astromancer_capernianAI : public advisorbase_ai { boss_grand_astromancer_capernianAI(Creature* creature) : advisorbase_ai(creature) @@ -1358,10 +1339,8 @@ class boss_master_engineer_telonicus : public CreatureScript { public: - boss_master_engineer_telonicus() - : CreatureScript("boss_master_engineer_telonicus") - { - } + boss_master_engineer_telonicus() : CreatureScript("boss_master_engineer_telonicus") { } + struct boss_master_engineer_telonicusAI : public advisorbase_ai { boss_master_engineer_telonicusAI(Creature* creature) : advisorbase_ai(creature) @@ -1449,10 +1428,8 @@ class npc_kael_flamestrike : public CreatureScript { public: - npc_kael_flamestrike() - : CreatureScript("npc_kael_flamestrike") - { - } + npc_kael_flamestrike() : CreatureScript("npc_kael_flamestrike") { } + struct npc_kael_flamestrikeAI : public ScriptedAI { npc_kael_flamestrikeAI(Creature* creature) : ScriptedAI(creature) @@ -1482,7 +1459,6 @@ class npc_kael_flamestrike : public CreatureScript void MoveInLineOfSight(Unit* /*who*/) override { } - void EnterCombat(Unit* /*who*/) override { } void UpdateAI(uint32 diff) override @@ -1523,10 +1499,8 @@ class npc_phoenix_tk : public CreatureScript { public: - npc_phoenix_tk() - : CreatureScript("npc_phoenix_tk") - { - } + npc_phoenix_tk() : CreatureScript("npc_phoenix_tk") { } + struct npc_phoenix_tkAI : public ScriptedAI { npc_phoenix_tkAI(Creature* creature) : ScriptedAI(creature) @@ -1585,10 +1559,8 @@ class npc_phoenix_egg_tk : public CreatureScript { public: - npc_phoenix_egg_tk() - : CreatureScript("npc_phoenix_egg_tk") - { - } + npc_phoenix_egg_tk() : CreatureScript("npc_phoenix_egg_tk") { } + struct npc_phoenix_egg_tkAI : public ScriptedAI { npc_phoenix_egg_tkAI(Creature* creature) : ScriptedAI(creature) @@ -1611,7 +1583,6 @@ class npc_phoenix_egg_tk : public CreatureScript //ignore any void MoveInLineOfSight(Unit* /*who*/) override { } - void AttackStart(Unit* who) override { if (me->Attack(who, false)) diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp index 9186b491fa4..29504166846 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Void_Reaver -SD%Complete: 90 -SDComment: Should reset if raid are out of room. -SDCategory: Tempest Keep, The Eye -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "the_eye.h" @@ -43,48 +35,35 @@ enum Spells SPELL_BERSERK = 27680 }; +enum Events +{ + EVENT_POUNDING = 1, + EVENT_ARCANE_ORB, + EVENT_KNOCK_AWAY, + EVENT_BERSERK +}; + class boss_void_reaver : public CreatureScript { public: + boss_void_reaver() : CreatureScript("boss_void_reaver") { } - boss_void_reaver() - : CreatureScript("boss_void_reaver") - { - } - - struct boss_void_reaverAI : public ScriptedAI + struct boss_void_reaverAI : public BossAI { - boss_void_reaverAI(Creature* creature) : ScriptedAI(creature) + boss_void_reaverAI(Creature* creature) : BossAI(creature, DATA_VOID_REAVER) { Initialize(); - instance = creature->GetInstanceScript(); } void Initialize() { - Pounding_Timer = 15000; - ArcaneOrb_Timer = 3000; - KnockAway_Timer = 30000; - Berserk_Timer = 600000; - Enraged = false; } - InstanceScript* instance; - - uint32 Pounding_Timer; - uint32 ArcaneOrb_Timer; - uint32 KnockAway_Timer; - uint32 Berserk_Timer; - - bool Enraged; - void Reset() override { Initialize(); - - if (me->IsAlive()) - instance->SetData(DATA_VOIDREAVEREVENT, NOT_STARTED); + _Reset(); } void KilledUnit(Unit* /*victim*/) override @@ -96,82 +75,91 @@ class boss_void_reaver : public CreatureScript { Talk(SAY_DEATH); DoZoneInCombat(); - - instance->SetData(DATA_VOIDREAVEREVENT, DONE); + _JustDied(); } void EnterCombat(Unit* /*who*/) override { Talk(SAY_AGGRO); + _EnterCombat(); - instance->SetData(DATA_VOIDREAVEREVENT, IN_PROGRESS); + events.ScheduleEvent(EVENT_POUNDING, 15000); + events.ScheduleEvent(EVENT_ARCANE_ORB, 3000); + events.ScheduleEvent(EVENT_KNOCK_AWAY, 30000); + events.ScheduleEvent(EVENT_BERSERK, 600000); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; - // Pounding - if (Pounding_Timer <= diff) - { - DoCastVictim(SPELL_POUNDING); - Talk(SAY_POUNDING); - Pounding_Timer = 15000; //cast time(3000) + cooldown time(12000) - } - else - Pounding_Timer -= diff; - // Arcane Orb - if (ArcaneOrb_Timer <= diff) - { - Unit* target = NULL; - std::list<HostileReference*> t_list = me->getThreatManager().getThreatList(); - std::vector<Unit*> target_list; - for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) - { - target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); - if (!target) - continue; - // exclude pets & totems, 18 yard radius minimum - if (target->GetTypeId() == TYPEID_PLAYER && target->IsAlive() && !target->IsWithinDist(me, 18, false)) - target_list.push_back(target); - target = NULL; - } - if (!target_list.empty()) - target = *(target_list.begin() + rand32() % target_list.size()); - else - target = me->GetVictim(); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (target) - me->CastSpell(target, SPELL_ARCANE_ORB, false, NULL, NULL); - ArcaneOrb_Timer = 3000; - } - else - ArcaneOrb_Timer -= diff; - // Single Target knock back, reduces aggro - if (KnockAway_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCastVictim(SPELL_KNOCK_AWAY); - //Drop 25% aggro - if (DoGetThreat(me->GetVictim())) - DoModifyThreatPercent(me->GetVictim(), -25); - KnockAway_Timer = 30000; - } - else - KnockAway_Timer -= diff; - //Berserk - if (Berserk_Timer < diff && !Enraged) - { - DoCast(me, SPELL_BERSERK); - Enraged = true; + switch (eventId) + { + case EVENT_POUNDING: + DoCastVictim(SPELL_POUNDING); + Talk(SAY_POUNDING); + events.ScheduleEvent(EVENT_POUNDING, 15000); + break; + case EVENT_ARCANE_ORB: + { + Unit* target = NULL; + std::list<HostileReference*> t_list = me->getThreatManager().getThreatList(); + std::vector<Unit*> target_list; + for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr) + { + target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); + if (!target) + continue; + // exclude pets & totems, 18 yard radius minimum + if (target->GetTypeId() == TYPEID_PLAYER && target->IsAlive() && !target->IsWithinDist(me, 18, false)) + target_list.push_back(target); + target = NULL; + } + + if (!target_list.empty()) + target = *(target_list.begin() + rand32() % target_list.size()); + else + target = me->GetVictim(); + + if (target) + me->CastSpell(target, SPELL_ARCANE_ORB, false, NULL, NULL); + + events.ScheduleEvent(EVENT_ARCANE_ORB, 3000); + break; + } + case EVENT_KNOCK_AWAY: + DoCastVictim(SPELL_KNOCK_AWAY); + // Drop 25% aggro + if (DoGetThreat(me->GetVictim())) + DoModifyThreatPercent(me->GetVictim(), -25); + + events.ScheduleEvent(EVENT_KNOCK_AWAY, 30000); + break; + case EVENT_BERSERK: + if (!Enraged) + { + DoCast(me, SPELL_BERSERK); + Enraged = true; + } + break; + default: + break; + } } - else - Berserk_Timer -= diff; DoMeleeAttackIfReady(); EnterEvadeIfOutOfCombatArea(diff); } + + private: + bool Enraged; }; CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp index 38c9cdd487c..c421b9974ce 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/instance_the_eye.cpp @@ -27,8 +27,6 @@ EndScriptData */ #include "InstanceScript.h" #include "the_eye.h" -#define MAX_ENCOUNTER 5 - /* The Eye encounters: 0 - Kael'thas event 1 - Al' ar event @@ -39,20 +37,16 @@ EndScriptData */ class instance_the_eye : public InstanceMapScript { public: - instance_the_eye() - : InstanceMapScript("instance_the_eye", 550) - { - } + instance_the_eye() : InstanceMapScript("instance_the_eye", 550) { } struct instance_the_eye_InstanceMapScript : public InstanceScript { instance_the_eye_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + SetBossNumber(EncounterCount); KaelthasEventPhase = 0; - AlarEventPhase = 0; } ObjectGuid ThaladredTheDarkener; @@ -63,44 +57,34 @@ class instance_the_eye : public InstanceMapScript ObjectGuid Astromancer; ObjectGuid Alar; uint8 KaelthasEventPhase; - uint8 AlarEventPhase; - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; - } void OnCreatureCreate(Creature* creature) override { switch (creature->GetEntry()) { - case 20064: - ThaladredTheDarkener = creature->GetGUID(); - break; - case 20063: - MasterEngineerTelonicus = creature->GetGUID(); - break; - case 20062: - GrandAstromancerCapernian = creature->GetGUID(); - break; - case 20060: - LordSanguinar = creature->GetGUID(); - break; - case 19622: - Kaelthas = creature->GetGUID(); - break; - case 18805: - Astromancer = creature->GetGUID(); - break; - case 19514: - Alar = creature->GetGUID(); - break; + case NPC_SANGUINAR: + LordSanguinar = creature->GetGUID(); + break; + case NPC_CAPERNIAN: + GrandAstromancerCapernian = creature->GetGUID(); + break; + case NPC_TELONICUS: + MasterEngineerTelonicus = creature->GetGUID(); + break; + case NPC_THALADRED: + ThaladredTheDarkener = creature->GetGUID(); + break; + case NPC_KAELTHAS: + Kaelthas = creature->GetGUID(); + break; + case NPC_HIGH_ASTROMANCER_SOLARIAN: + Astromancer = creature->GetGUID(); + break; + case NPC_ALAR: + Alar = creature->GetGUID(); + break; + default: + break; } } @@ -113,7 +97,7 @@ class instance_the_eye : public InstanceMapScript case DATA_GRANDASTROMANCERCAPERNIAN: return GrandAstromancerCapernian; case DATA_MASTERENGINEERTELONICUS: return MasterEngineerTelonicus; case DATA_KAELTHAS: return Kaelthas; - case DATA_ASTROMANCER: return Astromancer; + case DATA_HIGH_ASTROMANCER_SOLARIAN: return Astromancer; case DATA_ALAR: return Alar; } return ObjectGuid::Empty; @@ -123,64 +107,23 @@ class instance_the_eye : public InstanceMapScript { switch (type) { - case DATA_ALAREVENT: - AlarEventPhase = data; - m_auiEncounter[0] = data; - break; - case DATA_HIGHASTROMANCERSOLARIANEVENT: - m_auiEncounter[1] = data; - break; - case DATA_VOIDREAVEREVENT: - m_auiEncounter[2] = data; - break; - case DATA_KAELTHASEVENT: - KaelthasEventPhase = data; - m_auiEncounter[3] = data; - break; + case DATA_KAELTHASEVENT: + KaelthasEventPhase = data; + break; + default: + break; } - if (data == DONE) - SaveToDB(); } uint32 GetData(uint32 type) const override { switch (type) { - case DATA_ALAREVENT: return AlarEventPhase; - case DATA_HIGHASTROMANCERSOLARIANEVENT: return m_auiEncounter[1]; - case DATA_VOIDREAVEREVENT: return m_auiEncounter[2]; - case DATA_KAELTHASEVENT: return KaelthasEventPhase; + case DATA_KAELTHASEVENT: + return KaelthasEventPhase; } return 0; } - - std::string GetSaveData() override - { - OUT_SAVE_INST_DATA; - - std::ostringstream stream; - stream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3]; - - OUT_SAVE_INST_DATA_COMPLETE; - return stream.str(); - } - - void Load(const char* in) override - { - if (!in) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - OUT_LOAD_INST_DATA(in); - - std::istringstream stream(in); - stream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3]; - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. - m_auiEncounter[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; - } }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h index 718f37861d9..c46fe408274 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h +++ b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.h @@ -21,19 +21,33 @@ #define DataHeader "TE" +uint32 const EncounterCount = 4; + enum DataTypes { - DATA_ALAREVENT = 1, - DATA_ASTROMANCER = 2, - DATA_GRANDASTROMANCERCAPERNIAN = 3, - DATA_HIGHASTROMANCERSOLARIANEVENT = 4, - DATA_KAELTHAS = 5, + // Encounter States/Boss GUIDs + DATA_KAELTHAS = 0, + DATA_ALAR = 1, + DATA_HIGH_ASTROMANCER_SOLARIAN = 2, + DATA_VOID_REAVER = 3, + + DATA_ASTROMANCER = 4, + DATA_GRANDASTROMANCERCAPERNIAN = 5, DATA_KAELTHASEVENT = 6, DATA_LORDSANGUINAR = 7, DATA_MASTERENGINEERTELONICUS = 8, - DATA_THALADREDTHEDARKENER = 10, - DATA_VOIDREAVEREVENT = 11, - DATA_ALAR = 12 + DATA_THALADREDTHEDARKENER = 9 +}; + +enum CreatureIds +{ + NPC_SANGUINAR = 20060, + NPC_CAPERNIAN = 20062, + NPC_TELONICUS = 20063, + NPC_THALADRED = 20064, + NPC_KAELTHAS = 19622, + NPC_HIGH_ASTROMANCER_SOLARIAN = 18805, + NPC_ALAR = 19514 }; #endif diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index f3c8396832c..87bd5923c8f 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -338,7 +338,7 @@ class spell_q11396_11399_scourging_crystal_controller : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q11396_11399_scourging_crystal_controller_SpellScript(); - }; + } }; // 43882 Scourging Crystal Controller Dummy @@ -374,7 +374,7 @@ class spell_q11396_11399_scourging_crystal_controller_dummy : public SpellScript SpellScript* GetSpellScript() const override { return new spell_q11396_11399_scourging_crystal_controller_dummy_SpellScript(); - }; + } }; // http://www.wowhead.com/quest=11515 Blood for Blood @@ -855,7 +855,7 @@ class spell_symbol_of_life_dummy : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_symbol_of_life_dummy_SpellScript(); - }; + } }; // http://www.wowhead.com/quest=12659 Scalps! @@ -898,7 +898,7 @@ class spell_q12659_ahunaes_knife : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q12659_ahunaes_knife_SpellScript(); - }; + } }; enum StoppingTheSpread @@ -944,7 +944,7 @@ class spell_q9874_liquid_fire : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q9874_liquid_fire_SpellScript(); - }; + } }; enum SalvagingLifesStength @@ -988,7 +988,7 @@ class spell_q12805_lifeblood_dummy : public SpellScriptLoader SpellScript* GetSpellScript() const override { return new spell_q12805_lifeblood_dummy_SpellScript(); - }; + } }; /* diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h index dc9e948966d..e83340bdd84 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -38,6 +38,7 @@ #include <queue> #include <sstream> #include <algorithm> +#include <memory> #include <boost/optional.hpp> #include <boost/utility/in_place_factory.hpp> @@ -164,4 +165,14 @@ struct LocalizedString template <typename T> using Optional = boost::optional<T>; +namespace Trinity +{ + //! std::make_unique implementation (TODO: remove this once C++14 is supported) + template<typename T, typename ...Args> + std::unique_ptr<T> make_unique(Args&& ...args) + { + return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); + } +} + #endif diff --git a/src/server/shared/Cryptography/SHA1.h b/src/server/shared/Cryptography/SHA1.h index ebd9f721d4a..f59bdc25556 100644 --- a/src/server/shared/Cryptography/SHA1.h +++ b/src/server/shared/Cryptography/SHA1.h @@ -39,8 +39,8 @@ class SHA1Hash void Initialize(); void Finalize(); - uint8 *GetDigest(void) { return mDigest; }; - int GetLength(void) const { return SHA_DIGEST_LENGTH; }; + uint8 *GetDigest(void) { return mDigest; } + int GetLength(void) const { return SHA_DIGEST_LENGTH; } private: SHA_CTX mC; diff --git a/src/server/shared/Cryptography/SHA256.h b/src/server/shared/Cryptography/SHA256.h index 659236f9495..1d85545b2e0 100644 --- a/src/server/shared/Cryptography/SHA256.h +++ b/src/server/shared/Cryptography/SHA256.h @@ -38,8 +38,8 @@ class SHA256Hash void Initialize(); void Finalize(); - uint8 *GetDigest(void) { return mDigest; }; - int GetLength(void) const { return SHA256_DIGEST_LENGTH; }; + uint8 *GetDigest(void) { return mDigest; } + int GetLength(void) const { return SHA256_DIGEST_LENGTH; } private: SHA256_CTX mC; diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h index 4ce77c1cd28..c541a6651a3 100644 --- a/src/server/shared/DataStores/DB2Store.h +++ b/src/server/shared/DataStores/DB2Store.h @@ -112,6 +112,8 @@ public: void EraseRecord(uint32 id) override { if (id < _indexTableSize) _indexTable.AsT[id] = nullptr; } T const* LookupEntry(uint32 id) const { return (id >= _indexTableSize) ? nullptr : _indexTable.AsT[id]; } + T const* AssertEntry(uint32 id) const { return ASSERT_NOTNULL(LookupEntry(id)); } + std::string const& GetFileName() const { return _fileName; } uint32 GetNumRows() const { return _indexTableSize; } char const* GetFormat() const { return _format; } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 6c18a0e76ee..277ccd4569a 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -681,4 +681,21 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE, "UPDATE quest_tracker SET completed_by_gm = 1 WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_QUEST_TRACK_COMPLETE_TIME, "UPDATE quest_tracker SET quest_complete_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME, "UPDATE quest_tracker SET quest_abandon_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); + + // Garrison + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON, "SELECT siteLevelId, followerActivationsRemainingToday FROM character_garrison WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON, "INSERT INTO character_garrison (guid, siteLevelId, followerActivationsRemainingToday) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON, "DELETE FROM character_garrison WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS, "UPDATE character_garrison SET followerActivationsRemainingToday = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, "SELECT buildingId FROM character_garrison_blueprints WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, "INSERT INTO character_garrison_blueprints (guid, buildingId) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, "DELETE FROM character_garrison_blueprints WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, "SELECT plotInstanceId, buildingId, timeBuilt, active FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_BUILDINGS, "INSERT INTO character_garrison_buildings (guid, plotInstanceId, buildingId, timeBuilt, active) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, "DELETE FROM character_garrison_buildings WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, "SELECT dbId, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status FROM character_garrison_followers WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, "INSERT INTO character_garrison_followers (dbId, guid, followerId, quality, level, itemLevelWeapon, itemLevelArmor, xp, currentBuilding, currentMission, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, "DELETE gfab, gf FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE gf.guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "SELECT gfab.dbId, gfab.abilityId FROM character_garrison_follower_abilities gfab INNER JOIN character_garrison_followers gf ON gfab.dbId = gf.dbId WHERE guid = ? ORDER BY gfab.slot", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES, "INSERT INTO character_garrison_follower_abilities (dbId, abilityId, slot) VALUES (?, ?, ?)", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index ed3b6dd8098..fc9c930e6b1 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -598,6 +598,22 @@ enum CharacterDatabaseStatements CHAR_UPD_QUEST_TRACK_COMPLETE_TIME, CHAR_UPD_QUEST_TRACK_ABANDON_TIME, + CHAR_SEL_CHARACTER_GARRISON, + CHAR_INS_CHARACTER_GARRISON, + CHAR_DEL_CHARACTER_GARRISON, + CHAR_UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS, + CHAR_SEL_CHARACTER_GARRISON_BLUEPRINTS, + CHAR_INS_CHARACTER_GARRISON_BLUEPRINTS, + CHAR_DEL_CHARACTER_GARRISON_BLUEPRINTS, + CHAR_SEL_CHARACTER_GARRISON_BUILDINGS, + CHAR_INS_CHARACTER_GARRISON_BUILDINGS, + CHAR_DEL_CHARACTER_GARRISON_BUILDINGS, + CHAR_SEL_CHARACTER_GARRISON_FOLLOWERS, + CHAR_INS_CHARACTER_GARRISON_FOLLOWERS, + CHAR_DEL_CHARACTER_GARRISON_FOLLOWERS, + CHAR_SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES, + CHAR_INS_CHARACTER_GARRISON_FOLLOWER_ABILITIES, + MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.cpp b/src/server/shared/Database/Implementation/HotfixDatabase.cpp index e13863d9326..a7043b1d5ff 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/shared/Database/Implementation/HotfixDatabase.cpp @@ -39,12 +39,70 @@ void HotfixDatabaseConnection::DoPrepareStatements() PREPARE_LOCALE_STMT(HOTFIX_SEL_BROADCAST_TEXT, "SELECT ID, MaleText_lang, FemaleText_lang FROM broadcast_text_locale WHERE locale = ?", CONNECTION_SYNCH); // CurrencyTypes.db2 - PrepareStatement(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, CategoryID, Name, InventoryIcon1, InventoryIcon2, SpellWeight, SpellCategory, MaxQty, MaxEarnablePerWeek, Flags, Quality, Description FROM currency_types ORDER BY ID DESC", CONNECTION_SYNCH); - PREPARE_LOCALE_STMT(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, Name_lang, InventoryIcon1_lang, InventoryIcon2_lang, Description_lang FROM currency_types_locale WHERE locale = ?", CONNECTION_SYNCH); + PrepareStatement(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, CategoryID, Name, InventoryIcon1, InventoryIcon2, SpellWeight, SpellCategory, " + "MaxQty, MaxEarnablePerWeek, Flags, Quality, Description FROM currency_types ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_CURRENCY_TYPES, "SELECT ID, Name_lang, InventoryIcon1_lang, InventoryIcon2_lang, " + "Description_lang FROM currency_types_locale WHERE locale = ?", CONNECTION_SYNCH); // CurvePoint.db2 PrepareStatement(HOTFIX_SEL_CURVE_POINT, "SELECT ID, CurveID, `Index`, X, Y FROM curve_point ORDER BY ID DESC", CONNECTION_SYNCH); + // GameObjects.db2 + PrepareStatement(HOTFIX_SEL_GAMEOBJECTS, "SELECT ID, MapID, DisplayID, PositionX, PositionY, PositionZ, RotationX, RotationY, RotationZ, RotationW, Size, " + "PhaseUseFlags, PhaseID, PhaseGroupID, Type, Data0, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Name FROM gameobjects ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GAMEOBJECTS, "SELECT ID, Name_lang FROM gameobjects_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrAbility.db2 + PrepareStatement(HOTFIX_SEL_GARR_ABILITY, "SELECT ID, Flags, Name, Description, IconFileDataID, OtherFactionGarrAbilityID, " + "GarrAbilityCategoryID FROM garr_ability ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_ABILITY, "SELECT ID, Name_lang, Description_lang FROM garr_ability_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrBuilding.db2 + PrepareStatement(HOTFIX_SEL_GARR_BUILDING, "SELECT ID, HordeGameObjectID, AllianceGameObjectID, Unknown, Type, Level, NameAlliance, NameHorde, Description, " + "Tooltip, BuildDuration, CostCurrencyID, CostCurrencyAmount, HordeTexPrefixKitID, AllianceTexPrefixKitID, IconFileDataID, BonusAmount, Flags, " + "AllianceActivationScenePackageID, HordeActivationScenePackageID, MaxShipments, FollowerRequiredGarrAbilityID, FollowerGarrAbilityEffectID, CostMoney " + "FROM garr_building ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_BUILDING, "SELECT ID, NameAlliance_lang, NameHorde_lang, Description_lang, Tooltip_lang " + "FROM garr_building_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrBuildingPlotInst.db2 + PrepareStatement(HOTFIX_SEL_GARR_BUILDING_PLOT_INST, "SELECT ID, GarrBuildingID, UiTextureAtlasMemberID, GarrSiteLevelPlotInstID, " + "LandmarkOffsetX, LandmarkOffsetY FROM garr_building_plot_inst ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrClassSpec.db2 + PrepareStatement(HOTFIX_SEL_GARR_CLASS_SPEC, "SELECT ID, NameMale, NameFemale, NameGenderless, ClassAtlasID, GarrFollItemSetID " + "FROM garr_class_spec ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_CLASS_SPEC, "SELECT ID, NameMale_lang, NameFemale_lang, NameGenderless_lang FROM garr_class_spec_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrFollower.db2 + PrepareStatement(HOTFIX_SEL_GARR_FOLLOWER, "SELECT ID, HordeCreatureID, AllianceCreatureID, HordeUiAnimRaceInfoID, AllianceUiAnimRaceInfoID, Quality, " + "HordeGarrClassSpecID, AllianceGarrClassSpecID, HordeGarrFollItemSetID, AllianceGarrFollItemSetID, Level, ItemLevelWeapon, ItemLevelArmor, Unknown1, Flags, " + "HordeSourceText, AllianceSourceText, Unknown2, Unknown3, HordePortraitIconID, AlliancePortraitIconID FROM garr_follower ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_FOLLOWER, "SELECT ID, HordeSourceText_lang, AllianceSourceText_lang FROM garr_follower_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrFollowerXAbility.db2 + PrepareStatement(HOTFIX_SEL_GARR_FOLLOWER_X_ABILITY, "SELECT ID, GarrFollowerID, GarrAbilityID, FactionIndex FROM garr_follower_x_ability ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrPlot.db2 + PrepareStatement(HOTFIX_SEL_GARR_PLOT, "SELECT ID, GarrPlotUICategoryID, PlotType, Flags, Name, MinCount, MaxCount, " + "AllianceConstructionGameObjectID, HordeConstructionGameObjectID FROM garr_plot ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_PLOT, "SELECT ID, Name_lang FROM garr_plot_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrPlotBuilding.db2 + PrepareStatement(HOTFIX_SEL_GARR_PLOT_BUILDING, "SELECT ID, GarrPlotID, GarrBuildingID FROM garr_plot_building ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrPlotInstance.db2 + PrepareStatement(HOTFIX_SEL_GARR_PLOT_INSTANCE, "SELECT ID, GarrPlotID, Name FROM garr_plot_instance ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_GARR_PLOT_INSTANCE, "SELECT ID, Name_lang FROM garr_plot_instance_locale WHERE locale = ?", CONNECTION_SYNCH); + + // GarrSiteLevel.db2 + PrepareStatement(HOTFIX_SEL_GARR_SITE_LEVEL, "SELECT ID, Level, MapID, SiteID, UITextureKitID, TownHallX, TownHallY, MovieID, Level2, " + "UpgradeResourceCost, UpgradeMoneyCost FROM garr_site_level ORDER BY ID DESC", CONNECTION_SYNCH); + + // GarrSiteLevelPlotInst.db2 + PrepareStatement(HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST, "SELECT ID, GarrSiteLevelID, GarrPlotInstanceID, LandmarkX, LandmarkY, " + "Unknown FROM garr_site_level_plot_inst ORDER BY ID DESC", CONNECTION_SYNCH); + // Holidays.db2 PrepareStatement(HOTFIX_SEL_HOLIDAYS, "SELECT ID, Duration1, Duration2, Duration3, Duration4, Duration5, Duration6, Duration7, Duration8, Duration9, Duration10, " "Date1, Date2, Date3, Date4, Date5, Date6, Date7, Date8, Date9, Date10, Date11, Date12, Date13, Date14, Date15, Date16, Region, Looping, " diff --git a/src/server/shared/Database/Implementation/HotfixDatabase.h b/src/server/shared/Database/Implementation/HotfixDatabase.h index 3d8e528cd98..4adf555dc2f 100644 --- a/src/server/shared/Database/Implementation/HotfixDatabase.h +++ b/src/server/shared/Database/Implementation/HotfixDatabase.h @@ -54,6 +54,37 @@ enum HotfixDatabaseStatements HOTFIX_SEL_CURVE_POINT, + HOTFIX_SEL_GAMEOBJECTS, + HOTFIX_SEL_GAMEOBJECTS_LOCALE, + + HOTFIX_SEL_GARR_ABILITY, + HOTFIX_SEL_GARR_ABILITY_LOCALE, + + HOTFIX_SEL_GARR_BUILDING, + HOTFIX_SEL_GARR_BUILDING_LOCALE, + + HOTFIX_SEL_GARR_BUILDING_PLOT_INST, + + HOTFIX_SEL_GARR_CLASS_SPEC, + HOTFIX_SEL_GARR_CLASS_SPEC_LOCALE, + + HOTFIX_SEL_GARR_FOLLOWER, + HOTFIX_SEL_GARR_FOLLOWER_LOCALE, + + HOTFIX_SEL_GARR_FOLLOWER_X_ABILITY, + + HOTFIX_SEL_GARR_PLOT, + HOTFIX_SEL_GARR_PLOT_LOCALE, + + HOTFIX_SEL_GARR_PLOT_BUILDING, + + HOTFIX_SEL_GARR_PLOT_INSTANCE, + HOTFIX_SEL_GARR_PLOT_INSTANCE_LOCALE, + + HOTFIX_SEL_GARR_SITE_LEVEL, + + HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST, + HOTFIX_SEL_HOLIDAYS, HOTFIX_SEL_HOLIDAYS_LOCALE, @@ -86,7 +117,7 @@ enum HotfixDatabaseStatements HOTFIX_SEL_OVERRIDE_SPELL_DATA, HOTFIX_SEL_PHASE_GROUP, - + HOTFIX_SEL_QUEST_PACKAGE_ITEM, HOTFIX_SEL_SOUND_ENTRIES, diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 70350f3136c..0b2967f8922 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -46,7 +46,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_IP_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_IP_NOT_BANNED, "DELETE FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET unbandate = UNIX_TIMESTAMP(), active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM, "DELETE FROM realmcharacters WHERE acctid = ? AND realmid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); @@ -124,7 +124,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_EMAIL_BY_ID, "SELECT email FROM battlenet_accounts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_EMAIL, "SELECT id FROM battlenet_accounts WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_PASSWORD, "UPDATE battlenet_accounts SET v = '', s = '', sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = ? AND sha_pass_hash = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BNET_CHECK_PASSWORD, "SELECT 1 FROM battlenet_accounts WHERE id = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK, "UPDATE battlenet_accounts SET locked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY, "UPDATE battlenet_accounts SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, "SELECT battlenet_account FROM account WHERE id = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index f8f641a9ea7..e50cf42e439 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -61,6 +61,7 @@ HANDLE WheatyExceptionReport::m_hDumpFile; HANDLE WheatyExceptionReport::m_hProcess; SymbolPairs WheatyExceptionReport::symbols; std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; +bool WheatyExceptionReport::stackOverflowException; // Declare global instance of class WheatyExceptionReport g_WheatyExceptionReport; @@ -72,6 +73,7 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor // Install the unhandled exception filter function m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); m_hProcess = GetCurrentProcess(); + stackOverflowException = false; if (!IsDebuggerPresent()) { _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); @@ -97,6 +99,9 @@ WheatyExceptionReport::~WheatyExceptionReport() LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter( PEXCEPTION_POINTERS pExceptionInfo) { + if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) + stackOverflowException = true; + TCHAR module_folder_name[MAX_PATH]; GetModuleFileName(0, module_folder_name, MAX_PATH); TCHAR* pos = _tcsrchr(module_folder_name, '\\'); @@ -419,107 +424,114 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables) void WheatyExceptionReport::GenerateExceptionReport( PEXCEPTION_POINTERS pExceptionInfo) { - SYSTEMTIME systime; - GetLocalTime(&systime); - - // Start out with a banner - _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); - _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); - PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; - - PrintSystemInfo(); - // First print information about the type of fault - _tprintf(_T("\r\n//=====================================================\r\n")); - _tprintf(_T("Exception code: %08X %s\r\n"), - pExceptionRecord->ExceptionCode, - GetExceptionString(pExceptionRecord->ExceptionCode)); - - // Now print information about where the fault occured - TCHAR szFaultingModule[MAX_PATH]; - DWORD section; - DWORD_PTR offset; - GetLogicalAddress(pExceptionRecord->ExceptionAddress, - szFaultingModule, - sizeof(szFaultingModule), - section, offset); + __try + { + SYSTEMTIME systime; + GetLocalTime(&systime); + + // Start out with a banner + _tprintf(_T("Revision: %s\r\n"), _FULLVERSION); + _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute); + PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; + + PrintSystemInfo(); + // First print information about the type of fault + _tprintf(_T("\r\n//=====================================================\r\n")); + _tprintf(_T("Exception code: %08X %s\r\n"), + pExceptionRecord->ExceptionCode, + GetExceptionString(pExceptionRecord->ExceptionCode)); + + // Now print information about where the fault occured + TCHAR szFaultingModule[MAX_PATH]; + DWORD section; + DWORD_PTR offset; + GetLogicalAddress(pExceptionRecord->ExceptionAddress, + szFaultingModule, + sizeof(szFaultingModule), + section, offset); #ifdef _M_IX86 - _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); + _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); #endif #ifdef _M_X64 - _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), - pExceptionRecord->ExceptionAddress, - section, offset, szFaultingModule); + _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"), + pExceptionRecord->ExceptionAddress, + section, offset, szFaultingModule); #endif - PCONTEXT pCtx = pExceptionInfo->ContextRecord; + PCONTEXT pCtx = pExceptionInfo->ContextRecord; - // Show the registers - #ifdef _M_IX86 // X86 Only! - _tprintf(_T("\r\nRegisters:\r\n")); + // Show the registers +#ifdef _M_IX86 // X86 Only! + _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") - , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, - pCtx->Esi, pCtx->Edi); + _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n") + , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, + pCtx->Esi, pCtx->Edi); - _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); - _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), - pCtx->SegSs, pCtx->Esp, pCtx->Ebp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); - #endif + _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip); + _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"), + pCtx->SegSs, pCtx->Esp, pCtx->Ebp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); +#endif - #ifdef _M_X64 - _tprintf(_T("\r\nRegisters:\r\n")); - _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") - _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") - , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, - pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); - _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); - _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), - pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); - _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), - pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); - _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); - #endif +#ifdef _M_X64 + _tprintf(_T("\r\nRegisters:\r\n")); + _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n") + _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n") + , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx, + pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15); + _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip); + _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"), + pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); + _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), + pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); + _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags); +#endif - SymSetOptions(SYMOPT_DEFERRED_LOADS); + SymSetOptions(SYMOPT_DEFERRED_LOADS); - // Initialize DbgHelp - if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) - { - _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), - ErrorMessage(GetLastError())); - } + // Initialize DbgHelp + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) + { + _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"), + ErrorMessage(GetLastError())); + } - CONTEXT trashableContext = *pCtx; + CONTEXT trashableContext = *pCtx; - WriteStackDetails(&trashableContext, false, NULL); - printTracesForAllThreads(false); + WriteStackDetails(&trashableContext, false, NULL); + printTracesForAllThreads(false); -// #ifdef _M_IX86 // X86 Only! + // #ifdef _M_IX86 // X86 Only! - _tprintf(_T("========================\r\n")); - _tprintf(_T("Local Variables And Parameters\r\n")); + _tprintf(_T("========================\r\n")); + _tprintf(_T("Local Variables And Parameters\r\n")); - trashableContext = *pCtx; - WriteStackDetails(&trashableContext, true, NULL); - printTracesForAllThreads(true); + trashableContext = *pCtx; + WriteStackDetails(&trashableContext, true, NULL); + printTracesForAllThreads(true); - /*_tprintf(_T("========================\r\n")); - _tprintf(_T("Global Variables\r\n")); + /*_tprintf(_T("========================\r\n")); + _tprintf(_T("Global Variables\r\n")); - SymEnumSymbols(GetCurrentProcess(), + SymEnumSymbols(GetCurrentProcess(), (UINT_PTR)GetModuleHandle(szFaultingModule), 0, EnumerateSymbolsCallback, 0);*/ - // #endif // X86 Only! + // #endif // X86 Only! - SymCleanup(GetCurrentProcess()); + SymCleanup(GetCurrentProcess()); - _tprintf(_T("\r\n")); + _tprintf(_T("\r\n")); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + _tprintf(_T("Error writing the crash log\r\n")); + } } //====================================================================== @@ -1313,16 +1325,43 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address) //============================================================================ int __cdecl WheatyExceptionReport::_tprintf(const TCHAR * format, ...) { - TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; int retValue; - DWORD cbWritten; va_list argptr; - va_start(argptr, format); + if (stackOverflowException) + { + retValue = heapprintf(format, argptr); + va_end(argptr); + } + else + { + retValue = stackprintf(format, argptr); + va_end(argptr); + } + + return retValue; +} + +int __cdecl WheatyExceptionReport::stackprintf(const TCHAR * format, va_list argptr) +{ + int retValue; + DWORD cbWritten; + + TCHAR szBuff[WER_LARGE_BUFFER_SIZE]; retValue = vsprintf(szBuff, format, argptr); - va_end(argptr); + WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + return retValue; +} + +int __cdecl WheatyExceptionReport::heapprintf(const TCHAR * format, va_list argptr) +{ + int retValue; + DWORD cbWritten; + TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE); + retValue = vsprintf(szBuff, format, argptr); WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0); + free(szBuff); return retValue; } diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index b7731daaa2b..101b6187f2b 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -178,6 +178,8 @@ class WheatyExceptionReport static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); static int __cdecl _tprintf(const TCHAR * format, ...); + static int __cdecl stackprintf(const TCHAR * format, va_list argptr); + static int __cdecl heapprintf(const TCHAR * format, va_list argptr); static bool StoreSymbol(DWORD type , DWORD_PTR offset); static void ClearSymbols(); @@ -191,6 +193,7 @@ class WheatyExceptionReport static HANDLE m_hProcess; static SymbolPairs symbols; static std::stack<SymbolDetail> symbolDetails; + static bool stackOverflowException; static char* PushSymbolDetail(char* pszCurrBuffer); static char* PopSymbolDetail(char* pszCurrBuffer); diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index e22a06e635e..5b3782fce55 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -23,6 +23,7 @@ #include "Appender.h" #include "Logger.h" #include "StringFormat.h" +#include "Common.h" #include <boost/asio/io_service.hpp> #include <boost/asio/strand.hpp> @@ -64,7 +65,7 @@ class Log template<typename... Args> inline void outMessage(std::string const& filter, LogLevel const level, const char* fmt, Args const&... args) { - write(std::unique_ptr<LogMessage>(new LogMessage(level, filter, Trinity::StringFormat(fmt, args...)))); + write(Trinity::make_unique<LogMessage>(level, filter, Trinity::StringFormat(fmt, args...))); } template<typename... Args> @@ -73,7 +74,7 @@ class Log if (!ShouldLog("commands.gm", LOG_LEVEL_INFO)) return; - std::unique_ptr<LogMessage> msg(new LogMessage(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...)))); + std::unique_ptr<LogMessage> msg = Trinity::make_unique<LogMessage>(LOG_LEVEL_INFO, "commands.gm", std::move(Trinity::StringFormat(fmt, args...))); msg->param1 = std::to_string(account); diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h index 802442b5c31..d0c65f05c3d 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/server/shared/Networking/MessageBuffer.h @@ -55,9 +55,9 @@ public: uint8* GetBasePointer() { return _storage.data(); } - uint8* GetReadPointer() { return &_storage[_rpos]; } + uint8* GetReadPointer() { return GetBasePointer() + _rpos; } - uint8* GetWritePointer() { return &_storage[_wpos]; } + uint8* GetWritePointer() { return GetBasePointer() + _wpos; } void ReadCompleted(size_type bytes) { _rpos += bytes; } diff --git a/src/server/shared/PrecompiledHeaders/sharedPCH.h b/src/server/shared/PrecompiledHeaders/sharedPCH.h index d0c15b17f0c..87af9f44eb7 100644 --- a/src/server/shared/PrecompiledHeaders/sharedPCH.h +++ b/src/server/shared/PrecompiledHeaders/sharedPCH.h @@ -6,3 +6,4 @@ #include "SQLOperation.h" #include "Errors.h" #include "TypeList.h" +#include "TaskScheduler.h" diff --git a/src/server/shared/Updater/DBUpdater.cpp b/src/server/shared/Updater/DBUpdater.cpp index 9806151b4c4..10c8c163ec4 100644 --- a/src/server/shared/Updater/DBUpdater.cpp +++ b/src/server/shared/Updater/DBUpdater.cpp @@ -381,8 +381,27 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos args.push_back("-h" + host); args.push_back("-u" + user); args.push_back("-p" + password); + + // Check if we want to connect through ip or socket (Unix only) +#ifdef _WIN32 + args.push_back("-P" + port_or_socket); +#else + + if (!std::isdigit(port_or_socket[0])) + { + // We can't check here if host == "." because is named localhost if socket option is enabled + args.push_back("-P0"); + args.push_back("--protocol=SOCKET"); + args.push_back("-S" + port_or_socket); + } + else + // generic case + args.push_back("-P" + port_or_socket); + +#endif + // Set the default charset to utf8 args.push_back("--default-character-set=utf8"); diff --git a/src/server/shared/Utilities/TaskScheduler.cpp b/src/server/shared/Utilities/TaskScheduler.cpp new file mode 100644 index 00000000000..4b261413fd9 --- /dev/null +++ b/src/server/shared/Utilities/TaskScheduler.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "TaskScheduler.h" + +TaskScheduler& TaskScheduler::Update() +{ + _now = clock_t::now(); + Dispatch(); + return *this; +} + +TaskScheduler& TaskScheduler::Update(size_t const milliseconds) +{ + return Update(std::chrono::milliseconds(milliseconds)); +} + +TaskScheduler& TaskScheduler::Async(std::function<void()> const& callable) +{ + _asyncHolder.push(callable); + return *this; +} + +TaskScheduler& TaskScheduler::CancelAll() +{ + /// Clear the task holder + _task_holder.Clear(); + _asyncHolder = AsyncHolder(); + return *this; +} + +TaskScheduler& TaskScheduler::CancelGroup(group_t const group) +{ + _task_holder.RemoveIf([group](TaskContainer const& task) -> bool + { + return task->IsInGroup(group); + }); + return *this; +} + +TaskScheduler& TaskScheduler::CancelGroupsOf(std::vector<group_t> const& groups) +{ + std::for_each(groups.begin(), groups.end(), + std::bind(&TaskScheduler::CancelGroup, this, std::placeholders::_1)); + + return *this; +} + +TaskScheduler& TaskScheduler::InsertTask(TaskContainer task) +{ + _task_holder.Push(std::move(task)); + return *this; +} + +void TaskScheduler::Dispatch() +{ + // Process all asyncs + while (!_asyncHolder.empty()) + { + _asyncHolder.front()(); + _asyncHolder.pop(); + } + + while (!_task_holder.IsEmpty()) + { + if (_task_holder.First()->_end > _now) + break; + + // Perfect forward the context to the handler + // Use weak references to catch destruction before callbacks. + TaskContext context(_task_holder.Pop(), std::weak_ptr<TaskScheduler>(self_reference)); + + // Invoke the context + context.Invoke(); + } +} + +void TaskScheduler::TaskQueue::Push(TaskContainer&& task) +{ + container.insert(task); +} + +auto TaskScheduler::TaskQueue::Pop() -> TaskContainer +{ + TaskContainer result = *container.begin(); + container.erase(container.begin()); + return result; +} + +auto TaskScheduler::TaskQueue::First() const -> TaskContainer const& +{ + return *container.begin(); +} + +void TaskScheduler::TaskQueue::Clear() +{ + container.clear(); +} + +void TaskScheduler::TaskQueue::RemoveIf(std::function<bool(TaskContainer const&)> const& filter) +{ + for (auto itr = container.begin(); itr != container.end();) + if (filter(*itr)) + itr = container.erase(itr); + else + ++itr; +} + +void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)> const& filter) +{ + std::vector<TaskContainer> cache; + for (auto itr = container.begin(); itr != container.end();) + if (filter(*itr)) + { + cache.push_back(*itr); + itr = container.erase(itr); + } + else + ++itr; + + container.insert(cache.begin(), cache.end()); +} + +bool TaskScheduler::TaskQueue::IsEmpty() const +{ + return container.empty(); +} + +TaskContext& TaskContext::Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply) +{ + if (auto const owner = _owner.lock()) + apply(*owner); + + return *this; +} + +bool TaskContext::IsExpired() const +{ + return _owner.expired(); +} + +bool TaskContext::IsInGroup(TaskScheduler::group_t const group) const +{ + return _task->IsInGroup(group); +} + +TaskContext& TaskContext::SetGroup(TaskScheduler::group_t const group) +{ + _task->_group = group; + return *this; +} + +TaskContext& TaskContext::ClearGroup() +{ + _task->_group = boost::none; + return *this; +} + +TaskScheduler::repeated_t TaskContext::GetRepeatCounter() const +{ + return _task->_repeated; +} + +TaskContext& TaskContext::Async(std::function<void()> const& callable) +{ + return Dispatch(std::bind(&TaskScheduler::Async, std::placeholders::_1, callable)); +} + +TaskContext& TaskContext::CancelAll() +{ + return Dispatch(std::mem_fn(&TaskScheduler::CancelAll)); +} + +TaskContext& TaskContext::CancelGroup(TaskScheduler::group_t const group) +{ + return Dispatch(std::bind(&TaskScheduler::CancelGroup, std::placeholders::_1, group)); +} + +TaskContext& TaskContext::CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups) +{ + return Dispatch(std::bind(&TaskScheduler::CancelGroupsOf, std::placeholders::_1, std::cref(groups))); +} + +void TaskContext::AssertOnConsumed() const +{ + // This was adapted to TC to prevent static analysis tools from complaining. + // If you encounter this assertion check if you repeat a TaskContext more then 1 time! + ASSERT(!(*_consumed) && "Bad task logic, task context was consumed already!"); +} + +void TaskContext::Invoke() +{ + _task->_task(*this); +} diff --git a/src/server/shared/Utilities/TaskScheduler.h b/src/server/shared/Utilities/TaskScheduler.h new file mode 100644 index 00000000000..98e210e55b1 --- /dev/null +++ b/src/server/shared/Utilities/TaskScheduler.h @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _TASK_SCHEDULER_H_ +#define _TASK_SCHEDULER_H_ + +#include <algorithm> +#include <chrono> +#include <vector> +#include <queue> +#include <memory> +#include <utility> +#include <set> + +#include <boost/optional.hpp> + +#include "Util.h" + +class TaskContext; + +/// The TaskScheduler class provides the ability to schedule std::function's in the near future. +/// Use TaskScheduler::Update to update the scheduler. +/// Popular methods are: +/// * Schedule (Schedules a std::function which will be executed in the near future). +/// * Schedules an asynchronous function which will be executed at the next update tick. +/// * Cancel, Delay & Reschedule (Methods to manipulate already scheduled tasks). +/// Tasks are organized in groups (uint), multiple tasks can have the same group id, +/// you can provide a group or not, but keep in mind that you can only manipulate specific tasks through its group id! +/// Tasks callbacks use the function signature void(TaskContext) where TaskContext provides +/// access to the function schedule plan which makes it possible to repeat the task +/// with the same duration or a new one. +/// It also provides access to the repeat counter which is useful for task that repeat itself often +/// but behave different every time (spoken event dialogs for example). +class TaskScheduler +{ + friend class TaskContext; + + // Time definitions (use steady clock) + typedef std::chrono::steady_clock clock_t; + typedef clock_t::time_point timepoint_t; + typedef clock_t::duration duration_t; + + // Task group type + typedef uint32 group_t; + // Task repeated type + typedef uint32 repeated_t; + // Task handle type + typedef std::function<void(TaskContext)> task_handler_t; + + class Task + { + friend class TaskContext; + friend class TaskScheduler; + + timepoint_t _end; + duration_t _duration; + boost::optional<group_t> _group; + repeated_t _repeated; + task_handler_t _task; + + public: + // All Argument construct + Task(timepoint_t const& end, duration_t const& duration, boost::optional<group_t> const& group, + repeated_t const repeated, task_handler_t const& task) + : _end(end), _duration(duration), _group(group), _repeated(repeated), _task(task) { } + + // Minimal Argument construct + Task(timepoint_t const& end, duration_t const& duration, task_handler_t const& task) + : _end(end), _duration(duration), _group(boost::none), _repeated(0), _task(task) { } + + // Copy construct + Task(Task const&) = delete; + // Move construct + Task(Task&&) = delete; + // Copy Assign + Task& operator= (Task const&) = default; + // Move Assign + Task& operator= (Task&& right) = delete; + + // Order tasks by its end + inline bool operator< (Task const& other) const + { + return _end < other._end; + } + + inline bool operator> (Task const& other) const + { + return _end > other._end; + } + + // Compare tasks with its end + inline bool operator== (Task const& other) + { + return _end == other._end; + } + + // Returns true if the task is in the given group + inline bool IsInGroup(group_t const group) const + { + return _group == group; + } + }; + + typedef std::shared_ptr<Task> TaskContainer; + + /// Container which provides Task order, insert and reschedule operations. + struct Compare + { + bool operator() (TaskContainer const& left, TaskContainer const& right) + { + return (*left.get()) < (*right.get()); + }; + }; + + class TaskQueue + { + std::multiset<TaskContainer, Compare> container; + + public: + // Pushes the task in the container + void Push(TaskContainer&& task); + + /// Pops the task out of the container + TaskContainer Pop(); + + TaskContainer const& First() const; + + void Clear(); + + void RemoveIf(std::function<bool(TaskContainer const&)> const& filter); + + void ModifyIf(std::function<bool(TaskContainer const&)> const& filter); + + bool IsEmpty() const; + }; + + /// Contains a self reference to track if this object was deleted or not. + std::shared_ptr<TaskScheduler> self_reference; + + /// The current time point (now) + timepoint_t _now; + + /// The Task Queue which contains all task objects. + TaskQueue _task_holder; + + typedef std::queue<std::function<void()>> AsyncHolder; + + /// Contains all asynchronous tasks which will be invoked at + /// the next update tick. + AsyncHolder _asyncHolder; + +public: + TaskScheduler() : self_reference(this, [](TaskScheduler const*) { }), + _now(clock_t::now()) { } + + TaskScheduler(TaskScheduler const&) = delete; + TaskScheduler(TaskScheduler&&) = delete; + TaskScheduler& operator= (TaskScheduler const&) = delete; + TaskScheduler& operator= (TaskScheduler&&) = delete; + + /// Update the scheduler to the current time. + TaskScheduler& Update(); + + /// Update the scheduler with a difftime in ms. + TaskScheduler& Update(size_t const milliseconds); + + /// Update the scheduler with a difftime. + template<class _Rep, class _Period> + TaskScheduler& Update(std::chrono::duration<_Rep, _Period> const& difftime) + { + _now += difftime; + Dispatch(); + return *this; + } + + /// Schedule an callable function that is executed at the next update tick. + /// Its safe to modify the TaskScheduler from within the callable. + TaskScheduler& Async(std::function<void()> const& callable); + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _Rep, class _Period> + TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, + task_handler_t const& task) + { + return ScheduleAt(_now, time, task); + } + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _Rep, class _Period> + TaskScheduler& Schedule(std::chrono::duration<_Rep, _Period> const& time, + group_t const group, task_handler_t const& task) + { + return ScheduleAt(_now, time, group, task); + } + + /// Schedule an event with a randomized rate between min and max rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, task_handler_t const& task) + { + return Schedule(RandomDurationBetween(min, max), task); + } + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::Schedule instead! + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, group_t const group, + task_handler_t const& task) + { + return Schedule(RandomDurationBetween(min, max), group, task); + } + + /// Cancels all tasks. + /// Never call this from within a task context! Use TaskContext::CancelAll instead! + TaskScheduler& CancelAll(); + + /// Cancel all tasks of a single group. + /// Never call this from within a task context! Use TaskContext::CancelGroup instead! + TaskScheduler& CancelGroup(group_t const group); + + /// Cancels all groups in the given std::vector. + /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}" + TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups); + + /// Delays all tasks with the given duration. + template<class _Rep, class _Period> + TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration) + { + _task_holder.ModifyIf([&duration](TaskContainer const& task) -> bool + { + task->_end += duration; + return true; + }); + return *this; + } + + /// Delays all tasks with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayAll(RandomDurationBetween(min, max)); + } + + /// Delays all tasks of a group with the given duration. + template<class _Rep, class _Period> + TaskScheduler& DelayGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + _task_holder.ModifyIf([&duration, group](TaskContainer const& task) -> bool + { + if (task->IsInGroup(group)) + { + task->_end += duration; + return true; + } + else + return false; + }); + return *this; + } + + /// Delays all tasks of a group with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& DelayGroup(group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayGroup(group, RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks with a given duration. + template<class _Rep, class _Period> + TaskScheduler& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration) + { + auto const end = _now + duration; + _task_holder.ModifyIf([end](TaskContainer const& task) -> bool + { + task->_end = end; + return true; + }); + return *this; + } + + /// Reschedule all tasks with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleAll(RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks of a group with the given duration. + template<class _Rep, class _Period> + TaskScheduler& RescheduleGroup(group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + auto const end = _now + duration; + _task_holder.ModifyIf([end, group](TaskContainer const& task) -> bool + { + if (task->IsInGroup(group)) + { + task->_end = end; + return true; + } + else + return false; + }); + return *this; + } + + /// Reschedule all tasks of a group with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskScheduler& RescheduleGroup(group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleGroup(group, RandomDurationBetween(min, max)); + } + +private: + /// Insert a new task to the enqueued tasks. + TaskScheduler& InsertTask(TaskContainer task); + + template<class _Rep, class _Period> + TaskScheduler& ScheduleAt(timepoint_t const& end, + std::chrono::duration<_Rep, _Period> const& time, task_handler_t const& task) + { + return InsertTask(TaskContainer(new Task(end + time, time, task))); + } + + /// Schedule an event with a fixed rate. + /// Never call this from within a task context! Use TaskContext::schedule instead! + template<class _Rep, class _Period> + TaskScheduler& ScheduleAt(timepoint_t const& end, + std::chrono::duration<_Rep, _Period> const& time, + group_t const group, task_handler_t const& task) + { + static repeated_t const DEFAULT_REPEATED = 0; + return InsertTask(TaskContainer(new Task(end + time, time, group, DEFAULT_REPEATED, task))); + } + + // Returns a random duration between min and max + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + static std::chrono::milliseconds + RandomDurationBetween(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + auto const milli_min = std::chrono::duration_cast<std::chrono::milliseconds>(min); + auto const milli_max = std::chrono::duration_cast<std::chrono::milliseconds>(max); + + // TC specific: use SFMT URandom + return std::chrono::milliseconds(urand(milli_min.count(), milli_max.count())); + } + + /// Dispatch remaining tasks + void Dispatch(); +}; + +class TaskContext +{ + friend class TaskScheduler; + + /// Associated task + TaskScheduler::TaskContainer _task; + + /// Owner + std::weak_ptr<TaskScheduler> _owner; + + /// Marks the task as consumed + std::shared_ptr<bool> _consumed; + + /// Dispatches an action safe on the TaskScheduler + TaskContext& Dispatch(std::function<TaskScheduler&(TaskScheduler&)> const& apply); + +public: + // Empty constructor + TaskContext() + : _task(), _owner(), _consumed(std::make_shared<bool>(true)) { } + + // Construct from task and owner + explicit TaskContext(TaskScheduler::TaskContainer&& task, std::weak_ptr<TaskScheduler>&& owner) + : _task(task), _owner(owner), _consumed(std::make_shared<bool>(false)) { } + + // Copy construct + TaskContext(TaskContext const& right) + : _task(right._task), _owner(right._owner), _consumed(right._consumed) { } + + // Move construct + TaskContext(TaskContext&& right) + : _task(std::move(right._task)), _owner(std::move(right._owner)), _consumed(std::move(right._consumed)) { } + + // Copy assign + TaskContext& operator= (TaskContext const& right) + { + _task = right._task; + _owner = right._owner; + _consumed = right._consumed; + return *this; + } + + // Move assign + TaskContext& operator= (TaskContext&& right) + { + _task = std::move(right._task); + _owner = std::move(right._owner); + _consumed = std::move(right._consumed); + return *this; + } + + /// Returns true if the owner was deallocated and this context has expired. + bool IsExpired() const; + + /// Returns true if the event is in the given group + bool IsInGroup(TaskScheduler::group_t const group) const; + + /// Sets the event in the given group + TaskContext& SetGroup(TaskScheduler::group_t const group); + + /// Removes the group from the event + TaskContext& ClearGroup(); + + /// Returns the repeat counter which increases every time the task is repeated. + TaskScheduler::repeated_t GetRepeatCounter() const; + + /// Repeats the event and sets a new duration. + /// std::chrono::seconds(5) for example. + /// This will consume the task context, its not possible to repeat the task again + /// from the same task context! + template<class _Rep, class _Period> + TaskContext& Repeat(std::chrono::duration<_Rep, _Period> const& duration) + { + AssertOnConsumed(); + + // Set new duration, in-context timing and increment repeat counter + _task->_duration = duration; + _task->_end += duration; + _task->_repeated += 1; + (*_consumed) = true; + return Dispatch(std::bind(&TaskScheduler::InsertTask, std::placeholders::_1, _task)); + } + + /// Repeats the event with the same duration. + /// This will consume the task context, its not possible to repeat the task again + /// from the same task context! + TaskContext& Repeat() + { + return Repeat(_task->_duration); + } + + /// Repeats the event and set a new duration that is randomized between min and max. + /// std::chrono::seconds(5) for example. + /// This will consume the task context, its not possible to repeat the task again + /// from the same task context! + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& Repeat(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return Repeat(TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Schedule a callable function that is executed at the next update tick from within the context. + /// Its safe to modify the TaskScheduler from within the callable. + TaskContext& Async(std::function<void()> const& callable); + + /// Schedule an event with a fixed rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _Rep, class _Period> + TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time, + TaskScheduler::task_handler_t const& task) + { + auto const end = _task->_end; + return Dispatch([end, time, task](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.ScheduleAt<_Rep, _Period>(end, time, task); + }); + } + + /// Schedule an event with a fixed rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _Rep, class _Period> + TaskContext& Schedule(std::chrono::duration<_Rep, _Period> const& time, + TaskScheduler::group_t const group, TaskScheduler::task_handler_t const& task) + { + auto const end = _task->_end; + return Dispatch([end, time, group, task](TaskScheduler& scheduler) -> TaskScheduler& + { + return scheduler.ScheduleAt<_Rep, _Period>(end, time, group, task); + }); + } + + /// Schedule an event with a randomized rate between min and max rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::task_handler_t const& task) + { + return Schedule(TaskScheduler::RandomDurationBetween(min, max), task); + } + + /// Schedule an event with a randomized rate between min and max rate from within the context. + /// Its possible that the new event is executed immediately! + /// Use TaskScheduler::Async to create a task + /// which will be called at the next update tick. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& Schedule(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max, TaskScheduler::group_t const group, + TaskScheduler::task_handler_t const& task) + { + return Schedule(TaskScheduler::RandomDurationBetween(min, max), group, task); + } + + /// Cancels all tasks from within the context. + TaskContext& CancelAll(); + + /// Cancel all tasks of a single group from within the context. + TaskContext& CancelGroup(TaskScheduler::group_t const group); + + /// Cancels all groups in the given std::vector from within the context. + /// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}" + TaskContext& CancelGroupsOf(std::vector<TaskScheduler::group_t> const& groups); + + /// Delays all tasks with the given duration from within the context. + template<class _Rep, class _Period> + TaskContext& DelayAll(std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::DelayAll<_Rep, _Period>, std::placeholders::_1, duration)); + } + + /// Delays all tasks with a random duration between min and max from within the context. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& DelayAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayAll(TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Delays all tasks of a group with the given duration from within the context. + template<class _Rep, class _Period> + TaskContext& DelayGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::DelayGroup<_Rep, _Period>, std::placeholders::_1, group, duration)); + } + + /// Delays all tasks of a group with a random duration between min and max from within the context. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& DelayGroup(TaskScheduler::group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return DelayGroup(group, TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks with the given duration. + template<class _Rep, class _Period> + TaskContext& RescheduleAll(std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::RescheduleAll, std::placeholders::_1, duration)); + } + + /// Reschedule all tasks with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& RescheduleAll(std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleAll(TaskScheduler::RandomDurationBetween(min, max)); + } + + /// Reschedule all tasks of a group with the given duration. + template<class _Rep, class _Period> + TaskContext& RescheduleGroup(TaskScheduler::group_t const group, std::chrono::duration<_Rep, _Period> const& duration) + { + return Dispatch(std::bind(&TaskScheduler::RescheduleGroup<_Rep, _Period>, std::placeholders::_1, group, duration)); + } + + /// Reschedule all tasks of a group with a random duration between min and max. + template<class _RepLeft, class _PeriodLeft, class _RepRight, class _PeriodRight> + TaskContext& RescheduleGroup(TaskScheduler::group_t const group, + std::chrono::duration<_RepLeft, _PeriodLeft> const& min, + std::chrono::duration<_RepRight, _PeriodRight> const& max) + { + return RescheduleGroup(group, TaskScheduler::RandomDurationBetween(min, max)); + } + +private: + /// Asserts if the task was consumed already. + void AssertOnConsumed() const; + + /// Invokes the associated hook of the task. + void Invoke(); +}; + +/// Milliseconds shorthand typedef. +typedef std::chrono::milliseconds Milliseconds; + +/// Seconds shorthand typedef. +typedef std::chrono::seconds Seconds; + +/// Minutes shorthand typedef. +typedef std::chrono::minutes Minutes; + +/// Hours shorthand typedef. +typedef std::chrono::hours Hours; + +#endif /// _TASK_SCHEDULER_H_ diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index d4a6915894d..e39ccb3c98f 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -111,11 +111,11 @@ extern int main(int argc, char** argv) #ifdef _WIN32 if (configService.compare("install") == 0) - return WinServiceInstall() == true ? 0 : 1; + return WinServiceInstall() ? 0 : 1; else if (configService.compare("uninstall") == 0) - return WinServiceUninstall() == true ? 0 : 1; + return WinServiceUninstall() ? 0 : 1; else if (configService.compare("run") == 0) - WinServiceRun(); + return WinServiceRun() ? 0 : 0; #endif std::string configError; @@ -613,11 +613,13 @@ variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm); notify(vm); } - catch (std::exception& e) { + catch (std::exception& e) + { std::cerr << e.what() << "\n"; } - if (vm.count("help")) { + if (vm.count("help")) + { std::cout << all << "\n"; } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index c59b845e454..668cec43aca 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1018,7 +1018,7 @@ OffhandCheckAtSpellUnlearn = 1 # ClientCacheVersion # Description: Client cache version for client cache data reset. Use any value different # from DB and not recently been used to trigger client side cache reset. -# Default: 0 - (Use DB value from world DB db_version.cache_id field) +# Default: 0 - (Use DB value from world DB version.cache_id field) ClientCacheVersion = 0 diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index ab9774a3038..9059867dce4 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -402,7 +402,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.4"; +static char const* MAP_VERSION_MAGIC = "v1.5"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -1091,7 +1091,7 @@ void ExtractMaps(uint32 build) continue; sprintf(storagePath, "World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y); - sprintf(output_filename, "%s/maps/%03u%02u%02u.map", output_path, map_ids[z].id, y, x); + sprintf(output_filename, "%s/maps/%04u_%02u_%02u.map", output_path, map_ids[z].id, y, x); ConvertADT(storagePath, output_filename, y, x, build); sprintf(storagePath, "World\\Maps\\%s\\%s_%u_%u_obj0.adt", map_ids[z].name, map_ids[z].name, x, y); diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt index 48e30b1c3cf..4dfe106bd3e 100644 --- a/src/tools/mmaps_generator/CMakeLists.txt +++ b/src/tools/mmaps_generator/CMakeLists.txt @@ -12,7 +12,7 @@ file(GLOB_RECURSE mmap_gen_sources *.cpp *.h) set(mmap_gen_Includes ${CMAKE_BINARY_DIR} - ${CMAKE_SOURCE_DIR}/dep/libmpq + ${CMAKE_SOURCE_DIR}/dep/cppformat ${CMAKE_SOURCE_DIR}/dep/zlib ${CMAKE_SOURCE_DIR}/dep/bzip2 ${CMAKE_SOURCE_DIR}/dep/g3dlite/include @@ -30,13 +30,6 @@ set(mmap_gen_Includes ${CMAKE_SOURCE_DIR}/src/server/collision/Models ) -if( WIN32 ) - set(mmap_gen_Includes - ${mmap_gen_Includes} - ${CMAKE_SOURCE_DIR}/dep/libmpq/win - ) -endif() - include_directories(${mmap_gen_Includes}) add_executable(mmaps_generator ${mmap_gen_sources}) @@ -46,6 +39,7 @@ target_link_libraries(mmaps_generator g3dlib Recast Detour + format ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 412ba7a0055..b3d495f8a7e 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -19,6 +19,7 @@ #include "PathCommon.h" #include "MapBuilder.h" +#include "StringFormat.h" #include "MapTree.h" #include "ModelInstance.h" @@ -28,7 +29,7 @@ #include "DetourCommon.h" #define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 6 +#define MMAP_VERSION 7 struct MmapTileHeader { @@ -83,13 +84,12 @@ namespace MMAP { std::vector<std::string> files; uint32 mapID, tileX, tileY, tileID, count = 0; - char filter[12]; printf("Discovering maps... "); getDirContents(files, "maps"); for (uint32 i = 0; i < files.size(); ++i) { - mapID = uint32(atoi(files[i].substr(0,3).c_str())); + mapID = uint32(atoi(files[i].substr(0, 4).c_str())); if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end()) { m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>)); @@ -101,7 +101,7 @@ namespace MMAP getDirContents(files, "vmaps", "*.vmtree"); for (uint32 i = 0; i < files.size(); ++i) { - mapID = uint32(atoi(files[i].substr(0,3).c_str())); + mapID = uint32(atoi(files[i].substr(0, 4).c_str())); if (std::find(m_tiles.begin(), m_tiles.end(), mapID) == m_tiles.end()) { m_tiles.emplace_back(MapTiles(mapID, new std::set<uint32>)); @@ -117,26 +117,24 @@ namespace MMAP std::set<uint32>* tiles = (*itr).m_tiles; mapID = (*itr).m_mapId; - sprintf(filter, "%03u*.vmtile", mapID); files.clear(); - getDirContents(files, "vmaps", filter); + getDirContents(files, "vmaps", Trinity::StringFormat("%04u*.vmtile", mapID)); for (uint32 i = 0; i < files.size(); ++i) { - tileX = uint32(atoi(files[i].substr(7,2).c_str())); - tileY = uint32(atoi(files[i].substr(4,2).c_str())); + tileX = uint32(atoi(files[i].substr(8, 2).c_str())); + tileY = uint32(atoi(files[i].substr(5, 2).c_str())); tileID = StaticMapTree::packTileID(tileY, tileX); tiles->insert(tileID); count++; } - sprintf(filter, "%03u*", mapID); files.clear(); - getDirContents(files, "maps", filter); + getDirContents(files, "maps", Trinity::StringFormat("%04u*", mapID)); for (uint32 i = 0; i < files.size(); ++i) { - tileY = uint32(atoi(files[i].substr(3,2).c_str())); - tileX = uint32(atoi(files[i].substr(5,2).c_str())); + tileY = uint32(atoi(files[i].substr(5, 2).c_str())); + tileX = uint32(atoi(files[i].substr(8, 2).c_str())); tileID = StaticMapTree::packTileID(tileX, tileY); if (tiles->insert(tileID).second) @@ -386,12 +384,12 @@ namespace MMAP buildNavMesh(mapID, navMesh); if (!navMesh) { - printf("[Map %03i] Failed creating navmesh!\n", mapID); + printf("[Map %04i] Failed creating navmesh!\n", mapID); return; } // now start building mmtiles for each tile - printf("[Map %03i] We have %u tiles. \n", mapID, (unsigned int)tiles->size()); + printf("[Map %04i] We have %u tiles. \n", mapID, (unsigned int)tiles->size()); for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it) { uint32 tileX, tileY; @@ -408,13 +406,13 @@ namespace MMAP dtFreeNavMesh(navMesh); } - printf("[Map %03i] Complete!\n", mapID); + printf("[Map %04u] Complete!\n", mapID); } /**************************************************************************/ void MapBuilder::buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh) { - printf("[Map %03i] Building tile [%02u,%02u]\n", mapID, tileX, tileY); + printf("[Map %04i] Building tile [%02u,%02u]\n", mapID, tileX, tileY); MeshData meshData; @@ -500,22 +498,22 @@ namespace MMAP navMeshParams.maxPolys = maxPolysPerTile; navMesh = dtAllocNavMesh(); - printf("[Map %03i] Creating navMesh...\n", mapID); + printf("[Map %04u] Creating navMesh...\n", mapID); if (!navMesh->init(&navMeshParams)) { - printf("[Map %03i] Failed creating navmesh! \n", mapID); + printf("[Map %04u] Failed creating navmesh! \n", mapID); return; } char fileName[25]; - sprintf(fileName, "mmaps/%03u.mmap", mapID); + sprintf(fileName, "mmaps/%04u.mmap", mapID); FILE* file = fopen(fileName, "wb"); if (!file) { dtFreeNavMesh(navMesh); char message[1024]; - sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName); + sprintf(message, "[Map %04u] Failed to open %s for writing!\n", mapID, fileName); perror(message); return; } @@ -531,9 +529,8 @@ namespace MMAP dtNavMesh* navMesh) { // console output - char tileString[20]; - sprintf(tileString, "[Map %03i] [%02i,%02i]: ", mapID, tileX, tileY); - printf("%s Building movemap tiles...\n", tileString); + std::string tileString = Trinity::StringFormat("[Map %04u] [%02i,%02i]: ", mapID, tileX, tileY); + printf("%s Building movemap tiles...\n", tileString.c_str()); IntermediateValues iv; @@ -614,7 +611,7 @@ namespace MMAP tile.solid = rcAllocHeightfield(); if (!tile.solid || !rcCreateHeightfield(m_rcContext, *tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch)) { - printf("%s Failed building heightfield! \n", tileString); + printf("%s Failed building heightfield! \n", tileString.c_str()); continue; } @@ -635,33 +632,33 @@ namespace MMAP tile.chf = rcAllocCompactHeightfield(); if (!tile.chf || !rcBuildCompactHeightfield(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid, *tile.chf)) { - printf("%s Failed compacting heightfield! \n", tileString); + printf("%s Failed compacting heightfield! \n", tileString.c_str()); continue; } // build polymesh intermediates if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, *tile.chf)) { - printf("%s Failed eroding area! \n", tileString); + printf("%s Failed eroding area! \n", tileString.c_str()); continue; } if (!rcBuildDistanceField(m_rcContext, *tile.chf)) { - printf("%s Failed building distance field! \n", tileString); + printf("%s Failed building distance field! \n", tileString.c_str()); continue; } if (!rcBuildRegions(m_rcContext, *tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea)) { - printf("%s Failed building regions! \n", tileString); + printf("%s Failed building regions! \n", tileString.c_str()); continue; } tile.cset = rcAllocContourSet(); if (!tile.cset || !rcBuildContours(m_rcContext, *tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.cset)) { - printf("%s Failed building contours! \n", tileString); + printf("%s Failed building contours! \n", tileString.c_str()); continue; } @@ -669,14 +666,14 @@ namespace MMAP tile.pmesh = rcAllocPolyMesh(); if (!tile.pmesh || !rcBuildPolyMesh(m_rcContext, *tile.cset, tileCfg.maxVertsPerPoly, *tile.pmesh)) { - printf("%s Failed building polymesh! \n", tileString); + printf("%s Failed building polymesh! \n", tileString.c_str()); continue; } tile.dmesh = rcAllocPolyMeshDetail(); if (!tile.dmesh || !rcBuildPolyMeshDetail(m_rcContext, *tile.pmesh, *tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.dmesh)) { - printf("%s Failed building polymesh detail! \n", tileString); + printf("%s Failed building polymesh detail! \n", tileString.c_str()); continue; } @@ -699,7 +696,7 @@ namespace MMAP iv.polyMesh = rcAllocPolyMesh(); if (!iv.polyMesh) { - printf("%s alloc iv.polyMesh FIALED!\n", tileString); + printf("%s alloc iv.polyMesh FAILED!\n", tileString.c_str()); delete[] pmmerge; delete[] dmmerge; delete[] tiles; @@ -710,7 +707,7 @@ namespace MMAP iv.polyMeshDetail = rcAllocPolyMeshDetail(); if (!iv.polyMeshDetail) { - printf("%s alloc m_dmesh FIALED!\n", tileString); + printf("%s alloc m_dmesh FAILED!\n", tileString.c_str()); delete[] pmmerge; delete[] dmmerge; delete[] tiles; @@ -774,12 +771,12 @@ namespace MMAP // so we have a clear error message if (params.nvp > DT_VERTS_PER_POLYGON) { - printf("%s Invalid verts-per-polygon value! \n", tileString); + printf("%s Invalid verts-per-polygon value! \n", tileString.c_str()); break; } if (params.vertCount >= 0xffff) { - printf("%s Too many vertices! \n", tileString); + printf("%s Too many vertices! \n", tileString.c_str()); break; } if (!params.vertCount || !params.verts) @@ -788,7 +785,7 @@ namespace MMAP // loaded but those models don't span into this tile // message is an annoyance - //printf("%sNo vertices to build tile! \n", tileString); + //printf("%sNo vertices to build tile! \n", tileString.c_str()); break; } if (!params.polyCount || !params.polys || @@ -797,47 +794,47 @@ namespace MMAP // we have flat tiles with no actual geometry - don't build those, its useless // keep in mind that we do output those into debug info // drop tiles with only exact count - some tiles may have geometry while having less tiles - printf("%s No polygons to build on tile! \n", tileString); + printf("%s No polygons to build on tile! \n", tileString.c_str()); break; } if (!params.detailMeshes || !params.detailVerts || !params.detailTris) { - printf("%s No detail mesh to build tile! \n", tileString); + printf("%s No detail mesh to build tile! \n", tileString.c_str()); break; } - printf("%s Building navmesh tile...\n", tileString); + printf("%s Building navmesh tile...\n", tileString.c_str()); if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize)) { - printf("%s Failed building navmesh tile! \n", tileString); + printf("%s Failed building navmesh tile! \n", tileString.c_str()); break; } dtTileRef tileRef = 0; - printf("%s Adding tile to navmesh...\n", tileString); + printf("%s Adding tile to navmesh...\n", tileString.c_str()); // DT_TILE_FREE_DATA tells detour to unallocate memory when the tile // is removed via removeTile() dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef); if (!tileRef || dtResult != DT_SUCCESS) { - printf("%s Failed adding tile to navmesh! \n", tileString); + printf("%s Failed adding tile to navmesh! \n", tileString.c_str()); break; } // file output char fileName[255]; - sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX); + sprintf(fileName, "mmaps/%04u%02i%02i.mmtile", mapID, tileY, tileX); FILE* file = fopen(fileName, "wb"); if (!file) { char message[1024]; - sprintf(message, "[Map %03i] Failed to open %s for writing!\n", mapID, fileName); + sprintf(message, "[Map %04u] Failed to open %s for writing!\n", mapID, fileName); perror(message); navMesh->removeTile(tileRef, NULL, NULL); break; } - printf("%s Writing to file...\n", tileString); + printf("%s Writing to file...\n", tileString.c_str()); // write header MmapTileHeader header; @@ -898,6 +895,8 @@ namespace MMAP case 1: case 530: case 571: + case 870: + case 1116: return true; default: break; @@ -916,6 +915,12 @@ namespace MMAP case 597: // CraigTest.wdt case 605: // development_nonweighted.wdt case 606: // QA_DVD.wdt + case 651: // ElevatorSpawnTest.wdt + case 1060: // LevelDesignLand-DevOnly.wdt + case 1181: // PattyMackTestGarrisonBldgMap.wdt + case 1264: // Propland-DevOnly.wdt + case 1270: // devland3.wdt + case 1427: // PattyMackTestGarrisonBldgMap2.wdt return true; default: if (isTransportMap(mapID)) @@ -926,13 +931,21 @@ namespace MMAP if (m_skipBattlegrounds) switch (mapID) { - case 30: // AV + case 30: // Alterac Valley case 37: // ? - case 489: // WSG - case 529: // AB - case 566: // EotS - case 607: // SotA - case 628: // IoC + case 489: // Warsong Gulch + case 529: // Arathi Basin + case 566: // Eye of the Storm + case 607: // Strand of the Ancients + case 628: // Isle of Conquest + case 726: // Twin Peaks + case 727: // Silvershard Mines + case 761: // The Battle for Gilneas + case 968: // Rated Eye of the Storm + case 998: // Temple of Kotmogu + case 1010: // CTF3 + case 1105: // Deepwind Gorge + case 1280: // Southshore vs. Tarren Mill return true; default: break; @@ -970,11 +983,35 @@ namespace MMAP case 641: case 642: case 647: + case 662: case 672: case 673: + case 674: case 712: case 713: case 718: + case 738: + case 739: + case 740: + case 741: + case 742: + case 743: + case 747: + case 748: + case 749: + case 750: + case 762: + case 763: + case 765: + case 766: + case 767: + case 1113: + case 1132: + case 1133: + case 1172: + case 1173: + case 1192: + case 1231: return true; default: return false; @@ -985,7 +1022,7 @@ namespace MMAP bool MapBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) { char fileName[255]; - sprintf(fileName, "mmaps/%03u%02i%02i.mmtile", mapID, tileY, tileX); + sprintf(fileName, "mmaps/%04u%02i%02i.mmtile", mapID, tileY, tileX); FILE* file = fopen(fileName, "rb"); if (!file) return false; diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 8f85cfdbe83..125f630bb13 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -80,7 +80,7 @@ struct map_liquidHeader namespace MMAP { - char const* MAP_VERSION_MAGIC = "v1.4"; + char const* MAP_VERSION_MAGIC = "v1.5"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } @@ -134,7 +134,7 @@ namespace MMAP bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion) { char mapFileName[255]; - sprintf(mapFileName, "maps/%03u%02u%02u.map", mapID, tileY, tileX); + sprintf(mapFileName, "maps/%04u_%02u_%02u.map", mapID, tileY, tileX); FILE* mapFile = fopen(mapFileName, "rb"); if (!mapFile) diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index fb2cc0a20d0..9b01ecfb1df 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -72,7 +72,7 @@ bool preciseVectorData = false; //static const char * szWorkDirMaps = ".\\Maps"; const char* szWorkDirWmo = "./Buildings"; -const char* szRawVMAPMagic = "VMAP042"; +const char* szRawVMAPMagic = "VMAP043"; bool OpenCascStorage() { @@ -249,7 +249,7 @@ void ParsMapFiles() char id[10]; for (unsigned int i=0; i<map_count; ++i) { - sprintf(id,"%03u",map_ids[i].id); + sprintf(id, "%04u", map_ids[i].id); sprintf(fn,"World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name); WDTFile WDT(fn,map_ids[i].name); if(WDT.init(id, map_ids[i].id)) @@ -355,7 +355,7 @@ bool processArgv(int argc, char ** argv, const char *versionString) int main(int argc, char ** argv) { bool success = true; - const char *versionString = "V4.00 2012_02"; + const char *versionString = "V4.03 2015_05"; // Use command line arguments, when some if (!processArgv(argc, argv, versionString)) |