diff --git a/contrib/extractor/CMakeLists.txt b/contrib/extractor/CMakeLists.txt index a00dda120..9052903b1 100644 --- a/contrib/extractor/CMakeLists.txt +++ b/contrib/extractor/CMakeLists.txt @@ -12,10 +12,15 @@ cmake_minimum_required (VERSION 2.6) project (MANGOS_MAP_EXTRACTOR) add_subdirectory (libmpq) +add_subdirectory (loadlib) include_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/libmpq) -link_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/libmpq) +include_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/loadlib) -add_executable (ad adt.cpp dbcfile.cpp mpq_libmpq.cpp System.cpp) +link_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/libmpq) +link_directories (${MANGOS_MAP_EXTRACTOR_SOURCE_DIR}/loadlib) + +add_executable (ad dbcfile.cpp mpq_libmpq.cpp System.cpp) target_link_libraries (ad libmpq) +target_link_libraries (ad loadlib) diff --git a/contrib/extractor/System.cpp b/contrib/extractor/System.cpp index f9f684014..843fe616e 100644 --- a/contrib/extractor/System.cpp +++ b/contrib/extractor/System.cpp @@ -14,10 +14,10 @@ #include "dbcfile.h" #include "mpq_libmpq.h" -extern unsigned int iRes; -extern ArchiveSet gOpenArchives; +#include "loadlib/adt.h" +#include "loadlib/wdt.h" -bool ConvertADT(char*, char*); +extern ArchiveSet gOpenArchives; typedef struct { @@ -25,10 +25,6 @@ typedef struct uint32 id; } map_id; -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; - map_id *map_ids; uint16 *areas; uint16 *LiqType; @@ -36,18 +32,44 @@ char output_path[128] = "."; char input_path[128] = "."; uint32 maxAreaId = 0; +//************************************************** +// Extractor options +//************************************************** enum Extract { EXTRACT_MAP = 1, EXTRACT_DBC = 2 }; -int extract = EXTRACT_MAP | EXTRACT_DBC; + +// Select data for extract +int CONF_extract = EXTRACT_MAP | EXTRACT_DBC; +// This option allow limit minimum height to some value (Allow save some memory) +bool CONF_allow_height_limit = true; +float CONF_use_minHeight = -500.0f; + +// This option allow use float to int conversion +bool CONF_allow_float_to_int = true; +float CONF_float_to_int8_limit = 2.0f; // Max accuracy = val/256 +float CONF_float_to_int16_limit = 2048.0f; // Max accuracy = val/65536 +float CONF_flat_height_delta_limit = 0.005f; // If max - min less this value - surface is flat +float CONF_flat_liquid_delta_limit = 0.001f; // If max - min less this value - liquid surface is flat + +// List MPQ for extract from +char *CONF_mpq_list[]={ + "common.MPQ", + "common-2.MPQ", + "lichking.MPQ", + "expansion.MPQ", + "patch.MPQ", + "patch-2.MPQ", + "patch-3.MPQ", + "patch-4.MPQ", + "patch-5.MPQ", +}; static char* const langs[] = {"enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" }; #define LANG_COUNT 12 -#define ADT_RES 64 - void CreateDir( const std::string& Path ) { #ifdef WIN32 @@ -70,7 +92,14 @@ bool FileExists( const char* FileName ) void Usage(char* prg) { - printf("Usage:\n%s -[var] [value]\n-i set input path\n-o set output path\n-e extract only MAP(1)/DBC(2) - standard: both(3)\nExample: %s -r 256 -i \"c:\\games\\game\"", prg, prg); + printf( + "Usage:\n"\ + "%s -[var] [value]\n"\ + "-i set input path\n"\ + "-o set output path\n"\ + "-e extract only MAP(1)/DBC(2) - standard: both(3)\n"\ + "-f height stored as int (less map size but lost some accuracy) 1 by default\n"\ + "Example: %s -f 0 -i \"c:\\games\\game\"", prg, prg); exit(1); } @@ -80,8 +109,9 @@ void HandleArgs(int argc, char * arg[]) { // i - input path // o - output path - // r - resolution, array of (r * r) heights will be created // e - extract only MAP(1)/DBC(2) - standard both(3) + // f - use float to int conversion + // h - limit minimum height if(arg[c][0] != '-') Usage(arg[0]); @@ -99,11 +129,17 @@ void HandleArgs(int argc, char * arg[]) else Usage(arg[0]); break; + case 'f': + if(c + 1 < argc) // all ok + CONF_allow_float_to_int=atoi(arg[(c++) + 1])!=0; + else + Usage(arg[0]); + break; case 'e': if(c + 1 < argc) // all ok { - extract=atoi(arg[(c++) + 1]); - if(!(extract > 0 && extract < 4)) + CONF_extract=atoi(arg[(c++) + 1]); + if(!(CONF_extract > 0 && CONF_extract < 4)) Usage(arg[0]); } else @@ -165,10 +201,603 @@ void ReadLiquidTypeTableDBC() printf("Done! (%u LiqTypes loaded)\n", LiqType_count); } +// +// Adt file convertor function and data +// + +// Map file format data +#define MAP_MAGIC 'SPAM' +#define MAP_VERSION_MAGIC '0.1w' +#define MAP_AREA_MAGIC 'AERA' +#define MAP_HEIGTH_MAGIC 'TGHM' +#define MAP_LIQUID_MAGIC 'QILM' + +struct map_fileheader{ + uint32 mapMagic; + uint32 versionMagic; + uint32 areaMapOffset; + uint32 areaMapSize; + uint32 heightMapOffset; + uint32 heightMapSize; + uint32 liquidMapOffset; + uint32 liquidMapSize; +}; + +#define MAP_AREA_NO_AREA 0x0001 +struct map_areaHeader{ + uint32 fourcc; + uint16 flags; + uint16 gridArea; +}; + +#define MAP_HEIGHT_NO_HIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 + +struct map_heightHeader{ + uint32 fourcc; + uint32 flags; + float gridHeight; + float gridMaxHeight; +}; + +#define MAP_LIQUID_TYPE_NO_WATER 0x00 +#define MAP_LIQUID_TYPE_WATER 0x01 +#define MAP_LIQUID_TYPE_OCEAN 0x02 +#define MAP_LIQUID_TYPE_MAGMA 0x04 +#define MAP_LIQUID_TYPE_SLIME 0x08 + +#define MAP_LIQUID_TYPE_DARK_WATER 0x10 +#define MAP_LIQUID_TYPE_WMO_WATER 0x20 + + +#define MAP_LIQUID_NO_TYPE 0x0001 +#define MAP_LIQUID_NO_HIGHT 0x0002 + +struct map_liquidHeader{ + uint32 fourcc; + uint16 flags; + uint16 liquidType; + uint8 offsetX; + uint8 offsetY; + uint8 width; + uint8 height; + float liquidLevel; +}; + +float selectUInt8StepStore(float maxDiff) +{ + return 255 / maxDiff; +} + +float selectUInt16StepStore(float maxDiff) +{ + return 65535 / maxDiff; +} +// Temporary grid data store +uint16 area_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + +float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]; +float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; +uint16 uint16_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]; +uint16 uint16_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; +uint8 uint8_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]; +uint8 uint8_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; + +uint8 liquid_type[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]; +float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; + +bool ConvertADT(char *filename, char *filename2, int cell_y, int cell_x) +{ + ADT_file adt; + + if (!adt.loadFile(filename)) + return false; + + adt_MCIN *cells = adt.a_grid->getMCIN(); + if (!cells) + { + printf("Can't find cells in '%s'\n", filename); + return false; + } + + memset(liquid_show, 0, sizeof(liquid_show)); + memset(liquid_type, 0, sizeof(liquid_type)); + + // Prepare map header + map_fileheader map; + map.mapMagic = MAP_MAGIC; + map.versionMagic = MAP_VERSION_MAGIC; + + // Get area flags data + for (int i=0;igetMCNK(i,j); + uint32 areaid = cell->areaid; + if(areaid && areaid <= maxAreaId) + { + if(areas[areaid] != 0xffff) + { + area_flags[i][j] = areas[areaid]; + continue; + } + printf("File: filename\nCan't find area flag for areaid %u [%d, %d].\n", filename, areaid, cell->ix, cell->iy); + } + area_flags[i][j] = 0xffff; + } + } + //============================================ + // Try pack area data + //============================================ + bool fullAreaData = false; + uint32 areaflag = area_flags[0][0]; + for (int y=0;ygetMCNK(i,j); + if (!cell) + continue; + // Height values for triangles stored in order: + // 1 2 3 4 5 6 7 8 9 + // 10 11 12 13 14 15 16 17 + // 18 19 20 21 22 23 24 25 26 + // 27 28 29 30 31 32 33 34 + // . . . . . . . . + // For better get height values merge it to V9 and V8 map + // V9 height map: + // 1 2 3 4 5 6 7 8 9 + // 18 19 20 21 22 23 24 25 26 + // . . . . . . . . + // V8 height map: + // 10 11 12 13 14 15 16 17 + // 27 28 29 30 31 32 33 34 + // . . . . . . . . + + // Set map height as grid height + for (int y=0; y <= ADT_CELL_SIZE; y++) + { + int cy = i*ADT_CELL_SIZE + y; + for (int x=0; x <= ADT_CELL_SIZE; x++) + { + int cx = j*ADT_CELL_SIZE + x; + V9[cy][cx]=cell->ypos; + } + } + for (int y=0; y < ADT_CELL_SIZE; y++) + { + int cy = i*ADT_CELL_SIZE + y; + for (int x=0; x < ADT_CELL_SIZE; x++) + { + int cx = j*ADT_CELL_SIZE + x; + V8[cy][cx]=cell->ypos; + } + } + // Get custom height + adt_MCVT *v = cell->getMCVT(); + if (!v) + continue; + // get V9 height map + for (int y=0; y <= ADT_CELL_SIZE; y++) + { + int cy = i*ADT_CELL_SIZE + y; + for (int x=0; x <= ADT_CELL_SIZE; x++) + { + int cx = j*ADT_CELL_SIZE + x; + V9[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+x]; + } + } + // get V8 height map + for (int y=0; y < ADT_CELL_SIZE; y++) + { + int cy = i*ADT_CELL_SIZE + y; + for (int x=0; x < ADT_CELL_SIZE; x++) + { + int cx = j*ADT_CELL_SIZE + x; + V8[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+ADT_CELL_SIZE+1+x]; + } + } + } + } + //============================================ + // Try pack height data + //============================================ + float maxHeight = -20000; + float minHeight = 20000; + for (int y=0; y h) minHeight = h; + } + } + for (int y=0; y<=ADT_GRID_SIZE; y++) + { + for(int x=0;x<=ADT_GRID_SIZE;x++) + { + float h = V9[y][x]; + if (maxHeight < h) maxHeight = h; + if (minHeight > h) minHeight = h; + } + } + + // Check for allow limit minimum height (not store height in deep ochean - allow save some memory) + if (CONF_allow_height_limit && minHeight < CONF_use_minHeight) + { + for (int y=0; ygetMH2O(); + if (h2o) + { + for (int i=0;igetLiquidData(i,j); + if (!h) + continue; + + int count = 0; + uint64 show = h2o->getLiquidShowMap(h); + for (int y=0; y < h->height;y++) + { + int cy = i*ADT_CELL_SIZE + y + h->yOffset; + for (int x=0; x < h->width; x++) + { + int cx = j*ADT_CELL_SIZE + x + h->xOffset; + if (show & 1) + { + liquid_show[cy][cx] = true; + ++count; + } + show>>=1; + } + } + + uint32 type = LiqType[h->liquidType]; + switch (type) + { + case LIQUID_TYPE_WATER: liquid_type[i][j] |= MAP_LIQUID_TYPE_WATER; break; + case LIQUID_TYPE_OCEAN: liquid_type[i][j] |= MAP_LIQUID_TYPE_OCEAN; break; + case LIQUID_TYPE_MAGMA: liquid_type[i][j] |= MAP_LIQUID_TYPE_MAGMA; break; + case LIQUID_TYPE_SLIME: liquid_type[i][j] |= MAP_LIQUID_TYPE_SLIME; break; + default: + printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, filename, i, j); + break; + } + // Dark water detect + if (type == LIQUID_TYPE_OCEAN) + { + uint8 *lm = h2o->getLiquidLightMap(h); + if (!lm) + liquid_type[i][j]|=MAP_LIQUID_TYPE_DARK_WATER; + } + + if (!count && liquid_type[i][j]) + printf("Wrong liquid detect in MH2O chunk"); + + float *height = h2o->getLiquidHeightMap(h); + int pos = 0; + for (int y=0; y<=h->height;y++) + { + int cy = i*ADT_CELL_SIZE + y + h->yOffset; + for (int x=0; x<= h->width; x++) + { + int cx = j*ADT_CELL_SIZE + x + h->xOffset; + if (height) + liquid_height[cy][cx] = height[pos]; + else + liquid_height[cy][cx] = h->heightLevel1; + pos++; + } + } + } + } + } + else + { + // Get from MCLQ chunk (old) + for (int i=0;igetMCNK(i, j); + if (!cell) + continue; + + adt_MCLQ *liquid = cell->getMCLQ(); + int count = 0; + if (!liquid || cell->sizeMCLQ <= 8) + continue; + + for (int y=0; y < ADT_CELL_SIZE; y++) + { + int cy = i*ADT_CELL_SIZE + y; + for (int x=0; x < ADT_CELL_SIZE; x++) + { + int cx = j*ADT_CELL_SIZE + x; + if (liquid->flags[y][x] != 0x0F) + { + liquid_show[cy][cx] = true; + if (liquid->flags[y][x]&(1<<7)) + liquid_type[i][j]|=MAP_LIQUID_TYPE_DARK_WATER; + ++count; + } + } + } + + uint32 c_flag = cell->flags; + if(c_flag & (1<<2)) + liquid_type[i][j]|=MAP_LIQUID_TYPE_WATER; // water + if(c_flag & (1<<3)) + liquid_type[i][j]|=MAP_LIQUID_TYPE_OCEAN; // ochean + if(c_flag & (1<<4)) + liquid_type[i][j]|=MAP_LIQUID_TYPE_MAGMA; // magma/slime + + if (!count && liquid_type[i][j]) + printf("Wrong liquid detect in MCLQ chunk"); + + for (int y=0; y <= ADT_CELL_SIZE; y++) + { + int cy = i*ADT_CELL_SIZE + y; + for (int x=0; x<= ADT_CELL_SIZE; x++) + { + int cx = j*ADT_CELL_SIZE + x; + liquid_height[cy][cx] = liquid->liquid[y][x].height; + } + } + } + } + } + + //============================================ + // Pack liquid data + //============================================ + uint8 type = liquid_type[0][0]; + bool fullType = false; + for (int y=0;y x) minX = x; + if (maxX < x) maxX = x; + if (minY > y) minY = y; + if (maxY < y) maxY = y; + float h = liquid_height[y][x]; + if (maxHeight < h) maxHeight = h; + if (minHeight > h) minHeight = h; + } + else + liquid_height[y][x] = CONF_use_minHeight; + } + } + map.liquidMapOffset = map.heightMapOffset + map.heightMapSize; + map.liquidMapSize = sizeof(map_liquidHeader); + liquidHeader.fourcc = MAP_LIQUID_MAGIC; + liquidHeader.flags = 0; + liquidHeader.liquidType = 0; + liquidHeader.offsetX = minX; + liquidHeader.offsetY = minY; + liquidHeader.width = maxX - minX + 1; + liquidHeader.height = maxY - minY + 1; + liquidHeader.liquidLevel = minHeight; + + if (maxHeight == minHeight) + liquidHeader.flags|=MAP_LIQUID_NO_HIGHT; + + // Not need store if flat surface + if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_liquid_delta_limit) + liquidHeader.flags|=MAP_LIQUID_NO_HIGHT; + + if (!fullType) + liquidHeader.flags|=MAP_LIQUID_NO_TYPE; + + if (liquidHeader.flags&MAP_LIQUID_NO_TYPE) + liquidHeader.liquidType = type; + else + map.liquidMapSize+=sizeof(liquid_type); + + if (!(liquidHeader.flags&MAP_LIQUID_NO_HIGHT)) + map.liquidMapSize+=sizeof(float)*liquidHeader.width*liquidHeader.height; + } + + // Ok all data prepared - store it + FILE *output=fopen(filename2, "wb"); + if(!output) + { + printf("Can't create the output file '%s'\n", filename2); + return false; + } + fwrite(&map, sizeof(map), 1, output); + // Store area data + fwrite(&areaHeader, sizeof(areaHeader), 1, output); + if (!(areaHeader.flags&MAP_AREA_NO_AREA)) + fwrite(area_flags, sizeof(area_flags), 1, output); + + // Store height data + fwrite(&heightHeader, sizeof(heightHeader), 1, output); + if (!(heightHeader.flags&MAP_HEIGHT_NO_HIGHT)) + { + if (heightHeader.flags&MAP_HEIGHT_AS_INT16) + { + fwrite(uint16_V9, sizeof(uint16_V9), 1, output); + fwrite(uint16_V8, sizeof(uint16_V8), 1, output); + } + else if (heightHeader.flags&MAP_HEIGHT_AS_INT8) + { + fwrite(uint8_V9, sizeof(uint8_V9), 1, output); + fwrite(uint8_V8, sizeof(uint8_V8), 1, output); + } + else + { + fwrite(V9, sizeof(V9), 1, output); + fwrite(V8, sizeof(V8), 1, output); + } + } + + // Store liquid data if need + if (map.liquidMapOffset) + { + fwrite(&liquidHeader, sizeof(liquidHeader), 1, output); + if (!(liquidHeader.flags&MAP_LIQUID_NO_TYPE)) + fwrite(liquid_type, sizeof(liquid_type), 1, output); + if (!(liquidHeader.flags&MAP_LIQUID_NO_HIGHT)) + { + for (int y=0; yadt_list[y][x].exist) + continue; sprintf(mpq_filename, "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); - ConvertADT(mpq_filename, output_filename); - done++; + ConvertADT(mpq_filename, output_filename, y, x); } // draw progress bar - printf("Processing........................%d%%\r", (100 * done) / total); + printf("Processing........................%d%%\r", (100 * (y+1)) / WDT_MAP_SIZE); } } - delete [] areas; delete [] map_ids; } -//bool WMO(char* filename); - void ExtractDBCFiles(int locale, bool basicLocale) { printf("Extracting dbc files...\n"); @@ -277,21 +912,10 @@ void LoadLocaleMPQFiles(int const locale) void LoadCommonMPQFiles() { char filename[512]; - - sprintf(filename,"%s/Data/common-2.MPQ", input_path); - new MPQArchive(filename); - sprintf(filename,"%s/Data/lichking.MPQ", input_path); - new MPQArchive(filename); - sprintf(filename,"%s/Data/expansion.MPQ", input_path); - new MPQArchive(filename); - - for(int i = 1; i < 5; ++i) + int count = sizeof(CONF_mpq_list)/sizeof(char*); + for(int i = 0; i < count; ++i) { - char ext[3] = ""; - if(i > 1) - sprintf(ext, "-%i", i); - - sprintf(filename, "%s/Data/patch%s.MPQ", input_path, ext); + sprintf(filename, "%s/Data/%s", input_path, CONF_mpq_list[i]); if(FileExists(filename)) new MPQArchive(filename); } @@ -323,7 +947,7 @@ int main(int argc, char * arg[]) //Open MPQs LoadLocaleMPQFiles(i); - if((extract & EXTRACT_DBC) == 0) + if((CONF_extract & EXTRACT_DBC) == 0) { FirstLocale = i; break; @@ -349,7 +973,7 @@ int main(int argc, char * arg[]) return 0; } - if (extract & EXTRACT_MAP) + if (CONF_extract & EXTRACT_MAP) { printf("Using locale: %s\n", langs[FirstLocale]); diff --git a/contrib/extractor/VC71_ad.vcproj b/contrib/extractor/VC71_ad.vcproj index fd2d16120..541540cea 100644 --- a/contrib/extractor/VC71_ad.vcproj +++ b/contrib/extractor/VC71_ad.vcproj @@ -213,7 +213,15 @@ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" > + + + + + + @@ -253,6 +257,10 @@ /> + + diff --git a/contrib/extractor/VC90_ad.vcproj b/contrib/extractor/VC90_ad.vcproj index 59fdf6d21..9a039a0fb 100644 --- a/contrib/extractor/VC90_ad.vcproj +++ b/contrib/extractor/VC90_ad.vcproj @@ -216,7 +216,15 @@ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" > + + + + -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "adt.h" -#include "mpq_libmpq.h" - -extern uint16 *areas; -extern uint16 *LiqType; -extern uint32 maxAreaId; - -vec wmoc; - -Cell *cell; -mcell *mcells; -int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888}; -int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000}; - -bool LoadADT(char* filename) -{ - size_t size; - MPQFile mf(filename); - - if(mf.isEof()) - { - //printf("No such file %s\n", filename); - return false; - } - - MapLiqFlag = new uint8[256]; - for(uint32 j = 0; j < 256; ++j) - MapLiqFlag[j] = 0; // no water - - MapLiqHeight = new float[16384]; - for(uint32 j = 0; j < 16384; ++j) - MapLiqHeight[j] = -999999; // no water - - mcells = new mcell; - - wmoc.x = 65 * TILESIZE; - wmoc.z = 65 * TILESIZE; - - size_t mcnk_offsets[256], mcnk_sizes[256]; - - chunk_num = 0; - k = 0; - m = 0; - while (!mf.isEof()) - { - uint32 fourcc; - mf.read(&fourcc, 4); - mf.read(&size, 4); - - size_t nextpos = mf.getPos() + size; - - //if(fourcc==0x4d484452) // MHDR header - //if(fourcc==0x4d564552) // MVER - if(fourcc == 0x4d43494e) // MCIN - { - for (uint32 i = 0; i < 256; ++i) - { - mf.read(&mcnk_offsets[i], 4); - mf.read(&mcnk_sizes[i], 4); - mf.seekRelative(8); - } - } - //if(fourcc == 0x4d544558) // MTEX textures (strings) - //if(fourcc == 0x4d4d4458) // MMDX m2 models (strings) - //if(fourcc == 0x4d4d4944) // MMID offsets for strings in MMDX - //if(fourcc == 0x4d574d4f) // MWMO - //if(fourcc == 0x4d574944) // MWID offsets for strings in MWMO - //if(fourcc == 0x4d444446) // MDDF - //if(fourcc == 0x4d4f4446) // MODF - if(fourcc == 0x4d48324f) // MH2O new in WotLK - { - // здесь надо запомнить базовую позицию в файле тк все смещения будут от него - uint32 base_pos = mf.getPos(); - uint32 header_pos = 0; - MH2O_offsData *LiqOffsData = new MH2O_offsData; - MH2O_Data1 *LiqChunkData1 = new MH2O_Data1; - float *ChunkLiqHeight = new float[81]; - for(chunk_num = 0; chunk_num < 256; ++chunk_num) - { - mf.read(LiqOffsData, 0x0C); - header_pos = mf.getPos(); - if(LiqOffsData->offsData1 != 0) // если данные в Data1 о воде есть, то их надо конвертировать - { - // переходим по смещению из offsData1 ОТ НАЧАЛА куска - mf.seek(base_pos + LiqOffsData->offsData1); - mf.read(LiqChunkData1, 0x18); // считываем сами данные в структуру типа MH2O_Data1 - // заносим данные флага для куска - if(LiqType[LiqChunkData1->LiquidTypeId] == 0xffff) - printf("\nCan't find Liquid type for map %s\nchunk %d\n", filename, chunk_num); - else if(LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_WATER || LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_OCEAN) - MapLiqFlag[chunk_num] |= 1; // water/ocean - else if(LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_MAGMA || LiqType[LiqChunkData1->LiquidTypeId] == LIQUID_TYPE_SLIME) - MapLiqFlag[chunk_num] |= 2; // magma/slime - // предварительно заполняем весь кусок данными - нет воды - for(int j = 0; j < 81; ++j) - { - ChunkLiqHeight[j] = -999999; // no liquid/water - } - // теперь вычисляем те что с водой и перезаписываем их в куске - for(int b = 0; b <= LiqChunkData1->height; ++b) - { - for(int c = LiqChunkData1->xOffset; c <= (LiqChunkData1->xOffset + LiqChunkData1->width); ++c) - { - int n = (9 * (LiqChunkData1->yOffset + b)) + c; - ChunkLiqHeight[n] = LiqChunkData1->heightLevel1; - } - } - mf.seek(header_pos); // и не забыть вернуться на исходную позицию именно В ХИДЕРЕ - } - else // если данных в Data1 нет, то надо заполнить весь кусок, но данными - нет воды - { - for(int j = 0; j < 81; ++j) - ChunkLiqHeight[j] = -999999; // no liquid/water - } - - if(!(chunk_num % 16)) - m = 1024 * (chunk_num / 16); // смещение по рядам кусков с перекрытием = 1024 - k = m + (chunk_num % 16) * 8; // устанавливаемся на начальный индекс для заполнения ряда - // заносим данные куска в массив для карты, с перекрытием и обрезанием кусков тк данных 81 - // это аналог старого обрезания граничных правых-боковых и нижних данных - for(int p = 0; p < 72; p += 9) // нижние 8 не заносим тк они дублируется след куском - { - for(int s = 0; s < 8; ++s) // 9 значение в строке не заносим тк оно дублируется след куском, а в правых-боковых обрезается для 128х128 - { - MapLiqHeight[k] = ChunkLiqHeight[p + s]; - ++k; - } - k = k + 120; - } - } - delete LiqOffsData; - delete LiqChunkData1; - delete []ChunkLiqHeight; - - } - //case 0x4d434e4b: // MCNK - //case 0x4d46424f: // MFBO new in BC - //case 0x4d545846: // MTXF new in WotLK - mf.seek(nextpos); - } - - //printf("Loading chunks info\n"); - // read individual map chunks - chunk_num = 0; - k = 0; - m = 0; - for (int j = 0; j < 16; ++j) - { - for (int i = 0; i < 16; ++i) - { - mf.seek((int)mcnk_offsets[j * 16 + i]); - LoadMapChunk(mf, &(mcells->ch[i][j])); - ++chunk_num; - } - } - mf.close(); - return true; -} - -bool isHole(int holes, int i, int j) -{ - int testi = i / 2; - int testj = j / 4; - if(testi > 3) testi = 3; - if(testj > 3) testj = 3; - return (holes & holetab_h[testi] & holetab_v[testj]) != 0; -} - -inline void LoadMapChunk(MPQFile &mf, chunk *_chunk) -{ - float h; - uint32 fourcc; - uint32 size; - MapChunkHeader header; - - mf.seekRelative(4); - mf.read(&size, 4); - - size_t lastpos = mf.getPos() + size; - mf.read(&header, 0x80); // what if header size got changed? - _chunk->area_id = header.areaid; - - float xbase = header.xpos; - float ybase = header.ypos; - float zbase = header.zpos; - zbase = TILESIZE * 32 - zbase; - xbase = TILESIZE * 32 - xbase; - if(wmoc.x > xbase) wmoc.x = xbase; - if(wmoc.z > zbase) wmoc.z = zbase; - int chunkflags = header.flags; - //printf("LMC: flags %X\n", chunkflags); - float zmin = 999999999.0f; - float zmax = -999999999.0f; - // must be there, bl!zz uses some crazy format - while (mf.getPos() < lastpos) - { - mf.read(&fourcc, 4); - mf.read(&size, 4); - size_t nextpos = mf.getPos() + size; - if(fourcc == 0x4d435654) // MCVT - { - for (int j = 0; j < 17; ++j) - { - for (int i = 0; i < ((j % 2) ? 8 : 9); ++i) - { - mf.read(&h, 4); - float z = h + ybase; - if (j % 2) - { - if(isHole(header.holes, i, j)) - _chunk->v8[i][j / 2] = -1000; - else - _chunk->v8[i][j / 2] = z; - } - else - { - if(isHole(header.holes, i, j)) - _chunk->v9[i][j / 2] = -1000; - else - _chunk->v9[i][j / 2] = z; - } - - if(z > zmax) zmax = z; - //if(z < zmin) zmin = z; - } - } - } - else if(fourcc == 0x4d434e52) // MCNR - { - nextpos = mf.getPos() + 0x1C0; // size fix - } - else if(fourcc == 0x4d434c51) // не будем учитывать если уже были данные в MH2O, перестраховка :) // MCLQ - { - // liquid / water level - char fcc1[5]; - mf.read(fcc1, 4); - flipcc(fcc1); - fcc1[4] = 0; - float *ChunkLiqHeight = new float[81]; - - if (!strcmp(fcc1, "MCSE")) - { - for(int j = 0; j < 81; ++j) - { - ChunkLiqHeight[j] = -999999; // no liquid/water - } - } - else - { - float maxheight; - mf.read(&maxheight, 4); - for(int j = 0; j < 81; ++j) - { - LiqData liq; - mf.read(&liq, 8); - - if(liq.height > maxheight) - ChunkLiqHeight[j] = -999999; - else - ChunkLiqHeight[j] = h; - } - - if(chunkflags & 4 || chunkflags & 8) - MapLiqFlag[chunk_num] |= 1; // water - if(chunkflags & 16) - MapLiqFlag[chunk_num] |= 2; // magma/slime - } - // заполнем так же как в MH2O - if(!(chunk_num % 16)) - m = 1024 * (chunk_num / 16); - k = m + (chunk_num % 16) * 8; - - for(int p = 0; p < 72; p += 9) - { - for(int s = 0; s < 8; ++s) - { - MapLiqHeight[k] = ChunkLiqHeight[p + s]; - ++k; - } - k = k + 120; - } - delete []ChunkLiqHeight; - break; - } - mf.seek(nextpos); - } -} - -inline void TransformData() -{ - cell = new Cell; - - for(uint32 x = 0; x < 128; ++x) - { - for(uint32 y = 0; y < 128; ++y) - { - cell->v8[y][x] = (float)mcells->ch[x / 8][y / 8].v8[x % 8][y % 8]; - cell->v9[y][x] = (float)mcells->ch[x / 8][y / 8].v9[x % 8][y % 8]; - } - - // extra 1 point on bounds - cell->v9[128][x] = (float)mcells->ch[x / 8][15].v9[x % 8][8]; - // x == y - cell->v9[x][128] = (float)mcells->ch[15][x / 8].v9[8][x % 8]; - - } - - // and the last 1 - cell->v9[128][128] = (float)mcells->ch[15][15].v9[8][8]; - - delete mcells; -} - -const char MAP_MAGIC[] = "MAP_3.00"; - -bool ConvertADT(char *filename, char *filename2) -{ - if(!LoadADT(filename)) - return false; - - FILE *output=fopen(filename2, "wb"); - if(!output) - { - printf("Can't create the output file '%s'\n", filename2); - delete [] MapLiqHeight; - delete [] MapLiqFlag; - return false; - } - - // write magic header - fwrite(MAP_MAGIC, 1, 8, output); - - for(uint32 x = 0; x < 16; ++x) - { - for(uint32 y = 0; y < 16; ++y) - { - if(mcells->ch[y][x].area_id && mcells->ch[y][x].area_id <= maxAreaId) - { - if(areas[mcells->ch[y][x].area_id] == 0xffff) - printf("\nCan't find area flag for areaid %u.\n", mcells->ch[y][x].area_id); - - fwrite(&areas[mcells->ch[y][x].area_id], 1, 2, output); - } - else - { - uint16 flag = 0xffff; - fwrite(&flag, 1, 2, output); - } - } - } - - fwrite(MapLiqFlag, 1, 256, output); - delete [] MapLiqFlag; - - fwrite(MapLiqHeight, sizeof(float), 16384, output); - delete [] MapLiqHeight; - - TransformData(); - - fwrite(&cell->v9, 1, sizeof(cell->v9), output); - fwrite(&cell->v8, 1, sizeof(cell->v8), output); - fclose(output); - delete cell; - - return true; -} diff --git a/contrib/extractor/adt.h b/contrib/extractor/adt.h deleted file mode 100644 index 52196c4e7..000000000 --- a/contrib/extractor/adt.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef ADT_H -#define ADT_H - -#define TILESIZE (533.33333f) -#define CHUNKSIZE ((TILESIZE) / 16.0f) -#define UNITSIZE (CHUNKSIZE / 8.0f) - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -class Liquid; -typedef struct -{ - float x; - float y; - float z; -} svec; - -typedef struct -{ - double x; - double y; - double z; -} vec; - -typedef struct -{ - vec v[3]; -} triangle; - -typedef struct -{ - float v9[16 * 8 + 1][16 * 8 + 1]; - float v8[16 * 8][16 * 8]; -} Cell; - -typedef struct -{ - double v9[9][9]; - double v8[8][8]; - uint16 area_id; -} chunk; - -typedef struct -{ - chunk ch[16][16]; -} mcell; - -struct MapChunkHeader -{ - uint32 flags; - uint32 ix; - uint32 iy; - uint32 nLayers; - uint32 nDoodadRefs; - uint32 ofsHeight; - uint32 ofsNormal; - uint32 ofsLayer; - uint32 ofsRefs; - uint32 ofsAlpha; - uint32 sizeAlpha; - uint32 ofsShadow; - uint32 sizeShadow; - uint32 areaid; - uint32 nMapObjRefs; - uint32 holes; - uint16 s1; - uint16 s2; - uint32 d1; - uint32 d2; - uint32 d3; - uint32 predTex; - uint32 nEffectDoodad; - uint32 ofsSndEmitters; - uint32 nSndEmitters; - uint32 ofsLiquid; // not use in WotLK - uint32 sizeLiquid; // not use in WotLK - float zpos; - float xpos; - float ypos; - uint32 textureId; // new offsColorValues in WotLK - uint32 props; - uint32 effectId; -}; - -typedef struct -{ - uint32 offsData1; - uint32 used; - uint32 offsData2; -} MH2O_offsData; - -typedef struct -{ - uint16 LiquidTypeId; - uint16 type; - float heightLevel1; - float heightLevel2; - uint8 xOffset; - uint8 yOffset; - uint8 width; - uint8 height; - uint32 ofsData2a; - uint32 ofsData2b; -} MH2O_Data1; - -typedef struct -{ - uint16 unk1; - uint16 unk2; - float height; -} LiqData; - -enum LiquidType -{ - LIQUID_TYPE_WATER = 0, - LIQUID_TYPE_OCEAN = 1, - LIQUID_TYPE_MAGMA = 2, - LIQUID_TYPE_SLIME = 3 -}; - -class MPQFile; - -float *MapLiqHeight; -uint8 *MapLiqFlag; -uint32 k, m, chunk_num; -void LoadMapChunk(MPQFile &, chunk*); -#endif diff --git a/contrib/extractor/loadlib/CMakeLists.txt b/contrib/extractor/loadlib/CMakeLists.txt new file mode 100644 index 000000000..5680c61d4 --- /dev/null +++ b/contrib/extractor/loadlib/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (C) 2005-2009 MaNGOS project +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +add_library (loadlib loadlib.cpp adt.cpp wdt.cpp) +# link loadlib with zlib +target_link_libraries (loadlib z) diff --git a/contrib/extractor/loadlib/adt.cpp b/contrib/extractor/loadlib/adt.cpp new file mode 100644 index 000000000..fde706811 --- /dev/null +++ b/contrib/extractor/loadlib/adt.cpp @@ -0,0 +1,131 @@ +#define _CRT_SECURE_NO_DEPRECATE + +#include "adt.h" + +// Helper +int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888}; +int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000}; + +bool isHole(int holes, int i, int j) +{ + int testi = i / 2; + int testj = j / 4; + if(testi > 3) testi = 3; + if(testj > 3) testj = 3; + return (holes & holetab_h[testi] & holetab_v[testj]) != 0; +} + +// +// Adt file loader class +// +ADT_file::ADT_file() +{ + a_grid = 0; +} + +ADT_file::~ADT_file() +{ + free(); +} + +void ADT_file::free() +{ + a_grid = 0; + FileLoader::free(); +} + +// +// Adt file check function +// +bool ADT_file::prepareLoadedData() +{ + // Check parent + if (!FileLoader::prepareLoadedData()) + return false; + + // Check and prepare MHDR + a_grid = (adt_MHDR *)(GetData()+8+version->size); + if (!a_grid->prepareLoadedData()) + return false; + + return true; +} + +bool adt_MHDR::prepareLoadedData() +{ + if (fcc != 'MHDR') + return false; + + if (size!=sizeof(adt_MHDR)-8) + return false; + + // Check and prepare MCIN + if (offsMCIN && !getMCIN()->prepareLoadedData()) + return false; + + // Check and prepare MH2O + if (offsMH2O && !getMH2O()->prepareLoadedData()) + return false; + + return true; +} + +bool adt_MCIN::prepareLoadedData() +{ + if (fcc != 'MCIN') + return false; + + // Check cells data + for (int i=0; iprepareLoadedData()) + return false; + + return true; +} + +bool adt_MH2O::prepareLoadedData() +{ + if (fcc != 'MH2O') + return false; + + // Check liquid data +// for (int i=0; iprepareLoadedData()) + return false; + // Check liquid data + if (offsMCLQ && !getMCLQ()->prepareLoadedData()) + return false; + + return true; +} + +bool adt_MCVT::prepareLoadedData() +{ + if (fcc != 'MCVT') + return false; + + if (size != sizeof(adt_MCVT)-8) + return false; + + return true; +} + +bool adt_MCLQ::prepareLoadedData() +{ + if (fcc != 'MCLQ') + return false; + + return true; +} \ No newline at end of file diff --git a/contrib/extractor/loadlib/adt.h b/contrib/extractor/loadlib/adt.h new file mode 100644 index 000000000..725c5b994 --- /dev/null +++ b/contrib/extractor/loadlib/adt.h @@ -0,0 +1,289 @@ +#ifndef ADT_H +#define ADT_H + +#include "loadlib.h" + +#define TILESIZE (533.33333f) +#define CHUNKSIZE ((TILESIZE) / 16.0f) +#define UNITSIZE (CHUNKSIZE / 8.0f) + +enum LiquidType +{ + LIQUID_TYPE_WATER = 0, + LIQUID_TYPE_OCEAN = 1, + LIQUID_TYPE_MAGMA = 2, + LIQUID_TYPE_SLIME = 3 +}; + +//************************************************************************************** +// ADT file class +//************************************************************************************** +#define ADT_CELLS_PER_GRID 16 +#define ADT_CELL_SIZE 8 +#define ADT_GRID_SIZE (ADT_CELLS_PER_GRID*ADT_CELL_SIZE) + +// +// Adt file height map chunk +// +class adt_MCVT +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; +public: + float height_map[(ADT_CELL_SIZE+1)*(ADT_CELL_SIZE+1)+ADT_CELL_SIZE*ADT_CELL_SIZE]; + + bool prepareLoadedData(); +}; + +// +// Adt file liquid map chunk (old) +// +class adt_MCLQ +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; +public: + float height1; + float height2; + struct liquid_data{ + uint32 light; + float height; + } liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1]; + + // 1<<0 - ochen + // 1<<1 - lava/slime + // 1<<2 - water + // 1<<6 - all water + // 1<<7 - dark water + // == 0x0F - not show liquid + uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE]; + uint8 data[84]; + bool prepareLoadedData(); +}; + +// +// Adt file cell chunk +// +class adt_MCNK +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; +public: + uint32 flags; + uint32 ix; + uint32 iy; + uint32 nLayers; + uint32 nDoodadRefs; + uint32 offsMCVT; // height map + uint32 offsMCNR; // Normal vectors for each vertex + uint32 offsMCLY; // Texture layer definitions + uint32 offsMCRF; // A list of indices into the parent file's MDDF chunk + uint32 offsMCAL; // Alpha maps for additional texture layers + uint32 sizeMCAL; + uint32 offsMCSH; // Shadow map for static shadows on the terrain + uint32 sizeMCSH; + uint32 areaid; + uint32 nMapObjRefs; + uint32 holes; + uint16 s[2]; + uint32 data1; + uint32 data2; + uint32 data3; + uint32 predTex; + uint32 nEffectDoodad; + uint32 offsMCSE; + uint32 nSndEmitters; + uint32 offsMCLQ; // Liqid level (old) + uint32 sizeMCLQ; // + float zpos; + float xpos; + float ypos; + uint32 offsMCCV; // offsColorValues in WotLK + uint32 props; + uint32 effectId; + + bool prepareLoadedData(); + adt_MCVT *getMCVT() + { + if (offsMCVT) + return (adt_MCVT *)((uint8 *)this + offsMCVT); + return 0; + } + adt_MCLQ *getMCLQ() + { + if (offsMCLQ) + return (adt_MCLQ *)((uint8 *)this + offsMCLQ); + return 0; + } +}; + +// +// Adt file grid chunk +// +class adt_MCIN +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; +public: + struct adt_CELLS{ + uint32 offsMCNK; + uint32 size; + uint32 flags; + uint32 asyncId; + } cells[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + + bool prepareLoadedData(); + // offset from begin file (used this-84) + adt_MCNK *getMCNK(int x, int y) + { + if (cells[x][y].offsMCNK) + return (adt_MCNK *)((uint8 *)this + cells[x][y].offsMCNK - 84); + return 0; + } +}; + +#define ADT_LIQUID_HEADER_FULL_LIGHT 0x01 +#define ADT_LIQUID_HEADER_NO_HIGHT 0x02 + +struct adt_liquid_header{ + uint16 liquidType; // Index from LiquidType.dbc + uint16 formatFlags; + float heightLevel1; + float heightLevel2; + uint8 xOffset; + uint8 yOffset; + uint8 width; + uint8 height; + uint32 offsData2a; + uint32 offsData2b; +}; + +// +// Adt file liquid data chunk (new) +// +class adt_MH2O +{ +public: + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; + + struct adt_LIQUID{ + uint32 offsData1; + uint32 used; + uint32 offsData2; + } liquid[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + + bool prepareLoadedData(); + + adt_liquid_header *getLiquidData(int x, int y) + { + if (liquid[x][y].used && liquid[x][y].offsData1) + return (adt_liquid_header *)((uint8*)this + 8 + liquid[x][y].offsData1); + return 0; + } + + float *getLiquidHeightMap(adt_liquid_header *h) + { + if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT) + return 0; + if (h->offsData2b) + return (float *)((uint8*)this + 8 + h->offsData2b); + return 0; + } + + uint8 *getLiquidLightMap(adt_liquid_header *h) + { + if (h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT) + return 0; + if (h->offsData2b) + { + if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT) + return (uint8 *)((uint8*)this + 8 + h->offsData2b); + return (uint8 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4); + } + return 0; + } + + uint32 *getLiquidFullLightMap(adt_liquid_header *h) + { + if (!(h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT)) + return 0; + if (h->offsData2b) + { + if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT) + return (uint32 *)((uint8*)this + 8 + h->offsData2b); + return (uint32 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4); + } + return 0; + } + + uint64 getLiquidShowMap(adt_liquid_header *h) + { + if (h->offsData2a) + return *((uint64 *)((uint8*)this + 8 + h->offsData2a)); + else + return 0xFFFFFFFFFFFFFFFFLL; + } + +}; + +// +// Adt file header chunk +// +class adt_MHDR +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; + + uint32 pad; + uint32 offsMCIN; // MCIN + uint32 offsTex; // MTEX + uint32 offsModels; // MMDX + uint32 offsModelsIds; // MMID + uint32 offsMapObejcts; // MWMO + uint32 offsMapObejctsIds; // MWID + uint32 offsDoodsDef; // MDDF + uint32 offsObjectsDef; // MODF + uint32 offsMFBO; // MFBO + uint32 offsMH2O; // MH2O + uint32 data1; + uint32 data2; + uint32 data3; + uint32 data4; + uint32 data5; +public: + bool prepareLoadedData(); + adt_MCIN *getMCIN(){ return (adt_MCIN *)((uint8 *)&pad+offsMCIN);} + adt_MH2O *getMH2O(){ return offsMH2O ? (adt_MH2O *)((uint8 *)&pad+offsMH2O) : 0;} + +}; + +class ADT_file : public FileLoader{ +public: + bool prepareLoadedData(); + ADT_file(); + ~ADT_file(); + void free(); + + adt_MHDR *a_grid; +}; + +#endif diff --git a/contrib/extractor/loadlib/loadlib.cpp b/contrib/extractor/loadlib/loadlib.cpp new file mode 100644 index 000000000..ed5bd9acb --- /dev/null +++ b/contrib/extractor/loadlib/loadlib.cpp @@ -0,0 +1,64 @@ +#define _CRT_SECURE_NO_DEPRECATE + +#include "loadlib.h" +#include "../mpq_libmpq.h" + +class MPQFile; + +FileLoader::FileLoader() +{ + data = 0; + data_size = 0; + version = 0; +} + +FileLoader::~FileLoader() +{ + free(); +} + +bool FileLoader::loadFile(char *filename, bool log) +{ + free(); + MPQFile mf(filename); + if(mf.isEof()) + { + if (log) + printf("No such file %s\n", filename); + return false; + } + + data_size = mf.getSize(); + + data = new uint8 [data_size]; + if (data) + { + mf.read(data, data_size); + mf.close(); + if (prepareLoadedData()) + return true; + } + printf("Error loading %s", filename); + mf.close(); + free(); + return false; +} + +bool FileLoader::prepareLoadedData() +{ + // Check version + version = (file_MVER *) data; + if (version->fcc != 'MVER') + return false; + if (version->ver != FILE_FORMAT_VERSION) + return false; + return true; +} + +void FileLoader::free() +{ + if (data) delete[] data; + data = 0; + data_size = 0; + version = 0; +} \ No newline at end of file diff --git a/contrib/extractor/loadlib/loadlib.h b/contrib/extractor/loadlib/loadlib.h new file mode 100644 index 000000000..6acfd107e --- /dev/null +++ b/contrib/extractor/loadlib/loadlib.h @@ -0,0 +1,57 @@ +#ifndef LOAD_LIB_H +#define LOAD_LIB_H + +#ifdef WIN32 +typedef __int64 int64; +typedef long int32; +typedef short int16; +typedef char int8; +typedef unsigned __int64 uint64; +typedef unsigned long uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; +#else +#include +#ifndef uint64_t +#include +#endif +typedef int64_t int64; +typedef long int32; +typedef short int16; +typedef char int8; +typedef uint64_t uint64; +typedef unsigned long uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; +#endif + +#define FILE_FORMAT_VERSION 18 + +// +// File version chunk +// +struct file_MVER +{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; + uint32 ver; +}; + +class FileLoader{ + uint8 *data; + uint32 data_size; +public: + virtual bool prepareLoadedData(); + uint8 *GetData() {return data;} + uint32 GetDataSize() {return data_size;} + + file_MVER *version; + FileLoader(); + ~FileLoader(); + bool loadFile(char *filename, bool log = true); + virtual void free(); +}; +#endif diff --git a/contrib/extractor/loadlib/wdt.cpp b/contrib/extractor/loadlib/wdt.cpp new file mode 100644 index 000000000..dedefbb64 --- /dev/null +++ b/contrib/extractor/loadlib/wdt.cpp @@ -0,0 +1,62 @@ +#define _CRT_SECURE_NO_DEPRECATE + +#include "wdt.h" + +bool wdt_MWMO::prepareLoadedData() +{ + if (fcc != 'MWMO') + return false; + return true; +} + +bool wdt_MPHD::prepareLoadedData() +{ + if (fcc != 'MPHD') + return false; + return true; +} + +bool wdt_MAIN::prepareLoadedData() +{ + if (fcc != 'MAIN') + return false; + return true; +} + +WDT_file::WDT_file() +{ + mphd = 0; + main = 0; + wmo = 0; +} + +WDT_file::~WDT_file() +{ + free(); +} + +void WDT_file::free() +{ + mphd = 0; + main = 0; + wmo = 0; + FileLoader::free(); +} + +bool WDT_file::prepareLoadedData() +{ + // Check parent + if (!FileLoader::prepareLoadedData()) + return false; + + mphd = (wdt_MPHD *)((uint8*)version+version->size+8); + if (!mphd->prepareLoadedData()) + return false; + main = (wdt_MAIN *)((uint8*)mphd + mphd->size+8); + if (!main->prepareLoadedData()) + return false; + wmo = (wdt_MWMO *)((uint8*)main+ main->size+8); + if (!wmo->prepareLoadedData()) + return false; + return true; +} \ No newline at end of file diff --git a/contrib/extractor/loadlib/wdt.h b/contrib/extractor/loadlib/wdt.h new file mode 100644 index 000000000..fcee8ac64 --- /dev/null +++ b/contrib/extractor/loadlib/wdt.h @@ -0,0 +1,68 @@ +#ifndef WDT_H +#define WDT_H +#include "loadlib.h" + +//************************************************************************************** +// WDT file class and structures +//************************************************************************************** +#define WDT_MAP_SIZE 64 + +class wdt_MWMO{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; +public: + uint32 size; + bool prepareLoadedData(); +}; + +class wdt_MPHD{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; +public: + uint32 size; + + uint32 data1; + uint32 data2; + uint32 data3; + uint32 data4; + uint32 data5; + uint32 data6; + uint32 data7; + uint32 data8; + bool prepareLoadedData(); +}; + +class wdt_MAIN{ + union{ + uint32 fcc; + char fcc_txt[4]; + }; +public: + uint32 size; + + struct adtData{ + uint32 exist; + uint32 data1; + } adt_list[64][64]; + + bool prepareLoadedData(); +}; + +class WDT_file : public FileLoader{ +public: + bool prepareLoadedData(); + + WDT_file(); + ~WDT_file(); + void free(); + + wdt_MPHD *mphd; + wdt_MAIN *main; + wdt_MWMO *wmo; +}; + +#endif \ No newline at end of file diff --git a/contrib/extractor/mpq_libmpq.h b/contrib/extractor/mpq_libmpq.h index 9b4984a50..7b5258e6a 100644 --- a/contrib/extractor/mpq_libmpq.h +++ b/contrib/extractor/mpq_libmpq.h @@ -4,6 +4,7 @@ #ifndef MPQ_H #define MPQ_H +#include "loadlib/loadlib.h" #include "libmpq/mpq.h" #include #include @@ -13,7 +14,6 @@ using namespace std; -typedef unsigned int uint32; class MPQArchive { diff --git a/sql/mangos.sql b/sql/mangos.sql index a75345530..9c54def8b 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -22,7 +22,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, - `required_7382_01_mangos_creature_template` bit(1) default NULL + `required_7439_01_mangos_mangos_string` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -135,6 +135,7 @@ CREATE TABLE `areatrigger_teleport` ( `heroic_key` mediumint(8) unsigned NOT NULL default '0', `heroic_key2` mediumint(8) unsigned NOT NULL default '0', `required_quest_done` int(11) unsigned NOT NULL default '0', + `required_quest_done_heroic` int(11) unsigned NOT NULL default '0', `required_failed_text` text, `target_map` smallint(5) unsigned NOT NULL default '0', `target_position_x` float NOT NULL default '0', @@ -1071,6 +1072,7 @@ CREATE TABLE `game_event` ( `end_time` timestamp NOT NULL default '0000-00-00 00:00:00' COMMENT 'Absolute end date, the event will never start afler', `occurence` bigint(20) unsigned NOT NULL default '86400' COMMENT 'Delay in hours between occurences of the event', `length` bigint(20) unsigned NOT NULL default '43200' COMMENT 'Length in hours of the event', + `holiday` mediumint(8) unsigned NOT NULL default '0' COMMENT 'Client side holiday id', `description` varchar(255) default NULL COMMENT 'Description of the event displayed in console', PRIMARY KEY (`entry`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -2407,6 +2409,7 @@ INSERT INTO `mangos_string` VALUES (172,'server console command',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (173,'You changed runic power of %s to %i/%i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (174,'%s changed your runic power to %i/%i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(175,'Liquid level: %f, ground: %f, type: %d, status: %d',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (200,'No selection.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (201,'Object GUID is: lowpart %u highpart %X',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (202,'The name was too long by %i characters.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2812,7 +2815,6 @@ INSERT INTO `mangos_string` VALUES (723,'Your group does not have enough players to join this match.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (724,'The Gold Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (725,'The Green Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(726,'There aren\'t enough players in this battleground. It will end soon unless some more players join to balance the fight.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (727,'Your group has an offline member. Please remove him before joining.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (728,'Your group has players from the opposing faction. You can\'t join the battleground as a group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (729,'Your group has players from different battleground brakets. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2833,6 +2835,11 @@ INSERT INTO `mangos_string` VALUES (744,'Modifying played count, arena points etc. for loaded arena teams, sending updated stats to online players...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (745,'Modification done.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (746,'Done flushing Arena points.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(750,'Not enough players. This game will close in %u mins.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(751,'Not enough players. This game will close in %u seconds.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(753,'The battle for Warsong Gulch begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(754,'The battle for Arathi Basin begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(755,'The battle for Eye of the Storm begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (801,'You do not have enough gold',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (802,'You do not have enough free slots',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (803,'Your partner does not have enough free bag slots',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), @@ -2843,6 +2850,11 @@ INSERT INTO `mangos_string` VALUES (808,'Player %s not found or offline',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (809,'Account for character %s not found',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (810,'|Hplayer:$N|h[$N]|h has earned the achievement $a!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(811,'Guild Master',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(812,'Officer',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(813,'Veteran',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(814,'Member',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(815,'Initiate',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1000,'Exiting daemon...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1001,'Account deleted: %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1002,'Account %s NOT deleted (probably sql file format was updated)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), diff --git a/sql/updates/7388_01_mangos_mangos_string.sql b/sql/updates/7388_01_mangos_mangos_string.sql new file mode 100644 index 000000000..5a876e713 --- /dev/null +++ b/sql/updates/7388_01_mangos_mangos_string.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_7382_01_mangos_creature_template required_7388_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry IN (750,751); +INSERT INTO mangos_string VALUES (750,'Not enough players. This game will close in %u mins.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO mangos_string VALUES (751,'Not enough players. This game will close in %u seconds.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/sql/updates/7390_01_mangos_areatrigger_teleport.sql b/sql/updates/7390_01_mangos_areatrigger_teleport.sql new file mode 100644 index 000000000..784272a57 --- /dev/null +++ b/sql/updates/7390_01_mangos_areatrigger_teleport.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7388_01_mangos_mangos_string required_7390_01_mangos_areatrigger_teleport bit; + +ALTER TABLE areatrigger_teleport + ADD COLUMN required_quest_done_heroic int(11) unsigned NOT NULL default '0' AFTER required_quest_done; \ No newline at end of file diff --git a/sql/updates/7393_01_mangos_game_event.sql b/sql/updates/7393_01_mangos_game_event.sql new file mode 100644 index 000000000..24e576462 --- /dev/null +++ b/sql/updates/7393_01_mangos_game_event.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7390_01_mangos_areatrigger_teleport required_7393_01_mangos_game_event bit; + +ALTER TABLE game_event + ADD COLUMN holiday mediumint(8) unsigned NOT NULL default '0' COMMENT 'Client side holiday id' AFTER length; diff --git a/sql/updates/7399_01_mangos_mangos_string.sql b/sql/updates/7399_01_mangos_mangos_string.sql new file mode 100644 index 000000000..d029d28d3 --- /dev/null +++ b/sql/updates/7399_01_mangos_mangos_string.sql @@ -0,0 +1,6 @@ +ALTER TABLE db_version CHANGE COLUMN required_7393_01_mangos_game_event required_7399_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry in (753, 754, 755); +INSERT INTO mangos_string VALUES (753,'The battle for Warsong Gulch begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO mangos_string VALUES (754,'The battle for Arathi Basin begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +INSERT INTO mangos_string VALUES (755,'The battle for Eye of the Storm begins in 2 minutes.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/sql/updates/7422_01_mangos_mangos_string.sql b/sql/updates/7422_01_mangos_mangos_string.sql new file mode 100644 index 000000000..affe8f747 --- /dev/null +++ b/sql/updates/7422_01_mangos_mangos_string.sql @@ -0,0 +1,9 @@ +ALTER TABLE db_version CHANGE COLUMN required_7399_01_mangos_mangos_string required_7422_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry in (811, 812, 813, 814, 815); +INSERT INTO mangos_string VALUES + (811,'Guild Master',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), + (812,'Officer',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), + (813,'Veteran',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), + (814,'Member',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), + (815,'Initiate',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/sql/updates/7439_01_mangos_mangos_string.sql b/sql/updates/7439_01_mangos_mangos_string.sql new file mode 100644 index 000000000..7dd26e104 --- /dev/null +++ b/sql/updates/7439_01_mangos_mangos_string.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_7422_01_mangos_mangos_string required_7439_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry in (175); +INSERT INTO mangos_string VALUES + (175,'Liquid level: %f, ground: %f, type: %d, status: %d',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); \ No newline at end of file diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 138a68cf7..7f44538c8 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -191,6 +191,12 @@ pkgdata_DATA = \ 7369_01_mangos_quest_template.sql \ 7376_01_mangos_spell_area.sql \ 7382_01_mangos_creature_template.sql \ + 7388_01_mangos_mangos_string.sql \ + 7390_01_mangos_areatrigger_teleport.sql \ + 7393_01_mangos_game_event.sql \ + 7399_01_mangos_mangos_string.sql \ + 7422_01_mangos_mangos_string.sql \ + 7439_01_mangos_mangos_string.sql \ README ## Additional files to include when running 'make dist' @@ -362,4 +368,10 @@ EXTRA_DIST = \ 7369_01_mangos_quest_template.sql \ 7376_01_mangos_spell_area.sql \ 7382_01_mangos_creature_template.sql \ + 7388_01_mangos_mangos_string.sql \ + 7390_01_mangos_areatrigger_teleport.sql \ + 7393_01_mangos_game_event.sql \ + 7399_01_mangos_mangos_string.sql \ + 7422_01_mangos_mangos_string.sql \ + 7439_01_mangos_mangos_string.sql \ README diff --git a/src/framework/Platform/Define.h b/src/framework/Platform/Define.h index 5602bb365..831849369 100644 --- a/src/framework/Platform/Define.h +++ b/src/framework/Platform/Define.h @@ -55,6 +55,8 @@ # define MANGOS_GET_PROC_ADDR dlsym # if defined(__APPLE_CC__) && defined(BIG_ENDIAN) # define MANGOS_IMPORT __attribute__ ((longcall)) +# elif defined(__x86_64__) +# define MANGOS_IMPORT # else # define MANGOS_IMPORT __attribute__ ((cdecl)) # endif //__APPLE_CC__ && BIG_ENDIAN diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index b06a2f1c7..3acf2caa5 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -21,10 +21,10 @@ #include "Player.h" #include "WorldPacket.h" #include "Database/DBCEnums.h" +#include "GameEventMgr.h" #include "ObjectMgr.h" #include "Guild.h" #include "Database/DatabaseEnv.h" -#include "GameEvent.h" #include "World.h" #include "SpellMgr.h" #include "ArenaTeam.h" @@ -308,7 +308,10 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) { - sLog.outDebug("AchievementMgr::SendAchievementEarned(%u)", achievement->ID); + #ifdef MANGOS_DEBUG + if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0) + sLog.outDebug("AchievementMgr::SendAchievementEarned(%u)", achievement->ID); + #endif if(Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId())) { @@ -392,7 +395,8 @@ static const uint32 achievIdForDangeon[][4] = */ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2, Unit *unit, uint32 time) { - sLog.outDetail("AchievementMgr::UpdateAchievementCriteria(%u, %u, %u, %u)", type, miscvalue1, miscvalue2, time); + if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0) + sLog.outDetail("AchievementMgr::UpdateAchievementCriteria(%u, %u, %u, %u)", type, miscvalue1, miscvalue2, time); if (!sWorld.getConfig(CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS) && m_player->GetSession()->GetSecurity() > SEC_PLAYER) return; @@ -455,6 +459,54 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui continue; if(achievementCriteria->kill_creature.creatureID != miscvalue1) continue; + + // LOT achievement->ID required special custom checks + switch(achievement->ID) + { + // Just heroic + case 489: case 490: case 491: case 492: case 493: case 494: case 495: + case 496: case 497: case 498: case 499: case 500: case 563: case 565: + case 567: case 569: case 573: case 575: case 577: case 623: case 625: + case 667: case 668: case 669: case 670: case 671: case 672: case 673: + case 674: case 675: case 676: case 677: case 678: case 679: case 680: + case 681: case 682: case 1367: case 1368: case 1378: case 1379: + case 1380: case 1381: case 1382: case 1383: case 1384: case 1385: + case 1386: case 1387: case 1388: case 1389: case 1390: case 1393: + case 1394: case 1400: case 1402: case 1504: case 1505: case 1506: + case 1507: case 1508: case 1509: case 1510: case 1511: case 1512: + case 1513: case 1514: case 1515: case 1721: case 1754: case 1756: + case 1768: case 1817: case 1865: + if(GetPlayer()->GetDifficulty()!=DIFFICULTY_HEROIC) + continue; + break; + // Heroic + other + case 579: case 1296: case 1297: case 1816: case 1834: case 1857: case 1859: + case 1860: case 1861: case 1862: case 1864: case 1866: case 1867: case 1868: + case 1870: case 1871: case 1872: case 1873: case 1875: case 1877: case 1919: + case 2036: case 2037: case 2038: case 2039: case 2040: case 2041: case 2042: + case 2043: case 2044: case 2045: case 2046: case 2048: case 2052: case 2053: + case 2054: case 2056: case 2057: case 2058: case 2139: case 2140: case 2147: + case 2149: case 2150: case 2151: case 2152: case 2154: case 2155: case 2156: + case 2157: case 2179: case 2181: case 2183: case 2185: case 2186: + if(GetPlayer()->GetDifficulty()!=DIFFICULTY_HEROIC) + continue; + // FIX ME: mark as fail always until implement + continue; + // Normal + other + case 578: case 624: case 1790: case 1856: case 1858: case 1869: case 1874: + case 1996: case 1997: case 2047: case 2049: case 2050: case 2051: case 2146: + case 2148: case 2153: case 2178: case 2180: case 2182: case 2184: case 2187: + if(GetPlayer()->GetDifficulty()!=DIFFICULTY_NORMAL) + continue; + // FIX ME: mark as fail always until implement + continue; + // Just Normal + default: + if(GetPlayer()->GetDifficulty()!=DIFFICULTY_NORMAL) + continue; + break; + }; + SetCriteriaProgress(achievementCriteria, miscvalue2, PROGRESS_ACCUMULATE); break; case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: @@ -606,8 +658,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui { if(Player::GetDrunkenstateByValue(GetPlayer()->GetDrunkValue()) != DRUNKEN_SMASHED) continue; - // TODO: hardcoding eventid is bad, it can differ from DB to DB - maye implement something using HolidayNames.dbc? - if(!gameeventmgr.IsActiveEvent(26)) + if(!IsHolidayActive(HOLIDAY_BREWFEST)) continue; } // miscvalue1 is the ingame fallheight*100 as stored in dbc @@ -730,6 +781,31 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); break; } + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + { + // miscvalue1 = emote + // miscvalue2 = achievement->ID for special requirement + if(!miscvalue1) + continue; + if(miscvalue1 != achievementCriteria->do_emote.emoteID) + continue; + if(achievementCriteria->do_emote.count) + { + // harcoded case + if(achievement->ID==247) + { + if (!unit || unit->GetTypeId() != TYPEID_PLAYER || + unit->isAlive() || ((Player*)unit)->GetDeathTimer() == 0) + continue; + } + // expected as scripted case + else if(!miscvalue2 || !achievement->ID != miscvalue2) + continue; + } + + SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + break; + } case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS: { uint32 spellCount = 0; @@ -798,7 +874,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS: case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE: - case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE: case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: @@ -927,6 +1002,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT: case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT: return progress->counter >= achievementCriteria->roll_greed_on_loot.count; + case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: + return progress->counter >= achievementCriteria->do_emote.count; case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD: return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper; case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY: @@ -998,7 +1075,9 @@ AchievementCompletionState AchievementMgr::GetAchievementCompletionState(Achieve void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype) { - sLog.outDetail("AchievementMgr::SetCriteriaProgress(%u, %u) for (GUID:%u)", entry->ID, changeValue); + if((sLog.getLogFilter() & LOG_FILTER_ACHIEVEMENT_UPDATES)==0) + sLog.outDetail("AchievementMgr::SetCriteriaProgress(%u, %u) for (GUID:%u)", entry->ID, changeValue); + CriteriaProgress *progress = NULL; CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID); @@ -1024,8 +1103,12 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, newValue = changeValue; break; case PROGRESS_ACCUMULATE: - newValue = progress->counter + changeValue; + { + // avoid overflow + uint32 max_value = std::numeric_limits::max(); + newValue = max_value - progress->counter > changeValue ? progress->counter + changeValue : max_value; break; + } case PROGRESS_HIGHEST: newValue = progress->counter < changeValue ? changeValue : progress->counter; break; diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp index 52f7dbf49..c792d0261 100644 --- a/src/game/AggressorAI.cpp +++ b/src/game/AggressorAI.cpp @@ -19,7 +19,6 @@ #include "AggressorAI.h" #include "Errors.h" #include "Creature.h" -#include "Player.h" #include "ObjectAccessor.h" #include "VMapFactory.h" #include "World.h" diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp index cc1136171..eb8906f73 100644 --- a/src/game/ArenaTeam.cpp +++ b/src/game/ArenaTeam.cpp @@ -575,6 +575,28 @@ void ArenaTeam::MemberLost(Player * plr, uint32 againstRating) } } +void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating) +{ + // called for offline player after ending rated arena match! + for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) + { + if(itr->guid == guid) + { + // update personal rating + float chance = GetChanceAgainst(itr->personal_rating, againstRating); + int32 mod = (int32)ceil(32.0f * (0.0f - chance)); + if (int32(itr->personal_rating) + mod < 0) + itr->personal_rating = 0; + else + itr->personal_rating += mod; + // update personal played stats + itr->games_week +=1; + itr->games_season +=1; + return; + } + } +} + void ArenaTeam::MemberWon(Player * plr, uint32 againstRating) { // called for each participant after winning a match diff --git a/src/game/ArenaTeam.h b/src/game/ArenaTeam.h index 42028499c..9ad3ea618 100644 --- a/src/game/ArenaTeam.h +++ b/src/game/ArenaTeam.h @@ -198,6 +198,7 @@ class ArenaTeam void MemberWon(Player * plr, uint32 againstRating); int32 LostAgainst(uint32 againstRating); void MemberLost(Player * plr, uint32 againstRating); + void OfflineMemberLost(uint64 guid, uint32 againstRating); void UpdateArenaPointsHelper(std::map & PlayerPoints); diff --git a/src/game/ArenaTeamHandler.cpp b/src/game/ArenaTeamHandler.cpp index f2a71f8c1..c31f39514 100644 --- a/src/game/ArenaTeamHandler.cpp +++ b/src/game/ArenaTeamHandler.cpp @@ -25,7 +25,6 @@ #include "ArenaTeam.h" #include "World.h" #include "SocialMgr.h" -#include "Language.h" void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data) { diff --git a/src/game/Bag.cpp b/src/game/Bag.cpp index 2f967752e..eae355166 100644 --- a/src/game/Bag.cpp +++ b/src/game/Bag.cpp @@ -21,9 +21,7 @@ #include "ObjectMgr.h" #include "Database/DatabaseEnv.h" #include "Log.h" -#include "WorldPacket.h" #include "UpdateData.h" -#include "WorldSession.h" Bag::Bag( ): Item() { diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 3cb669f59..35ad7b262 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -23,7 +23,6 @@ #include "Creature.h" #include "MapManager.h" #include "Language.h" -#include "Chat.h" #include "SpellAuras.h" #include "ArenaTeam.h" #include "World.h" @@ -31,12 +30,105 @@ #include "ObjectMgr.h" #include "WorldPacket.h" #include "Util.h" +#include "Formulas.h" +#include "GridNotifiersImpl.h" + +namespace MaNGOS +{ + class BattleGroundChatBuilder + { + public: + BattleGroundChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, va_list* args = NULL) + : i_msgtype(msgtype), i_textId(textId), i_source(source), i_args(args) {} + void operator()(WorldPacket& data, int32 loc_idx) + { + char const* text = objmgr.GetMangosString(i_textId,loc_idx); + + if(i_args) + { + // we need copy va_list before use or original va_list will corrupted + va_list ap; + va_copy(ap,*i_args); + + char str [2048]; + vsnprintf(str,2048,text, ap ); + va_end(ap); + + do_helper(data,&str[0]); + } + else + do_helper(data,text); + } + private: + void do_helper(WorldPacket& data, char const* text) + { + uint64 target_guid = i_source ? i_source ->GetGUID() : 0; + + data << uint8(i_msgtype); + data << uint32(LANG_UNIVERSAL); + data << uint64(target_guid); // there 0 for BG messages + data << uint32(0); // can be chat msg group or something + data << uint64(target_guid); + data << uint32(strlen(text)+1); + data << text; + data << uint8(i_source ? i_source->chatTag() : uint8(0)); + } + + ChatMsg i_msgtype; + int32 i_textId; + Player const* i_source; + va_list* i_args; + }; + + class BattleGround2ChatBuilder + { + public: + BattleGround2ChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, int32 arg1, int32 arg2) + : i_msgtype(msgtype), i_textId(textId), i_source(source), i_arg1(arg1), i_arg2(arg2) {} + void operator()(WorldPacket& data, int32 loc_idx) + { + char const* text = objmgr.GetMangosString(i_textId,loc_idx); + char const* arg1str = i_arg1 ? objmgr.GetMangosString(i_arg1,loc_idx) : ""; + char const* arg2str = i_arg2 ? objmgr.GetMangosString(i_arg2,loc_idx) : ""; + + char str [2048]; + snprintf(str,2048,text, arg1str, arg2str ); + + uint64 target_guid = i_source ? i_source ->GetGUID() : 0; + + data << uint8(i_msgtype); + data << uint32(LANG_UNIVERSAL); + data << uint64(target_guid); // there 0 for BG messages + data << uint32(0); // can be chat msg group or something + data << uint64(target_guid); + data << uint32(strlen(str)+1); + data << str; + data << uint8(i_source ? i_source->chatTag() : uint8(0)); + } + private: + + ChatMsg i_msgtype; + int32 i_textId; + Player const* i_source; + int32 i_arg1; + int32 i_arg2; + }; +} // namespace MaNGOS + +template +void BattleGround::BroadcastWorker(Do& _do) +{ + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + if(Player *plr = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) + _do(plr); +} BattleGround::BattleGround() { m_TypeID = BattleGroundTypeId(0); m_InstanceID = 0; m_Status = STATUS_NONE; + m_ClientInstanceID = 0; m_EndTime = 0; m_LastResurrectTime = 0; m_QueueId = QUEUE_ID_MAX_LEVEL_19; @@ -88,6 +180,16 @@ BattleGround::BattleGround() m_PrematureCountDown = false; m_PrematureCountDown = 0; + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_2M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set to some default existing values + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; } BattleGround::~BattleGround() @@ -126,50 +228,30 @@ BattleGround::~BattleGround() void BattleGround::Update(uint32 diff) { - if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize()) + if(!GetPlayersSize() && !GetReviveQueueSize()) //BG is empty return; - if(GetRemovedPlayersSize()) + // remove offline players from bg after 5 minutes + if( !m_OfflineQueue.empty() ) { - for(std::map::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr) + BattleGroundPlayerMap::iterator itr = m_Players.find(*(m_OfflineQueue.begin())); + if( itr != m_Players.end() ) { - Player *plr = objmgr.GetPlayer(itr->first); - switch(itr->second) + if( itr->second.OfflineRemoveTime <= sWorld.GetGameTime() ) { - case 1: // currently in bg and was removed from bg - if(plr) - RemovePlayerAtLeave(itr->first, true, true); - else - RemovePlayerAtLeave(itr->first, false, false); - break; - case 2: // revive queue - RemovePlayerFromResurrectQueue(itr->first); - break; - default: - sLog.outError("BattleGround: Unknown remove player case!"); + RemovePlayerAtLeave(itr->first, true, true);// remove player from BG + m_OfflineQueue.pop_front(); // remove from offline queue + //do not use itr for anything, because it is erased in RemovePlayerAtLeave() } } - m_RemovedPlayers.clear(); } - // remove offline players from bg after ~5 minutes - if(GetPlayersSize()) - { - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) - { - Player *plr = objmgr.GetPlayer(itr->first); - itr->second.LastOnlineTime += diff; + /*********************************************************/ + /*** BATTLEGROUND RESSURECTION SYSTEM ***/ + /*********************************************************/ - if(plr) - itr->second.LastOnlineTime = 0; // update last online time - else - if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME) // 5 minutes - m_RemovedPlayers[itr->first] = 1; // add to remove list (BG) - } - } - - //this should be handled by spell system: + //this should be handled by spell system m_LastResurrectTime += diff; if (m_LastResurrectTime >= RESURRECTION_INTERVAL) { @@ -219,6 +301,10 @@ void BattleGround::Update(uint32 diff) m_ResurrectQueue.clear(); } + /*********************************************************/ + /*** BATTLEGROUND BALLANCE SYSTEM ***/ + /*********************************************************/ + // if less then minimum players are in on one side, then start premature finish timer if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) { @@ -226,39 +312,137 @@ void BattleGround::Update(uint32 diff) { m_PrematureCountDown = true; m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime(); - SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING); } else if(m_PrematureCountDownTimer < diff) { // time's up! - EndBattleGround(0); // noone wins + uint32 winner = 0; + if( GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam() ) + winner = ALLIANCE; + else if( GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam() ) + winner = HORDE; + + EndBattleGround(winner); m_PrematureCountDown = false; } else { uint32 newtime = m_PrematureCountDownTimer - diff; // announce every minute - if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000) - SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING); + if( newtime > (MINUTE * IN_MILISECONDS) ) + { + if( newtime / (MINUTE * IN_MILISECONDS) != m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS) ) + PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / (MINUTE * IN_MILISECONDS))); + } + else + { + //announce every 15 seconds + if( newtime / (15 * IN_MILISECONDS) != m_PrematureCountDownTimer / (15 * IN_MILISECONDS) ) + PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(m_PrematureCountDownTimer / IN_MILISECONDS)); + } m_PrematureCountDownTimer = newtime; } } else if (m_PrematureCountDown) m_PrematureCountDown = false; + /*********************************************************/ + /*** BATTLEGROUND STARTING SYSTEM ***/ + /*********************************************************/ + + if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) + { + ModifyStartDelayTime(diff); + + if (!(m_Events & BG_STARTING_EVENT_1)) + { + m_Events |= BG_STARTING_EVENT_1; + + // setup here, only when at least one player has ported to the map + if(!SetupBattleGround()) + { + EndNow(); + return; + } + + StartingEventCloseDoors(); + SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FIRST]); + //first start warning - 2 or 1 minute + SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + // After 1 minute or 30 seconds, warning is signalled + else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(m_Events & BG_STARTING_EVENT_2)) + { + m_Events |= BG_STARTING_EVENT_2; + SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + // After 30 or 15 seconds, warning is signalled + else if (GetStartDelayTime() <= m_StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(m_Events & BG_STARTING_EVENT_3)) + { + m_Events |= BG_STARTING_EVENT_3; + SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL); + } + // delay expired (atfer 2 or 1 minute) + else if (GetStartDelayTime() <= 0 && !(m_Events & BG_STARTING_EVENT_4)) + { + m_Events |= BG_STARTING_EVENT_4; + + StartingEventOpenDoors(); + + SendMessageToAll(m_StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL); + SetStatus(STATUS_IN_PROGRESS); + SetStartDelayTime(m_StartDelayTimes[BG_STARTING_EVENT_FOURTH]); + + //remove preparation + if( isArena() ) + { + //TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START); + + for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + if(Player *plr = objmgr.GetPlayer(itr->first)) + plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); + + CheckArenaWinConditions(); + } + else + { + + PlaySoundToAll(SOUND_BG_START); + + for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) + if(Player* plr = objmgr.GetPlayer(itr->first)) + plr->RemoveAurasDueToSpell(SPELL_PREPARATION); + //Announce BG starting + if( sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) ) + { + sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel()); + } + } + } + } + + /*********************************************************/ + /*** BATTLEGROUND ENDING SYSTEM ***/ + /*********************************************************/ + if(GetStatus() == STATUS_WAIT_LEAVE) { // remove all players from battleground after 2 minutes m_EndTime += diff; if(m_EndTime >= TIME_TO_AUTOREMOVE) // 2 minutes { - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + BattleGroundPlayerMap::iterator itr, next; + for(itr = m_Players.begin(); itr != m_Players.end(); itr = next) { - m_RemovedPlayers[itr->first] = 1; // add to remove list (BG) + next = itr; + ++next; + //itr is erased here! + RemovePlayerAtLeave(itr->first, true, true);// remove player from BG + // do not change any battleground's private variables } - // do not change any battleground's private variables } } + } void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O) @@ -272,7 +456,7 @@ void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, flo void BattleGround::SendPacketToAll(WorldPacket *packet) { - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); if(plr) @@ -284,7 +468,7 @@ void BattleGround::SendPacketToAll(WorldPacket *packet) void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self) { - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -316,7 +500,7 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID) { WorldPacket data; - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -339,7 +523,7 @@ void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID) void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID) { - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -359,7 +543,7 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID) void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID) { - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -384,7 +568,7 @@ void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, if(!factionEntry) return; - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -425,15 +609,11 @@ void BattleGround::EndBattleGround(uint32 winner) uint32 loser_rating = 0; uint32 winner_rating = 0; WorldPacket data; - Player *Source = NULL; - const char *winmsg = ""; + int32 winmsg_id = 0; if(winner == ALLIANCE) { - if(isBattleGround()) - winmsg = GetMangosString(LANG_BG_A_WINS); - else - winmsg = GetMangosString(LANG_ARENA_GOLD_WINS); + winmsg_id = isBattleGround() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS; PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound @@ -441,10 +621,7 @@ void BattleGround::EndBattleGround(uint32 winner) } else if(winner == HORDE) { - if(isBattleGround()) - winmsg = GetMangosString(LANG_BG_H_WINS); - else - winmsg = GetMangosString(LANG_ARENA_GREEN_WINS); + winmsg_id = isBattleGround() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS; PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound @@ -461,33 +638,17 @@ void BattleGround::EndBattleGround(uint32 winner) // arena rating calculation if(isArena() && isRated()) { - if(winner == ALLIANCE) - { - winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); - loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); - } - else if(winner == HORDE) - { - winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); - loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); - } - if(winner_arena_team && loser_arena_team) + winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner)); + loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner))); + if( winner_arena_team && loser_arena_team ) { loser_rating = loser_arena_team->GetStats().rating; winner_rating = winner_arena_team->GetStats().rating; int32 winner_change = winner_arena_team->WonAgainst(loser_rating); int32 loser_change = loser_arena_team->LostAgainst(winner_rating); sLog.outDebug("--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---", winner_rating, loser_rating, winner_change, loser_change); - if(winner == ALLIANCE) - { - SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change); - SetArenaTeamRatingChangeForTeam(HORDE, loser_change); - } - else - { - SetArenaTeamRatingChangeForTeam(HORDE, winner_change); - SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change); - } + SetArenaTeamRatingChangeForTeam(winner, winner_change); + SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loser_change); } else { @@ -496,11 +657,21 @@ void BattleGround::EndBattleGround(uint32 winner) } } - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); + uint32 team = itr->second.Team; + if(!plr) { + //if rated arena match - make member lost! + if(isArena() && isRated() && winner_arena_team && loser_arena_team) + { + if(team == winner) + winner_arena_team->OfflineMemberLost(itr->first, loser_rating); + else + loser_arena_team->OfflineMemberLost(itr->first, winner_rating); + } sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first); continue; } @@ -515,8 +686,8 @@ void BattleGround::EndBattleGround(uint32 winner) plr->SpawnCorpseBones(); } - uint32 team = itr->second.Team; - if(!team) team = plr->GetTeam(); + //this line is obsolete - team is set ALWAYS + //if(!team) team = plr->GetTeam(); // per player calculation if(isArena() && isRated() && winner_arena_team && loser_arena_team) @@ -529,10 +700,7 @@ void BattleGround::EndBattleGround(uint32 winner) if(team == winner) { - if(!Source) - Source = plr; RewardMark(plr,ITEM_WINNER_COUNT); - UpdatePlayerScore(plr, SCORE_BONUS_HONOR, 20); RewardQuest(plr); } else @@ -548,7 +716,7 @@ void BattleGround::EndBattleGround(uint32 winner) plr->GetSession()->SendPacket(&data); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); plr->GetSession()->SendPacket(&data); plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } @@ -570,11 +738,14 @@ void BattleGround::EndBattleGround(uint32 winner) // inform invited players about the removal sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); - if(Source) - { - ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg); - SendPacketToAll(&data); - } + if(winmsg_id) + SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL); +} + +uint32 BattleGround::GetBonusHonorFromKill(uint32 kills) const +{ + //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill) + return MaNGOS::Honor::hk_honor_at_level(GetMaxLevel(), kills); } uint32 BattleGround::GetBattlemasterEntry() const @@ -723,10 +894,10 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac uint32 team = GetPlayerTeam(guid); bool participant = false; // Remove from lists/maps - std::map::iterator itr = m_Players.find(guid); + BattleGroundPlayerMap::iterator itr = m_Players.find(guid); if(itr != m_Players.end()) { - UpdatePlayersCountByTeam(team, true); // -1 player + UpdatePlayersCountByTeam(team, true); // -1 player m_Players.erase(itr); // check if the player was a participant of the match, or only entered through gm command (goname) participant = true; @@ -755,21 +926,21 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac RemovePlayer(plr, guid); // BG subclass specific code - if(plr) + if(participant) // if the player was a match participant, remove auras, calc rating, update queue { - plr->ClearAfkReports(); - - if(participant) // if the player was a match participant, remove auras, calc rating, update queue + BattleGroundTypeId bgTypeId = GetTypeID(); + BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); + if(plr) { + plr->ClearAfkReports(); + if(!team) team = plr->GetTeam(); - BattleGroundTypeId bgTypeId = GetTypeID(); - BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType()); // if arena, remove the specific arena auras if(isArena()) { - plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out - bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing) + plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out + bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing) // summon old pet if there was one and there isn't a current pet if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber()) @@ -784,65 +955,64 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac if(isRated() && GetStatus() == STATUS_IN_PROGRESS) { //left a rated match while the encounter was in progress, consider as loser - ArenaTeam * winner_arena_team = 0; - ArenaTeam * loser_arena_team = 0; - if(team == HORDE) - { - winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); - loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); - } - else - { - winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE)); - loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE)); - } + ArenaTeam * winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team))); + ArenaTeam * loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team)); if(winner_arena_team && loser_arena_team) - { loser_arena_team->MemberLost(plr,winner_arena_team->GetRating()); - } } } - - WorldPacket data; if(SendPacket) { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0); + WorldPacket data; + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); } // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg plr->RemoveBattleGroundQueueId(bgQueueTypeId); - - DecreaseInvitedCount(team); - //we should update battleground queue, but only if bg isn't ending - if (GetStatus() < STATUS_WAIT_LEAVE) - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId()); - - Group * group = plr->GetGroup(); - // remove from raid group if exist - if(group && group == GetBgRaid(team)) + } + else + // removing offline participant + { + if(isRated() && GetStatus() == STATUS_IN_PROGRESS) { - if(!group->RemoveMember(guid, 0)) // group was disbanded - { - SetBgRaid(team, NULL); - delete group; - } + //left a rated match while the encounter was in progress, consider as loser + ArenaTeam * others_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team))); + ArenaTeam * players_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(team)); + if( others_arena_team && players_arena_team ) + players_arena_team->OfflineMemberLost(guid, others_arena_team->GetRating()); } - - // Let others know - sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr); - SendPacketToTeam(team, &data, plr, false); } + // remove from raid group if player is member + if(Group *group = GetBgRaid(team)) + { + if( !group->RemoveMember(guid, 0) ) // group was disbanded + { + SetBgRaid(team, NULL); + delete group; + } + } + DecreaseInvitedCount(team); + //we should update battleground queue, but only if bg isn't ending + if( isBattleGround() && GetStatus() < STATUS_WAIT_LEAVE ) + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueId()); + // Let others know + WorldPacket data; + sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, guid); + SendPacketToTeam(team, &data, plr, false); + } + + if( plr ) + { // Do next only if found in battleground - plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. + plr->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG. // reset destination bg team plr->SetBGTeam(0); if(Transport) plr->TeleportTo(plr->GetBattleGroundEntryPoint()); - // Log sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName()); } @@ -900,7 +1070,7 @@ void BattleGround::AddPlayer(Player *plr) uint32 team = plr->GetBGTeam(); BattleGroundPlayer bp; - bp.LastOnlineTime = 0; + bp.OfflineRemoveTime = 0; bp.Team = team; // Add to list/maps @@ -963,7 +1133,7 @@ void BattleGround::AddPlayer(Player *plr) } // setup BG group membership - PlayerRelogin(plr); + PlayerAddedToBGCheckIfBGIsRunning(plr); AddOrSetPlayerToCorrectBgGroup(plr, guid, team); // Log @@ -992,6 +1162,38 @@ void BattleGround::AddOrSetPlayerToCorrectBgGroup(Player *plr, uint64 plr_guid, } } +// This method should be called when player logs into running battleground +void BattleGround::EventPlayerLoggedIn(Player* player, uint64 plr_guid) +{ + // player is correct pointer + for(std::deque::iterator itr = m_OfflineQueue.begin(); itr != m_OfflineQueue.end(); ++itr) + { + if( *itr == plr_guid ) + { + m_OfflineQueue.erase(itr); + break; + } + } + m_Players[plr_guid].OfflineRemoveTime = 0; + PlayerAddedToBGCheckIfBGIsRunning(player); + // if battleground is starting, then add preparation aura + // we don't have to do that, because preparation aura isn't removed when player logs out +} + +// This method should be called when player logs out from running battleground +void BattleGround::EventPlayerLoggedOut(Player* player) +{ + // player is correct pointer, it is checked in WorldSession::LogoutPlayer() + m_OfflineQueue.push_back(player->GetGUID()); + m_Players[player->GetGUID()].OfflineRemoveTime = sWorld.GetGameTime() + MAX_OFFLINE_TIME; + if( GetStatus() == STATUS_IN_PROGRESS ) + { + if( isBattleGround() ) + EventPlayerDroppedFlag(player); + else + CheckArenaWinConditions(); + } +} /* This method should be called only once ... it adds pointer to queue */ void BattleGround::AddToBGFreeSlotQueue() @@ -1024,7 +1226,7 @@ void BattleGround::RemoveFromBGFreeSlotQueue() // returns the number how many players can join battleground to MaxPlayersPerTeam uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const { - //if BG is starting ... invite anyone + //return free slot count to MaxPlayerPerTeam if (GetStatus() == STATUS_WAIT_JOIN || GetStatus() == STATUS_IN_PROGRESS) return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0; @@ -1357,19 +1559,30 @@ bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float return true; } -void BattleGround::SendMessageToAll(char const* text) +void BattleGround::SendMessageToAll(int32 entry, ChatMsg type, Player const* source) { - WorldPacket data; - ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL); - SendPacketToAll(&data); + MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source); + MaNGOS::LocalizedPacketDo bg_do(bg_builder); + BroadcastWorker(bg_do); } -void BattleGround::SendMessageToAll(int32 entry) +void BattleGround::PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...) { - char const* text = GetMangosString(entry); - WorldPacket data; - ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL); - SendPacketToAll(&data); + va_list ap; + va_start(ap, source); + + MaNGOS::BattleGroundChatBuilder bg_builder(type, entry, source, &ap); + MaNGOS::LocalizedPacketDo bg_do(bg_builder); + BroadcastWorker(bg_do); + + va_end(ap); +} + +void BattleGround::SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 arg1, int32 arg2) +{ + MaNGOS::BattleGround2ChatBuilder bg_builder(type, entry, source, arg1, arg2); + MaNGOS::LocalizedPacketDo bg_do(bg_builder); + BroadcastWorker(bg_do); } void BattleGround::EndNow() @@ -1381,13 +1594,6 @@ void BattleGround::EndNow() sBattleGroundMgr.m_BattleGroundQueues[BattleGroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this); } -// Battleground messages are localized using the dbc lang, they are not client language dependent -const char *BattleGround::GetMangosString(int32 entry) -{ - // FIXME: now we have different DBC locales and need localized message for each target client - return objmgr.GetMangosStringForDBCLocale(entry); -} - /* important notice: buffs aren't spawned/despawned when players captures anything @@ -1441,7 +1647,7 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1); UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1); - for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); @@ -1461,21 +1667,26 @@ void BattleGround::HandleKillPlayer( Player *player, Player *killer ) // used in same faction arena matches mainly uint32 BattleGround::GetPlayerTeam(uint64 guid) { - std::map::const_iterator itr = m_Players.find(guid); + BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid); if(itr!=m_Players.end()) return itr->second.Team; return 0; } +uint32 BattleGround::GetOtherTeam(uint32 teamId) +{ + return (teamId) ? ((teamId == ALLIANCE) ? HORDE : ALLIANCE) : 0; +} + bool BattleGround::IsPlayerInBattleGround(uint64 guid) { - std::map::const_iterator itr = m_Players.find(guid); - if(itr!=m_Players.end()) + BattleGroundPlayerMap::const_iterator itr = m_Players.find(guid); + if(itr != m_Players.end()) return true; return false; } -void BattleGround::PlayerRelogin(Player* plr) +void BattleGround::PlayerAddedToBGCheckIfBGIsRunning(Player* plr) { if(GetStatus() != STATUS_WAIT_LEAVE) return; @@ -1488,14 +1699,14 @@ void BattleGround::PlayerRelogin(Player* plr) sBattleGroundMgr.BuildPvpLogDataPacket(&data, this); plr->GetSession()->SendPacket(&data); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); plr->GetSession()->SendPacket(&data); } uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const { int count = 0; - for(std::map::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) + for(BattleGroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { if(itr->second.Team == Team) { @@ -1507,6 +1718,14 @@ uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const return count; } +void BattleGround::CheckArenaWinConditions() +{ + if( !GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE) ) + EndBattleGround(HORDE); + else if( GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE) ) + EndBattleGround(ALLIANCE); +} + void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid ) { Group* &old_raid = TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE]; @@ -1518,4 +1737,4 @@ void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid ) WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player ) { return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() ); -} \ No newline at end of file +} diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index 5dd56aa11..c55a89afc 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -89,15 +89,19 @@ enum BattleGroundTimeIntervals INVITATION_REMIND_TIME = 60000, // ms INVITE_ACCEPT_WAIT_TIME = 80000, // ms TIME_TO_AUTOREMOVE = 120000, // ms - MAX_OFFLINE_TIME = 300000, // ms - START_DELAY0 = 120000, // ms - START_DELAY1 = 60000, // ms - START_DELAY2 = 30000, // ms - START_DELAY3 = 15000, // ms used only in arena + MAX_OFFLINE_TIME = 300, // secs RESPAWN_ONE_DAY = 86400, // secs RESPAWN_IMMEDIATELY = 0, // secs BUFF_RESPAWN_TIME = 180, // secs - BG_HONOR_SCORE_TICKS = 330 // points +}; + +enum BattleGroundStartTimeIntervals +{ + BG_START_DELAY_2M = 120000, // ms (2 minutes) + BG_START_DELAY_1M = 60000, // ms (1 minute) + BG_START_DELAY_30S = 30000, // ms (30 seconds) + BG_START_DELAY_15S = 15000, // ms (15 seconds) Used only in arena + BG_START_DELAY_NONE = 0, // ms }; enum BattleGroundBuffObjects @@ -120,7 +124,7 @@ enum BattleGroundStatus struct BattleGroundPlayer { - uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes + time_t OfflineRemoveTime; // for tracking and removing offline players from queue after 5 minutes uint32 Team; // Player's team }; @@ -214,6 +218,24 @@ enum BattleGroundTeamId }; #define BG_TEAMS_COUNT 2 +enum BattleGroundStartingEvents +{ + BG_STARTING_EVENT_NONE = 0x00, + BG_STARTING_EVENT_1 = 0x01, + BG_STARTING_EVENT_2 = 0x02, + BG_STARTING_EVENT_3 = 0x04, + BG_STARTING_EVENT_4 = 0x08 +}; + +enum BattleGroundStartingEventsIds +{ + BG_STARTING_EVENT_FIRST = 0, + BG_STARTING_EVENT_SECOND = 1, + BG_STARTING_EVENT_THIRD = 2, + BG_STARTING_EVENT_FOURTH = 3 +}; +#define BG_STARTING_EVENT_COUNT 4 + enum BattleGroundJoinError { BG_JOIN_ERR_OK = 0, @@ -266,6 +288,8 @@ class BattleGround return true; } virtual void Reset(); // resets all common properties for battlegrounds, must be implemented and called in BG subclass + virtual void StartingEventCloseDoors() {} + virtual void StartingEventOpenDoors() {} /* Battleground */ // Get methods: @@ -274,6 +298,7 @@ class BattleGround BGQueueIdBasedOnLevel GetQueueId() const { return m_QueueId; } uint32 GetInstanceID() const { return m_InstanceID; } BattleGroundStatus GetStatus() const { return m_Status; } + uint32 GetClientInstanceID() const { return m_ClientInstanceID; } uint32 GetStartTime() const { return m_StartTime; } uint32 GetEndTime() const { return m_EndTime; } uint32 GetLastResurrectTime() const { return m_LastResurrectTime; } @@ -290,6 +315,7 @@ class BattleGround uint8 GetArenaType() const { return m_ArenaType; } uint8 GetWinner() const { return m_Winner; } uint32 GetBattlemasterEntry() const; + uint32 GetBonusHonorFromKill(uint32 kills) const; // Set methods: void SetName(char const* Name) { m_Name = Name; } @@ -303,6 +329,7 @@ class BattleGround } void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; } void SetStatus(BattleGroundStatus Status) { m_Status = Status; } + void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; } void SetStartTime(uint32 Time) { m_StartTime = Time; } void SetEndTime(uint32 Time) { m_EndTime = Time; } void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; } @@ -342,7 +369,6 @@ class BattleGround typedef std::map BattleGroundPlayerMap; BattleGroundPlayerMap const& GetPlayers() const { return m_Players; } uint32 GetPlayersSize() const { return m_Players.size(); } - uint32 GetRemovedPlayersSize() const { return m_RemovedPlayers.size(); } std::map::const_iterator GetPlayerScoresBegin() const { return m_PlayerScores.begin(); } std::map::const_iterator GetPlayerScoresEnd() const { return m_PlayerScores.end(); } @@ -374,6 +400,10 @@ class BattleGround virtual void FillInitialWorldStates(WorldPacket& /*data*/) {} void SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender = NULL, bool self = true); void SendPacketToAll(WorldPacket *packet); + + template + void BroadcastWorker(Do& _do); + void PlaySoundToTeam(uint32 SoundID, uint32 TeamID); void PlaySoundToAll(uint32 SoundID); void CastSpellOnTeam(uint32 SpellID, uint32 TeamID); @@ -387,8 +417,11 @@ class BattleGround void EndBattleGround(uint32 winner); void BlockMovement(Player *plr); - void SendMessageToAll(char const* text); - void SendMessageToAll(int32 entry); + void SendMessageToAll(int32 entry, ChatMsg type, Player const* source = NULL); + void PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ... ); + + // specialized version with 2 string id args + void SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 strId1 = 0, int32 strId2 = 0); /* Raid Group */ Group *GetBgRaid(uint32 TeamID) const { return TeamID == ALLIANCE ? m_BgRaids[BG_TEAM_ALLIANCE] : m_BgRaids[BG_TEAM_HORDE]; } @@ -409,9 +442,10 @@ class BattleGround // used for rated arena battles void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[GetTeamIndexByTeamId(Team)] = ArenaTeamId; } - uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; } + uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[GetTeamIndexByTeamId(Team)]; } void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 RatingChange) { m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)] = RatingChange; } - int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; } + int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; } + void CheckArenaWinConditions(); /* Triggers handle */ // must be implemented in BG subclass @@ -420,10 +454,11 @@ class BattleGround virtual void HandleKillPlayer(Player *player, Player *killer); /* Battleground events */ - /* these functions will return true event is possible, but false if player is bugger */ virtual void EventPlayerDroppedFlag(Player* /*player*/) {} virtual void EventPlayerClickedOnFlag(Player* /*player*/, GameObject* /*target_obj*/) {} virtual void EventPlayerCapturedFlag(Player* /*player*/) {} + void EventPlayerLoggedIn(Player* player, uint64 plr_guid); + void EventPlayerLoggedOut(Player* player); /* Death related */ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); @@ -452,20 +487,20 @@ class BattleGround void DoorOpen(uint32 type); void DoorClose(uint32 type); - const char *GetMangosString(int32 entry); virtual bool HandlePlayerUnderMap(Player * /*plr*/) { return false; } // since arenas can be AvA or Hvh, we have to get the "temporary" team of a player uint32 GetPlayerTeam(uint64 guid); + uint32 GetOtherTeam(uint32 teamId); bool IsPlayerInBattleGround(uint64 guid); - void PlayerRelogin(Player* plr); void SetDeleteThis() {m_SetDeleteThis = true;} protected: //this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround void EndNow(); + void PlayerAddedToBGCheckIfBGIsRunning(Player* plr); /* Scorekeeping */ // Player scores @@ -479,9 +514,12 @@ class BattleGround std::map > m_ReviveQueue; /* - this is important variable used for invitation messages + these are important variables used for starting messages */ uint8 m_Events; + BattleGroundStartTimeIntervals m_StartDelayTimes[BG_STARTING_EVENT_COUNT]; + //this must be filled in constructors! + uint32 m_StartMessageIds[BG_STARTING_EVENT_COUNT]; bool m_BuffChange; @@ -490,6 +528,7 @@ class BattleGround BattleGroundTypeId m_TypeID; uint32 m_InstanceID; //BattleGround Instance's GUID! BattleGroundStatus m_Status; + uint32 m_ClientInstanceID; //the instance-id which is sent to the client and without any other internal use uint32 m_StartTime; uint32 m_EndTime; uint32 m_LastResurrectTime; @@ -507,7 +546,7 @@ class BattleGround /* Player lists */ std::vector m_ResurrectQueue; // Player GUID - std::map m_RemovedPlayers; // uint8 is remove type (0 - bgqueue, 1 - bg, 2 - resurrect queue) + std::deque m_OfflineQueue; // Player GUID /* Invited counters are useful for player invitation to BG - do not allow, if BG is started to one faction to have 2 more players than another faction */ /* Invited counters will be changed only when removing already invited player from queue, removing player from battleground and inviting player to BG */ diff --git a/src/game/BattleGroundAA.cpp b/src/game/BattleGroundAA.cpp index fcf9bd4ce..b67eb73d6 100644 --- a/src/game/BattleGroundAA.cpp +++ b/src/game/BattleGroundAA.cpp @@ -19,10 +19,20 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundAA.h" +#include "Language.h" BattleGroundAA::BattleGroundAA() { + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; } BattleGroundAA::~BattleGroundAA() @@ -35,6 +45,14 @@ void BattleGroundAA::Update(uint32 diff) BattleGround::Update(diff); } +void BattleGroundAA::StartingEventCloseDoors() +{ +} + +void BattleGroundAA::StartingEventOpenDoors() +{ +} + void BattleGroundAA::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); diff --git a/src/game/BattleGroundAA.h b/src/game/BattleGroundAA.h index b144acae3..56a18dfc2 100644 --- a/src/game/BattleGroundAA.h +++ b/src/game/BattleGroundAA.h @@ -39,6 +39,9 @@ class BattleGroundAA : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround(); diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp index 282e25298..dae2b20de 100644 --- a/src/game/BattleGroundAB.cpp +++ b/src/game/BattleGroundAB.cpp @@ -21,9 +21,7 @@ #include "BattleGround.h" #include "BattleGroundAB.h" #include "Creature.h" -#include "Chat.h" #include "ObjectMgr.h" -#include "MapManager.h" #include "Language.h" #include "Util.h" #include "WorldPacket.h" @@ -33,6 +31,11 @@ BattleGroundAB::BattleGroundAB() m_BuffChange = true; m_BgObjects.resize(BG_AB_OBJECT_MAX); m_BgCreatures.resize(BG_AB_ALL_NODES_COUNT); + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_AB_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_AB_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_AB_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_AB_HAS_BEGUN; } BattleGroundAB::~BattleGroundAB() @@ -43,81 +46,7 @@ void BattleGroundAB::Update(uint32 diff) { BattleGround::Update(diff); - if( GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize() ) - { - ModifyStartDelayTime(diff); - - if( !(m_Events & 0x01) ) - { - m_Events |= 0x01; - - // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) - { - EndNow(); - return; - } - - sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ..."); - - // despawn banners, auras and buffs - for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj) - SpawnBGObject(obj, RESPAWN_ONE_DAY); - for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i) - SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY); - - // Starting doors - SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY); - DoorClose(BG_AB_OBJECT_GATE_A); - DoorClose(BG_AB_OBJECT_GATE_H); - - // Starting base spirit guides - _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE); - _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE); - - SetStartDelayTime(START_DELAY0); - } - // After 1 minute, warning is signalled - else if( GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04) ) - { - m_Events |= 0x04; - SendMessageToAll(GetMangosString(LANG_BG_AB_ONEMINTOSTART)); - } - // After 1,5 minute, warning is signalled - else if( GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08) ) - { - m_Events |= 0x08; - SendMessageToAll(GetMangosString(LANG_BG_AB_HALFMINTOSTART)); - } - // After 2 minutes, gates OPEN ! x) - else if( GetStartDelayTime() < 0 && !(m_Events & 0x10) ) - { - m_Events |= 0x10; - SendMessageToAll(GetMangosString(LANG_BG_AB_STARTED)); - - // spawn neutral banners - for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) - SpawnBGObject(banner, RESPAWN_IMMEDIATELY); - for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) - { - //randomly select buff to spawn - uint8 buff = urand(0, 2); - SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY); - } - DoorOpen(BG_AB_OBJECT_GATE_A); - DoorOpen(BG_AB_OBJECT_GATE_H); - - PlaySoundToAll(SOUND_BG_START); - SetStatus(STATUS_IN_PROGRESS); - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player* plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_PREPARATION); - } - - } - else if( GetStatus() == STATUS_IN_PROGRESS ) + if( GetStatus() == STATUS_IN_PROGRESS ) { int team_points[2] = { 0, 0 }; @@ -154,13 +83,19 @@ void BattleGroundAB::Update(uint32 diff) _SendNodeUpdate(node); _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); // Message to chatlog - char buf[256]; - uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE; - sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node)); - WorldPacket data; - ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL); - SendPacketToAll(&data); - PlaySoundToAll((teamIndex == 0) ? SOUND_NODE_CAPTURED_ALLIANCE : SOUND_NODE_CAPTURED_HORDE); + + if(teamIndex == 0) + { + // FIXME: team and node names not localized + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE,NULL,LANG_BG_AB_ALLY,_GetNodeNameId(node)); + PlaySoundToAll(SOUND_NODE_CAPTURED_ALLIANCE); + } + else + { + // FIXME: team and node names not localized + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE,NULL,LANG_BG_AB_HORDE,_GetNodeNameId(node)); + PlaySoundToAll(SOUND_NODE_CAPTURED_HORDE); + } } } @@ -182,22 +117,22 @@ void BattleGroundAB::Update(uint32 diff) m_TeamScores[team] += BG_AB_TickPoints[points]; m_HonorScoreTics[team] += BG_AB_TickPoints[points]; m_ReputationScoreTics[team] += BG_AB_TickPoints[points]; - if( m_ReputationScoreTics[team] >= 200 ) + if( m_ReputationScoreTics[team] >= m_ReputationTics ) { (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); - m_ReputationScoreTics[team] -= 200; + m_ReputationScoreTics[team] -= m_ReputationTics; } - if( m_HonorScoreTics[team] >= BG_HONOR_SCORE_TICKS ) + if( m_HonorScoreTics[team] >= m_HonorTics ) { - (team == BG_TEAM_ALLIANCE) ? RewardHonorToTeam(20, ALLIANCE) : RewardHonorToTeam(20, HORDE); - m_HonorScoreTics[team] -= BG_HONOR_SCORE_TICKS; + RewardHonorToTeam(GetBonusHonorFromKill(1), (team == BG_TEAM_ALLIANCE) ? ALLIANCE : HORDE); + m_HonorScoreTics[team] -= m_HonorTics; } if( !m_IsInformedNearVictory && m_TeamScores[team] > 1800 ) { if( team == BG_TEAM_ALLIANCE ) - SendMessageToAll(GetMangosString(LANG_BG_AB_A_NEAR_VICTORY)); + SendMessageToAll(LANG_BG_AB_A_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); else - SendMessageToAll(GetMangosString(LANG_BG_AB_H_NEAR_VICTORY)); + SendMessageToAll(LANG_BG_AB_H_NEAR_VICTORY, CHAT_MSG_BG_SYSTEM_NEUTRAL); PlaySoundToAll(SOUND_NEAR_VICTORY); m_IsInformedNearVictory = true; } @@ -219,6 +154,40 @@ void BattleGroundAB::Update(uint32 diff) } } +void BattleGroundAB::StartingEventCloseDoors() +{ + // despawn banners, auras and buffs + for (int obj = BG_AB_OBJECT_BANNER_NEUTRAL; obj < BG_AB_DYNAMIC_NODES_COUNT * 8; ++obj) + SpawnBGObject(obj, RESPAWN_ONE_DAY); + for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT * 3; ++i) + SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + i, RESPAWN_ONE_DAY); + + // Starting doors + DoorClose(BG_AB_OBJECT_GATE_A); + DoorClose(BG_AB_OBJECT_GATE_H); + SpawnBGObject(BG_AB_OBJECT_GATE_A, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_AB_OBJECT_GATE_H, RESPAWN_IMMEDIATELY); + + // Starting base spirit guides + _NodeOccupied(BG_AB_SPIRIT_ALIANCE,ALLIANCE); + _NodeOccupied(BG_AB_SPIRIT_HORDE,HORDE); +} + +void BattleGroundAB::StartingEventOpenDoors() +{ + // spawn neutral banners + for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) + SpawnBGObject(banner, RESPAWN_IMMEDIATELY); + for (int i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) + { + //randomly select buff to spawn + uint8 buff = urand(0, 2); + SpawnBGObject(BG_AB_OBJECT_SPEEDBUFF_STABLES + buff + i * 3, RESPAWN_IMMEDIATELY); + } + DoorOpen(BG_AB_OBJECT_GATE_A); + DoorOpen(BG_AB_OBJECT_GATE_H); +} + void BattleGroundAB::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); @@ -303,24 +272,19 @@ void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex) SpawnBGObject(obj, RESPAWN_ONE_DAY); } -const char* BattleGroundAB::_GetNodeName(uint8 node) +int32 BattleGroundAB::_GetNodeNameId(uint8 node) { switch (node) { - case BG_AB_NODE_STABLES: - return GetMangosString(LANG_BG_AB_NODE_STABLES); - case BG_AB_NODE_BLACKSMITH: - return GetMangosString(LANG_BG_AB_NODE_BLACKSMITH); - case BG_AB_NODE_FARM: - return GetMangosString(LANG_BG_AB_NODE_FARM); - case BG_AB_NODE_LUMBER_MILL: - return GetMangosString(LANG_BG_AB_NODE_LUMBER_MILL); - case BG_AB_NODE_GOLD_MINE: - return GetMangosString(LANG_BG_AB_NODE_GOLD_MINE); + case BG_AB_NODE_STABLES: return LANG_BG_AB_NODE_STABLES; + case BG_AB_NODE_BLACKSMITH: return LANG_BG_AB_NODE_BLACKSMITH; + case BG_AB_NODE_FARM: return LANG_BG_AB_NODE_FARM; + case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL; + case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE; default: ASSERT(0); } - return ""; + return 0; } void BattleGroundAB::FillInitialWorldStates(WorldPacket& data) @@ -451,10 +415,6 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam()); - // Message to chatlog - char buf[256]; - uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE; - // Check if player really could use this banner, not cheated if( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) ) return; @@ -473,7 +433,13 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); _SendNodeUpdate(node); m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; - sprintf(buf, GetMangosString(LANG_BG_AB_NODE_CLAIMED), _GetNodeName(node), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE)); + + // FIXME: team and node names not localized + if(teamIndex == 0) + SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node), LANG_BG_AB_ALLY); + else + SendMessage2ToAll(LANG_BG_AB_NODE_CLAIMED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node), LANG_BG_AB_HORDE); + sound = SOUND_NODE_CLAIMED; } // If node is contested @@ -491,7 +457,12 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); _SendNodeUpdate(node); m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; - sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node)); + + // FIXME: node names not localized + if(teamIndex == 0) + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); } // If contested, change back to occupied else @@ -506,7 +477,12 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ _SendNodeUpdate(node); m_NodeTimers[node] = 0; _NodeOccupied(node,(teamIndex == 0) ? ALLIANCE:HORDE); - sprintf(buf, GetMangosString(LANG_BG_AB_NODE_DEFENDED), _GetNodeName(node)); + + // FIXME: node names not localized + if(teamIndex == 0) + SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_DEFENDED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); } sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE; } @@ -523,18 +499,24 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ _SendNodeUpdate(node); _NodeDeOccupied(node); m_NodeTimers[node] = BG_AB_FLAG_CAPTURING_TIME; - sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node)); + + // FIXME: node names not localized + if(teamIndex == 0) + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_ALLIANCE, source, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_ASSAULTED,CHAT_MSG_BG_SYSTEM_HORDE, source, _GetNodeNameId(node)); + sound = (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE; } - WorldPacket data; - ChatHandler::FillMessageData(&data, source->GetSession(), type, LANG_UNIVERSAL, NULL, source->GetGUID(), buf, NULL); - SendPacketToAll(&data); + // If node is occupied again, send "X has taken the Y" msg. if( m_Nodes[node] >= BG_AB_NODE_TYPE_OCCUPIED ) { - sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node)); - ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL); - SendPacketToAll(&data); + // FIXME: team and node names not localized + if(teamIndex == 0) + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_ALLIANCE, NULL, LANG_BG_AB_ALLY, _GetNodeNameId(node)); + else + SendMessage2ToAll(LANG_BG_AB_NODE_TAKEN,CHAT_MSG_BG_SYSTEM_HORDE, NULL, LANG_BG_AB_HORDE, _GetNodeNameId(node)); } PlaySoundToAll(sound); } @@ -591,6 +573,10 @@ void BattleGroundAB::Reset() m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0; m_ReputationScoreTics[BG_TEAM_HORDE] = 0; m_IsInformedNearVictory = false; + bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call! + m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks; + m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks; + for (uint8 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i) { m_Nodes[i] = 0; @@ -604,6 +590,20 @@ void BattleGroundAB::Reset() DelCreature(i); } +void BattleGroundAB::EndBattleGround(uint32 winner) +{ + //win reward + if( winner == ALLIANCE ) + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + if( winner == HORDE ) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + //complete map_end rewards (even if no team wins) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + + BattleGround::EndBattleGround(winner); +} + WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player) { uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam()); diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h index 3b38b3a96..644556d0e 100644 --- a/src/game/BattleGroundAB.h +++ b/src/game/BattleGroundAB.h @@ -170,6 +170,11 @@ enum BG_AB_Sounds SOUND_NEAR_VICTORY = 8456 }; +#define BG_AB_NotABBGWeekendHonorTicks 330 +#define BG_AB_ABBGWeekendHonorTicks 200 +#define BG_AB_NotABBGWeekendReputationTicks 200 +#define BG_AB_ABBGWeekendReputationTicks 150 + // x, y, z, o const float BG_AB_NodePositions[BG_AB_DYNAMIC_NODES_COUNT][4] = { {1166.785f, 1200.132f, -56.70859f, 0.9075713f}, // stables @@ -238,10 +243,13 @@ class BattleGroundAB : public BattleGround void Update(uint32 diff); void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); void RemovePlayer(Player *plr,uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); virtual bool SetupBattleGround(); virtual void Reset(); + void EndBattleGround(uint32 winner); virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); /* Scorekeeping */ @@ -263,7 +271,7 @@ class BattleGroundAB : public BattleGround void _NodeOccupied(uint8 node,Team team); void _NodeDeOccupied(uint8 node); - const char* _GetNodeName(uint8 node); + int32 _GetNodeNameId(uint8 node); /* Nodes info: 0: neutral @@ -271,14 +279,18 @@ class BattleGroundAB : public BattleGround 2: horde contested 3: ally occupied 4: horde occupied */ - uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT]; - uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT]; - BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT]; - int32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT]; - uint32 m_TeamScores[2]; - uint32 m_lastTick[2]; - uint32 m_HonorScoreTics[2]; - uint32 m_ReputationScoreTics[2]; - bool m_IsInformedNearVictory; + uint8 m_Nodes[BG_AB_DYNAMIC_NODES_COUNT]; + uint8 m_prevNodes[BG_AB_DYNAMIC_NODES_COUNT]; + BG_AB_BannerTimer m_BannerTimers[BG_AB_DYNAMIC_NODES_COUNT]; + int32 m_NodeTimers[BG_AB_DYNAMIC_NODES_COUNT]; + uint32 m_TeamScores[2]; + uint32 m_lastTick[2]; + uint32 m_HonorScoreTics[2]; + uint32 m_ReputationScoreTics[2]; + bool m_IsInformedNearVictory; + uint32 m_HonorTics; + uint32 m_ReputationTics; + + }; #endif diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp index c444bcbb2..af5bd2360 100644 --- a/src/game/BattleGroundAV.cpp +++ b/src/game/BattleGroundAV.cpp @@ -20,13 +20,16 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundAV.h" -#include "Creature.h" -#include "MapManager.h" #include "Language.h" BattleGroundAV::BattleGroundAV() { + //TODO FIX ME! + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN; } BattleGroundAV::~BattleGroundAV() @@ -39,6 +42,14 @@ void BattleGroundAV::Update(uint32 diff) BattleGround::Update(diff); } +void BattleGroundAV::StartingEventCloseDoors() +{ +} + +void BattleGroundAV::StartingEventOpenDoors() +{ +} + void BattleGroundAV::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); diff --git a/src/game/BattleGroundAV.h b/src/game/BattleGroundAV.h index c2e12a872..edacf1cfe 100644 --- a/src/game/BattleGroundAV.h +++ b/src/game/BattleGroundAV.h @@ -46,6 +46,8 @@ class BattleGroundAV : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); void RemovePlayer(Player *plr,uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); diff --git a/src/game/BattleGroundBE.cpp b/src/game/BattleGroundBE.cpp index 412479093..2b99d9463 100644 --- a/src/game/BattleGroundBE.cpp +++ b/src/game/BattleGroundBE.cpp @@ -20,15 +20,23 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundBE.h" -#include "Creature.h" #include "ObjectMgr.h" -#include "MapManager.h" #include "WorldPacket.h" #include "Language.h" BattleGroundBE::BattleGroundBE() { m_BgObjects.resize(BG_BE_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; } BattleGroundBE::~BattleGroundBE() @@ -40,73 +48,30 @@ void BattleGroundBE::Update(uint32 diff) { BattleGround::Update(diff); - // after bg start we get there - if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) - { - ModifyStartDelayTime(diff); - - if (!(m_Events & 0x01)) - { - m_Events |= 0x01; - // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) - { - EndNow(); - return; - } - for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - - for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++) - SpawnBGObject(i, RESPAWN_ONE_DAY); - - SetStartDelayTime(START_DELAY1); - SendMessageToAll(LANG_ARENA_ONE_MINUTE); - } - // After 30 seconds, warning is signalled - else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04)) - { - m_Events |= 0x04; - SendMessageToAll(LANG_ARENA_THIRTY_SECONDS); - } - // After 15 seconds, warning is signalled - else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08)) - { - m_Events |= 0x08; - SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS); - } - // delay expired (1 minute) - else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10)) - { - m_Events |= 0x10; - - for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; i++) - DoorOpen(i); - - for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++) - SpawnBGObject(i, 60); - - SendMessageToAll(LANG_ARENA_BEGUN); - SetStatus(STATUS_IN_PROGRESS); - SetStartDelayTime(0); - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player *plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); - - if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) - EndBattleGround(HORDE); - else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE)) - EndBattleGround(ALLIANCE); - } - } - /*if(GetStatus() == STATUS_IN_PROGRESS) { // update something }*/ } +void BattleGroundBE::StartingEventCloseDoors() +{ + for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_4; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + + for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++) + SpawnBGObject(i, RESPAWN_ONE_DAY); +} + +void BattleGroundBE::StartingEventOpenDoors() +{ + for(uint32 i = BG_BE_OBJECT_DOOR_1; i <= BG_BE_OBJECT_DOOR_2; i++) + DoorOpen(i); + + for(uint32 i = BG_BE_OBJECT_BUFF_1; i <= BG_BE_OBJECT_BUFF_2; i++) + SpawnBGObject(i, 60); +} + void BattleGroundBE::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); @@ -127,10 +92,7 @@ void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE)); - if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) - EndBattleGround(HORDE); - else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE)) - EndBattleGround(ALLIANCE); + CheckArenaWinConditions(); } void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer) @@ -149,16 +111,7 @@ void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer) UpdateWorldState(0x9f1, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(0x9f0, GetAlivePlayersCountByTeam(HORDE)); - if(!GetAlivePlayersCountByTeam(ALLIANCE)) - { - // all opponents killed - EndBattleGround(HORDE); - } - else if(!GetAlivePlayersCountByTeam(HORDE)) - { - // all opponents killed - EndBattleGround(ALLIANCE); - } + CheckArenaWinConditions(); } bool BattleGroundBE::HandlePlayerUnderMap(Player *player) diff --git a/src/game/BattleGroundBE.h b/src/game/BattleGroundBE.h index 3d15d612d..0fea026e5 100644 --- a/src/game/BattleGroundBE.h +++ b/src/game/BattleGroundBE.h @@ -59,6 +59,8 @@ class BattleGroundBE : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); diff --git a/src/game/BattleGroundDS.cpp b/src/game/BattleGroundDS.cpp index 825a52967..78360b9b1 100644 --- a/src/game/BattleGroundDS.cpp +++ b/src/game/BattleGroundDS.cpp @@ -19,10 +19,20 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundDS.h" +#include "Language.h" BattleGroundDS::BattleGroundDS() { + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; } BattleGroundDS::~BattleGroundDS() @@ -35,6 +45,14 @@ void BattleGroundDS::Update(uint32 diff) BattleGround::Update(diff); } +void BattleGroundDS::StartingEventCloseDoors() +{ +} + +void BattleGroundDS::StartingEventOpenDoors() +{ +} + void BattleGroundDS::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); diff --git a/src/game/BattleGroundDS.h b/src/game/BattleGroundDS.h index 7f9de8ca7..44a6cfbd3 100644 --- a/src/game/BattleGroundDS.h +++ b/src/game/BattleGroundDS.h @@ -39,6 +39,9 @@ class BattleGroundDS : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround(); diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index acdd4ca51..4ba6953fb 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -21,9 +21,7 @@ #include "BattleGround.h" #include "BattleGroundEY.h" #include "Creature.h" -#include "Chat.h" #include "ObjectMgr.h" -#include "MapManager.h" #include "Language.h" #include "WorldPacket.h" #include "Util.h" @@ -37,6 +35,11 @@ BattleGroundEY::BattleGroundEY() m_Points_Trigger[BLOOD_ELF] = TR_BLOOD_ELF_BUFF; m_Points_Trigger[DRAENEI_RUINS] = TR_DRAENEI_RUINS_BUFF; m_Points_Trigger[MAGE_TOWER] = TR_MAGE_TOWER_BUFF; + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_EY_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_EY_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_EY_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_EY_HAS_BEGUN; } BattleGroundEY::~BattleGroundEY() @@ -46,71 +49,8 @@ BattleGroundEY::~BattleGroundEY() void BattleGroundEY::Update(uint32 diff) { BattleGround::Update(diff); - // after bg start we get there (once) - if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) - { - ModifyStartDelayTime(diff); - if(!(m_Events & 0x01)) - { - m_Events |= 0x01; - - // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) - { - EndNow(); - return; - } - - SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY); - SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY); - -// SpawnBGCreature(EY_SPIRIT_MAIN_ALLIANCE, RESPAWN_IMMEDIATELY); -// SpawnBGCreature(EY_SPIRIT_MAIN_HORDE, RESPAWN_IMMEDIATELY); - for(uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i) - SpawnBGObject(i, RESPAWN_ONE_DAY); - - SetStartDelayTime(START_DELAY0); - } - // After 1 minute, warning is signalled - else if(GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04)) - { - m_Events |= 0x04; - SendMessageToAll(GetMangosString(LANG_BG_EY_ONE_MINUTE)); - } - // After 1,5 minute, warning is signalled - else if(GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08)) - { - m_Events |= 0x08; - SendMessageToAll(GetMangosString(LANG_BG_EY_HALF_MINUTE)); - } - // After 2 minutes, gates OPEN ! x) - else if(GetStartDelayTime() < 0 && !(m_Events & 0x10)) - { - m_Events |= 0x10; - SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY); - SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY); - - for(uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - for(uint32 i = 0; i < EY_POINTS_MAX; ++i) - { - //randomly spawn buff - uint8 buff = urand(0, 2); - SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY); - } - - SendMessageToAll(GetMangosString(LANG_BG_EY_BEGIN)); - - PlaySoundToAll(SOUND_BG_START); - SetStatus(STATUS_IN_PROGRESS); - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player *plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_PREPARATION); - } - } - else if(GetStatus() == STATUS_IN_PROGRESS) + if( GetStatus() == STATUS_IN_PROGRESS ) { m_PointAddingTimer -= diff; if(m_PointAddingTimer <= 0) @@ -152,15 +92,39 @@ void BattleGroundEY::Update(uint32 diff) } } +void BattleGroundEY::StartingEventCloseDoors() +{ + SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_IMMEDIATELY); + SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_IMMEDIATELY); + + for(uint32 i = BG_EY_OBJECT_A_BANNER_FEL_REALVER_CENTER; i < BG_EY_OBJECT_MAX; ++i) + SpawnBGObject(i, RESPAWN_ONE_DAY); +} + +void BattleGroundEY::StartingEventOpenDoors() +{ + SpawnBGObject(BG_EY_OBJECT_DOOR_A, RESPAWN_ONE_DAY); + SpawnBGObject(BG_EY_OBJECT_DOOR_H, RESPAWN_ONE_DAY); + + for(uint32 i = BG_EY_OBJECT_N_BANNER_FEL_REALVER_CENTER; i <= BG_EY_OBJECT_FLAG_NETHERSTORM; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + for(uint32 i = 0; i < EY_POINTS_MAX; ++i) + { + //randomly spawn buff + uint8 buff = urand(0, 2); + SpawnBGObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REALVER + buff + i * 3, RESPAWN_IMMEDIATELY); + } +} + void BattleGroundEY::AddPoints(uint32 Team, uint32 Points) { uint8 team_index = GetTeamIndexByTeamId(Team); m_TeamScores[team_index] += Points; m_HonorScoreTics[team_index] += Points; - if (m_HonorScoreTics[team_index] >= BG_HONOR_SCORE_TICKS) + if (m_HonorScoreTics[team_index] >= m_HonorTics ) { - RewardHonorToTeam(20, Team); - m_HonorScoreTics[team_index] -= BG_HONOR_SCORE_TICKS; + RewardHonorToTeam(GetBonusHonorFromKill(1), Team); + m_HonorScoreTics[team_index] -= m_HonorTics; } UpdateTeamScore(Team); } @@ -183,7 +147,7 @@ void BattleGroundEY::CheckSomeoneJoinedPoint() ++j; continue; } - if (plr->isAllowUseBattleGroundObject() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) + if (plr->CanCaptureTowerPoint() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) { //player joined point! //show progress bar @@ -226,7 +190,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint() ++j; continue; } - if (!plr->isAllowUseBattleGroundObject() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) + if (!plr->CanCaptureTowerPoint() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS)) //move player out of point (add him to players that are out of points { m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); @@ -306,6 +270,20 @@ void BattleGroundEY::UpdateTeamScore(uint32 Team) UpdateWorldState(EY_HORDE_RESOURCES, score); } +void BattleGroundEY::EndBattleGround(uint32 winner) +{ + //win reward + if( winner == ALLIANCE ) + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + if( winner == HORDE ) + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + //complete map reward + RewardHonorToTeam(GetBonusHonorFromKill(1), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(1), HORDE); + + BattleGround::EndBattleGround(winner); +} + void BattleGroundEY::UpdatePointsCount(uint32 Team) { if(Team == ALLIANCE) @@ -530,6 +508,8 @@ void BattleGroundEY::Reset() m_DroppedFlagGUID = 0; m_PointAddingTimer = 0; m_TowerCapCheckTimer = 0; + bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call! + uint32 m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks; for(uint8 i = 0; i < EY_POINTS_MAX; ++i) { @@ -554,7 +534,7 @@ void BattleGroundEY::RespawnFlag(bool send_message) if(send_message) { - SendMessageToAll(GetMangosString(LANG_BG_EY_RESETED_FLAG)); + SendMessageToAll(LANG_BG_EY_RESETED_FLAG, CHAT_MSG_BG_SYSTEM_NEUTRAL); PlaySoundToAll(BG_EY_SOUND_FLAG_RESET); // flags respawned sound... } @@ -603,32 +583,20 @@ void BattleGroundEY::EventPlayerDroppedFlag(Player *Source) if(GetFlagPickerGUID() != Source->GetGUID()) return; - const char *message = ""; - uint8 type = 0; - SetFlagPicker(0); Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); m_FlagState = BG_EY_FLAG_STATE_ON_GROUND; m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME; Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); Source->CastSpell(Source, BG_EY_PLAYER_DROPPED_FLAG_SPELL, true); - if(Source->GetTeam() == ALLIANCE) - { - message = GetMangosString(LANG_BG_EY_DROPPED_FLAG); - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - } - else - { - message = GetMangosString(LANG_BG_EY_DROPPED_FLAG); - type = CHAT_MSG_BG_SYSTEM_HORDE; - } //this does not work correctly :( (it should remove flag carrier name) UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_WAIT_RESPAWN); UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_WAIT_RESPAWN); - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + if(Source->GetTeam() == ALLIANCE) + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(LANG_BG_EY_DROPPED_FLAG,CHAT_MSG_BG_SYSTEM_HORDE, Source); } void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target_obj) @@ -636,20 +604,14 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target if(GetStatus() != STATUS_IN_PROGRESS || IsFlagPickedup() || !Source->IsWithinDistInMap(target_obj, 10)) return; - const char *message; - uint8 type = 0; - message = GetMangosString(LANG_BG_EY_HAS_TAKEN_FLAG); - if(Source->GetTeam() == ALLIANCE) { UpdateWorldState(NETHERSTORM_FLAG_STATE_ALLIANCE, BG_EY_FLAG_STATE_ON_PLAYER); - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_ALLIANCE); } else { UpdateWorldState(NETHERSTORM_FLAG_STATE_HORDE, BG_EY_FLAG_STATE_ON_PLAYER); - type = CHAT_MSG_BG_SYSTEM_HORDE; PlaySoundToAll(BG_EY_SOUND_FLAG_PICKED_UP_HORDE); } @@ -663,9 +625,10 @@ void BattleGroundEY::EventPlayerClickedOnFlag(Player *Source, GameObject* target Source->CastSpell(Source, BG_EY_NETHERSTORM_FLAG_SPELL, true); Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + if(Source->GetTeam() == ALLIANCE) + SendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(LANG_BG_EY_HAS_TAKEN_FLAG,CHAT_MSG_BG_SYSTEM_HORDE, Source); } void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) @@ -674,8 +637,6 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) return; //Natural point - uint8 message_type = 0; - const char *message = ""; uint32 Team = m_PointOwnedByTeam[Point]; if(!Team) @@ -684,8 +645,6 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) if (Team == ALLIANCE) { m_TeamPointsCount[BG_TEAM_ALLIANCE]--; - message_type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - message = GetMangosString(m_LoosingPointTypes[Point].MessageIdAlliance); SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance, RESPAWN_ONE_DAY); SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 1, RESPAWN_ONE_DAY); SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeAlliance + 2, RESPAWN_ONE_DAY); @@ -693,8 +652,6 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) else { m_TeamPointsCount[BG_TEAM_HORDE]--; - message_type = CHAT_MSG_BG_SYSTEM_HORDE; - message = GetMangosString(m_LoosingPointTypes[Point].MessageIdHorde); SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde, RESPAWN_ONE_DAY); SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 1, RESPAWN_ONE_DAY); SpawnBGObject(m_LoosingPointTypes[Point].DespawnObjectTypeHorde + 2, RESPAWN_ONE_DAY); @@ -709,9 +666,10 @@ void BattleGroundEY::EventTeamLostPoint(Player *Source, uint32 Point) m_PointOwnedByTeam[Point] = EY_POINT_NO_OWNER; m_PointState[Point] = EY_POINT_NO_OWNER; - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), message_type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + if (Team == ALLIANCE) + SendMessageToAll(m_LoosingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(m_LoosingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); UpdatePointsIcons(Team, Point); UpdatePointsCount(Team); @@ -722,8 +680,6 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) if(GetStatus() != STATUS_IN_PROGRESS) return; - uint8 type = 0; - const char *message = ""; uint32 Team = Source->GetTeam(); SpawnBGObject(m_CapturingPointTypes[Point].DespawnNeutralObjectType, RESPAWN_ONE_DAY); @@ -733,8 +689,6 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) if (Team == ALLIANCE) { m_TeamPointsCount[BG_TEAM_ALLIANCE]++; - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - message = GetMangosString(m_CapturingPointTypes[Point].MessageIdAlliance); SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 1, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeAlliance + 2, RESPAWN_IMMEDIATELY); @@ -742,8 +696,6 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) else { m_TeamPointsCount[BG_TEAM_HORDE]++; - type = CHAT_MSG_BG_SYSTEM_HORDE; - message = GetMangosString(m_CapturingPointTypes[Point].MessageIdHorde); SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 1, RESPAWN_IMMEDIATELY); SpawnBGObject(m_CapturingPointTypes[Point].SpawnObjectTypeHorde + 2, RESPAWN_IMMEDIATELY); @@ -754,9 +706,10 @@ void BattleGroundEY::EventTeamCapturedPoint(Player *Source, uint32 Point) m_PointOwnedByTeam[Point] = Team; m_PointState[Point] = EY_POINT_UNDER_CONTROL; - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + if (Team == ALLIANCE) + SendMessageToAll(m_CapturingPointTypes[Point].MessageIdAlliance,CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(m_CapturingPointTypes[Point].MessageIdHorde,CHAT_MSG_BG_SYSTEM_HORDE, Source); if(m_BgCreatures[Point]) DelCreature(Point); @@ -778,38 +731,33 @@ void BattleGroundEY::EventPlayerCapturedFlag(Player *Source, uint32 BgObjectType if(GetStatus() != STATUS_IN_PROGRESS || GetFlagPickerGUID() != Source->GetGUID()) return; - uint8 type = 0; - uint8 team_id = 0; - const char *message = ""; - SetFlagPicker(0); m_FlagState = BG_EY_FLAG_STATE_WAIT_RESPAWN; Source->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + if(Source->GetTeam() == ALLIANCE) - { PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_ALLIANCE); - team_id = BG_TEAM_ALLIANCE; - message = GetMangosString(LANG_BG_EY_CAPTURED_FLAG_A); - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; - } else - { PlaySoundToAll(BG_EY_SOUND_FLAG_CAPTURED_HORDE); - team_id = BG_TEAM_HORDE; - message = GetMangosString(LANG_BG_EY_CAPTURED_FLAG_H); - type = CHAT_MSG_BG_SYSTEM_HORDE; - } SpawnBGObject(BgObjectType, RESPAWN_IMMEDIATELY); m_FlagsTimer = BG_EY_FLAG_RESPAWN_TIME; m_FlagCapturedBgObjectType = BgObjectType; - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + uint8 team_id = 0; + if(Source->GetTeam() == ALLIANCE) + { + team_id = BG_TEAM_ALLIANCE; + SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_A, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + } + else + { + team_id = BG_TEAM_HORDE; + SendMessageToAll(LANG_BG_EY_CAPTURED_FLAG_H, CHAT_MSG_BG_SYSTEM_HORDE, Source); + } if(m_TeamPointsCount[team_id] > 0) AddPoints(Source->GetTeam(), BG_EY_FlagPoints[m_TeamPointsCount[team_id] - 1]); diff --git a/src/game/BattleGroundEY.h b/src/game/BattleGroundEY.h index 0da776457..17b678e8f 100644 --- a/src/game/BattleGroundEY.h +++ b/src/game/BattleGroundEY.h @@ -210,6 +210,9 @@ enum EYBattleGroundObjectTypes BG_EY_OBJECT_MAX = 59 }; +#define BG_EY_NotEYWeekendHonorTicks 330 +#define BG_EY_EYWeekendHonorTicks 200 + enum BG_EY_FlagState { BG_EY_FLAG_STATE_ON_BASE = 0, @@ -302,6 +305,8 @@ class BattleGroundEY : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); /* BG Flags */ uint64 GetFlagPickerGUID() const { return m_FlagKeeper; } @@ -319,6 +324,7 @@ class BattleGroundEY : public BattleGround virtual bool SetupBattleGround(); virtual void Reset(); void UpdateTeamScore(uint32 Team); + void EndBattleGround(uint32 winner); void UpdatePlayerScore(Player *Source, uint32 type, uint32 value); virtual void FillInitialWorldStates(WorldPacket& data); void SetDroppedFlagGUID(uint64 guid) { m_DroppedFlagGUID = guid;} @@ -368,5 +374,6 @@ class BattleGroundEY : public BattleGround uint8 m_CurrentPointPlayersCount[2*EY_POINTS_MAX]; int32 m_PointAddingTimer; + uint32 m_HonorTics; }; #endif diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index 8fc8ce370..a3c3c1920 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -23,7 +23,6 @@ #include "Player.h" #include "ObjectMgr.h" #include "WorldSession.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "Object.h" #include "Chat.h" @@ -111,9 +110,9 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) return; // get bg instance or bg template if instance not found - BattleGround * bg = 0; + BattleGround * bg = NULL; if(instanceId) - BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId, bgTypeId); + BattleGround *bg = sBattleGroundMgr.GetBattleGroundThroughClientInstance(instanceId, bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId))) { @@ -157,10 +156,11 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) // if we're here, then the conditions to join a bg are met. We can proceed in joining. // _player->GetGroup() was already checked, grp is already initialized + GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0); + uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); if(joinAsGroup /* && _player->GetGroup()*/) { sLog.outDebug("Battleground: the following players are joining as group:"); - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, isPremade, 0); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); @@ -173,7 +173,7 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) WorldPacket data; // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0); member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); @@ -181,9 +181,6 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: group end"); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - if(!ginfo->IsInvitedToBGInstanceGUID) - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } else { @@ -194,16 +191,15 @@ void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data ) WorldPacket data; // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0); SendPacket(&data); - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, false, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); - if(!ginfo->IsInvitedToBGInstanceGUID) - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); + if(!ginfo->IsInvitedToBGInstanceGUID) + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ ) @@ -323,22 +319,16 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - // if the player is not in queue, continue - if(itrPlayerStatus == qpMap.end()) - continue; - - // no group information, this should never happen - if(!itrPlayerStatus->second.GroupInfo) + // if the player is not in queue, continue or no group information - this should never happen + if(itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo) continue; BattleGround * bg = NULL; - // get possibly needed data from groupinfo uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated; uint8 status = 0; - if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID) { // not invited to bg, get template @@ -362,7 +352,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) // re - invite player with proper data WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype); SendPacket(&data); } } @@ -429,6 +419,12 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) sLog.outError("Battleground: Invalid player queue info!"); return; } + //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue + if( arenatype == 0 && !_player->CanJoinToBattleground() ) + { + sLog.outDebug("Battleground: player %s (%u) has a deserter debuff, do not port him to battleground!", _player->GetName(), _player->GetGUIDLow()); + action = 0; + } WorldPacket data; switch(action) { @@ -449,7 +445,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) } _player->RemoveFromGroup(); queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false); @@ -484,7 +480,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data ) } } _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it, maybe now his group fits in sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(bgTypeId),arenatype,israted,rating); @@ -528,84 +524,41 @@ void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ ) sLog.outDebug( "WORLD: Battleground status" ); WorldPacket data; + uint32 queueSlot = PLAYER_MAX_BATTLEGROUND_QUEUES; - // TODO: we must put player back to battleground in case disconnect (< 5 minutes offline time) or teleport player on login(!) from battleground map to entry point if(_player->InBattleGround()) { BattleGround *bg = _player->GetBattleGround(); - if(bg) + if(!bg) + return; + BattleGroundQueueTypeId bgQueueTypeId_tmp = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); + queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId_tmp); + if((bg->GetStatus() <= STATUS_IN_PROGRESS)) { - BattleGroundQueueTypeId bgQueueTypeId_tmp = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); - uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId_tmp); - if((bg->GetStatus() <= STATUS_IN_PROGRESS)) - { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); - SendPacket(&data); - } - for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - { - BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if (i == queueSlot || !bgQueueTypeId) - continue; - BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); - uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); - uint8 isRated = 0; - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if(itrPlayerStatus == qpMap.end()) - continue; - if(itrPlayerStatus->second.GroupInfo) - { - arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; - isRated = itrPlayerStatus->second.GroupInfo->IsRated; - } - BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - if(bg2) - { - //in this call is small bug, this call should be filled by player's waiting time in queue - //this call nulls all timers for client : - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated); - SendPacket(&data); - } - } - } - } - else - { - // we should update all queues? .. i'm not sure if this code is correct - for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - { - BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); - if(!bgQueueTypeId) - continue; - BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); - uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); - uint8 isRated = 0; - BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); - BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; - BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); - if(itrPlayerStatus == qpMap.end()) - continue; - if(itrPlayerStatus->second.GroupInfo) - { - arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; - isRated = itrPlayerStatus->second.GroupInfo->IsRated; - } - if(bg) - { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); - SendPacket(&data); - } - } - } -/* else // not sure if it needed... - { - for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) - { - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); SendPacket(&data); } - }*/ + } + // we should update all queues? .. i'm not sure if this code is correct + for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) + { + BattleGroundQueueTypeId bgQueueTypeId = _player->GetBattleGroundQueueTypeId(i); + if(!bgQueueTypeId || i == queueSlot) //queueslot check in case we already send it in the above code + continue; + BattleGroundTypeId bgTypeId = BattleGroundMgr::BGTemplateId(bgQueueTypeId); + uint8 arenatype = BattleGroundMgr::BGArenaType(bgQueueTypeId); + BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); + if(!bg) + continue; + BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers; + BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID()); + if(itrPlayerStatus == qpMap.end() || !itrPlayerStatus->second.GroupInfo) + continue; + arenatype = itrPlayerStatus->second.GroupInfo->ArenaType; + uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(itrPlayerStatus->second.GroupInfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTime()-itrPlayerStatus->second.GroupInfo->JoinTime, arenatype); + SendPacket(&data); + } } void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data ) @@ -768,9 +721,10 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) arenaRating = avg_pers_rating; } + GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); + uint32 avgTime = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].GetAverageQueueWaitTime(ginfo, _player->GetBattleGroundQueueIdFromLevel(bgTypeId)); if(asGroup) { - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating, ateamId); sLog.outDebug("Battleground: arena join as group start"); if(isRated) sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(arenaslot),_player->GetName(),arenaRating,arenatype); @@ -786,7 +740,7 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) WorldPacket data; // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data); @@ -794,7 +748,6 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName()); } sLog.outDebug("Battleground: arena join as group end"); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); if(isRated) sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AnnounceWorld(ginfo, _player->GetGUID(), true); } @@ -807,13 +760,12 @@ void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data ) WorldPacket data; // send status packet (in queue) - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); SendPacket(&data); - GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, false, arenaRating); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo); - sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName()); } + sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(bgTypeId), arenatype, isRated, arenaRating); } void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data ) diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 141a306d5..2ca465b48 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -52,6 +52,16 @@ INSTANTIATE_SINGLETON_1( BattleGroundMgr ); BattleGroundQueue::BattleGroundQueue() { + for(uint32 i = 0; i < BG_TEAMS_COUNT; i++) + { + for(uint32 j = 0; j < MAX_BATTLEGROUND_QUEUES; j++) + { + m_SumOfWaitTimes[i][j] = 0; + m_WaitTimeLastPlayer[i][j] = 0; + for(uint32 k = 0; k < COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; k++) + m_WaitTimes[i][j][k] = 0; + } + } } BattleGroundQueue::~BattleGroundQueue() @@ -81,7 +91,7 @@ void BattleGroundQueue::SelectionPool::Init() // remove group info from selection pool // returns true when we need to try to add new group to selection pool -// or false when pool is ok +// returns false when selection pool is ok or when we kicked smaller group than we need to kick // sometimes it can be called on empty selection pool bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) { @@ -105,7 +115,8 @@ bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) GroupQueueInfo* ginfo = (*groupToKick); SelectedGroups.erase(groupToKick); PlayerCount -= ginfo->Players.size(); - if (abs((int32)(ginfo->Players.size() - size)) <= 1) + //return false if we kicked smaller group or there are enough players in selection pool + if (ginfo->Players.size() <= size + 1) return false; } return true; @@ -113,8 +124,8 @@ bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size) // add group to selection pool // used when building selection pools -// returns true if we can invite more players -// returns false when selection pool is set +// returns true if we can invite more players, or when we added group to selection pool +// returns false when selection pool is full bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount) { //if group is larger than desired count - don't allow to add it to pool @@ -123,6 +134,7 @@ bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 de SelectedGroups.push_back(ginfo); // increase selected players count PlayerCount += ginfo->Players.size(); + return true; } if( PlayerCount < desiredCount ) return true; @@ -147,7 +159,7 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId ginfo->ArenaTeamId = arenateamid; ginfo->IsRated = isRated; ginfo->IsInvitedToBGInstanceGUID = 0; - ginfo->JoinTime = getMSTime(); + ginfo->JoinTime = sWorld.GetGameTime() * IN_MILISECONDS; ginfo->Team = leader->GetTeam(); ginfo->ArenaTeamRating = arenaRating; ginfo->OpponentsTeamRating = 0; @@ -173,8 +185,6 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) { //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak PlayerQueueInfo& info = m_QueuedPlayers[plr->GetGUID()]; - info.InviteTime = 0; - info.LastInviteTime = 0; info.LastOnlineTime = getMSTime(); info.GroupInfo = ginfo; @@ -182,6 +192,55 @@ void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo) ginfo->Players[plr->GetGUID()] = &info; } +void BattleGroundQueue::PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id) +{ + uint32 timeInQueue = (sWorld.GetGameTime() * IN_MILISECONDS) - ginfo->JoinTime; + uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas! + if( !ginfo->ArenaType ) + { + if( ginfo->Team == HORDE ) + team_index = BG_TEAM_HORDE; + } + else + { + if( ginfo->IsRated ) + team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE + } + + //store pointer to arrayindex of player that was added first + uint32* lastPlayerAddedPointer = &(m_WaitTimeLastPlayer[team_index][queue_id]); + //remove his time from sum + m_SumOfWaitTimes[team_index][queue_id] -= m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)]; + //set average time to new + m_WaitTimes[team_index][queue_id][(*lastPlayerAddedPointer)] = timeInQueue; + //add new time to sum + m_SumOfWaitTimes[team_index][queue_id] += timeInQueue; + //set index of last player added to next one + (*lastPlayerAddedPointer)++; + (*lastPlayerAddedPointer) %= COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME; +} + +uint32 BattleGroundQueue::GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id) +{ + uint8 team_index = BG_TEAM_ALLIANCE; //default set to BG_TEAM_ALLIANCE - or non rated arenas! + if( !ginfo->ArenaType ) + { + if( ginfo->Team == HORDE ) + team_index = BG_TEAM_HORDE; + } + else + { + if( ginfo->IsRated ) + team_index = BG_TEAM_HORDE; //for rated arenas use BG_TEAM_HORDE + } + //check if there is enought values(we always add values > 0) + if(m_WaitTimes[team_index][queue_id][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME - 1] ) + return (m_SumOfWaitTimes[team_index][queue_id] / COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME); + else + //if there aren't enough values return 0 - not available + return 0; +} + //remove player from queue and from group info, if group info is empty then remove it too void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCount) { @@ -232,7 +291,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou } sLog.outDebug("BattleGroundQueue: Removing player GUID %u, from queue_id %u", GUID_LOPART(guid), (uint32)queue_id); - // ALL variables are corrcetly set + // ALL variables are correctly set // We can ignore leveling up in queue - it should not cause crash // remove player from group // if only one player there, remove group @@ -257,6 +316,22 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou if( (decreaseInvitedCount && !group->ArenaType) || (group->ArenaType && group->IsRated && group->Players.empty()) ) AnnounceWorld(group, guid, false); + //if player leaves queue and he is invited to rated arena match, then he have to loose + if( group->IsInvitedToBGInstanceGUID && group->IsRated && decreaseInvitedCount ) + { + ArenaTeam * at = objmgr.GetArenaTeamById(group->ArenaTeamId); + if( at ) + { + sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(guid), group->OpponentsTeamRating); + Player *plr = objmgr.GetPlayer(guid); + if( plr ) + at->MemberLost(plr, group->OpponentsTeamRating); + else + at->OfflineMemberLost(guid, group->OpponentsTeamRating); + at->SaveToDB(); + } + } + // remove group queue info if needed if( group->Players.empty() ) { @@ -278,7 +353,7 @@ void BattleGroundQueue::RemovePlayer(const uint64& guid, bool decreaseInvitedCou plr2->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to // queue->removeplayer, it causes bugs WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr2->GetTeam(), queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); plr2->GetSession()->SendPacket(&data); } // then actually delete, this may delete the group as well! @@ -355,13 +430,10 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b // set invitation ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID(); BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType()); + BGQueueIdBasedOnLevel queue_id = bg->GetQueueId(); // loop through the players for(std::map::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr) { - // set status - itr->second->InviteTime = getMSTime(); - itr->second->LastInviteTime = getMSTime(); - // get the player Player* plr = objmgr.GetPlayer(itr->first); // if offline, skip him, this should not happen - player is removed from queue when he logs out @@ -369,6 +441,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b continue; // invite the player + PlayerInvitedToBGUpdateAverageWaitTime(ginfo, queue_id); sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(), bg->GetTypeID(), ginfo->Team); WorldPacket data; @@ -378,7 +451,7 @@ bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * b sLog.outDebug("Battleground: invited plr %s (%u) to BG instance %u queueindex %u bgtype %u, I can't help it if they don't press the enter battle button.",plr->GetName(),plr->GetGUIDLow(),bg->GetInstanceID(),queueSlot,bg->GetTypeID()); // send status packet - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0); plr->GetSession()->SendPacket(&data); } return true; @@ -410,7 +483,6 @@ void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg) { // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop uint32 to_remove = ginfo->Players.size(); - uint32 team = ginfo->Team; for(uint32 j = 0; j < to_remove; j++) { // always remove the first one in the group @@ -436,7 +508,7 @@ void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg) // remove player from queue, this might delete the ginfo as well! don't use that pointer after this! RemovePlayer(itr2->first, true); WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); } } @@ -499,7 +571,7 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel //if ali selection is already empty, then kick horde group, but if there are less horde than ali in bg - break; if( !m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() ) { - if( aliFree <= diffHorde - 1 ) + if( aliFree <= diffHorde + 1 ) break; m_SelectionPools[BG_TEAM_HORDE].KickGroup(diffHorde - diffAli); } @@ -514,7 +586,7 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel } if( !m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() ) { - if( hordeFree <= diffAli - 1 ) + if( hordeFree <= diffAli + 1 ) break; m_SelectionPools[BG_TEAM_ALLIANCE].KickGroup(diffAli - diffHorde); } @@ -622,7 +694,7 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBas return false; } //allow 1v0 if debug bg - if( sBattleGroundMgr.isTesting() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) ) + if( sBattleGroundMgr.isTesting() && bg_template->isBattleGround() && (m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() || m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount()) ) return true; //return true if there are enough players in selection pools - enable to work .debug bg command correctly return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers; @@ -995,7 +1067,7 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) { WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, INVITATION_REMIND_TIME, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITATION_REMIND_TIME, 0); plr->GetSession()->SendPacket(&data); } } @@ -1030,21 +1102,11 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) BattleGroundQueue::QueuedPlayersMap::iterator qMapItr = qpMap.find(m_PlayerGuid); if (qMapItr != qpMap.end() && qMapItr->second.GroupInfo && qMapItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) { - if (qMapItr->second.GroupInfo->IsRated) - { - ArenaTeam * at = objmgr.GetArenaTeamById(qMapItr->second.GroupInfo->ArenaTeamId); - if (at) - { - sLog.outDebug("UPDATING memberLost's personal arena rating for %u by opponents rating: %u", GUID_LOPART(plr->GetGUID()), qMapItr->second.GroupInfo->OpponentsTeamRating); - at->MemberLost(plr, qMapItr->second.GroupInfo->OpponentsTeamRating); - at->SaveToDB(); - } - } plr->RemoveBattleGroundQueueId(bgQueueTypeId); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true); sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bg->GetTypeID(), bg->GetQueueId()); WorldPacket data; - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0); + sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); } } @@ -1075,10 +1137,10 @@ BattleGroundMgr::BattleGroundMgr() : m_AutoDistributionTimeChecker(0), m_ArenaTe BattleGroundMgr::~BattleGroundMgr() { - DeleteAlllBattleGrounds(); + DeleteAllBattleGrounds(); } -void BattleGroundMgr::DeleteAlllBattleGrounds() +void BattleGroundMgr::DeleteAllBattleGrounds() { for(uint32 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; i++) { @@ -1086,6 +1148,8 @@ void BattleGroundMgr::DeleteAlllBattleGrounds() { BattleGround * bg = itr->second; m_BattleGrounds[i].erase(itr++); + if(!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty()) + m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID()); delete bg; } } @@ -1120,6 +1184,8 @@ void BattleGroundMgr::Update(uint32 diff) { BattleGround * bg = itr->second; m_BattleGrounds[i].erase(itr); + if(!m_ClientBattleGroundIds[i][bg->GetQueueId()].empty()) + m_ClientBattleGroundIds[i][bg->GetQueueId()].erase(bg->GetClientInstanceID()); delete bg; } } @@ -1160,7 +1226,7 @@ void BattleGroundMgr::Update(uint32 diff) } } -void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted) +void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype) { // we can be in 3 queues in same time... if(StatusID == 0) @@ -1175,9 +1241,10 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time // uint64 in client *data << uint64( uint64(arenatype ? arenatype : bg->GetArenaType()) | (uint64(0x0D) << 8) | (uint64(bg->GetTypeID()) << 16) | (uint64(0x1F90) << 48) ); - *data << uint32(0); // unknown + *data << uint32(bg->GetClientInstanceID()); // alliance/horde for BG and skirmish/rated for Arenas - *data << uint8(bg->isArena() ? ( israted ? israted : bg->isRated() ) : bg->GetTeamIndexByTeamId(team)); + // following displays the minimap-icon 0 = faction icon 1 = arenaicon + *data << uint8(bg->isArena()); /* *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!! switch(bg->GetTypeID()) // value depends on bg id { @@ -1227,10 +1294,7 @@ void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGro *data << uint16(0x1F90); // unk value 8080 *data << uint32(bg->GetInstanceID()); // instance id - if(bg->isBattleGround()) - *data << uint8(bg->GetTeamIndexByTeamId(team)); // team - else - *data << uint8(israted?israted:bg->isRated()); // is rated battle + *data << uint8(bg->isArena()); // minimap-icon 0=faction 1=arena */ *data << uint32(StatusID); // status switch(StatusID) @@ -1386,10 +1450,10 @@ void BattleGroundMgr::BuildPlaySoundPacket(WorldPacket *data, uint32 soundid) *data << uint32(soundid); } -void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr) +void BattleGroundMgr::BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid) { data->Initialize(SMSG_BATTLEGROUND_PLAYER_LEFT, 8); - *data << uint64(plr->GetGUID()); + *data << uint64(guid); } void BattleGroundMgr::BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr) @@ -1435,6 +1499,25 @@ void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGro plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(INVITE_ACCEPT_WAIT_TIME)); } +BattleGround * BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) +{ + //cause at HandleBattleGroundJoinOpcode the clients sends the instanceid he gets from + //SMSG_BATTLEFIELD_LIST we need to find the battleground with this clientinstance-id + BattleGround* bg = GetBattleGroundTemplate(bgTypeId); + if( !bg ) + return NULL; + + if(bg->isArena()) + return GetBattleGround(instanceId, bgTypeId); + + for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr) + { + if(itr->second->GetClientInstanceID() == instanceId) + return itr->second; + } + return NULL; +} + BattleGround * BattleGroundMgr::GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId) { //search if needed @@ -1459,6 +1542,28 @@ BattleGround * BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTyp return m_BattleGrounds[bgTypeId].empty() ? NULL : m_BattleGrounds[bgTypeId].begin()->second; } +uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id) +{ + if( IsArenaType(bgTypeId) ) + return 0; //arenas don't have client-instanceids + + // we create here an instanceid, which is just for + // displaying this to the client and without any other use.. + // the client-instanceIds are unique for each battleground-type + // the instance-id just needs to be as low as possible, beginning with 1 + // the following works, because std::set is default ordered with "<" + // the optimalization would be to use as bitmask std::vector - but that would only make code unreadable + uint32 lastId = 0; + for(std::set::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();) + { + if( (++lastId) != *itr) //if there is a gap between the ids, we will break.. + break; + lastId = *itr; + } + m_ClientBattleGroundIds[bgTypeId][queue_id].insert(lastId + 1); + return lastId + 1; +} + // create a new battleground that will really be used to play BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated) { @@ -1528,6 +1633,7 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeI // generate a new instance id bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id + bg->SetClientInstanceID(CreateClientVisibleInstanceId(bgTypeId, queue_id)); // reset the new bg (set status to status_wait_queue from status_none) bg->Reset(); @@ -1752,7 +1858,7 @@ void BattleGroundMgr::DistributeArenaPoints() for (std::map::iterator plr_itr = PlayerPoints.begin(); plr_itr != PlayerPoints.end(); ++plr_itr) { //update to database - CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE `guid` = '%u'", plr_itr->second, plr_itr->first); + CharacterDatabase.PExecute("UPDATE characters SET arena_pending_points = '%u' WHERE guid = '%u'", plr_itr->second, plr_itr->first); //add points if player is online Player* pl = objmgr.GetPlayer(plr_itr->first); if (pl) @@ -1803,16 +1909,11 @@ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, const uint6 uint32 count = 0; *data << uint32(0x00); // number of bg instances - for(BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr) + uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(bgTypeId); + for(std::set::iterator itr = m_ClientBattleGroundIds[bgTypeId][queue_id].begin(); itr != m_ClientBattleGroundIds[bgTypeId][queue_id].end();++itr) { - // skip sending battleground template - if( itr == m_BattleGrounds[bgTypeId].begin() ) - continue; - if( PlayerLevel >= itr->second->GetMinLevel() && PlayerLevel <= itr->second->GetMaxLevel() ) - { - *data << uint32(itr->second->GetInstanceID()); - ++count; - } + *data << uint32(*itr); + ++count; } data->put( count_pos , count); } diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index dc2979267..6e6dd3141 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -30,12 +30,11 @@ typedef std::list BGFreeSlotQueueType; typedef UNORDERED_MAP BattleMastersMap; #define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_DAY 86400 // seconds in a day +#define COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME 10 struct GroupQueueInfo; // type predefinition struct PlayerQueueInfo // stores information for players in queue { - uint32 InviteTime; // first invite time - uint32 LastInviteTime; // last invite time uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes GroupQueueInfo * GroupInfo; // pointer to the associated groupqueueinfo }; @@ -79,6 +78,9 @@ class BattleGroundQueue GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0); void AddPlayer(Player *plr, GroupQueueInfo *ginfo); void RemovePlayer(const uint64& guid, bool decreaseInvitedCount); + void PlayerInvitedToBGUpdateAverageWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); + uint32 GetAverageQueueWaitTime(GroupQueueInfo* ginfo, BGQueueIdBasedOnLevel queue_id); + void DecreaseGroupLength(uint32 queueId, uint32 AsGroup); void BGEndedRemoveInvites(BattleGround * bg); void AnnounceWorld(GroupQueueInfo *ginfo, const uint64& playerGUID, bool isAddedToQueue); @@ -120,6 +122,9 @@ class BattleGroundQueue private: bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side); + uint32 m_WaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES][COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME]; + uint32 m_WaitTimeLastPlayer[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES]; + uint32 m_SumOfWaitTimes[BG_TEAMS_COUNT][MAX_BATTLEGROUND_QUEUES]; }; /* @@ -174,12 +179,12 @@ class BattleGroundMgr /* Packet Building */ void BuildPlayerJoinedBattleGroundPacket(WorldPacket *data, Player *plr); - void BuildPlayerLeftBattleGroundPacket(WorldPacket *data, Player *plr); + void BuildPlayerLeftBattleGroundPacket(WorldPacket *data, const uint64& guid); void BuildBattleGroundListPacket(WorldPacket *data, const uint64& guid, Player *plr, BattleGroundTypeId bgTypeId); void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, BattleGroundTypeId bgTypeId); void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value); void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg); - void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0); + void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0); void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, const uint64& guid); @@ -188,18 +193,20 @@ class BattleGroundMgr void InvitePlayer(Player* plr, uint32 bgInstanceGUID, BattleGroundTypeId bgTypeId, uint32 team); /* Battlegrounds */ + BattleGround* GetBattleGroundThroughClientInstance(uint32 instanceId, BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); BattleGround* GetBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId); //there must be uint32 because MAX_BATTLEGROUND_TYPE_ID means unknown - BattleGround * GetBattleGroundTemplate(BattleGroundTypeId bgTypeId); - BattleGround * CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated); + BattleGround* GetBattleGroundTemplate(BattleGroundTypeId bgTypeId); + BattleGround* CreateNewBattleGround(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType, bool isRated); uint32 CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsArena, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO); void AddBattleGround(uint32 InstanceID, BattleGroundTypeId bgTypeId, BattleGround* BG) { m_BattleGrounds[bgTypeId][InstanceID] = BG; }; void RemoveBattleGround(uint32 instanceID, BattleGroundTypeId bgTypeId) { m_BattleGrounds[bgTypeId].erase(instanceID); } + uint32 CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id); void CreateInitialBattleGrounds(); - void DeleteAlllBattleGrounds(); + void DeleteAllBattleGrounds(); void SendToBattleGround(Player *pl, uint32 InstanceID, BattleGroundTypeId bgTypeId); @@ -240,6 +247,7 @@ class BattleGroundMgr /* Battlegrounds */ BattleGroundSet m_BattleGrounds[MAX_BATTLEGROUND_TYPE_ID]; + std::set m_ClientBattleGroundIds[MAX_BATTLEGROUND_TYPE_ID][MAX_BATTLEGROUND_QUEUES]; //the instanceids just visible for the client uint32 m_NextRatingDiscardUpdate; uint64 m_NextAutoDistributionTime; uint32 m_AutoDistributionTimeChecker; diff --git a/src/game/BattleGroundNA.cpp b/src/game/BattleGroundNA.cpp index 01d766adf..070a33f25 100644 --- a/src/game/BattleGroundNA.cpp +++ b/src/game/BattleGroundNA.cpp @@ -20,15 +20,23 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundNA.h" -#include "Creature.h" #include "ObjectMgr.h" -#include "MapManager.h" #include "WorldPacket.h" #include "Language.h" BattleGroundNA::BattleGroundNA() { m_BgObjects.resize(BG_NA_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; } BattleGroundNA::~BattleGroundNA() @@ -40,70 +48,27 @@ void BattleGroundNA::Update(uint32 diff) { BattleGround::Update(diff); - // after bg start we get there - if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) - { - ModifyStartDelayTime(diff); - - if (!(m_Events & 0x01)) - { - m_Events |= 0x01; - // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) - { - EndNow(); - return; - } - for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - - SetStartDelayTime(START_DELAY1); - SendMessageToAll(LANG_ARENA_ONE_MINUTE); - } - // After 30 seconds, warning is signalled - else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04)) - { - m_Events |= 0x04; - SendMessageToAll(LANG_ARENA_THIRTY_SECONDS); - } - // After 15 seconds, warning is signalled - else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08)) - { - m_Events |= 0x08; - SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS); - } - // delay expired (1 minute) - else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10)) - { - m_Events |= 0x10; - - for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++) - DoorOpen(i); - - for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; i++) - SpawnBGObject(i, 60); - - SendMessageToAll(LANG_ARENA_BEGUN); - SetStatus(STATUS_IN_PROGRESS); - SetStartDelayTime(0); - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player *plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); - - if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) - EndBattleGround(HORDE); - else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE)) - EndBattleGround(ALLIANCE); - } - } - /*if(GetStatus() == STATUS_IN_PROGRESS) { // update something }*/ } +void BattleGroundNA::StartingEventCloseDoors() +{ + for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_4; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + +void BattleGroundNA::StartingEventOpenDoors() +{ + for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++) + DoorOpen(i); + + for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; i++) + SpawnBGObject(i, 60); +} + void BattleGroundNA::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); @@ -124,10 +89,7 @@ void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE)); - if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) - EndBattleGround(HORDE); - else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE)) - EndBattleGround(ALLIANCE); + CheckArenaWinConditions(); } void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer) @@ -146,16 +108,7 @@ void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer) UpdateWorldState(0xa0f, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(0xa10, GetAlivePlayersCountByTeam(HORDE)); - if(!GetAlivePlayersCountByTeam(ALLIANCE)) - { - // all opponents killed - EndBattleGround(HORDE); - } - else if(!GetAlivePlayersCountByTeam(HORDE)) - { - // all opponents killed - EndBattleGround(ALLIANCE); - } + CheckArenaWinConditions(); } bool BattleGroundNA::HandlePlayerUnderMap(Player *player) diff --git a/src/game/BattleGroundNA.h b/src/game/BattleGroundNA.h index ab70dea55..1d35b839e 100644 --- a/src/game/BattleGroundNA.h +++ b/src/game/BattleGroundNA.h @@ -60,6 +60,8 @@ class BattleGroundNA : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); diff --git a/src/game/BattleGroundRL.cpp b/src/game/BattleGroundRL.cpp index b1dbaec55..02f3b60ae 100644 --- a/src/game/BattleGroundRL.cpp +++ b/src/game/BattleGroundRL.cpp @@ -20,15 +20,23 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundRL.h" -#include "Creature.h" #include "ObjectMgr.h" -#include "MapManager.h" #include "Language.h" #include "WorldPacket.h" BattleGroundRL::BattleGroundRL() { m_BgObjects.resize(BG_RL_OBJECT_MAX); + + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; } BattleGroundRL::~BattleGroundRL() @@ -40,71 +48,27 @@ void BattleGroundRL::Update(uint32 diff) { BattleGround::Update(diff); - if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) - { - ModifyStartDelayTime(diff); - - if (!(m_Events & 0x01)) - { - m_Events |= 0x01; - - // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) - { - EndNow(); - return; - } - - for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - - SetStartDelayTime(START_DELAY1); - SendMessageToAll(LANG_ARENA_ONE_MINUTE); - } - // After 30 seconds, warning is signalled - else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x04)) - { - m_Events |= 0x04; - SendMessageToAll(LANG_ARENA_THIRTY_SECONDS); - } - // After 15 seconds, warning is signalled - else if (GetStartDelayTime() <= START_DELAY3 && !(m_Events & 0x08)) - { - m_Events |= 0x08; - SendMessageToAll(LANG_ARENA_FIFTEEN_SECONDS); - } - // delay expired (1 minute) - else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10)) - { - m_Events |= 0x10; - - for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++) - DoorOpen(i); - - for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; i++) - SpawnBGObject(i, 60); - - SendMessageToAll(LANG_ARENA_BEGUN); - SetStatus(STATUS_IN_PROGRESS); - SetStartDelayTime(0); - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player *plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); - - if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) - EndBattleGround(HORDE); - else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE)) - EndBattleGround(ALLIANCE); - } - } - /*if(GetStatus() == STATUS_IN_PROGRESS) { // update something }*/ } +void BattleGroundRL::StartingEventCloseDoors() +{ + for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + +void BattleGroundRL::StartingEventOpenDoors() +{ + for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++) + DoorOpen(i); + + for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; i++) + SpawnBGObject(i, 60); +} + void BattleGroundRL::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); @@ -125,10 +89,7 @@ void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE)); - if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE)) - EndBattleGround(HORDE); - else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE)) - EndBattleGround(ALLIANCE); + CheckArenaWinConditions(); } void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer) @@ -147,16 +108,7 @@ void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer) UpdateWorldState(0xbb8, GetAlivePlayersCountByTeam(ALLIANCE)); UpdateWorldState(0xbb9, GetAlivePlayersCountByTeam(HORDE)); - if(!GetAlivePlayersCountByTeam(ALLIANCE)) - { - // all opponents killed - EndBattleGround(HORDE); - } - else if(!GetAlivePlayersCountByTeam(HORDE)) - { - // all opponents killed - EndBattleGround(ALLIANCE); - } + CheckArenaWinConditions(); } bool BattleGroundRL::HandlePlayerUnderMap(Player *player) diff --git a/src/game/BattleGroundRL.h b/src/game/BattleGroundRL.h index 87ac54a98..dd0dfd2af 100644 --- a/src/game/BattleGroundRL.h +++ b/src/game/BattleGroundRL.h @@ -58,6 +58,8 @@ class BattleGroundRL : public BattleGround virtual void AddPlayer(Player *plr); virtual void Reset(); virtual void FillInitialWorldStates(WorldPacket &d); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); diff --git a/src/game/BattleGroundRV.cpp b/src/game/BattleGroundRV.cpp index a66f0ce30..8c252c35c 100644 --- a/src/game/BattleGroundRV.cpp +++ b/src/game/BattleGroundRV.cpp @@ -19,10 +19,20 @@ #include "Player.h" #include "BattleGround.h" #include "BattleGroundRV.h" +#include "Language.h" BattleGroundRV::BattleGroundRV() { + m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; + m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; + m_StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_15S; + m_StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE; + //we must set messageIds + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_ARENA_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_ARENA_THIRTY_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_ARENA_FIFTEEN_SECONDS; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_ARENA_HAS_BEGUN; } BattleGroundRV::~BattleGroundRV() @@ -35,6 +45,14 @@ void BattleGroundRV::Update(uint32 diff) BattleGround::Update(diff); } +void BattleGroundRV::StartingEventCloseDoors() +{ +} + +void BattleGroundRV::StartingEventOpenDoors() +{ +} + void BattleGroundRV::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); diff --git a/src/game/BattleGroundRV.h b/src/game/BattleGroundRV.h index 2d2ad12c9..e3e94baf1 100644 --- a/src/game/BattleGroundRV.h +++ b/src/game/BattleGroundRV.h @@ -39,6 +39,9 @@ class BattleGroundRV : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround(); diff --git a/src/game/BattleGroundSA.cpp b/src/game/BattleGroundSA.cpp index d5585fd93..68ef2af19 100644 --- a/src/game/BattleGroundSA.cpp +++ b/src/game/BattleGroundSA.cpp @@ -16,13 +16,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "Player.h" #include "BattleGround.h" #include "BattleGroundSA.h" -#include "Player.h" +#include "Language.h" BattleGroundSA::BattleGroundSA() { - + //TODO FIX ME! + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; } BattleGroundSA::~BattleGroundSA() @@ -35,6 +40,14 @@ void BattleGroundSA::Update(uint32 diff) BattleGround::Update(diff); } +void BattleGroundSA::StartingEventCloseDoors() +{ +} + +void BattleGroundSA::StartingEventOpenDoors() +{ +} + void BattleGroundSA::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); diff --git a/src/game/BattleGroundSA.h b/src/game/BattleGroundSA.h index 331a41455..3ba23d026 100644 --- a/src/game/BattleGroundSA.h +++ b/src/game/BattleGroundSA.h @@ -39,6 +39,8 @@ class BattleGroundSA : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); void RemovePlayer(Player *plr,uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp index 0c85dff86..bf9185e51 100644 --- a/src/game/BattleGroundWS.cpp +++ b/src/game/BattleGroundWS.cpp @@ -22,8 +22,6 @@ #include "BattleGroundWS.h" #include "Creature.h" #include "GameObject.h" -#include "Chat.h" -#include "MapManager.h" #include "ObjectMgr.h" #include "WorldPacket.h" #include "Language.h" @@ -32,6 +30,11 @@ BattleGroundWS::BattleGroundWS() { m_BgObjects.resize(BG_WS_OBJECT_MAX); m_BgCreatures.resize(BG_CREATURES_MAX_WS); + + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; } BattleGroundWS::~BattleGroundWS() @@ -42,75 +45,7 @@ void BattleGroundWS::Update(uint32 diff) { BattleGround::Update(diff); - // after bg start we get there (once) - if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) - { - ModifyStartDelayTime(diff); - - if(!(m_Events & 0x01)) - { - m_Events |= 0x01; - - // setup here, only when at least one player has ported to the map - if(!SetupBattleGround()) - { - EndNow(); - return; - } - -// for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++) -// SpawnBGCreature(i, RESPAWN_IMMEDIATELY); - - for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++) - { - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - DoorClose(i); - } - for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++) - SpawnBGObject(i, RESPAWN_ONE_DAY); - - SetStartDelayTime(START_DELAY0); - } - // After 1 minute, warning is signalled - else if(GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04)) - { - m_Events |= 0x04; - SendMessageToAll(GetMangosString(LANG_BG_WS_ONE_MINUTE)); - } - // After 1,5 minute, warning is signalled - else if(GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08)) - { - m_Events |= 0x08; - SendMessageToAll(GetMangosString(LANG_BG_WS_HALF_MINUTE)); - } - // After 2 minutes, gates OPEN ! x) - else if(GetStartDelayTime() < 0 && !(m_Events & 0x10)) - { - m_Events |= 0x10; - for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; i++) - DoorOpen(i); - for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; i++) - DoorOpen(i); - - SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY); - SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY); - SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY); - SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY); - - for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++) - SpawnBGObject(i, RESPAWN_IMMEDIATELY); - - SendMessageToAll(GetMangosString(LANG_BG_WS_BEGIN)); - - PlaySoundToAll(SOUND_BG_START); - SetStatus(STATUS_IN_PROGRESS); - - for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) - if(Player* plr = objmgr.GetPlayer(itr->first)) - plr->RemoveAurasDueToSpell(SPELL_PREPARATION); - } - } - else if(GetStatus() == STATUS_IN_PROGRESS) + if(GetStatus() == STATUS_IN_PROGRESS) { if(m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) { @@ -155,6 +90,33 @@ void BattleGroundWS::Update(uint32 diff) } } +void BattleGroundWS::StartingEventCloseDoors() +{ + for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++) + { + DoorClose(i); + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + } + for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++) + SpawnBGObject(i, RESPAWN_ONE_DAY); +} + +void BattleGroundWS::StartingEventOpenDoors() +{ + for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_A_4; i++) + DoorOpen(i); + for(uint32 i = BG_WS_OBJECT_DOOR_H_1; i <= BG_WS_OBJECT_DOOR_H_2; i++) + DoorOpen(i); + + SpawnBGObject(BG_WS_OBJECT_DOOR_A_5, RESPAWN_ONE_DAY); + SpawnBGObject(BG_WS_OBJECT_DOOR_A_6, RESPAWN_ONE_DAY); + SpawnBGObject(BG_WS_OBJECT_DOOR_H_3, RESPAWN_ONE_DAY); + SpawnBGObject(BG_WS_OBJECT_DOOR_H_4, RESPAWN_ONE_DAY); + + for(uint32 i = BG_WS_OBJECT_A_FLAG; i <= BG_WS_OBJECT_BERSERKBUFF_2; i++) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); +} + void BattleGroundWS::AddPlayer(Player *plr) { BattleGround::AddPlayer(plr); @@ -182,7 +144,7 @@ void BattleGroundWS::RespawnFlag(uint32 Team, bool captured) //when map_update will be allowed for battlegrounds this code will be useless SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); - SendMessageToAll(GetMangosString(LANG_BG_WS_F_PLACED)); + SendMessageToAll(LANG_BG_WS_F_PLACED, CHAT_MSG_BG_SYSTEM_NEUTRAL); PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); // flag respawned sound... } } @@ -196,12 +158,12 @@ void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) if(team == ALLIANCE) { SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_IMMEDIATELY); - SendMessageToAll(GetMangosString(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED)); + SendMessageToAll(LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); } else { SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_IMMEDIATELY); - SendMessageToAll(GetMangosString(LANG_BG_WS_HORDE_FLAG_RESPAWNED)); + SendMessageToAll(LANG_BG_WS_HORDE_FLAG_RESPAWNED, CHAT_MSG_BG_SYSTEM_NEUTRAL); } PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); @@ -220,11 +182,7 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) if(GetStatus() != STATUS_IN_PROGRESS) return; - uint8 type = 0; uint32 winner = 0; - const char *message = ""; - - //TODO FIX reputation and honor gains for low level players! Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); if(Source->GetTeam() == ALLIANCE) @@ -236,13 +194,10 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; // Drop Horde Flag from Player Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); - message = GetMangosString(LANG_BG_WS_CAPTURED_HF); - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; if(GetTeamScore(ALLIANCE) < BG_WS_MAX_TEAM_SCORE) AddPoint(ALLIANCE, 1); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_ALLIANCE); - RewardReputationToTeam(890, 35, ALLIANCE); // +35 reputation - RewardHonorToTeam(40, ALLIANCE); // +40 bonushonor + RewardReputationToTeam(890, m_ReputationCapture, ALLIANCE); } else { @@ -253,26 +208,26 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_WAIT_RESPAWN; // Drop Alliance Flag from Player Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); - message = GetMangosString(LANG_BG_WS_CAPTURED_AF); - type = CHAT_MSG_BG_SYSTEM_HORDE; if(GetTeamScore(HORDE) < BG_WS_MAX_TEAM_SCORE) AddPoint(HORDE, 1); PlaySoundToAll(BG_WS_SOUND_FLAG_CAPTURED_HORDE); - RewardReputationToTeam(889, 35, HORDE); // +35 reputation - RewardHonorToTeam(40, HORDE); // +40 bonushonor + RewardReputationToTeam(889, m_ReputationCapture, HORDE); } + //for flag capture is reward 2 honorable kills + RewardHonorToTeam(GetBonusHonorFromKill(2), Source->GetTeam()); SpawnBGObject(BG_WS_OBJECT_H_FLAG, BG_WS_FLAG_RESPAWN_TIME); SpawnBGObject(BG_WS_OBJECT_A_FLAG, BG_WS_FLAG_RESPAWN_TIME); - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + if(Source->GetTeam() == ALLIANCE) + SendMessageToAll(LANG_BG_WS_CAPTURED_HF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); + else + SendMessageToAll(LANG_BG_WS_CAPTURED_AF, CHAT_MSG_BG_SYSTEM_HORDE, Source); UpdateFlagState(Source->GetTeam(), 1); // flag state none UpdateTeamScore(Source->GetTeam()); // only flag capture should be updated - UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures... + UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures if(GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE) winner = ALLIANCE; @@ -324,8 +279,6 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) return; } - const char *message = ""; - uint8 type = 0; bool set = false; if(Source->GetTeam() == ALLIANCE) @@ -337,8 +290,6 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) SetHordeFlagPicker(0); Source->RemoveAurasDueToSpell(BG_WS_SPELL_WARSONG_FLAG); m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_GROUND; - message = GetMangosString(LANG_BG_WS_DROPPED_HF); - type = CHAT_MSG_BG_SYSTEM_HORDE; Source->CastSpell(Source, BG_WS_SPELL_WARSONG_FLAG_DROPPED, true); set = true; } @@ -352,8 +303,6 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) SetAllianceFlagPicker(0); Source->RemoveAurasDueToSpell(BG_WS_SPELL_SILVERWING_FLAG); m_FlagState[BG_TEAM_ALLIANCE] = BG_WS_FLAG_STATE_ON_GROUND; - message = GetMangosString(LANG_BG_WS_DROPPED_AF); - type = CHAT_MSG_BG_SYSTEM_ALLIANCE; Source->CastSpell(Source, BG_WS_SPELL_SILVERWING_FLAG_DROPPED, true); set = true; } @@ -364,14 +313,16 @@ void BattleGroundWS::EventPlayerDroppedFlag(Player *Source) Source->CastSpell(Source, SPELL_RECENTLY_DROPPED_FLAG, true); UpdateFlagState(Source->GetTeam(), 1); - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); - if(Source->GetTeam() == ALLIANCE) + { + SendMessageToAll(LANG_BG_WS_DROPPED_HF, CHAT_MSG_BG_SYSTEM_HORDE, Source); UpdateWorldState(BG_WS_FLAG_UNK_HORDE, uint32(-1)); + } else + { + SendMessageToAll(LANG_BG_WS_DROPPED_AF, CHAT_MSG_BG_SYSTEM_ALLIANCE, Source); UpdateWorldState(BG_WS_FLAG_UNK_ALLIANCE, uint32(-1)); + } m_FlagsDropTimer[GetTeamIndexByTeamId(Source->GetTeam()) ? 0 : 1] = BG_WS_FLAG_DROP_TIME; } @@ -382,14 +333,14 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target if(GetStatus() != STATUS_IN_PROGRESS) return; - const char *message = NULL; - uint8 type = 0; + int32 message_id = 0; + ChatMsg type; //alliance flag picked up from base if(Source->GetTeam() == HORDE && GetFlagState(ALLIANCE) == BG_WS_FLAG_STATE_ON_BASE && m_BgObjects[BG_WS_OBJECT_A_FLAG] == target_obj->GetGUID()) { - message = GetMangosString(LANG_BG_WS_PICKEDUP_AF); + message_id = LANG_BG_WS_PICKEDUP_AF; type = CHAT_MSG_BG_SYSTEM_HORDE; PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY); @@ -405,7 +356,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target if (Source->GetTeam() == ALLIANCE && GetFlagState(HORDE) == BG_WS_FLAG_STATE_ON_BASE && m_BgObjects[BG_WS_OBJECT_H_FLAG] == target_obj->GetGUID()) { - message = GetMangosString(LANG_BG_WS_PICKEDUP_HF); + message_id = LANG_BG_WS_PICKEDUP_HF; type = CHAT_MSG_BG_SYSTEM_ALLIANCE; PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY); @@ -422,7 +373,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target { if(Source->GetTeam() == ALLIANCE) { - message = GetMangosString(LANG_BG_WS_RETURNED_AF); + message_id = LANG_BG_WS_RETURNED_AF; type = CHAT_MSG_BG_SYSTEM_ALLIANCE; UpdateFlagState(HORDE, BG_WS_FLAG_STATE_WAIT_RESPAWN); RespawnFlag(ALLIANCE, false); @@ -432,7 +383,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target } else { - message = GetMangosString(LANG_BG_WS_PICKEDUP_AF); + message_id = LANG_BG_WS_PICKEDUP_AF; type = CHAT_MSG_BG_SYSTEM_HORDE; PlaySoundToAll(BG_WS_SOUND_ALLIANCE_FLAG_PICKED_UP); SpawnBGObject(BG_WS_OBJECT_A_FLAG, RESPAWN_ONE_DAY); @@ -451,7 +402,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target { if(Source->GetTeam() == HORDE) { - message = GetMangosString(LANG_BG_WS_RETURNED_HF); + message_id = LANG_BG_WS_RETURNED_HF; type = CHAT_MSG_BG_SYSTEM_HORDE; UpdateFlagState(ALLIANCE, BG_WS_FLAG_STATE_WAIT_RESPAWN); RespawnFlag(HORDE, false); @@ -461,7 +412,7 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target } else { - message = GetMangosString(LANG_BG_WS_PICKEDUP_HF); + message_id = LANG_BG_WS_PICKEDUP_HF; type = CHAT_MSG_BG_SYSTEM_ALLIANCE; PlaySoundToAll(BG_WS_SOUND_HORDE_FLAG_PICKED_UP); SpawnBGObject(BG_WS_OBJECT_H_FLAG, RESPAWN_ONE_DAY); @@ -475,12 +426,10 @@ void BattleGroundWS::EventPlayerClickedOnFlag(Player *Source, GameObject* target //target_obj->Delete(); } - if (!type) + if (!message_id) return; - WorldPacket data; - ChatHandler::FillMessageData(&data, Source->GetSession(), type, LANG_UNIVERSAL, NULL, Source->GetGUID(), message, NULL); - SendPacketToAll(&data); + SendMessageToAll(message_id, type, Source); Source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); } @@ -642,16 +591,33 @@ void BattleGroundWS::Reset() m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; m_TeamScores[BG_TEAM_ALLIANCE] = 0; m_TeamScores[BG_TEAM_HORDE] = 0; + bool isBGWeekend = false; //TODO FIXME - call sBattleGroundMgr.IsBGWeekend(m_TypeID); - you must also implement that call! + m_ReputationCapture = (isBGWeekend) ? 45 : 35; + m_HonorWinKills = (isBGWeekend) ? 3 : 1; + m_HonorEndKills = (isBGWeekend) ? 4 : 2; /* Spirit nodes is static at this BG and then not required deleting at BG reset. if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE]) DelCreature(WS_SPIRIT_MAIN_ALLIANCE); - if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE]) DelCreature(WS_SPIRIT_MAIN_HORDE); */ } +void BattleGroundWS::EndBattleGround(uint32 winner) +{ + //win reward + if( winner == ALLIANCE ) + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), ALLIANCE); + if( winner == HORDE ) + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorWinKills), HORDE); + //complete map_end rewards (even if no team wins) + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), ALLIANCE); + RewardHonorToTeam(GetBonusHonorFromKill(m_HonorEndKills), HORDE); + + BattleGround::EndBattleGround(winner); +} + void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer) { if(GetStatus() != STATUS_IN_PROGRESS) @@ -684,6 +650,29 @@ void BattleGroundWS::UpdatePlayerScore(Player *Source, uint32 type, uint32 value } } +WorldSafeLocsEntry const* BattleGroundWS::GetClosestGraveYard(Player* player) +{ + //if status in progress, it returns main graveyards with spiritguides + //else it will return the graveyard in the flagroom - this is especially good + //if a player dies in preparation phase - then the player can't cheat + //and teleport to the graveyard outside the flagroom + //and start running around, while the doors are still closed + if(player->GetTeam() == ALLIANCE) + { + if(GetStatus() == STATUS_IN_PROGRESS) + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_ALLIANCE); + else + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_ALLIANCE); + } + else + { + if(GetStatus() == STATUS_IN_PROGRESS) + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_MAIN_HORDE); + else + return sWorldSafeLocsStore.LookupEntry(WS_GRAVEYARD_FLAGROOM_HORDE); + } +} + void BattleGroundWS::FillInitialWorldStates(WorldPacket& data) { data << uint32(BG_WS_FLAG_CAPTURES_ALLIANCE) << uint32(GetTeamScore(ALLIANCE)); diff --git a/src/game/BattleGroundWS.h b/src/game/BattleGroundWS.h index f36834f65..093da3e53 100644 --- a/src/game/BattleGroundWS.h +++ b/src/game/BattleGroundWS.h @@ -105,8 +105,10 @@ enum BG_WS_FlagState enum BG_WS_Graveyards { - WS_GRAVEYARD_MAIN_ALLIANCE = 771, - WS_GRAVEYARD_MAIN_HORDE = 772 + WS_GRAVEYARD_FLAGROOM_ALLIANCE = 769, + WS_GRAVEYARD_FLAGROOM_HORDE = 770, + WS_GRAVEYARD_MAIN_ALLIANCE = 771, + WS_GRAVEYARD_MAIN_HORDE = 772 }; enum BG_WS_CreatureTypes @@ -138,6 +140,8 @@ class BattleGroundWS : public BattleGround /* inherited from BattlegroundClass */ virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); /* BG Flags */ uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; } @@ -160,6 +164,8 @@ class BattleGroundWS : public BattleGround void HandleKillPlayer(Player *player, Player *killer); bool SetupBattleGround(); virtual void Reset(); + void EndBattleGround(uint32 winner); + virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); void UpdateFlagState(uint32 team, uint32 value); void UpdateTeamScore(uint32 team); @@ -181,5 +187,9 @@ class BattleGroundWS : public BattleGround uint32 m_TeamScores[2]; int32 m_FlagsTimer[2]; int32 m_FlagsDropTimer[2]; + + uint32 m_ReputationCapture; + uint32 m_HonorWinKills; + uint32 m_HonorEndKills; }; #endif diff --git a/src/game/Channel.h b/src/game/Channel.h index 9839a8312..6e2fab2a5 100644 --- a/src/game/Channel.h +++ b/src/game/Channel.h @@ -21,7 +21,6 @@ #include "Common.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "Opcodes.h" #include "Player.h" diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index ae51ae60d..e162ef242 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -29,7 +29,6 @@ #include "Guild.h" #include "UpdateMask.h" #include "Auth/md5.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "Group.h" #include "Database/DatabaseImpl.h" diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index dac790ca4..b5d0301e4 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -28,7 +28,6 @@ #include "Player.h" #include "UpdateMask.h" #include "Chat.h" -#include "MapManager.h" #include "GridNotifiersImpl.h" #include "CellImpl.h" #include "AccountMgr.h" @@ -418,26 +417,25 @@ ChatCommand * ChatHandler::getCommandTable() static ChatCommand npcCommandTable[] = { - { "say", SEC_MODERATOR, false, &ChatHandler::HandleNpcSayCommand, "", NULL }, - { "textemote", SEC_MODERATOR, false, &ChatHandler::HandleNpcTextEmoteCommand, "", NULL }, { "add", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddCommand, "", NULL }, + { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddVendorItemCommand, "", NULL }, + { "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL }, + { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL }, + { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcChangeLevelCommand, "", NULL }, { "delete", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcDeleteCommand, "", NULL }, + { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL }, + { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL }, + { "follow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFollowCommand, "", NULL }, + { "info", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcInfoCommand, "", NULL }, + { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcMoveCommand, "", NULL }, + { "playemote", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcPlayEmoteCommand, "", NULL }, + { "setmodel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetModelCommand, "", NULL }, + { "setmovetype", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetMoveTypeCommand, "", NULL }, + { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetPhaseCommand, "", NULL }, { "spawndist", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnDistCommand, "", NULL }, { "spawntime", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSpawnTimeCommand, "", NULL }, - { "factionid", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFactionIdCommand, "", NULL }, - { "addmove", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcAddMoveCommand, "", NULL }, - { "setmovetype", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetMoveTypeCommand, "", NULL }, - { "move", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcMoveCommand, "", NULL }, - { "changelevel", SEC_GAMEMASTER, false, &ChatHandler::HandleChangeLevelCommand, "", NULL }, - { "setmodel", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetModelCommand, "", NULL }, - { "additem", SEC_GAMEMASTER, false, &ChatHandler::HandleAddVendorItemCommand, "", NULL }, - { "delitem", SEC_GAMEMASTER, false, &ChatHandler::HandleDelVendorItemCommand, "", NULL }, - { "flag", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFlagCommand, "", NULL }, - { "changeentry", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcChangeEntryCommand, "", NULL }, - { "info", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcInfoCommand, "", NULL }, - { "playemote", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcPlayEmoteCommand, "", NULL }, - { "follow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcFollowCommand, "", NULL }, - { "setphase", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetPhaseCommand, "", NULL }, + { "say", SEC_MODERATOR, false, &ChatHandler::HandleNpcSayCommand, "", NULL }, + { "textemote", SEC_MODERATOR, false, &ChatHandler::HandleNpcTextEmoteCommand, "", NULL }, { "unfollow", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcUnFollowCommand, "", NULL }, { "whisper", SEC_MODERATOR, false, &ChatHandler::HandleNpcWhisperCommand, "", NULL }, { "yell", SEC_MODERATOR, false, &ChatHandler::HandleNpcYellCommand, "", NULL }, @@ -445,9 +443,9 @@ ChatCommand * ChatHandler::getCommandTable() { "setdeathstate", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSetDeathStateCommand, "", NULL }, //{ TODO: fix or remove this commands - { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNameCommand, "", NULL }, - { "subname", SEC_GAMEMASTER, false, &ChatHandler::HandleSubNameCommand, "", NULL }, - { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAddWeaponCommand, "", NULL }, + { "addweapon", SEC_ADMINISTRATOR, false, &ChatHandler::HandleNpcAddWeaponCommand, "", NULL }, + { "name", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcNameCommand, "", NULL }, + { "subname", SEC_GAMEMASTER, false, &ChatHandler::HandleNpcSubNameCommand, "", NULL }, //} { NULL, 0, false, NULL, "", NULL } diff --git a/src/game/Chat.h b/src/game/Chat.h index 0ab3bd902..b9dc9f01e 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -176,10 +176,14 @@ class ChatHandler bool HandleModifyPhaseCommand(const char* args); bool HandleModifyGenderCommand(const char* args); + //-----------------------Npc Commands----------------------- bool HandleNpcAddCommand(const char* args); bool HandleNpcAddMoveCommand(const char* args); + bool HandleNpcAddVendorItemCommand(const char* args); bool HandleNpcChangeEntryCommand(const char *args); + bool HandleNpcChangeLevelCommand(const char* args); bool HandleNpcDeleteCommand(const char* args); + bool HandleNpcDelVendorItemCommand(const char* args); bool HandleNpcFactionIdCommand(const char* args); bool HandleNpcFlagCommand(const char* args); bool HandleNpcFollowCommand(const char* args); @@ -187,6 +191,7 @@ class ChatHandler bool HandleNpcMoveCommand(const char* args); bool HandleNpcPlayEmoteCommand(const char* args); bool HandleNpcSayCommand(const char* args); + bool HandleNpcSetDeathStateCommand(const char* args); bool HandleNpcSetModelCommand(const char* args); bool HandleNpcSetMoveTypeCommand(const char* args); bool HandleNpcSetPhaseCommand(const char* args); @@ -197,7 +202,12 @@ class ChatHandler bool HandleNpcUnFollowCommand(const char* args); bool HandleNpcWhisperCommand(const char* args); bool HandleNpcYellCommand(const char* args); - bool HandleNpcSetDeathStateCommand(const char* args); + + //TODO: NpcCommands that needs to be fixed : + bool HandleNpcAddWeaponCommand(const char* args); + bool HandleNpcNameCommand(const char* args); + bool HandleNpcSubNameCommand(const char* args); + //---------------------------------------------------------- bool HandleReloadAllCommand(const char* args); bool HandleReloadAllAreaCommand(const char* args); @@ -300,13 +310,8 @@ class ChatHandler bool HandleDebugSpellFailCommand(const char* args); bool HandleGUIDCommand(const char* args); - bool HandleNameCommand(const char* args); - bool HandleSubNameCommand(const char* args); bool HandleItemMoveCommand(const char* args); bool HandleDeMorphCommand(const char* args); - bool HandleAddVendorItemCommand(const char* args); - bool HandleDelVendorItemCommand(const char* args); - bool HandleChangeLevelCommand(const char* args); bool HandleSetPoiCommand(const char* args); bool HandleEquipErrorCommand(const char* args); bool HandleGoCreatureCommand(const char* args); @@ -341,7 +346,6 @@ class ChatHandler bool HandleGoXYZCommand(const char* args); bool HandleGoZoneXYCommand(const char* args); bool HandleGoGridCommand(const char* args); - bool HandleAddWeaponCommand(const char* args); bool HandleAllowMovementCommand(const char* args); bool HandleGoCommand(const char* args); diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index ea5061001..1bde9d37d 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -28,7 +28,6 @@ #include "ChannelMgr.h" #include "Group.h" #include "Guild.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "ScriptCalls.h" #include "Player.h" @@ -522,44 +521,42 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) } EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote); - if (em) + if (!em) + return; + + GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); + + uint32 emote_anim = em->textid; + + WorldPacket data; + + switch(emote_anim) { - uint32 emote_anim = em->textid; - - WorldPacket data; - - switch(emote_anim) - { - case EMOTE_STATE_SLEEP: - case EMOTE_STATE_SIT: - case EMOTE_STATE_KNEEL: - case EMOTE_ONESHOT_NONE: - break; - default: - GetPlayer()->HandleEmoteCommand(emote_anim); - break; - } - - data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); - data << GetPlayer()->GetGUID(); - data << (uint32)text_emote; - data << emoteNum; - data << (uint32)namlen; - if( namlen > 1 ) - { - data.append(nam, namlen); - } - else - { - data << (uint8)0x00; - } - - GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true); - - //Send scripted event call - if (pCreature && Script) - Script->ReceiveEmote(GetPlayer(),pCreature,text_emote); + case EMOTE_STATE_SLEEP: + case EMOTE_STATE_SIT: + case EMOTE_STATE_KNEEL: + case EMOTE_ONESHOT_NONE: + break; + default: + GetPlayer()->HandleEmoteCommand(emote_anim); + break; } + + data.Initialize(SMSG_TEXT_EMOTE, (20+namlen)); + data << GetPlayer()->GetGUID(); + data << (uint32)text_emote; + data << emoteNum; + data << (uint32)namlen; + if( namlen > 1 ) + data.append(nam, namlen); + else + data << (uint8)0x00; + + GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true); + + //Send scripted event call + if (pCreature && Script) + Script->ReceiveEmote(GetPlayer(),pCreature,text_emote); } void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data ) diff --git a/src/game/CombatHandler.cpp b/src/game/CombatHandler.cpp index 86605c397..12fedd89a 100644 --- a/src/game/CombatHandler.cpp +++ b/src/game/CombatHandler.cpp @@ -20,7 +20,6 @@ #include "Log.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "World.h" #include "ObjectAccessor.h" #include "CreatureAI.h" #include "ObjectDefines.h" diff --git a/src/game/Corpse.cpp b/src/game/Corpse.cpp index 780eb8c96..9fa295cbb 100644 --- a/src/game/Corpse.cpp +++ b/src/game/Corpse.cpp @@ -20,12 +20,9 @@ #include "Corpse.h" #include "Player.h" #include "UpdateMask.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "Database/DatabaseEnv.h" #include "Opcodes.h" -#include "WorldSession.h" -#include "WorldPacket.h" #include "GossipDef.h" #include "World.h" diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index bfdd2d58a..2d9a48981 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -19,7 +19,6 @@ #include "Common.h" #include "Database/DatabaseEnv.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" @@ -35,7 +34,6 @@ #include "CreatureAI.h" #include "CreatureAISelector.h" #include "Formulas.h" -#include "SpellAuras.h" #include "WaypointMovementGenerator.h" #include "InstanceData.h" #include "BattleGroundMgr.h" @@ -1564,7 +1562,7 @@ SpellEntry const *Creature::reachWithSpellAttack(Unit *pVictim) SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); if(!spellInfo) { - sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); + sLog.outError("WORLD: unknown spell id %i", m_spells[i]); continue; } @@ -1614,7 +1612,7 @@ SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim) SpellEntry const *spellInfo = sSpellStore.LookupEntry(m_spells[i] ); if(!spellInfo) { - sLog.outError("WORLD: unknown spell id %i\n", m_spells[i]); + sLog.outError("WORLD: unknown spell id %i", m_spells[i]); continue; } @@ -2117,4 +2115,4 @@ void Creature::SetActiveObjectState( bool on ) if(world) map->Add(this); -} \ No newline at end of file +} diff --git a/src/game/CreatureAIRegistry.cpp b/src/game/CreatureAIRegistry.cpp index 7790ff992..83fd1cbe4 100644 --- a/src/game/CreatureAIRegistry.cpp +++ b/src/game/CreatureAIRegistry.cpp @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "CreatureAIRegistry.h" #include "NullCreatureAI.h" #include "ReactorAI.h" #include "AggressorAI.h" @@ -26,7 +25,6 @@ #include "RandomMovementGenerator.h" #include "CreatureAIImpl.h" #include "MovementGeneratorImpl.h" -#include "MapManager.h" #include "CreatureAIRegistry.h" #include "WaypointMovementGenerator.h" diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h index d91eb8bcd..0db69fdde 100644 --- a/src/game/DestinationHolderImp.h +++ b/src/game/DestinationHolderImp.h @@ -19,7 +19,6 @@ #ifndef MANGOS_DESTINATIONHOLDERIMP_H #define MANGOS_DESTINATIONHOLDERIMP_H -#include "Creature.h" #include "MapManager.h" #include "DestinationHolder.h" diff --git a/src/game/DuelHandler.cpp b/src/game/DuelHandler.cpp index a355931e5..e9e1fa0b6 100644 --- a/src/game/DuelHandler.cpp +++ b/src/game/DuelHandler.cpp @@ -19,11 +19,9 @@ #include "Common.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "World.h" #include "Log.h" #include "Opcodes.h" #include "UpdateData.h" -#include "MapManager.h" #include "Player.h" void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket) diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index a8589d91a..66210cc53 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -17,16 +17,11 @@ */ #include "Common.h" -#include "GameObject.h" #include "UpdateMask.h" #include "Opcodes.h" -#include "WorldPacket.h" -#include "WorldSession.h" #include "World.h" #include "ObjectAccessor.h" #include "Database/DatabaseEnv.h" -#include "SpellAuras.h" -#include "MapManager.h" #include "GridNotifiers.h" #include "CellImpl.h" #include "GridNotifiersImpl.h" diff --git a/src/game/FleeingMovementGenerator.h b/src/game/FleeingMovementGenerator.h index ec3d3f91a..045f02498 100644 --- a/src/game/FleeingMovementGenerator.h +++ b/src/game/FleeingMovementGenerator.h @@ -22,7 +22,6 @@ #include "MovementGenerator.h" #include "DestinationHolder.h" #include "Traveller.h" -#include "MapManager.h" template class MANGOS_DLL_SPEC FleeingMovementGenerator diff --git a/src/game/GMTicketHandler.cpp b/src/game/GMTicketHandler.cpp index c33968221..3a1aefdfd 100644 --- a/src/game/GMTicketHandler.cpp +++ b/src/game/GMTicketHandler.cpp @@ -119,7 +119,7 @@ void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data ) data.Initialize( SMSG_GMTICKET_CREATE, 4 ); data << uint32(2); SendPacket( &data ); - DEBUG_LOG("update the ticket\n"); + DEBUG_LOG("update the ticket"); //TODO: Guard player map HashMapHolder::MapType &m = ObjectAccessor::Instance().GetPlayers(); diff --git a/src/game/GameEvent.cpp b/src/game/GameEventMgr.cpp similarity index 89% rename from src/game/GameEvent.cpp rename to src/game/GameEventMgr.cpp index 2504f454f..e2b7386a8 100644 --- a/src/game/GameEvent.cpp +++ b/src/game/GameEventMgr.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "GameEvent.h" +#include "GameEventMgr.h" #include "World.h" #include "ObjectMgr.h" #include "PoolHandler.h" @@ -26,9 +26,9 @@ #include "MapManager.h" #include "Policies/SingletonImp.h" -INSTANTIATE_SINGLETON_1(GameEvent); +INSTANTIATE_SINGLETON_1(GameEventMgr); -bool GameEvent::CheckOneGameEvent(uint16 entry) const +bool GameEventMgr::CheckOneGameEvent(uint16 entry) const { // Get the event information time_t currenttime = time(NULL); @@ -39,7 +39,7 @@ bool GameEvent::CheckOneGameEvent(uint16 entry) const return false; } -uint32 GameEvent::NextCheck(uint16 entry) const +uint32 GameEventMgr::NextCheck(uint16 entry) const { time_t currenttime = time(NULL); @@ -65,7 +65,7 @@ uint32 GameEvent::NextCheck(uint16 entry) const return delay; } -void GameEvent::StartEvent( uint16 event_id, bool overwrite ) +void GameEventMgr::StartEvent( uint16 event_id, bool overwrite ) { AddActiveEvent(event_id); ApplyNewEvent(event_id); @@ -77,7 +77,7 @@ void GameEvent::StartEvent( uint16 event_id, bool overwrite ) } } -void GameEvent::StopEvent( uint16 event_id, bool overwrite ) +void GameEventMgr::StopEvent( uint16 event_id, bool overwrite ) { RemoveActiveEvent(event_id); UnApplyEvent(event_id); @@ -89,7 +89,7 @@ void GameEvent::StopEvent( uint16 event_id, bool overwrite ) } } -void GameEvent::LoadFromDB() +void GameEventMgr::LoadFromDB() { { QueryResult *result = WorldDatabase.Query("SELECT MAX(entry) FROM game_event"); @@ -108,7 +108,7 @@ void GameEvent::LoadFromDB() mGameEvent.resize(max_event_id+1); } - QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,description FROM game_event"); + QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,holiday,description FROM game_event"); if( !result ) { mGameEvent.clear(); @@ -142,6 +142,8 @@ void GameEvent::LoadFromDB() pGameEvent.end = time_t(endtime); pGameEvent.occurence = fields[3].GetUInt32(); pGameEvent.length = fields[4].GetUInt32(); + pGameEvent.holiday_id = fields[5].GetUInt32(); + if(pGameEvent.length==0) // length>0 is validity check { @@ -149,7 +151,16 @@ void GameEvent::LoadFromDB() continue; } - pGameEvent.description = fields[5].GetCppString(); + if(pGameEvent.holiday_id) + { + if(!sHolidaysStore.LookupEntry(pGameEvent.holiday_id)) + { + sLog.outErrorDb("`game_event` game event id (%i) have not existed holiday id %u.",event_id,pGameEvent.holiday_id); + pGameEvent.holiday_id = 0; + } + } + + pGameEvent.description = fields[6].GetCppString(); } while( result->NextRow() ); delete result; @@ -405,7 +416,7 @@ void GameEvent::LoadFromDB() } } -uint32 GameEvent::Initialize() // return the next event delay in ms +uint32 GameEventMgr::Initialize() // return the next event delay in ms { m_ActiveEvents.clear(); uint32 delay = Update(); @@ -414,7 +425,7 @@ uint32 GameEvent::Initialize() // return the next e return delay; } -uint32 GameEvent::Update() // return the next event delay in ms +uint32 GameEventMgr::Update() // return the next event delay in ms { uint32 nextEventDelay = max_ge_check_delay; // 1 day uint32 calcDelay; @@ -450,7 +461,7 @@ uint32 GameEvent::Update() // return the next e return (nextEventDelay + 1) * IN_MILISECONDS; // Add 1 second to be sure event has started/stopped at next call } -void GameEvent::UnApplyEvent(uint16 event_id) +void GameEventMgr::UnApplyEvent(uint16 event_id) { sLog.outString("GameEvent %u \"%s\" removed.", event_id, mGameEvent[event_id].description.c_str()); // un-spawn positive event tagged objects @@ -464,7 +475,7 @@ void GameEvent::UnApplyEvent(uint16 event_id) UpdateEventQuests(event_id, false); } -void GameEvent::ApplyNewEvent(uint16 event_id) +void GameEventMgr::ApplyNewEvent(uint16 event_id) { switch(sWorld.getConfig(CONFIG_EVENT_ANNOUNCE)) { @@ -487,13 +498,13 @@ void GameEvent::ApplyNewEvent(uint16 event_id) UpdateEventQuests(event_id, true); } -void GameEvent::GameEventSpawn(int16 event_id) +void GameEventMgr::GameEventSpawn(int16 event_id) { int32 internal_event_id = mGameEvent.size() + event_id - 1; if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size()) { - sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size()); + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size()); return; } @@ -526,7 +537,7 @@ void GameEvent::GameEventSpawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size()) { - sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size()); + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size()); return; } @@ -560,7 +571,7 @@ void GameEvent::GameEventSpawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size()) { - sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size()); + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size()); return; } @@ -570,13 +581,13 @@ void GameEvent::GameEventSpawn(int16 event_id) } } -void GameEvent::GameEventUnspawn(int16 event_id) +void GameEventMgr::GameEventUnspawn(int16 event_id) { int32 internal_event_id = mGameEvent.size() + event_id - 1; if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size()) { - sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size()); + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size()); return; } @@ -597,7 +608,7 @@ void GameEvent::GameEventUnspawn(int16 event_id) if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size()) { - sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size()); + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size()); return; } @@ -614,7 +625,7 @@ void GameEvent::GameEventUnspawn(int16 event_id) } if(internal_event_id < 0 || internal_event_id >= mGameEventPoolIds.size()) { - sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size()); + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: %u)",internal_event_id,mGameEventPoolIds.size()); return; } @@ -624,7 +635,7 @@ void GameEvent::GameEventUnspawn(int16 event_id) } } -void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate) +void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate) { for(ModelEquipList::iterator itr = mGameEventModelEquip[event_id].begin();itr != mGameEventModelEquip[event_id].end();++itr) { @@ -703,7 +714,7 @@ void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate) } } -void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate) +void GameEventMgr::UpdateEventQuests(uint16 event_id, bool Activate) { QuestRelList::iterator itr; for (itr = mGameEventQuests[event_id].begin();itr != mGameEventQuests[event_id].end();++itr) @@ -729,7 +740,19 @@ void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate) } } -GameEvent::GameEvent() +GameEventMgr::GameEventMgr() { isSystemInit = false; } + +MANGOS_DLL_SPEC bool IsHolidayActive( HolidayIds id ) +{ + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::ActiveEvents const& ae = gameeventmgr.GetActiveEventList(); + + for(GameEventMgr::ActiveEvents::const_iterator itr = ae.begin(); itr != ae.end(); ++itr) + if(events[id].holiday_id==id) + return true; + + return false; +} \ No newline at end of file diff --git a/src/game/GameEvent.h b/src/game/GameEventMgr.h similarity index 90% rename from src/game/GameEvent.h rename to src/game/GameEventMgr.h index e1752a952..2710c987c 100644 --- a/src/game/GameEvent.h +++ b/src/game/GameEventMgr.h @@ -16,15 +16,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef MANGOS_GAMEEVENT_H -#define MANGOS_GAMEEVENT_H +#ifndef MANGOS_GAMEEVENT_MGR_H +#define MANGOS_GAMEEVENT_MGR_H +#include "Common.h" +#include "SharedDefines.h" #include "Platform/Define.h" -#include "Creature.h" -#include "GameObject.h" #define max_ge_check_delay 86400 // 1 day in seconds +class Creature; +class GameObject; + struct GameEventData { GameEventData() : start(1),end(0),occurence(0),length(0) {} @@ -32,6 +35,7 @@ struct GameEventData time_t end; uint32 occurence; uint32 length; + uint32 holiday_id; std::string description; bool isValid() const { return length > 0; } @@ -45,11 +49,11 @@ struct ModelEquip uint32 equipement_id_prev; }; -class GameEvent +class GameEventMgr { public: - GameEvent(); - ~GameEvent() {}; + GameEventMgr(); + ~GameEventMgr() {}; typedef std::set ActiveEvents; typedef std::vector GameEventDataMap; ActiveEvents const& GetActiveEventList() const { return m_ActiveEvents; } @@ -92,5 +96,8 @@ class GameEvent bool isSystemInit; }; -#define gameeventmgr MaNGOS::Singleton::Instance() +#define gameeventmgr MaNGOS::Singleton::Instance() + +MANGOS_DLL_SPEC bool IsHolidayActive(HolidayIds id); + #endif diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index a63de107d..f38503e30 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -26,10 +26,8 @@ #include "UpdateMask.h" #include "Opcodes.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "World.h" #include "Database/DatabaseEnv.h" -#include "MapManager.h" #include "LootMgr.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -472,14 +470,15 @@ void GameObject::getFishLoot(Loot *fishloot, Player* loot_owner) { fishloot->clear(); - uint32 subzone = GetAreaId(); + uint32 zone, subzone; + GetZoneAndAreaId(zone,subzone); // if subzone loot exist use it if(LootTemplates_Fishing.HaveLootFor(subzone)) fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner,true); // else use zone loot else - fishloot->FillLoot(GetZoneId(), LootTemplates_Fishing, loot_owner,true); + fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner,true); } void GameObject::SaveToDB() @@ -1000,11 +999,12 @@ void GameObject::Use(Unit* user) // 2) if skill == base_zone_skill => 5% chance // 3) chance is linear dependence from (base_zone_skill-skill) - uint32 subzone = GetAreaId(); + uint32 zone, subzone; + GetZoneAndAreaId(zone,subzone); int32 zone_skill = objmgr.GetFishingBaseSkillLevel( subzone ); if(!zone_skill) - zone_skill = objmgr.GetFishingBaseSkillLevel( GetZoneId() ); + zone_skill = objmgr.GetFishingBaseSkillLevel( zone ); //provide error, no fishable zone or area should be 0 if(!zone_skill) @@ -1174,7 +1174,7 @@ void GameObject::Use(Unit* user) Player* player = (Player*)user; - if( player->isAllowUseBattleGroundObject() ) + if( player->CanUseBattleGroundObject() ) { // in battleground check BattleGround *bg = player->GetBattleGround(); @@ -1199,7 +1199,7 @@ void GameObject::Use(Unit* user) Player* player = (Player*)user; - if( player->isAllowUseBattleGroundObject() ) + if( player->CanUseBattleGroundObject() ) { // in battleground check BattleGround *bg = player->GetBattleGround(); diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp index 8f49150d3..b1acc2b61 100644 --- a/src/game/GridNotifiers.cpp +++ b/src/game/GridNotifiers.cpp @@ -22,7 +22,6 @@ #include "UpdateData.h" #include "Item.h" #include "Map.h" -#include "MapManager.h" #include "Transports.h" #include "ObjectAccessor.h" diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index 9c893fd60..6ad2a4703 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -862,6 +862,27 @@ namespace MaNGOS std::vector i_data_cache; // 0 = default, i => i-1 locale index }; + // Prepare using Builder localized packets with caching and send to player + template + class LocalizedPacketListDo + { + public: + typedef std::vector WorldPacketList; + explicit LocalizedPacketListDo(Builder& builder) : i_builder(builder) {} + + ~LocalizedPacketListDo() + { + for(size_t i = 0; i < i_data_cache.size(); ++i) + for(int j = 0; j < i_data_cache[i].size(); ++j) + delete i_data_cache[i][j]; + } + void operator()( Player* p ); + + private: + Builder& i_builder; + std::vector i_data_cache; + // 0 = default, i => i-1 locale index + }; #ifndef WIN32 template<> void PlayerRelocationNotifier::Visit(CreatureMapType &); diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h index 6903fa23d..75d1ef9c9 100644 --- a/src/game/GridNotifiersImpl.h +++ b/src/game/GridNotifiersImpl.h @@ -562,4 +562,28 @@ void MaNGOS::LocalizedPacketDo::operator()( Player* p ) p->SendDirectMessage(data); } +template +void MaNGOS::LocalizedPacketListDo::operator()( Player* p ) +{ + uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex(); + uint32 cache_idx = loc_idx+1; + WorldPacketList* data_list; + + // create if not cached yet + if(i_data_cache.size() < cache_idx+1 || i_data_cache[cache_idx].empty()) + { + if(i_data_cache.size() < cache_idx+1) + i_data_cache.resize(cache_idx+1); + + data_list = &i_data_cache[cache_idx]; + + i_builder(*data_list,loc_idx); + } + else + data_list = &i_data_cache[cache_idx]; + + for(size_t i = 0; i < data_list->size(); ++i) + p->SendDirectMessage((*data_list)[i]); +} + #endif // MANGOS_GRIDNOTIFIERSIMPL_H diff --git a/src/game/GridStates.cpp b/src/game/GridStates.cpp index 4743860f5..289be47a1 100644 --- a/src/game/GridStates.cpp +++ b/src/game/GridStates.cpp @@ -18,7 +18,6 @@ #include "GridStates.h" #include "GridNotifiers.h" -#include "ObjectAccessor.h" #include "GameSystem/Grid.h" #include "Log.h" diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index 9ec47103e..44fa9c290 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -26,8 +26,6 @@ #include "ObjectMgr.h" #include "Player.h" #include "Group.h" -#include "ObjectAccessor.h" -#include "MapManager.h" #include "SocialMgr.h" #include "Util.h" @@ -215,26 +213,16 @@ void WorldSession::HandleGroupDeclineOpcode( WorldPacket & /*recv_data*/ ) Group *group = GetPlayer()->GetGroupInvite(); if (!group) return; + // remember leader if online Player *leader = objmgr.GetPlayer(group->GetLeaderGUID()); - /** error handling **/ + // uninvite, group can be deleted + GetPlayer()->UninviteFromGroup(); + if(!leader || !leader->GetSession()) return; - /********************/ - - // everything's fine, do it - if(!group->IsCreated()) - { - // note: this means that if you invite more than one person - // and one of them declines before the first one accepts - // all invites will be cleared - // fixme: is that ok ? - group->RemoveAllInvites(); - delete group; - } - - GetPlayer()->SetGroupInvite(NULL); + // report WorldPacket data( SMSG_GROUP_DECLINE, 10 ); // guess size data << GetPlayer()->GetName(); leader->GetSession()->SendPacket( &data ); diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp index 4ff5471e0..a13fc049d 100644 --- a/src/game/Guild.cpp +++ b/src/game/Guild.cpp @@ -19,7 +19,6 @@ #include "Database/DatabaseEnv.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "MapManager.h" #include "Player.h" #include "Opcodes.h" #include "ObjectMgr.h" @@ -27,6 +26,7 @@ #include "Chat.h" #include "SocialMgr.h" #include "Util.h" +#include "Language.h" Guild::Guild() { @@ -50,27 +50,25 @@ Guild::~Guild() } -bool Guild::create(uint64 lGuid, std::string gname) +bool Guild::create(Player* leader, std::string gname) { - std::string rname; - std::string lName; - - if(!objmgr.GetPlayerNameByGUID(lGuid, lName)) - return false; if(objmgr.GetGuildByName(gname)) return false; - sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(lGuid)); + WorldSession* lSession = leader->GetSession(); + if(!lSession) + return false; - leaderGuid = lGuid; + leaderGuid = leader->GetGUID(); name = gname; GINFO = ""; MOTD = "No message set."; guildbank_money = 0; purchased_tabs = 0; - Id = objmgr.GenerateGuildId(); + sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(leaderGuid)); + // gname already assigned to Guild::name, use it to encode string for DB CharacterDatabase.escape_string(gname); @@ -88,18 +86,13 @@ bool Guild::create(uint64 lGuid, std::string gname) Id, gname.c_str(), GUID_LOPART(leaderGuid), dbGINFO.c_str(), dbMOTD.c_str(), EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, guildbank_money); CharacterDatabase.CommitTransaction(); - rname = "Guild Master"; - CreateRank(rname,GR_RIGHT_ALL); - rname = "Officer"; - CreateRank(rname,GR_RIGHT_ALL); - rname = "Veteran"; - CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - rname = "Member"; - CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - rname = "Initiate"; - CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + CreateRank(lSession->GetMangosString(LANG_GUILD_MASTER), GR_RIGHT_ALL); + CreateRank(lSession->GetMangosString(LANG_GUILD_OFFICER), GR_RIGHT_ALL); + CreateRank(lSession->GetMangosString(LANG_GUILD_VETERAN), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + CreateRank(lSession->GetMangosString(LANG_GUILD_MEMBER), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + CreateRank(lSession->GetMangosString(LANG_GUILD_INITIATE),GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - return AddMember(lGuid, (uint32)GR_GUILDMASTER); + return AddMember(leaderGuid, (uint32)GR_GUILDMASTER); } bool Guild::AddMember(uint64 plGuid, uint32 plRank) diff --git a/src/game/Guild.h b/src/game/Guild.h index ec764bef6..8890baf44 100644 --- a/src/game/Guild.h +++ b/src/game/Guild.h @@ -267,7 +267,7 @@ class Guild Guild(); ~Guild(); - bool create(uint64 lGuid, std::string gname); + bool create(Player* leader, std::string gname); void Disband(); typedef std::map MemberList; diff --git a/src/game/GuildHandler.cpp b/src/game/GuildHandler.cpp index 7a2e17cca..f9bde8849 100644 --- a/src/game/GuildHandler.cpp +++ b/src/game/GuildHandler.cpp @@ -24,7 +24,6 @@ #include "Log.h" #include "Opcodes.h" #include "Guild.h" -#include "MapManager.h" #include "GossipDef.h" #include "SocialMgr.h" @@ -63,7 +62,7 @@ void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) return; Guild *guild = new Guild; - if(!guild->create(GetPlayer()->GetGUID(),gname)) + if(!guild->create(GetPlayer(),gname)) { delete guild; return; diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp index 2c9ae048f..a0c090989 100644 --- a/src/game/HomeMovementGenerator.cpp +++ b/src/game/HomeMovementGenerator.cpp @@ -20,8 +20,6 @@ #include "Creature.h" #include "CreatureAI.h" #include "Traveller.h" -#include "MapManager.h" -#include "ObjectAccessor.h" #include "DestinationHolderImp.h" #include "ObjectMgr.h" #include "WorldPacket.h" diff --git a/src/game/IdleMovementGenerator.cpp b/src/game/IdleMovementGenerator.cpp index 370099ebd..085ab46e7 100644 --- a/src/game/IdleMovementGenerator.cpp +++ b/src/game/IdleMovementGenerator.cpp @@ -17,7 +17,7 @@ */ #include "IdleMovementGenerator.h" -#include "Creature.h" +#include "Unit.h" IdleMovementGenerator si_idleMovement; diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index 6c51b2024..200068aa1 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -16,13 +16,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "InstanceSaveMgr.h" #include "Common.h" #include "Database/SQLStorage.h" #include "Player.h" #include "GridNotifiers.h" -#include "WorldSession.h" #include "Log.h" #include "GridStates.h" #include "CellImpl.h" @@ -34,7 +32,6 @@ #include "GridNotifiersImpl.h" #include "Config/ConfigEnv.h" #include "Transports.h" -#include "ObjectAccessor.h" #include "ObjectMgr.h" #include "World.h" #include "Group.h" diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index 33b94943c..fedbf8da0 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -19,7 +19,6 @@ #include "Common.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "World.h" #include "Opcodes.h" #include "Log.h" #include "ObjectMgr.h" diff --git a/src/game/Language.h b/src/game/Language.h index c0e3bbd32..c25d1e6f4 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -170,7 +170,8 @@ enum MangosStrings LANG_CONSOLE_COMMAND = 172, LANG_YOU_CHANGE_RUNIC_POWER = 173, LANG_YOURS_RUNIC_POWER_CHANGED = 174, - // Room for more level 1 175-199 not used + LANG_LIQUID_STATUS = 175, + // Room for more level 1 176-199 not used // level 2 chat LANG_NO_SELECTION = 200, @@ -569,9 +570,11 @@ enum MangosStrings // Battleground LANG_BG_A_WINS = 600, LANG_BG_H_WINS = 601, - LANG_BG_WS_ONE_MINUTE = 602, - LANG_BG_WS_HALF_MINUTE = 603, - LANG_BG_WS_BEGIN = 604, + + LANG_BG_WS_START_TWO_MINUTES = 753, + LANG_BG_WS_START_ONE_MINUTE = 602, + LANG_BG_WS_START_HALF_MINUTE = 603, + LANG_BG_WS_HAS_BEGUN = 604, LANG_BG_WS_CAPTURED_HF = 605, LANG_BG_WS_CAPTURED_AF = 606, @@ -585,9 +588,10 @@ enum MangosStrings LANG_BG_WS_ALLIANCE_FLAG_RESPAWNED = 614, LANG_BG_WS_HORDE_FLAG_RESPAWNED = 615, - LANG_BG_EY_ONE_MINUTE = 636, - LANG_BG_EY_HALF_MINUTE = 637, - LANG_BG_EY_BEGIN = 638, + LANG_BG_EY_START_TWO_MINUTES = 755, + LANG_BG_EY_START_ONE_MINUTE = 636, + LANG_BG_EY_START_HALF_MINUTE = 637, + LANG_BG_EY_HAS_BEGUN = 638, LANG_BG_AB_ALLY = 650, LANG_BG_AB_HORDE = 651, @@ -600,9 +604,11 @@ enum MangosStrings LANG_BG_AB_NODE_DEFENDED = 658, LANG_BG_AB_NODE_ASSAULTED = 659, LANG_BG_AB_NODE_CLAIMED = 660, - LANG_BG_AB_ONEMINTOSTART = 661, - LANG_BG_AB_HALFMINTOSTART = 662, - LANG_BG_AB_STARTED = 663, + + LANG_BG_AB_START_TWO_MINUTES = 754, + LANG_BG_AB_START_ONE_MINUTE = 661, + LANG_BG_AB_START_HALF_MINUTE = 662, + LANG_BG_AB_HAS_BEGUN = 663, LANG_BG_AB_A_NEAR_VICTORY = 664, LANG_BG_AB_H_NEAR_VICTORY = 665, LANG_BG_MARK_BY_MAIL = 666, @@ -633,7 +639,7 @@ enum MangosStrings LANG_ARENA_ONE_MINUTE = 701, LANG_ARENA_THIRTY_SECONDS = 702, LANG_ARENA_FIFTEEN_SECONDS = 703, - LANG_ARENA_BEGUN = 704, + LANG_ARENA_HAS_BEGUN = 704, LANG_WAIT_BEFORE_SPEAKING = 705, LANG_NOT_EQUIPPED_ITEM = 706, @@ -658,7 +664,7 @@ enum MangosStrings LANG_ARENA_NOT_ENOUGH_PLAYERS = 723, // "Your group does not have enough players to join this match." LANG_ARENA_GOLD_WINS = 724, // "The Gold Team wins!" LANG_ARENA_GREEN_WINS = 725, // "The Green Team wins!" - LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 726, // The battleground will end soon, because there aren't enough players. Get more ppl or win already! +// = 726, not used LANG_BG_GROUP_OFFLINE_MEMBER = 727, // "Your group has an offline member. Please remove him before joining." LANG_BG_GROUP_MIXED_FACTION = 728, // "Your group has players from the opposing faction. You can't join the battleground as a group." LANG_BG_GROUP_MIXED_LEVELS = 729, // "Your group has players from different battleground brakets. You can't join as group." @@ -680,7 +686,16 @@ enum MangosStrings LANG_DIST_ARENA_POINTS_TEAM_START = 744, LANG_DIST_ARENA_POINTS_TEAM_END = 745, LANG_DIST_ARENA_POINTS_END = 746, - // Room for batleground/arena strings 747-799 not used +// = 747, not used +// = 748, not used +// = 749, not used + LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 750, // "Not enough players. This game will close in %u mins." + LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS = 751, // "Not enough players. This game will close in %u seconds." +// = 752, not used +// LANG_BG_WS_START_TWO_MINUTES = 753, +// LANG_BG_AB_START_TWO_MINUTES = 754, +// LANG_BG_EY_START_TWO_MINUTES = 755, + // Room for batleground/arena strings 756-799 not used // in game strings // = 800, not used @@ -694,7 +709,12 @@ enum MangosStrings LANG_PLAYER_NOT_EXIST_OR_OFFLINE = 808, LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND = 809, LANG_ACHIEVEMENT_EARNED = 810, - // Room for in-game strings 811-999 not used + LANG_GUILD_MASTER = 811, + LANG_GUILD_OFFICER = 812, + LANG_GUILD_VETERAN = 813, + LANG_GUILD_MEMBER = 814, + LANG_GUILD_INITIATE = 815, + // Room for in-game strings 816-999 not used // Level 4 (CLI only commands) LANG_COMMAND_EXIT = 1000, diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp index 15e0747e7..8cea1ee30 100644 --- a/src/game/Level0.cpp +++ b/src/game/Level0.cpp @@ -18,13 +18,10 @@ #include "Common.h" #include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" #include "World.h" #include "Player.h" #include "Opcodes.h" #include "Chat.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "Language.h" #include "AccountMgr.h" diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 4fd4e4a86..fd97a033a 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -36,6 +36,7 @@ #include "VMapFactory.h" #endif +//-----------------------Npc Commands----------------------- bool ChatHandler::HandleNpcSayCommand(const char* args) { if(!*args) @@ -119,6 +120,7 @@ bool ChatHandler::HandleNpcWhisperCommand(const char* args) return true; } +//---------------------------------------------------------- // global announce bool ChatHandler::HandleAnnounceCommand(const char* args) @@ -282,8 +284,8 @@ bool ChatHandler::HandleGPSCommand(const char* args) CellPair cell_val = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); Cell cell(cell_val); - uint32 zone_id = obj->GetZoneId(); - uint32 area_id = obj->GetAreaId(); + uint32 zone_id, area_id; + obj->GetZoneAndAreaId(zone_id,area_id); MapEntry const* mapEntry = sMapStore.LookupEntry(obj->GetMapId()); AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zone_id); @@ -329,6 +331,12 @@ bool ChatHandler::HandleGPSCommand(const char* args) cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), obj->GetInstanceId(), zone_x, zone_y, ground_z, floor_z, have_map, have_vmap ); + LiquidData liquid_status; + ZLiquidStatus res = map->getLiquidStatus(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), MAP_ALL_LIQUIDS, &liquid_status); + if (res) + { + PSendSysMessage(LANG_LIQUID_STATUS, liquid_status.level, liquid_status.depth_level, liquid_status.type, res); + } return true; } diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 7edc4db75..2654ecb15 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -18,9 +18,6 @@ #include "Common.h" #include "Database/DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" #include "ObjectMgr.h" #include "Player.h" #include "Item.h" @@ -31,7 +28,7 @@ #include "MapManager.h" #include "Language.h" #include "World.h" -#include "GameEvent.h" +#include "GameEventMgr.h" #include "SpellMgr.h" #include "PoolHandler.h" #include "AccountMgr.h" @@ -162,7 +159,7 @@ bool ChatHandler::HandleTargetObjectCommand(const char* args) { Player* pl = m_session->GetPlayer(); QueryResult *result; - GameEvent::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList(); + GameEventMgr::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList(); if(*args) { int32 id = atoi((char*)args); @@ -185,7 +182,7 @@ bool ChatHandler::HandleTargetObjectCommand(const char* args) eventFilter << " AND (event IS NULL "; bool initString = true; - for (GameEvent::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) + for (GameEventMgr::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr) { if (initString) { @@ -734,134 +731,7 @@ bool ChatHandler::HandleModifyRepCommand(const char * args) return true; } -bool ChatHandler::HandleNameCommand(const char* /*args*/) -{ - /* Temp. disabled - if(!*args) - return false; - - if(strlen((char*)args)>75) - { - PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75); - return true; - } - - for (uint8 i = 0; i < strlen(args); i++) - { - if(!isalpha(args[i]) && args[i]!=' ') - { - SendSysMessage(LANG_CHARS_ONLY); - return false; - } - } - - uint64 guid; - guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - pCreature->SetName(args); - uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName()); - pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); - - pCreature->SaveToDB(); - */ - - return true; -} - -bool ChatHandler::HandleSubNameCommand(const char* /*args*/) -{ - /* Temp. disabled - - if(!*args) - args = ""; - - if(strlen((char*)args)>75) - { - - PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75); - return true; - } - - for (uint8 i = 0; i < strlen(args); i++) - { - if(!isalpha(args[i]) && args[i]!=' ') - { - SendSysMessage(LANG_CHARS_ONLY); - return false; - } - } - uint64 guid; - guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID)); - pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); - - pCreature->SaveToDB(); - */ - return true; -} - -//move item to other slot -bool ChatHandler::HandleItemMoveCommand(const char* args) -{ - if(!*args) - return false; - uint8 srcslot, dstslot; - - char* pParam1 = strtok((char*)args, " "); - if (!pParam1) - return false; - - char* pParam2 = strtok(NULL, " "); - if (!pParam2) - return false; - - srcslot = (uint8)atoi(pParam1); - dstslot = (uint8)atoi(pParam2); - - if(srcslot==dstslot) - return true; - - if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot)) - return false; - - if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot)) - return false; - - uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); - uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); - - m_session->GetPlayer()->SwapItem( src, dst ); - - return true; -} - +//-----------------------Npc Commands----------------------- //add spawn of creature bool ChatHandler::HandleNpcAddCommand(const char* args) { @@ -913,322 +783,8 @@ bool ChatHandler::HandleNpcAddCommand(const char* args) return true; } -bool ChatHandler::HandleNpcDeleteCommand(const char* args) -{ - Creature* unit = NULL; - - if(*args) - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid)) - unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT)); - } - else - unit = getSelectedCreature(); - - if(!unit || unit->isPet() || unit->isTotem() || unit->isVehicle()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // Delete the creature - unit->CombatStop(); - unit->DeleteFromDB(); - unit->CleanupsBeforeDelete(); - unit->AddObjectToRemoveList(); - - SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); - - return true; -} - -//delete object by selection or guid -bool ChatHandler::HandleDelObjectCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if(!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - uint64 owner_guid = obj->GetOwnerGUID(); - if(owner_guid) - { - Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid); - if(!owner && !IS_PLAYER_GUID(owner_guid)) - { - PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow()); - SetSentErrorMessage(true); - return false; - } - - owner->RemoveGameObject(obj,false); - } - - obj->SetRespawnTime(0); // not save respawn time - obj->Delete(); - obj->DeleteFromDB(); - - PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow()); - - return true; -} - -//turn selected object -bool ChatHandler::HandleTurnObjectCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if(!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* po = strtok(NULL, " "); - float o; - - if (po) - { - o = (float)atof(po); - } - else - { - Player *chr = m_session->GetPlayer(); - o = chr->GetOrientation(); - } - - float rot2 = sin(o/2); - float rot3 = cos(o/2); - - Map* map = obj->GetMap(); - map->Remove(obj,false); - - obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); - - obj->SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rot2); - obj->SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rot3); - - map->Add(obj); - - obj->SaveToDB(); - obj->Refresh(); - - PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o); - - return true; -} - -//move selected creature -bool ChatHandler::HandleNpcMoveCommand(const char* args) -{ - uint32 lowguid = 0; - - Creature* pCreature = getSelectedCreature(); - - if(!pCreature) - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hcreature"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - - /* FIXME: impossibel without entry - if(lowguid) - pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); - */ - - // Attempting creature load from DB data - if(!pCreature) - { - CreatureData const* data = objmgr.GetCreatureData(lowguid); - if(!data) - { - PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - uint32 map_id = data->mapid; - - if(m_session->GetPlayer()->GetMapId()!=map_id) - { - PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); - SetSentErrorMessage(true); - return false; - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - } - else - { - lowguid = pCreature->GetDBTableGUIDLow(); - } - - float x = m_session->GetPlayer()->GetPositionX(); - float y = m_session->GetPlayer()->GetPositionY(); - float z = m_session->GetPlayer()->GetPositionZ(); - float o = m_session->GetPlayer()->GetOrientation(); - - if (pCreature) - { - if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow())) - { - const_cast(data)->posX = x; - const_cast(data)->posY = y; - const_cast(data)->posZ = z; - const_cast(data)->orientation = o; - } - pCreature->GetMap()->CreatureRelocation(pCreature,x, y, z,o); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - } - - WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid); - PSendSysMessage(LANG_COMMAND_CREATUREMOVED); - return true; -} - -//move selected object -bool ChatHandler::HandleMoveObjectCommand(const char* args) -{ - // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r - char* cId = extractKeyFromLink((char*)args,"Hgameobject"); - if(!cId) - return false; - - uint32 lowguid = atoi(cId); - if(!lowguid) - return false; - - GameObject* obj = NULL; - - // by DB guid - if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) - obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); - - if(!obj) - { - PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); - SetSentErrorMessage(true); - return false; - } - - char* px = strtok(NULL, " "); - char* py = strtok(NULL, " "); - char* pz = strtok(NULL, " "); - - if (!px) - { - Player *chr = m_session->GetPlayer(); - - Map* map = obj->GetMap(); - map->Remove(obj,false); - - obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); - - map->Add(obj); - } - else - { - if(!py || !pz) - return false; - - float x = (float)atof(px); - float y = (float)atof(py); - float z = (float)atof(pz); - - if(!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); - SetSentErrorMessage(true); - return false; - } - - Map* map = obj->GetMap(); - map->Remove(obj,false); - - obj->Relocate(x, y, z, obj->GetOrientation()); - - map->Add(obj); - } - - obj->SaveToDB(); - obj->Refresh(); - - PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow()); - - return true; -} - -//demorph player or unit -bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) -{ - Unit *target = getSelectedUnit(); - if(!target) - target = m_session->GetPlayer(); - - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - target->DeMorph(); - - return true; -} - //add item in vendorlist -bool ChatHandler::HandleAddVendorItemCommand(const char* args) +bool ChatHandler::HandleNpcAddVendorItemCommand(const char* args) { if (!*args) return false; @@ -1275,7 +831,7 @@ bool ChatHandler::HandleAddVendorItemCommand(const char* args) } //del item from vendor list -bool ChatHandler::HandleDelVendorItemCommand(const char* args) +bool ChatHandler::HandleNpcDelVendorItemCommand(const char* args) { if (!*args) return false; @@ -1373,7 +929,188 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args) return true; } -/** +//change level of creature or pet +bool ChatHandler::HandleNpcChangeLevelCommand(const char* args) +{ + if (!*args) + return false; + + uint8 lvl = (uint8) atoi((char*)args); + if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if(pCreature->isPet()) + { + ((Pet*)pCreature)->GivePetLevel(lvl); + } + else + { + pCreature->SetMaxHealth( 100 + 30*lvl); + pCreature->SetHealth( 100 + 30*lvl); + pCreature->SetLevel( lvl); + pCreature->SaveToDB(); + } + + return true; +} + +//set npcflag of creature +bool ChatHandler::HandleNpcFlagCommand(const char* args) +{ + if (!*args) + return false; + + uint32 npcFlags = (uint32) atoi((char*)args); + + Creature* pCreature = getSelectedCreature(); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); + + WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); + + SendSysMessage(LANG_VALUE_SAVED_REJOIN); + + return true; +} + +bool ChatHandler::HandleNpcDeleteCommand(const char* args) +{ + Creature* unit = NULL; + + if(*args) + { + // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid)) + unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT)); + } + else + unit = getSelectedCreature(); + + if(!unit || unit->isPet() || unit->isTotem() || unit->isVehicle()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // Delete the creature + unit->CombatStop(); + unit->DeleteFromDB(); + unit->CleanupsBeforeDelete(); + unit->AddObjectToRemoveList(); + + SendSysMessage(LANG_COMMAND_DELCREATMESSAGE); + + return true; +} + +//move selected creature +bool ChatHandler::HandleNpcMoveCommand(const char* args) +{ + uint32 lowguid = 0; + + Creature* pCreature = getSelectedCreature(); + + if(!pCreature) + { + // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hcreature"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + + /* FIXME: impossibel without entry + if(lowguid) + pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT)); + */ + + // Attempting creature load from DB data + if(!pCreature) + { + CreatureData const* data = objmgr.GetCreatureData(lowguid); + if(!data) + { + PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + uint32 map_id = data->mapid; + + if(m_session->GetPlayer()->GetMapId()!=map_id) + { + PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid); + SetSentErrorMessage(true); + return false; + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + } + else + { + lowguid = pCreature->GetDBTableGUIDLow(); + } + + float x = m_session->GetPlayer()->GetPositionX(); + float y = m_session->GetPlayer()->GetPositionY(); + float z = m_session->GetPlayer()->GetPositionZ(); + float o = m_session->GetPlayer()->GetOrientation(); + + if (pCreature) + { + if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow())) + { + const_cast(data)->posX = x; + const_cast(data)->posY = y; + const_cast(data)->posZ = z; + const_cast(data)->orientation = o; + } + pCreature->GetMap()->CreatureRelocation(pCreature,x, y, z,o); + pCreature->GetMotionMaster()->Initialize(); + if(pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + } + + WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid); + PSendSysMessage(LANG_COMMAND_CREATUREMOVED); + return true; +} + +/**HandleNpcSetMoveTypeCommand * Set the movement type for an NPC.
*
* Valid movement types are: @@ -1512,69 +1249,6 @@ bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args) PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str); } - return true; -} // HandleNpcSetMoveTypeCommand - -//change level of creature or pet -bool ChatHandler::HandleChangeLevelCommand(const char* args) -{ - if (!*args) - return false; - - uint8 lvl = (uint8) atoi((char*)args); - if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if(pCreature->isPet()) - { - ((Pet*)pCreature)->GivePetLevel(lvl); - } - else - { - pCreature->SetMaxHealth( 100 + 30*lvl); - pCreature->SetHealth( 100 + 30*lvl); - pCreature->SetLevel( lvl); - pCreature->SaveToDB(); - } - - return true; -} - -//set npcflag of creature -bool ChatHandler::HandleNpcFlagCommand(const char* args) -{ - if (!*args) - return false; - - uint32 npcFlags = (uint32) atoi((char*)args); - - Creature* pCreature = getSelectedCreature(); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags); - - WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry()); - - SendSysMessage(LANG_VALUE_SAVED_REJOIN); - return true; } @@ -1602,28 +1276,6 @@ bool ChatHandler::HandleNpcSetModelCommand(const char* args) return true; } - -//morph creature or player -bool ChatHandler::HandleMorphCommand(const char* args) -{ - if (!*args) - return false; - - uint16 display_id = (uint16)atoi((char*)args); - - Unit *target = getSelectedUnit(); - if(!target) - target = m_session->GetPlayer(); - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) - return false; - - target->SetDisplayId(display_id); - - return true; -} - //set faction of creature bool ChatHandler::HandleNpcFactionIdCommand(const char* args) { @@ -1664,6 +1316,614 @@ bool ChatHandler::HandleNpcFactionIdCommand(const char* args) return true; } +//set spawn dist of creature +bool ChatHandler::HandleNpcSpawnDistCommand(const char* args) +{ + if(!*args) + return false; + + float option = atof((char*)args); + if (option < 0.0f) + { + SendSysMessage(LANG_BAD_VALUE); + return false; + } + + MovementGeneratorType mtype = IDLE_MOTION_TYPE; + if (option >0.0f) + mtype = RANDOM_MOTION_TYPE; + + Creature *pCreature = getSelectedCreature(); + uint32 u_guidlow = 0; + + if (pCreature) + u_guidlow = pCreature->GetDBTableGUIDLow(); + else + return false; + + pCreature->SetRespawnRadius((float)option); + pCreature->SetDefaultMovementType(mtype); + pCreature->GetMotionMaster()->Initialize(); + if(pCreature->isAlive()) // dead creature will reset movement generator at respawn + { + pCreature->setDeathState(JUST_DIED); + pCreature->Respawn(); + } + + WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow); + PSendSysMessage(LANG_COMMAND_SPAWNDIST,option); + return true; +} +//spawn time handling +bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args) +{ + if(!*args) + return false; + + char* stime = strtok((char*)args, " "); + + if (!stime) + return false; + + int i_stime = atoi((char*)stime); + + if (i_stime < 0) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature *pCreature = getSelectedCreature(); + uint32 u_guidlow = 0; + + if (pCreature) + u_guidlow = pCreature->GetDBTableGUIDLow(); + else + return false; + + WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow); + pCreature->SetRespawnDelay((uint32)i_stime); + PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime); + + return true; +} +//npc follow handling +bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/) +{ + Player *player = m_session->GetPlayer(); + Creature *creature = getSelectedCreature(); + + if(!creature) + { + PSendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + // Follow player - Using pet's default dist and angle + creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + + PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName()); + return true; +} +//npc unfollow handling +bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/) +{ + Player *player = m_session->GetPlayer(); + Creature *creature = getSelectedCreature(); + + if(!creature) + { + PSendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (creature->GetMotionMaster()->empty() || + creature->GetMotionMaster()->GetCurrentMovementGeneratorType ()!=TARGETED_MOTION_TYPE) + { + PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); + SetSentErrorMessage(true); + return false; + } + + TargetedMovementGenerator const* mgen + = static_cast const*>((creature->GetMotionMaster()->top())); + + if(mgen->GetTarget()!=player) + { + PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); + SetSentErrorMessage(true); + return false; + } + + // reset movement + creature->GetMotionMaster()->MovementExpired(true); + + PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName()); + return true; +} +//npc tame handling +bool ChatHandler::HandleNpcTameCommand(const char* /*args*/) +{ + Creature *creatureTarget = getSelectedCreature (); + if (!creatureTarget || creatureTarget->isPet ()) + { + PSendSysMessage (LANG_SELECT_CREATURE); + SetSentErrorMessage (true); + return false; + } + + Player *player = m_session->GetPlayer (); + + if(player->GetPetGUID ()) + { + SendSysMessage (LANG_YOU_ALREADY_HAVE_PET); + SetSentErrorMessage (true); + return false; + } + + CreatureInfo const* cInfo = creatureTarget->GetCreatureInfo(); + + if (!cInfo->isTameable ()) + { + PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); + SetSentErrorMessage (true); + return false; + } + + // Everything looks OK, create new pet + Pet* pet = player->CreateTamedPetFrom (creatureTarget); + if (!pet) + { + PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); + SetSentErrorMessage (true); + return false; + } + + // place pet before player + float x,y,z; + player->GetClosePoint (x,y,z,creatureTarget->GetObjectSize (),CONTACT_DISTANCE); + pet->Relocate (x,y,z,M_PI-player->GetOrientation ()); + + // set pet to defensive mode by default (some classes can't control controlled pets in fact). + pet->GetCharmInfo()->SetReactState(REACT_DEFENSIVE); + + // calculate proper level + uint32 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel(); + + // prepare visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); + + // add to world + pet->GetMap()->Add((Creature*)pet); + + // visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); + + // caster have pet now + player->SetPet(pet); + + pet->SavePetToDB(PET_SAVE_AS_CURRENT); + player->PetSpellInitialize(); + + return true; +} +//npc phasemask handling +//change phasemask of creature or pet +bool ChatHandler::HandleNpcSetPhaseCommand(const char* args) +{ + if (!*args) + return false; + + uint32 phasemask = (uint32) atoi((char*)args); + if ( phasemask == 0 ) + { + SendSysMessage(LANG_BAD_VALUE); + SetSentErrorMessage(true); + return false; + } + + Creature* pCreature = getSelectedCreature(); + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + pCreature->SetPhaseMask(phasemask,true); + + if(!pCreature->isPet()) + pCreature->SaveToDB(); + + return true; +} +//npc deathstate handling +bool ChatHandler::HandleNpcSetDeathStateCommand(const char* args) +{ + if (!*args) + return false; + + Creature* pCreature = getSelectedCreature(); + if(!pCreature || pCreature->isPet()) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + if (strncmp(args, "on", 3) == 0) + pCreature->SetDeadByDefault(true); + else if (strncmp(args, "off", 4) == 0) + pCreature->SetDeadByDefault(false); + else + { + SendSysMessage(LANG_USE_BOL); + SetSentErrorMessage(true); + return false; + } + + pCreature->SaveToDB(); + pCreature->Respawn(); + + return true; +} + +//TODO: NpcCommands that need to be fixed : + +bool ChatHandler::HandleNpcNameCommand(const char* /*args*/) +{ + /* Temp. disabled + if(!*args) + return false; + + if(strlen((char*)args)>75) + { + PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75); + return true; + } + + for (uint8 i = 0; i < strlen(args); i++) + { + if(!isalpha(args[i]) && args[i]!=' ') + { + SendSysMessage(LANG_CHARS_ONLY); + return false; + } + } + + uint64 guid; + guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + pCreature->SetName(args); + uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName()); + pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); + + pCreature->SaveToDB(); + */ + + return true; +} + +bool ChatHandler::HandleNpcSubNameCommand(const char* /*args*/) +{ + /* Temp. disabled + + if(!*args) + args = ""; + + if(strlen((char*)args)>75) + { + + PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75); + return true; + } + + for (uint8 i = 0; i < strlen(args); i++) + { + if(!isalpha(args[i]) && args[i]!=' ') + { + SendSysMessage(LANG_CHARS_ONLY); + return false; + } + } + uint64 guid; + guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID)); + pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname); + + pCreature->SaveToDB(); + */ + return true; +} + +//move item to other slot +bool ChatHandler::HandleItemMoveCommand(const char* args) +{ + if(!*args) + return false; + uint8 srcslot, dstslot; + + char* pParam1 = strtok((char*)args, " "); + if (!pParam1) + return false; + + char* pParam2 = strtok(NULL, " "); + if (!pParam2) + return false; + + srcslot = (uint8)atoi(pParam1); + dstslot = (uint8)atoi(pParam2); + + if(srcslot==dstslot) + return true; + + if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot)) + return false; + + if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot)) + return false; + + uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot); + uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot); + + m_session->GetPlayer()->SwapItem( src, dst ); + + return true; +} + +//delete object by selection or guid +bool ChatHandler::HandleDelObjectCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if(!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + uint64 owner_guid = obj->GetOwnerGUID(); + if(owner_guid) + { + Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid); + if(!owner && !IS_PLAYER_GUID(owner_guid)) + { + PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow()); + SetSentErrorMessage(true); + return false; + } + + owner->RemoveGameObject(obj,false); + } + + obj->SetRespawnTime(0); // not save respawn time + obj->Delete(); + obj->DeleteFromDB(); + + PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow()); + + return true; +} + +//turn selected object +bool ChatHandler::HandleTurnObjectCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if(!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* po = strtok(NULL, " "); + float o; + + if (po) + { + o = (float)atof(po); + } + else + { + Player *chr = m_session->GetPlayer(); + o = chr->GetOrientation(); + } + + float rot2 = sin(o/2); + float rot3 = cos(o/2); + + Map* map = obj->GetMap(); + map->Remove(obj,false); + + obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o); + + obj->SetFloatValue(GAMEOBJECT_FACING, o); + obj->SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rot2); + obj->SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rot3); + + map->Add(obj); + + obj->SaveToDB(); + obj->Refresh(); + + PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o); + + return true; +} + +//move selected object +bool ChatHandler::HandleMoveObjectCommand(const char* args) +{ + // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r + char* cId = extractKeyFromLink((char*)args,"Hgameobject"); + if(!cId) + return false; + + uint32 lowguid = atoi(cId); + if(!lowguid) + return false; + + GameObject* obj = NULL; + + // by DB guid + if (GameObjectData const* go_data = objmgr.GetGOData(lowguid)) + obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id); + + if(!obj) + { + PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid); + SetSentErrorMessage(true); + return false; + } + + char* px = strtok(NULL, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + + if (!px) + { + Player *chr = m_session->GetPlayer(); + + Map* map = obj->GetMap(); + map->Remove(obj,false); + + obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation()); + obj->SetFloatValue(GAMEOBJECT_POS_X, chr->GetPositionX()); + obj->SetFloatValue(GAMEOBJECT_POS_Y, chr->GetPositionY()); + obj->SetFloatValue(GAMEOBJECT_POS_Z, chr->GetPositionZ()); + + map->Add(obj); + } + else + { + if(!py || !pz) + return false; + + float x = (float)atof(px); + float y = (float)atof(py); + float z = (float)atof(pz); + + if(!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId()); + SetSentErrorMessage(true); + return false; + } + + Map* map = obj->GetMap(); + map->Remove(obj,false); + + obj->Relocate(x, y, z, obj->GetOrientation()); + obj->SetFloatValue(GAMEOBJECT_POS_X, x); + obj->SetFloatValue(GAMEOBJECT_POS_Y, y); + obj->SetFloatValue(GAMEOBJECT_POS_Z, z); + + map->Add(obj); + } + + obj->SaveToDB(); + obj->Refresh(); + + PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow()); + + return true; +} + +//demorph player or unit +bool ChatHandler::HandleDeMorphCommand(const char* /*args*/) +{ + Unit *target = getSelectedUnit(); + if(!target) + target = m_session->GetPlayer(); + + + // check online security + else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) + return false; + + target->DeMorph(); + + return true; +} + +//morph creature or player +bool ChatHandler::HandleMorphCommand(const char* args) +{ + if (!*args) + return false; + + uint16 display_id = (uint16)atoi((char*)args); + + Unit *target = getSelectedUnit(); + if(!target) + target = m_session->GetPlayer(); + + // check online security + else if (target->GetTypeId() == TYPEID_PLAYER && HasLowerSecurity((Player*)target, 0)) + return false; + + target->SetDisplayId(display_id); + + return true; +} //kick player bool ChatHandler::HandleKickPlayerCommand(const char *args) @@ -2107,79 +2367,6 @@ bool ChatHandler::HandleDelTicketCommand(const char *args) return true; } -//set spawn dist of creature -bool ChatHandler::HandleNpcSpawnDistCommand(const char* args) -{ - if(!*args) - return false; - - float option = atof((char*)args); - if (option < 0.0f) - { - SendSysMessage(LANG_BAD_VALUE); - return false; - } - - MovementGeneratorType mtype = IDLE_MOTION_TYPE; - if (option >0.0f) - mtype = RANDOM_MOTION_TYPE; - - Creature *pCreature = getSelectedCreature(); - uint32 u_guidlow = 0; - - if (pCreature) - u_guidlow = pCreature->GetDBTableGUIDLow(); - else - return false; - - pCreature->SetRespawnRadius((float)option); - pCreature->SetDefaultMovementType(mtype); - pCreature->GetMotionMaster()->Initialize(); - if(pCreature->isAlive()) // dead creature will reset movement generator at respawn - { - pCreature->setDeathState(JUST_DIED); - pCreature->Respawn(); - } - - WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow); - PSendSysMessage(LANG_COMMAND_SPAWNDIST,option); - return true; -} - -bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args) -{ - if(!*args) - return false; - - char* stime = strtok((char*)args, " "); - - if (!stime) - return false; - - int i_stime = atoi((char*)stime); - - if (i_stime < 0) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature *pCreature = getSelectedCreature(); - uint32 u_guidlow = 0; - - if (pCreature) - u_guidlow = pCreature->GetDBTableGUIDLow(); - else - return false; - - WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow); - pCreature->SetRespawnDelay((uint32)i_stime); - PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime); - - return true; -} - /** * Add a waypoint to a creature. * @@ -3610,8 +3797,8 @@ bool ChatHandler::HandleLookupEventCommand(const char* args) uint32 counter = 0; - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); for(uint32 id = 0; id < events.size(); ++id ) { @@ -3644,12 +3831,12 @@ bool ChatHandler::HandleEventActiveListCommand(const char* /*args*/) { uint32 counter = 0; - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); char const* active = GetMangosString(LANG_ACTIVE); - for(GameEvent::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr ) + for(GameEventMgr::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr ) { uint32 event_id = *itr; GameEventData const& eventData = events[event_id]; @@ -3680,7 +3867,7 @@ bool ChatHandler::HandleEventInfoCommand(const char* args) uint32 event_id = atoi(cId); - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); if(event_id >=events.size()) { @@ -3697,7 +3884,7 @@ bool ChatHandler::HandleEventInfoCommand(const char* args) return false; } - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); bool active = activeEvents.find(event_id) != activeEvents.end(); char const* activeStr = active ? GetMangosString(LANG_ACTIVE) : ""; @@ -3729,7 +3916,7 @@ bool ChatHandler::HandleEventStartCommand(const char* args) int32 event_id = atoi(cId); - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); if(event_id < 1 || event_id >=events.size()) { @@ -3746,7 +3933,7 @@ bool ChatHandler::HandleEventStartCommand(const char* args) return false; } - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); if(activeEvents.find(event_id) != activeEvents.end()) { PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id); @@ -3770,7 +3957,7 @@ bool ChatHandler::HandleEventStopCommand(const char* args) int32 event_id = atoi(cId); - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); if(event_id < 1 || event_id >=events.size()) { @@ -3787,7 +3974,7 @@ bool ChatHandler::HandleEventStopCommand(const char* args) return false; } - GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); + GameEventMgr::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList(); if(activeEvents.find(event_id) == activeEvents.end()) { @@ -4119,158 +4306,6 @@ bool ChatHandler::HandleWaterwalkCommand(const char* args) return true; } -bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/) -{ - Player *player = m_session->GetPlayer(); - Creature *creature = getSelectedCreature(); - - if(!creature) - { - PSendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - // Follow player - Using pet's default dist and angle - creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - - PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName()); - return true; -} - -bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/) -{ - Player *player = m_session->GetPlayer(); - Creature *creature = getSelectedCreature(); - - if(!creature) - { - PSendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (creature->GetMotionMaster()->empty() || - creature->GetMotionMaster()->GetCurrentMovementGeneratorType ()!=TARGETED_MOTION_TYPE) - { - PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); - SetSentErrorMessage(true); - return false; - } - - TargetedMovementGenerator const* mgen - = static_cast const*>((creature->GetMotionMaster()->top())); - - if(mgen->GetTarget()!=player) - { - PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU); - SetSentErrorMessage(true); - return false; - } - - // reset movement - creature->GetMotionMaster()->MovementExpired(true); - - PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName()); - return true; -} - -bool ChatHandler::HandleNpcTameCommand(const char* /*args*/) -{ - Creature *creatureTarget = getSelectedCreature (); - if (!creatureTarget || creatureTarget->isPet ()) - { - PSendSysMessage (LANG_SELECT_CREATURE); - SetSentErrorMessage (true); - return false; - } - - Player *player = m_session->GetPlayer (); - - if(player->GetPetGUID ()) - { - SendSysMessage (LANG_YOU_ALREADY_HAVE_PET); - SetSentErrorMessage (true); - return false; - } - - CreatureInfo const* cInfo = creatureTarget->GetCreatureInfo(); - - if (!cInfo->isTameable ()) - { - PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); - SetSentErrorMessage (true); - return false; - } - - // Everything looks OK, create new pet - Pet* pet = player->CreateTamedPetFrom (creatureTarget); - if (!pet) - { - PSendSysMessage (LANG_CREATURE_NON_TAMEABLE,cInfo->Entry); - SetSentErrorMessage (true); - return false; - } - - // place pet before player - float x,y,z; - player->GetClosePoint (x,y,z,creatureTarget->GetObjectSize (),CONTACT_DISTANCE); - pet->Relocate (x,y,z,M_PI-player->GetOrientation ()); - - // set pet to defensive mode by default (some classes can't control controlled pets in fact). - pet->GetCharmInfo()->SetReactState(REACT_DEFENSIVE); - - // calculate proper level - uint32 level = (creatureTarget->getLevel() < (player->getLevel() - 5)) ? (player->getLevel() - 5) : creatureTarget->getLevel(); - - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, level - 1); - - // add to world - pet->GetMap()->Add((Creature*)pet); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, level); - - // caster have pet now - player->SetPet(pet); - - pet->SavePetToDB(PET_SAVE_AS_CURRENT); - player->PetSpellInitialize(); - - return true; -} - -//change phasemask of creature or pet -bool ChatHandler::HandleNpcSetPhaseCommand(const char* args) -{ - if (!*args) - return false; - - uint32 phasemask = (uint32) atoi((char*)args); - if ( phasemask == 0 ) - { - SendSysMessage(LANG_BAD_VALUE); - SetSentErrorMessage(true); - return false; - } - - Creature* pCreature = getSelectedCreature(); - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - pCreature->SetPhaseMask(phasemask,true); - - if(!pCreature->isPet()) - pCreature->SaveToDB(); - - return true; -} - //set pahsemask for selected object bool ChatHandler::HandleGOPhaseCommand(const char* args) { @@ -4309,34 +4344,3 @@ bool ChatHandler::HandleGOPhaseCommand(const char* args) obj->SaveToDB(); return true; } - -bool ChatHandler::HandleNpcSetDeathStateCommand(const char* args) -{ - if (!*args) - return false; - - Creature* pCreature = getSelectedCreature(); - if(!pCreature || pCreature->isPet()) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - - if (strncmp(args, "on", 3) == 0) - pCreature->SetDeadByDefault(true); - else if (strncmp(args, "off", 4) == 0) - pCreature->SetDeadByDefault(false); - else - { - SendSysMessage(LANG_USE_BOL); - SetSentErrorMessage(true); - return false; - } - - pCreature->SaveToDB(); - pCreature->Respawn(); - - return true; -} - diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index ec2bd95d5..68cdb1717 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -33,7 +33,6 @@ #include "Guild.h" #include "ObjectAccessor.h" #include "MapManager.h" -#include "SpellAuras.h" #include "ScriptCalls.h" #include "Language.h" #include "GridNotifiersImpl.h" @@ -3066,7 +3065,7 @@ bool ChatHandler::HandleGuildCreateCommand(const char* args) } Guild *guild = new Guild; - if (!guild->create (player->GetGUID (),guildname)) + if (!guild->create (player,guildname)) { delete guild; SendSysMessage (LANG_GUILD_NOT_CREATED); @@ -3261,77 +3260,6 @@ bool ChatHandler::HandleGetDistanceCommand(const char* args) return true; } -// FIX-ME!!! - -bool ChatHandler::HandleAddWeaponCommand(const char* /*args*/) -{ - /*if (!*args) - return false; - - uint64 guid = m_session->GetPlayer()->GetSelection(); - if (guid == 0) - { - SendSysMessage(LANG_NO_SELECTION); - return true; - } - - Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); - - if(!pCreature) - { - SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - char* pSlotID = strtok((char*)args, " "); - if (!pSlotID) - return false; - - char* pItemID = strtok(NULL, " "); - if (!pItemID) - return false; - - uint32 ItemID = atoi(pItemID); - uint32 SlotID = atoi(pSlotID); - - ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID); - - bool added = false; - if(tmpItem) - { - switch(SlotID) - { - case 1: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); - added = true; - break; - case 2: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); - added = true; - break; - case 3: - pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); - added = true; - break; - default: - PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID); - added = false; - break; - } - if(added) - { - PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID); - } - } - else - { - PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID); - return true; - } - */ - return true; -} - bool ChatHandler::HandleDieCommand(const char* /*args*/) { Unit* target = getSelectedUnit(); @@ -3592,7 +3520,7 @@ bool ChatHandler::HandleLinkGraveCommand(const char* args) return false; } - if(objmgr.AddGraveYardLink(g_id,player->GetZoneId(),g_team)) + if(objmgr.AddGraveYardLink(g_id,zoneId,g_team)) PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, g_id,zoneId); else PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, g_id,zoneId); @@ -3616,6 +3544,7 @@ bool ChatHandler::HandleNearGraveCommand(const char* args) return false; Player* player = m_session->GetPlayer(); + uint32 zone_id = player->GetZoneId(); WorldSafeLocsEntry const* graveyard = objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(),player->GetMapId(),g_team); @@ -3624,7 +3553,7 @@ bool ChatHandler::HandleNearGraveCommand(const char* args) { uint32 g_id = graveyard->ID; - GraveYardData const* data = objmgr.FindGraveYardData(g_id,player->GetZoneId()); + GraveYardData const* data = objmgr.FindGraveYardData(g_id,zone_id); if (!data) { PSendSysMessage(LANG_COMMAND_GRAVEYARDERROR,g_id); @@ -3643,7 +3572,7 @@ bool ChatHandler::HandleNearGraveCommand(const char* args) else if(g_team == ALLIANCE) team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ALLIANCE); - PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),player->GetZoneId()); + PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, g_id,team_name.c_str(),zone_id); } else { @@ -3657,29 +3586,36 @@ bool ChatHandler::HandleNearGraveCommand(const char* args) team_name = GetMangosString(LANG_COMMAND_GRAVEYARD_ALLIANCE); if(g_team == ~uint32(0)) - PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, player->GetZoneId()); + PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id); else - PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, player->GetZoneId(),team_name.c_str()); + PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id,team_name.c_str()); } return true; } -//play npc emote -bool ChatHandler::HandleNpcPlayEmoteCommand(const char* args) +//-----------------------Npc Commands----------------------- +bool ChatHandler::HandleNpcChangeEntryCommand(const char *args) { - uint32 emote = atoi((char*)args); + if(!args) + return false; - Creature* target = getSelectedCreature(); - if(!target) + uint32 newEntryNum = atoi(args); + if(!newEntryNum) + return false; + + Unit* unit = getSelectedUnit(); + if(!unit || unit->GetTypeId() != TYPEID_UNIT) { SendSysMessage(LANG_SELECT_CREATURE); SetSentErrorMessage(true); return false; } - - target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote); - + Creature* creature = (Creature*)unit; + if(creature->UpdateEntry(newEntryNum)) + SendSysMessage(LANG_DONE); + else + SendSysMessage(LANG_ERROR); return true; } @@ -3728,6 +3664,95 @@ bool ChatHandler::HandleNpcInfoCommand(const char* /*args*/) return true; } +//play npc emote +bool ChatHandler::HandleNpcPlayEmoteCommand(const char* args) +{ + uint32 emote = atoi((char*)args); + + Creature* target = getSelectedCreature(); + if(!target) + { + SendSysMessage(LANG_SELECT_CREATURE); + SetSentErrorMessage(true); + return false; + } + + target->SetUInt32Value(UNIT_NPC_EMOTESTATE,emote); + + return true; +} + +//TODO: NpcCommands that needs to be fixed : + +bool ChatHandler::HandleNpcAddWeaponCommand(const char* /*args*/) +{ + /*if (!*args) + return false; + + uint64 guid = m_session->GetPlayer()->GetSelection(); + if (guid == 0) + { + SendSysMessage(LANG_NO_SELECTION); + return true; + } + + Creature *pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid); + + if(!pCreature) + { + SendSysMessage(LANG_SELECT_CREATURE); + return true; + } + + char* pSlotID = strtok((char*)args, " "); + if (!pSlotID) + return false; + + char* pItemID = strtok(NULL, " "); + if (!pItemID) + return false; + + uint32 ItemID = atoi(pItemID); + uint32 SlotID = atoi(pSlotID); + + ItemPrototype* tmpItem = objmgr.GetItemPrototype(ItemID); + + bool added = false; + if(tmpItem) + { + switch(SlotID) + { + case 1: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); + added = true; + break; + case 2: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); + added = true; + break; + case 3: + pCreature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); + added = true; + break; + default: + PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST,SlotID); + added = false; + break; + } + + if(added) + PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT,ItemID,tmpItem->Name1,SlotID); + } + else + { + PSendSysMessage(LANG_ITEM_NOT_FOUND,ItemID); + return true; + } + */ + return true; +} +//---------------------------------------------------------- + bool ChatHandler::HandleExploreCheatCommand(const char* args) { if (!*args) @@ -5686,30 +5711,6 @@ bool ChatHandler::HandleLoadPDumpCommand(const char *args) return true; } -bool ChatHandler::HandleNpcChangeEntryCommand(const char *args) -{ - if(!args) - return false; - - uint32 newEntryNum = atoi(args); - if(!newEntryNum) - return false; - - Unit* unit = getSelectedUnit(); - if(!unit || unit->GetTypeId() != TYPEID_UNIT) - { - SendSysMessage(LANG_SELECT_CREATURE); - SetSentErrorMessage(true); - return false; - } - Creature* creature = (Creature*)unit; - if(creature->UpdateEntry(newEntryNum)) - SendSysMessage(LANG_DONE); - else - SendSysMessage(LANG_ERROR); - return true; -} - bool ChatHandler::HandleWritePDumpCommand(const char *args) { if(!args) diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index 3097cff41..a190a058a 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -114,11 +114,18 @@ void LootStore::LoadLootTable() float chanceOrQuestChance = fields[2].GetFloat(); uint8 group = fields[3].GetUInt8(); int32 mincountOrRef = fields[4].GetInt32(); - uint8 maxcount = fields[5].GetUInt8(); + uint32 maxcount = fields[5].GetUInt32(); ConditionType condition = (ConditionType)fields[6].GetUInt8(); uint32 cond_value1 = fields[7].GetUInt32(); uint32 cond_value2 = fields[8].GetUInt32(); + if(maxcount > std::numeric_limits::max()) + { + sLog.outErrorDb("Table '%s' entry %d item %d: maxcount value (%u) to large. must be less %u - skipped", GetName(), entry, item, maxcount,std::numeric_limits::max()); + continue; // error already printed to log/console. + } + + if(!PlayerCondition::IsValid(condition,cond_value1, cond_value2)) { sLog.outErrorDb("... in table '%s' entry %u item %u", GetName(), entry, item); @@ -248,6 +255,12 @@ bool LootStoreItem::Roll(bool rate) const // Checks correctness of values bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const { + if(group >= 1 << 7) // it stored in 7 bit field + { + sLog.outErrorDb("Table '%s' entry %d item %d: group (%u) must be less %u - skipped", store.GetName(), entry, itemid, group, 1 << 7); + return false; + } + if (mincountOrRef == 0) { sLog.outErrorDb("Table '%s' entry %d item %d: wrong mincountOrRef (%d) - skipped", store.GetName(), entry, itemid, mincountOrRef); diff --git a/src/game/LootMgr.h b/src/game/LootMgr.h index 0c34d7904..b16757d49 100644 --- a/src/game/LootMgr.h +++ b/src/game/LootMgr.h @@ -63,17 +63,17 @@ struct LootStoreItem uint32 itemid; // id of the item float chance; // always positive, chance to drop for both quest and non-quest items, chance to be used for refs int32 mincountOrRef; // mincount for drop items (positive) or minus referenced TemplateleId (negative) - uint8 group :8; + uint8 group :7; + bool needs_quest :1; // quest drop (negative ChanceOrQuestChance in DB) uint8 maxcount :8; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative) uint16 conditionId :16; // additional loot condition Id - bool needs_quest :1; // quest drop (negative ChanceOrQuestChance in DB) // Constructor, converting ChanceOrQuestChance -> (chance, needs_quest) // displayid is filled in IsValid() which must be called after LootStoreItem(uint32 _itemid, float _chanceOrQuestChance, int8 _group, uint8 _conditionId, int32 _mincountOrRef, uint8 _maxcount) : itemid(_itemid), chance(fabs(_chanceOrQuestChance)), mincountOrRef(_mincountOrRef), - group(_group), maxcount(_maxcount), conditionId(_conditionId), - needs_quest(_chanceOrQuestChance < 0) {} + group(_group), needs_quest(_chanceOrQuestChance < 0), maxcount(_maxcount), conditionId(_conditionId) + {} bool Roll(bool rate) const; // Checks if the entry takes it's chance (at loot generation) bool IsValid(LootStore const& store, uint32 entry) const; diff --git a/src/game/Makefile.am b/src/game/Makefile.am index 2b10e7b6e..f769811b9 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -109,8 +109,8 @@ libmangosgame_a_SOURCES = \ FleeingMovementGenerator.cpp \ FleeingMovementGenerator.h \ Formulas.h \ - GameEvent.cpp \ - GameEvent.h \ + GameEventMgr.cpp \ + GameEventMgr.h \ GameObject.cpp \ GameObject.h \ GlobalEvents.cpp \ diff --git a/src/game/Map.cpp b/src/game/Map.cpp index cafb3464c..f78871d8b 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -19,7 +19,6 @@ #include "MapManager.h" #include "Player.h" #include "GridNotifiers.h" -#include "WorldSession.h" #include "Log.h" #include "GridStates.h" #include "CellImpl.h" @@ -42,9 +41,6 @@ #define DEFAULT_GRID_EXPIRY 300 #define MAX_GRID_LOAD_TIME 50 -// magic *.map header -const char MAP_MAGIC[] = "MAP_3.00"; - GridState* si_GridStates[MAX_GRID_STATE]; Map::~Map() @@ -67,9 +63,9 @@ bool Map::ExistMap(uint32 mapid,int x,int y) return false; } - char magic[8]; - fread(magic,1,8,pf); - if(strncmp(MAP_MAGIC,magic,8)) + map_fileheader header; + fread(&header, sizeof(header), 1, pf); + if (header.mapMagic != MAP_MAGIC || header.versionMagic != MAP_VERSION_MAGIC) { sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp); delete [] tmp; @@ -79,7 +75,6 @@ bool Map::ExistMap(uint32 mapid,int x,int y) delete [] tmp; fclose(pf); - return true; } @@ -158,29 +153,13 @@ void Map::LoadMap(uint32 mapid, uint32 instanceid, int x,int y) snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),mapid,x,y); sLog.outDetail("Loading map %s",tmp); // loading data - FILE *pf=fopen(tmp,"rb"); - if(!pf) + GridMaps[x][y] = new GridMap(); + if (!GridMaps[x][y]->loadData(tmp)) { - delete [] tmp; - return; + sLog.outError("Error load map file: \n %s\n", tmp); } - - char magic[8]; - fread(magic,1,8,pf); - if(strncmp(MAP_MAGIC,magic,8)) - { - sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.",tmp); - delete [] tmp; - fclose(pf); //close file before return - return; - } - delete [] tmp; - - GridMap * buf= new GridMap; - fread(buf,1,sizeof(GridMap),pf); - fclose(pf); - - GridMaps[x][y] = buf; + delete [] tmp; + return; } void Map::LoadMapAndVMap(uint32 mapid, uint32 instanceid, int x,int y) @@ -1032,7 +1011,11 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce) { if (i_InstanceId == 0) { - if(GridMaps[gx][gy]) delete (GridMaps[gx][gy]); + if(GridMaps[gx][gy]) + { + GridMaps[gx][gy]->unloadData(); + delete GridMaps[gx][gy]; + } // x and y are swapped VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx); } @@ -1057,94 +1040,527 @@ void Map::UnloadAll(bool pForce) } } -float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const +//***************************** +// Grid function +//***************************** +GridMap::GridMap() { - GridPair p = MaNGOS::ComputeGridPair(x, y); + m_flags = 0; + // Area data + m_gridArea = 0; + m_area_map = NULL; + // Height level data + m_gridHeight = INVALID_HEIGHT; + m_gridGetHeight = &GridMap::getHeightFromFlat; + m_V9 = NULL; + m_V8 = NULL; + // Liquid data + m_liquidType = 0; + m_liquid_offX = 0; + m_liquid_offY = 0; + m_liquid_width = 0; + m_liquid_height = 0; + m_liquidLevel = INVALID_HEIGHT; + m_liquid_type = NULL; + m_liquid_map = NULL; +} +GridMap::~GridMap() +{ + unloadData(); +} + +bool GridMap::loadData(char *filename) +{ + // Unload old data if exist + unloadData(); + + map_fileheader header; + // Not return error if file not found + FILE *in = fopen(filename, "rb"); + if (!in) + return true; + fread(&header, sizeof(header),1,in); + if (header.mapMagic == MAP_MAGIC && header.versionMagic == MAP_VERSION_MAGIC) + { + // loadup area data + if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) + { + sLog.outError("Error loading map area data\n"); + fclose(in); + return false; + } + // loadup height data + if (header.heightMapOffset && !loadHeihgtData(in, header.heightMapOffset, header.heightMapSize)) + { + sLog.outError("Error loading map height data\n"); + fclose(in); + return false; + } + // loadup liquid data + if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize)) + { + sLog.outError("Error loading map liquids data\n"); + fclose(in); + return false; + } + fclose(in); + return true; + } + sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.", filename); + fclose(in); + return false; +} + +void GridMap::unloadData() +{ + if (m_area_map) delete[] m_area_map; + if (m_V9) delete[] m_V9; + if (m_V8) delete[] m_V8; + if (m_liquid_type) delete[] m_liquid_type; + if (m_liquid_map) delete[] m_liquid_map; + m_area_map = NULL; + m_V9 = NULL; + m_V8 = NULL; + m_liquid_type = NULL; + m_liquid_map = NULL; + m_gridGetHeight = &GridMap::getHeightFromFlat; +} + +bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 size) +{ + map_areaHeader header; + fseek(in, offset, SEEK_SET); + fread(&header, sizeof(header), 1, in); + if (header.fourcc != MAP_AREA_MAGIC) + return false; + + m_gridArea = header.gridArea; + if (!(header.flags&MAP_AREA_NO_AREA)) + { + m_area_map = new uint16 [16*16]; + fread(m_area_map, sizeof(uint16), 16*16, in); + } + return true; +} + +bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size) +{ + map_heightHeader header; + fseek(in, offset, SEEK_SET); + fread(&header, sizeof(header), 1, in); + if (header.fourcc != MAP_HEIGTH_MAGIC) + return false; + + m_gridHeight = header.gridHeight; + if (!(header.flags&MAP_HEIGHT_NO_HIGHT)) + { + if ((header.flags&MAP_HEIGHT_AS_INT16)) + { + m_uint16_V9 = new uint16 [129*129]; + m_uint16_V8 = new uint16 [128*128]; + fread(m_uint16_V9, sizeof(uint16), 129*129, in); + fread(m_uint16_V8, sizeof(uint16), 128*128, in); + m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; + m_gridGetHeight = &GridMap::getHeightFromUint16; + } + else if ((header.flags&MAP_HEIGHT_AS_INT8)) + { + m_uint8_V9 = new uint8 [129*129]; + m_uint8_V8 = new uint8 [128*128]; + fread(m_uint8_V9, sizeof(uint8), 129*129, in); + fread(m_uint8_V8, sizeof(uint8), 128*128, in); + m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255; + m_gridGetHeight = &GridMap::getHeightFromUint8; + } + else + { + m_V9 = new float [129*129]; + m_V8 = new float [128*128]; + fread(m_V9, sizeof(float), 129*129, in); + fread(m_V8, sizeof(float), 128*128, in); + m_gridGetHeight = &GridMap::getHeightFromFloat; + } + } + else + m_gridGetHeight = &GridMap::getHeightFromFlat; + return true; +} + +bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size) +{ + map_liquidHeader header; + fseek(in, offset, SEEK_SET); + fread(&header, sizeof(header), 1, in); + if (header.fourcc != MAP_LIQUID_MAGIC) + return false; + + m_liquidType = header.liquidType; + m_liquid_offX = header.offsetX; + m_liquid_offY = header.offsetY; + m_liquid_width = header.width; + m_liquid_height= header.height; + m_liquidLevel = header.liquidLevel; + + if (!(header.flags&MAP_LIQUID_NO_TYPE)) + { + m_liquid_type = new uint8 [16*16]; + fread(m_liquid_type, sizeof(uint8), 16*16, in); + } + if (!(header.flags&MAP_LIQUID_NO_HIGHT)) + { + m_liquid_map = new float [m_liquid_width*m_liquid_height]; + fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in); + } + return true; +} + +uint16 GridMap::getArea(float x, float y) +{ + if (!m_area_map) + return m_gridArea; + + x = 16 * (32 - x/SIZE_OF_GRIDS); + y = 16 * (32 - y/SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return m_area_map[lx*16 + ly]; +} + +float GridMap::getHeightFromFlat(float x, float y) const +{ + return m_gridHeight; +} + +float GridMap::getHeightFromFloat(float x, float y) const +{ + if (!m_V8 || !m_V9) + return m_gridHeight; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int&=(MAP_RESOLUTION - 1); + y_int&=(MAP_RESOLUTION - 1); + + // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid + // +--------------> X + // | h1-------h2 Coordinates is: + // | | \ 1 / | h1 0,0 + // | | \ / | h2 0,1 + // | | 2 h5 3 | h3 1,0 + // | | / \ | h4 1,1 + // | | / 4 \ | h5 1/2,1/2 + // | h3-------h4 + // V Y + // For find height need + // 1 - detect triangle + // 2 - solve linear equation from triangle points + // Calculate coefficients for solve h = a*x + b*y + c + + float a,b,c; + // Select triangle: + if (x+y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + float h1 = m_V9[(x_int )*129 + y_int]; + float h2 = m_V9[(x_int+1)*129 + y_int]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h2-h1; + b = h5-h1-h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + float h1 = m_V9[x_int*129 + y_int ]; + float h3 = m_V9[x_int*129 + y_int+1]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + float h2 = m_V9[(x_int+1)*129 + y_int ]; + float h4 = m_V9[(x_int+1)*129 + y_int+1]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + float h3 = m_V9[(x_int )*129 + y_int+1]; + float h4 = m_V9[(x_int+1)*129 + y_int+1]; + float h5 = 2 * m_V8[x_int*128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return a * x + b * y + c; +} + +float GridMap::getHeightFromUint8(float x, float y) const +{ + if (!m_uint8_V8 || !m_uint8_V9) + return m_gridHeight; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int&=(MAP_RESOLUTION - 1); + y_int&=(MAP_RESOLUTION - 1); + + int32 a, b, c; + uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int]; + if (x+y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + int32 h1 = V9_h1_ptr[ 0]; + int32 h2 = V9_h1_ptr[129]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h2-h1; + b = h5-h1-h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h3 = V9_h1_ptr[1]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + int32 h2 = V9_h1_ptr[129]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + int32 h3 = V9_h1_ptr[ 1]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; +} + +float GridMap::getHeightFromUint16(float x, float y) const +{ + if (!m_uint16_V8 || !m_uint16_V9) + return m_gridHeight; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)x; + int y_int = (int)y; + x -= x_int; + y -= y_int; + x_int&=(MAP_RESOLUTION - 1); + y_int&=(MAP_RESOLUTION - 1); + + int32 a, b, c; + uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int]; + if (x+y < 1) + { + if (x > y) + { + // 1 triangle (h1, h2, h5 points) + int32 h1 = V9_h1_ptr[ 0]; + int32 h2 = V9_h1_ptr[129]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h2-h1; + b = h5-h1-h2; + c = h1; + } + else + { + // 2 triangle (h1, h3, h5 points) + int32 h1 = V9_h1_ptr[0]; + int32 h3 = V9_h1_ptr[1]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h5 - h1 - h3; + b = h3 - h1; + c = h1; + } + } + else + { + if (x > y) + { + // 3 triangle (h2, h4, h5 points) + int32 h2 = V9_h1_ptr[129]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h2 + h4 - h5; + b = h4 - h2; + c = h5 - h4; + } + else + { + // 4 triangle (h3, h4, h5 points) + int32 h3 = V9_h1_ptr[ 1]; + int32 h4 = V9_h1_ptr[130]; + int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int]; + a = h4 - h3; + b = h3 + h4 - h5; + c = h5 - h4; + } + } + // Calculate height + return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; +} + +float GridMap::getLiquidLevel(float x, float y) +{ + if (!m_liquid_map) + return m_liquidLevel; + + x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int cx_int = ((int)x & (MAP_RESOLUTION-1)) - m_liquid_offY; + int cy_int = ((int)y & (MAP_RESOLUTION-1)) - m_liquid_offX; + + if (cx_int < 0 || cx_int >=m_liquid_height) + return INVALID_HEIGHT; + if (cy_int < 0 || cy_int >=m_liquid_width ) + return INVALID_HEIGHT; + + return m_liquid_map[cx_int*m_liquid_width + cy_int]; +} + +uint8 GridMap::getTerrainType(float x, float y) +{ + if (!m_liquid_type) + return m_liquidType; + + x = 16 * (32 - x/SIZE_OF_GRIDS); + y = 16 * (32 - y/SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return m_liquid_type[lx*16 + ly]; +} + +// Get water state on map +inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) +{ + // Check water type (if no water return) + if (!m_liquid_type && !m_liquidType) + return LIQUID_MAP_NO_WATER; + + // Get cell + float cx = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS); + float cy = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS); + + int x_int = (int)cx & (MAP_RESOLUTION-1); + int y_int = (int)cy & (MAP_RESOLUTION-1); + + // Check water type in cell + uint8 type = m_liquid_type ? m_liquid_type[(x_int>>3)*16 + (y_int>>3)] : m_liquidType; + if (type == 0) + return LIQUID_MAP_NO_WATER; + + // Check req liquid type mask + if (ReqLiquidType && !(ReqLiquidType&type)) + return LIQUID_MAP_NO_WATER; + + // Check water level: + // Check water height map + int lx_int = x_int - m_liquid_offY; + int ly_int = y_int - m_liquid_offX; + if (lx_int < 0 || lx_int >=m_liquid_height) + return LIQUID_MAP_NO_WATER; + if (ly_int < 0 || ly_int >=m_liquid_width ) + return LIQUID_MAP_NO_WATER; + + // Get water level + float liquid_level = m_liquid_map ? m_liquid_map[lx_int*m_liquid_width + ly_int] : m_liquidLevel; + // Get ground level (sub 0.2 for fix some errors) + float ground_level = getHeight(x, y); + + // Check water level and ground level + if (liquid_level < ground_level || z < ground_level - 2) + return LIQUID_MAP_NO_WATER; + + // All ok in water -> store data + if (data) + { + data->type = type; + data->level = liquid_level; + data->depth_level = ground_level; + } + + // For speed check as int values + int delta = (liquid_level - z) * 10; + + // Get position delta + if (delta > 20) // Under water + return LIQUID_MAP_UNDER_WATER; + if (delta > 0 ) // In water + return LIQUID_MAP_IN_WATER; + if (delta > -1) // Walk on water + return LIQUID_MAP_WATER_WALK; + // Above water + return LIQUID_MAP_ABOVE_WATER; +} + +inline GridMap *Map::GetGrid(float x, float y) +{ // half opt method int gx=(int)(32-x/SIZE_OF_GRIDS); //grid x int gy=(int)(32-y/SIZE_OF_GRIDS); //grid y - float lx=MAP_RESOLUTION*(32 -x/SIZE_OF_GRIDS - gx); - float ly=MAP_RESOLUTION*(32 -y/SIZE_OF_GRIDS - gy); - // ensure GridMap is loaded - const_cast(this)->EnsureGridCreated(GridPair(63-gx,63-gy)); + EnsureGridCreated(GridPair(63-gx,63-gy)); + return GridMaps[gx][gy]; +} + +float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const +{ // find raw .map surface under Z coordinates float mapHeight; - if(GridMap* gmap = GridMaps[gx][gy]) + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) { - int lx_int = (int)lx; - int ly_int = (int)ly; - lx -= lx_int; - ly -= ly_int; - - // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid - // +--------------> X - // | h1-------h2 Coordinates is: - // | | \ 1 / | h1 0,0 - // | | \ / | h2 0,1 - // | | 2 h5 3 | h3 1,0 - // | | / \ | h4 1,1 - // | | / 4 \ | h5 1/2,1/2 - // | h3-------h4 - // V Y - // For find height need - // 1 - detect triangle - // 2 - solve linear equation from triangle points - - // Calculate coefficients for solve h = a*x + b*y + c - float a,b,c; - // Select triangle: - if (lx+ly < 1) - { - if (lx > ly) - { - // 1 triangle (h1, h2, h5 points) - float h1 = gmap->v9[lx_int][ly_int]; - float h2 = gmap->v9[lx_int+1][ly_int]; - float h5 = 2 * gmap->v8[lx_int][ly_int]; - a = h2-h1; - b = h5-h1-h2; - c = h1; - } - else - { - // 2 triangle (h1, h3, h5 points) - float h1 = gmap->v9[lx_int][ly_int]; - float h3 = gmap->v9[lx_int][ly_int+1]; - float h5 = 2 * gmap->v8[lx_int][ly_int]; - a = h5 - h1 - h3; - b = h3 - h1; - c = h1; - } - } - else - { - if (lx > ly) - { - // 3 triangle (h2, h4, h5 points) - float h2 = gmap->v9[lx_int+1][ly_int]; - float h4 = gmap->v9[lx_int+1][ly_int+1]; - float h5 = 2 * gmap->v8[lx_int][ly_int]; - a = h2 + h4 - h5; - b = h4 - h2; - c = h5 - h4; - } - else - { - // 4 triangle (h3, h4, h5 points) - float h3 = gmap->v9[lx_int][ly_int+1]; - float h4 = gmap->v9[lx_int+1][ly_int+1]; - float h5 = 2 * gmap->v8[lx_int][ly_int]; - a = h4 - h3; - b = h3 + h4 - h5; - c = h5 - h4; - } - } - // Calculate height - float _mapheight = a * lx + b * ly + c; + float _mapheight = gmap->getHeight(x,y); // look from a bit higher pos to find the floor, ignore under surface case if(z + 2.0f > _mapheight) @@ -1203,25 +1619,9 @@ float Map::GetHeight(float x, float y, float z, bool pUseVmaps) const uint16 Map::GetAreaFlag(float x, float y, float z) const { - //local x,y coords - float lx,ly; - int gx,gy; - GridPair p = MaNGOS::ComputeGridPair(x, y); - - // half opt method - gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x - gy=(int)(32-y/SIZE_OF_GRIDS); //grid y - - lx=16*(32 -x/SIZE_OF_GRIDS - gx); - ly=16*(32 -y/SIZE_OF_GRIDS - gy); - //DEBUG_LOG("my %d %d si %d %d",gx,gy,p.x_coord,p.y_coord); - - // ensure GridMap is loaded - const_cast(this)->EnsureGridCreated(GridPair(63-gx,63-gy)); - uint16 areaflag; - if(GridMaps[gx][gy]) - areaflag = GridMaps[gx][gy]->area_flag[(int)(lx)][(int)(ly)]; + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) + areaflag = gmap->getArea(x, y); // this used while not all *.map files generated (instances) else areaflag = GetAreaFlagByMapId(i_id); @@ -1240,6 +1640,11 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const case 856: // The Noxious Glade (Eastern Plaguelands) case 2456: // Death's Breach (Eastern Plaguelands) if(z > 350.0f) areaflag = 1950; break; + // Dalaran + case 1593: + case 2484: + case 2492: + if( (x < 6116 && x > 5568) && (y < 982 && y > 282) && z > 563.0f) areaflag = 2153; break; } return areaflag; @@ -1247,49 +1652,29 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const uint8 Map::GetTerrainType(float x, float y ) const { - //local x,y coords - float lx,ly; - int gx,gy; - - // half opt method - gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x - gy=(int)(32-y/SIZE_OF_GRIDS); //grid y - - lx=16*(32 -x/SIZE_OF_GRIDS - gx); - ly=16*(32 -y/SIZE_OF_GRIDS - gy); - - // ensure GridMap is loaded - const_cast(this)->EnsureGridCreated(GridPair(63-gx,63-gy)); - - if(GridMaps[gx][gy]) - return GridMaps[gx][gy]->terrain_type[(int)(lx)][(int)(ly)]; + if(GridMap *gmap = const_cast(this)->GetGrid(x, y)) + return gmap->getTerrainType(x, y); else return 0; } +ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data) const +{ + if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) + return gmap->getLiquidStatus(x, y, z, ReqLiquidType, data); + else + return LIQUID_MAP_NO_WATER; +} + float Map::GetWaterLevel(float x, float y ) const { - //local x,y coords - float lx,ly; - int gx,gy; - - // half opt method - gx=(int)(32-x/SIZE_OF_GRIDS) ; //grid x - gy=(int)(32-y/SIZE_OF_GRIDS); //grid y - - lx=128*(32 -x/SIZE_OF_GRIDS - gx); - ly=128*(32 -y/SIZE_OF_GRIDS - gy); - - // ensure GridMap is loaded - const_cast(this)->EnsureGridCreated(GridPair(63-gx,63-gy)); - - if(GridMaps[gx][gy]) - return GridMaps[gx][gy]->liquid_level[(int)(lx)][(int)(ly)]; + if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) + return gmap->getLiquidLevel(x, y); else return 0; } -uint32 Map::GetAreaId(uint16 areaflag,uint32 map_id) +uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id) { AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); @@ -1299,7 +1684,7 @@ uint32 Map::GetAreaId(uint16 areaflag,uint32 map_id) return 0; } -uint32 Map::GetZoneId(uint16 areaflag,uint32 map_id) +uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id) { AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); @@ -1309,26 +1694,37 @@ uint32 Map::GetZoneId(uint16 areaflag,uint32 map_id) return 0; } +void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id) +{ + AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); + + areaid = entry ? entry->ID : 0; + zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0; +} + bool Map::IsInWater(float x, float y, float pZ) const { - // This method is called too often to use vamps for that (4. parameter = false). - // The pZ pos is taken anyway for future use - float z = GetHeight(x,y,pZ,false); // use .map base surface height - - // underground or instance without vmap - if(z <= INVALID_HEIGHT) - return false; - - float water_z = GetWaterLevel(x,y); - uint8 flag = GetTerrainType(x,y); - return (z < (water_z-2)) && (flag & 0x01); + // Check surface in x, y point for liquid + if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + { + LiquidData liquid_status; + if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status)) + { + if (liquid_status.level - liquid_status.depth_level > 2) + return true; + } + } + return false; } bool Map::IsUnderWater(float x, float y, float z) const { - float water_z = GetWaterLevel(x,y); - uint8 flag = GetTerrainType(x,y); - return (z < (water_z-2)) && (flag & 0x01); + if (GridMap* gmap = const_cast(this)->GetGrid(x, y)) + { + if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER) + return true; + } + return false; } bool Map::CheckGridIntegrity(Creature* c, bool moved) const @@ -1817,7 +2213,6 @@ bool InstanceMap::Add(Player *player) // first player enters (no players yet) SetResetSchedule(false); - player->SendInitWorldStates(); sLog.outDetail("MAP: Player '%s' entered the instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName()); // initialize unload state m_unloadTimer = 0; @@ -1933,7 +2328,7 @@ void InstanceMap::PermBindAllPlayers(Player *player) InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); if(!save) { - sLog.outError("Cannot bind players, no instance save available for map!\n"); + sLog.outError("Cannot bind players, no instance save available for map!"); return; } diff --git a/src/game/Map.h b/src/game/Map.h index 80f042674..b40a46a4a 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -68,14 +68,135 @@ typedef RGuard GridReadGuard; typedef WGuard GridWriteGuard; typedef MaNGOS::SingleThreaded::Lock NullGuard; -typedef struct +//****************************************** +// Map file format defines +//****************************************** +#define MAP_MAGIC 'SPAM' +#define MAP_VERSION_MAGIC '0.1w' +#define MAP_AREA_MAGIC 'AERA' +#define MAP_HEIGTH_MAGIC 'TGHM' +#define MAP_LIQUID_MAGIC 'QILM' + +struct map_fileheader{ + uint32 mapMagic; + uint32 versionMagic; + uint32 areaMapOffset; + uint32 areaMapSize; + uint32 heightMapOffset; + uint32 heightMapSize; + uint32 liquidMapOffset; + uint32 liquidMapSize; +}; + +#define MAP_AREA_NO_AREA 0x0001 +struct map_areaHeader{ + uint32 fourcc; + uint16 flags; + uint16 gridArea; +}; + +#define MAP_HEIGHT_NO_HIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 + +struct map_heightHeader{ + uint32 fourcc; + uint32 flags; + float gridHeight; + float gridMaxHeight; +}; + +#define MAP_LIQUID_NO_TYPE 0x0001 +#define MAP_LIQUID_NO_HIGHT 0x0002 +struct map_liquidHeader{ + uint32 fourcc; + uint16 flags; + uint16 liquidType; + uint8 offsetX; + uint8 offsetY; + uint8 width; + uint8 height; + float liquidLevel; +}; + +enum ZLiquidStatus{ + LIQUID_MAP_NO_WATER = 0x00000000, + LIQUID_MAP_ABOVE_WATER = 0x00000001, + LIQUID_MAP_WATER_WALK = 0x00000002, + LIQUID_MAP_IN_WATER = 0x00000004, + LIQUID_MAP_UNDER_WATER = 0x00000008 +}; + +#define MAP_LIQUID_TYPE_NO_WATER 0x00 +#define MAP_LIQUID_TYPE_WATER 0x01 +#define MAP_LIQUID_TYPE_OCEAN 0x02 +#define MAP_LIQUID_TYPE_MAGMA 0x04 +#define MAP_LIQUID_TYPE_SLIME 0x08 + +#define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME) + +#define MAP_LIQUID_TYPE_DARK_WATER 0x10 +#define MAP_LIQUID_TYPE_WMO_WATER 0x20 + +struct LiquidData{ + uint32 type; + float level; + float depth_level; +}; + +class GridMap { - uint16 area_flag[16][16]; - uint8 terrain_type[16][16]; - float liquid_level[128][128]; - float v9[MAP_RESOLUTION + 1][MAP_RESOLUTION + 1]; - float v8[MAP_RESOLUTION][MAP_RESOLUTION]; -}GridMap; + uint32 m_flags; + // Area data + uint16 m_gridArea; + uint16 *m_area_map; + // Height level data + float m_gridHeight; + float m_gridIntHeightMultiplier; + union{ + float *m_V9; + uint16 *m_uint16_V9; + uint8 *m_uint8_V9; + }; + union{ + float *m_V8; + uint16 *m_uint16_V8; + uint8 *m_uint8_V8; + }; + // Liquid data + uint16 m_liquidType; + uint8 m_liquid_offX; + uint8 m_liquid_offY; + uint8 m_liquid_width; + uint8 m_liquid_height; + float m_liquidLevel; + uint8 *m_liquid_type; + float *m_liquid_map; + + bool loadAreaData(FILE *in, uint32 offset, uint32 size); + bool loadHeihgtData(FILE *in, uint32 offset, uint32 size); + bool loadLiquidData(FILE *in, uint32 offset, uint32 size); + + // Get height functions and pointers + typedef float (GridMap::*pGetHeightPtr) (float x, float y) const; + pGetHeightPtr m_gridGetHeight; + float getHeightFromFloat(float x, float y) const; + float getHeightFromUint16(float x, float y) const; + float getHeightFromUint8(float x, float y) const; + float getHeightFromFlat(float x, float y) const; + +public: + GridMap(); + ~GridMap(); + bool loadData(char *filaname); + void unloadData(); + + uint16 getArea(float x, float y); + inline float getHeight(float x, float y) {return (this->*m_gridGetHeight)(x, y);} + float getLiquidLevel(float x, float y); + uint8 getTerrainType(float x, float y); + ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0); +}; struct CreatureMover { @@ -190,22 +311,30 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj float GetHeight(float x, float y, float z, bool pCheckVMap=true) const; bool IsInWater(float x, float y, float z) const; // does not use z pos. This is for future use + ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0) const; + uint16 GetAreaFlag(float x, float y, float z) const; uint8 GetTerrainType(float x, float y ) const; float GetWaterLevel(float x, float y ) const; bool IsUnderWater(float x, float y, float z) const; - static uint32 GetAreaId(uint16 areaflag,uint32 map_id); - static uint32 GetZoneId(uint16 areaflag,uint32 map_id); + static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id); + static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id); + static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag,uint32 map_id); uint32 GetAreaId(float x, float y, float z) const { - return GetAreaId(GetAreaFlag(x,y,z),i_id); + return GetAreaIdByAreaFlag(GetAreaFlag(x,y,z),i_id); } uint32 GetZoneId(float x, float y, float z) const { - return GetZoneId(GetAreaFlag(x,y,z),i_id); + return GetZoneIdByAreaFlag(GetAreaFlag(x,y,z),i_id); + } + + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const + { + GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(x,y,z),i_id); } virtual void MoveAllCreaturesInMoveList(); @@ -277,6 +406,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj private: void LoadVMap(int pX, int pY); void LoadMap(uint32 mapid, uint32 instanceid, int x,int y); + GridMap *GetGrid(float x, float y); void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } //uint64 CalculateGridMask(const uint32 &y) const; diff --git a/src/game/MapManager.h b/src/game/MapManager.h index 677c26120..24fb222c4 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -50,8 +50,18 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::SingletonGetAreaFlag(x, y, z); } - uint32 GetAreaId(uint32 mapid, float x, float y, float z) const { return Map::GetAreaId(GetAreaFlag(mapid, x, y, z),mapid); } - uint32 GetZoneId(uint32 mapid, float x, float y, float z) const { return Map::GetZoneId(GetAreaFlag(mapid, x, y, z),mapid); } + uint32 GetAreaId(uint32 mapid, float x, float y, float z) const + { + return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); + } + uint32 GetZoneId(uint32 mapid, float x, float y, float z) const + { + return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z),mapid); + } + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) + { + Map::GetZoneAndAreaIdByAreaFlag(zoneid,areaid,GetAreaFlag(mapid, x, y, z),mapid); + } void Initialize(void); void Update(uint32); diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index d069929f6..172d4bd49 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -34,11 +34,9 @@ #include "Chat.h" #include "ScriptCalls.h" #include -#include "MapManager.h" #include "ObjectAccessor.h" #include "Object.h" #include "BattleGround.h" -#include "SpellAuras.h" #include "Pet.h" #include "SocialMgr.h" @@ -386,10 +384,10 @@ void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data ) sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone); - if(newZone != _player->GetZoneId()) - GetPlayer()->SendInitWorldStates(); // only if really enters to new zone, not just area change, works strange... - - GetPlayer()->UpdateZone(newZone); + // use server size data + uint32 newzone, newarea; + GetPlayer()->GetZoneAndAreaId(newzone,newarea); + GetPlayer()->UpdateZone(newzone,newarea); } void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data ) @@ -859,8 +857,16 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) } uint32 missingQuest = 0; - if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest)) - missingQuest = at->requiredQuest; + if(GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC) + { + if (at->requiredQuestHeroic && !GetPlayer()->GetQuestRewardStatus(at->requiredQuestHeroic)) + missingQuest = at->requiredQuestHeroic; + } + else + { + if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest)) + missingQuest = at->requiredQuest; + } if(missingLevel || missingItem || missingKey || missingQuest) { diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index ef7fee4df..147b920a7 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -21,9 +21,9 @@ #include "WorldSession.h" #include "Opcodes.h" #include "Log.h" -#include "World.h" #include "Corpse.h" #include "Player.h" +#include "Vehicle.h" #include "MapManager.h" #include "Transports.h" #include "BattleGround.h" diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index d762b9a77..65163b924 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -23,17 +23,14 @@ #include "WorldSession.h" #include "Opcodes.h" #include "Log.h" -#include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" #include "Player.h" #include "GossipDef.h" -#include "SpellAuras.h" #include "UpdateMask.h" #include "ScriptCalls.h" #include "ObjectAccessor.h" #include "Creature.h" -#include "MapManager.h" #include "Pet.h" #include "BattleGroundMgr.h" #include "BattleGround.h" @@ -436,11 +433,12 @@ void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) void WorldSession::SendBindPoint(Creature *npc) { uint32 bindspell = 3286; + uint32 zone_id = _player->GetZoneId(); // update sql homebind - CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), _player->GetZoneId(), _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow()); + CharacterDatabase.PExecute("UPDATE character_homebind SET map = '%u', zone = '%u', position_x = '%f', position_y = '%f', position_z = '%f' WHERE guid = '%u'", _player->GetMapId(), zone_id, _player->GetPositionX(), _player->GetPositionY(), _player->GetPositionZ(), _player->GetGUIDLow()); _player->m_homebindMapId = _player->GetMapId(); - _player->m_homebindZoneId = _player->GetZoneId(); + _player->m_homebindZoneId = zone_id; _player->m_homebindX = _player->GetPositionX(); _player->m_homebindY = _player->GetPositionY(); _player->m_homebindZ = _player->GetPositionZ(); @@ -459,19 +457,19 @@ void WorldSession::SendBindPoint(Creature *npc) data << float(_player->GetPositionY()); data << float(_player->GetPositionZ()); data << uint32(_player->GetMapId()); - data << uint32(_player->GetZoneId()); + data << uint32(zone_id); SendPacket( &data ); DEBUG_LOG("New Home Position X is %f",_player->GetPositionX()); DEBUG_LOG("New Home Position Y is %f",_player->GetPositionY()); DEBUG_LOG("New Home Position Z is %f",_player->GetPositionZ()); DEBUG_LOG("New Home MapId is %u",_player->GetMapId()); - DEBUG_LOG("New Home ZoneId is %u",_player->GetZoneId()); + DEBUG_LOG("New Home ZoneId is %u",zone_id); // zone update data.Initialize( SMSG_PLAYERBOUND, 8+4 ); data << uint64(_player->GetGUID()); - data << uint32(_player->GetZoneId()); + data << uint32(zone_id); SendPacket( &data ); _player->PlayerTalkClass->CloseGossip(); diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 288d5a7eb..271c15f0f 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -25,8 +25,8 @@ #include "Object.h" #include "Creature.h" #include "Player.h" +#include "Vehicle.h" #include "ObjectMgr.h" -#include "WorldSession.h" #include "UpdateData.h" #include "UpdateMask.h" #include "Util.h" @@ -1096,6 +1096,11 @@ uint32 WorldObject::GetAreaId() const return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY,m_positionZ); } +void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const +{ + MapManager::Instance().GetBaseMap(m_mapId)->GetZoneAndAreaId(zoneid,areaid,m_positionX,m_positionY,m_positionZ); +} + InstanceData* WorldObject::GetInstanceData() { Map *map = GetMap(); diff --git a/src/game/Object.h b/src/game/Object.h index 1fab62410..2b74a1a30 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -414,6 +414,7 @@ class MANGOS_DLL_SPEC WorldObject : public Object uint32 GetZoneId() const; uint32 GetAreaId() const; + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const; InstanceData* GetInstanceData(); diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 8359bd2b9..25dcffd44 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -23,8 +23,7 @@ #include "Creature.h" #include "GameObject.h" #include "DynamicObject.h" -#include "Corpse.h" -#include "WorldSession.h" +#include "Vehicle.h" #include "WorldPacket.h" #include "Item.h" #include "Corpse.h" @@ -409,7 +408,7 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia) return NULL; } - DEBUG_LOG("Deleting Corpse and spawning bones.\n"); + DEBUG_LOG("Deleting Corpse and spawning bones."); // remove corpse from player_guid -> corpse map RemoveCorpse(corpse); diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 77ffb3d60..270a27e9b 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -31,7 +31,6 @@ #include "GridDefines.h" #include "Object.h" #include "Player.h" -#include "Vehicle.h" #include @@ -40,6 +39,7 @@ class Corpse; class Unit; class GameObject; class DynamicObject; +class Vehicle; class WorldObject; class Map; diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index 04a343d36..de73ee183 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -19,7 +19,6 @@ #include "ObjectGridLoader.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" -#include "MapManager.h" #include "Creature.h" #include "GameObject.h" #include "DynamicObject.h" diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 167e6c69c..24253e6ff 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -28,14 +28,13 @@ #include "SpellMgr.h" #include "UpdateMask.h" #include "World.h" -#include "WorldSession.h" #include "Group.h" #include "Guild.h" #include "ArenaTeam.h" #include "Transports.h" #include "ProgressBar.h" #include "Language.h" -#include "GameEvent.h" +#include "GameEventMgr.h" #include "Spell.h" #include "Chat.h" #include "AccountMgr.h" @@ -43,7 +42,6 @@ #include "SpellAuras.h" #include "Util.h" #include "WaypointManager.h" -#include "BattleGround.h" INSTANTIATE_SINGLETON_1(ObjectMgr); @@ -1767,7 +1765,10 @@ void ObjectMgr::LoadPetLevelInfo() if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum sLog.outErrorDb("Wrong (> %u) level %u in `pet_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); else + { sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `pet_levelstats` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } continue; } else if(current_level < 1) @@ -2146,7 +2147,10 @@ void ObjectMgr::LoadPlayerInfo() if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum sLog.outErrorDb("Wrong (> %u) level %u in `player_classlevelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); else + { sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } continue; } @@ -2241,7 +2245,10 @@ void ObjectMgr::LoadPlayerInfo() if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum sLog.outErrorDb("Wrong (> %u) level %u in `player_levelstats` table, ignoring.",STRONG_MAX_LEVEL,current_level); else + { sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_levelstats` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } continue; } @@ -2349,7 +2356,10 @@ void ObjectMgr::LoadPlayerInfo() if(current_level > STRONG_MAX_LEVEL) // hardcoded level maximum sLog.outErrorDb("Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL,current_level); else + { sLog.outDetail("Unused (> MaxPlayerLevel in mangosd.conf) level %u in `player_xp_for_levels` table, ignoring.",current_level); + ++count; // make result loading percent "expected" correct in case disabled detail mode for example. + } continue; } //PlayerXPperLevel @@ -3273,14 +3283,15 @@ void ObjectMgr::LoadQuests() if(qinfo->NextQuestInChain) { - if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end()) + QuestMap::iterator qNextItr = mQuestTemplates.find(qinfo->NextQuestInChain); + if(qNextItr == mQuestTemplates.end()) { sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain ); qinfo->NextQuestInChain = 0; } else - mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId()); + qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId()); } // fill additional data stores @@ -3298,14 +3309,15 @@ void ObjectMgr::LoadQuests() if(qinfo->NextQuestId) { - if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end()) + QuestMap::iterator qNextItr = mQuestTemplates.find(abs(qinfo->GetNextQuestId())); + if (qNextItr == mQuestTemplates.end()) { sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId()); } else { int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId()); - mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId); + qNextItr->second->prevQuests.push_back(signedQuestId); } } @@ -4850,8 +4862,8 @@ void ObjectMgr::LoadAreaTriggerTeleports() uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_quest_done_heroic, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport"); if( !result ) { @@ -4878,18 +4890,19 @@ void ObjectMgr::LoadAreaTriggerTeleports() AreaTrigger at; - at.requiredLevel = fields[1].GetUInt8(); - at.requiredItem = fields[2].GetUInt32(); - at.requiredItem2 = fields[3].GetUInt32(); - at.heroicKey = fields[4].GetUInt32(); - at.heroicKey2 = fields[5].GetUInt32(); - at.requiredQuest = fields[6].GetUInt32(); - at.requiredFailedText = fields[7].GetCppString(); - at.target_mapId = fields[8].GetUInt32(); - at.target_X = fields[9].GetFloat(); - at.target_Y = fields[10].GetFloat(); - at.target_Z = fields[11].GetFloat(); - at.target_Orientation = fields[12].GetFloat(); + at.requiredLevel = fields[1].GetUInt8(); + at.requiredItem = fields[2].GetUInt32(); + at.requiredItem2 = fields[3].GetUInt32(); + at.heroicKey = fields[4].GetUInt32(); + at.heroicKey2 = fields[5].GetUInt32(); + at.requiredQuest = fields[6].GetUInt32(); + at.requiredQuestHeroic = fields[7].GetUInt32(); + at.requiredFailedText = fields[8].GetCppString(); + at.target_mapId = fields[9].GetUInt32(); + at.target_X = fields[10].GetFloat(); + at.target_Y = fields[11].GetFloat(); + at.target_Z = fields[12].GetFloat(); + at.target_Orientation = fields[13].GetFloat(); AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID); if(!atEntry) @@ -4939,13 +4952,24 @@ void ObjectMgr::LoadAreaTriggerTeleports() if(at.requiredQuest) { - if(!mQuestTemplates[at.requiredQuest]) + QuestMap::iterator qReqItr = mQuestTemplates.find(at.requiredQuest); + if(qReqItr == mQuestTemplates.end()) { sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID); at.requiredQuest = 0; } } + if(at.requiredQuestHeroic) + { + QuestMap::iterator qReqItr = mQuestTemplates.find(at.requiredQuestHeroic); + if(qReqItr == mQuestTemplates.end()) + { + sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuestHeroic,Trigger_ID); + at.requiredQuestHeroic = 0; + } + } + MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId); if(!mapEntry) { @@ -6692,7 +6716,7 @@ bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 val } case CONDITION_ACTIVE_EVENT: { - GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap(); + GameEventMgr::GameEventDataMap const& events = gameeventmgr.GetEventMap(); if(value1 >=events.size() || !events[value1].isValid()) { sLog.outErrorDb("Active event condition requires existed event id (%u), skipped", value1); diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 8fda417b6..88dc20c59 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -103,6 +103,7 @@ struct AreaTrigger uint32 heroicKey; uint32 heroicKey2; uint32 requiredQuest; + uint32 requiredQuestHeroic; std::string requiredFailedText; uint32 target_mapId; float target_X; diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 7cf205f67..7ae39ebb3 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -19,12 +19,10 @@ #include "Common.h" #include "Database/DatabaseEnv.h" #include "Log.h" -#include "WorldSession.h" #include "WorldPacket.h" #include "ObjectMgr.h" #include "SpellMgr.h" #include "Pet.h" -#include "MapManager.h" #include "Formulas.h" #include "SpellAuras.h" #include "CreatureAI.h" diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 15adc88a5..02f371c35 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -19,18 +19,15 @@ #include "Common.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" #include "Log.h" #include "Opcodes.h" #include "Spell.h" #include "ObjectAccessor.h" -#include "MapManager.h" #include "CreatureAI.h" #include "Util.h" #include "Pet.h" -#include "Language.h" void WorldSession::HandlePetAction( WorldPacket & recv_data ) { @@ -47,16 +44,16 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) // used also for charmed creature Unit* pet= ObjectAccessor::GetUnit(*_player, guid1); - sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.\n", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) ); + sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) ); if(!pet) { - sLog.outError( "Pet %u not exist.\n", uint32(GUID_LOPART(guid1)) ); + sLog.outError( "Pet %u not exist.", uint32(GUID_LOPART(guid1)) ); return; } if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm()) { - sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.\n", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() ); + sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName() ); return; } @@ -146,7 +143,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) _player->Uncharm(); break; default: - sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid); + sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid); } break; case ACT_REACTION: // 0x600 @@ -174,7 +171,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid ); if(!spellInfo) { - sLog.outError("WORLD: unknown PET spell id %i\n", spellid); + sLog.outError("WORLD: unknown PET spell id %i", spellid); return; } @@ -264,7 +261,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) break; } default: - sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid); + sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid); } } @@ -272,7 +269,7 @@ void WorldSession::HandlePetNameQuery( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data,4+8); - sLog.outDetail( "HandlePetNameQuery. CMSG_PET_NAME_QUERY\n" ); + sLog.outDetail( "HandlePetNameQuery. CMSG_PET_NAME_QUERY" ); uint32 petnumber; uint64 petguid; @@ -312,7 +309,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 8+4+2+2); - sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION\n" ); + sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION" ); uint64 petguid; uint32 position; @@ -331,7 +328,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm())) { - sLog.outError( "HandlePetSetAction: Unknown pet or pet owner.\n" ); + sLog.outError( "HandlePetSetAction: Unknown pet or pet owner." ); return; } @@ -349,7 +346,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) recv_data >> spell_id; recv_data >> act_state; - sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X\n", _player->GetName(), position, spell_id, act_state); + sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state); //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) @@ -381,7 +378,7 @@ void WorldSession::HandlePetRename( WorldPacket & recv_data ) { CHECK_PACKET_SIZE(recv_data, 8+1); - sLog.outDetail( "HandlePetRename. CMSG_PET_RENAME\n" ); + sLog.outDetail( "HandlePetRename. CMSG_PET_RENAME" ); uint64 petguid; uint8 isdeclined; @@ -499,7 +496,7 @@ void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket) if(guid != pet->GetGUID()) { - sLog.outError( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); + sLog.outError( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); return; } @@ -534,7 +531,7 @@ void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket ) if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm())) { - sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); + sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); return; } @@ -586,7 +583,7 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) if(!pet || (pet != _player->GetPet() && pet!= _player->GetCharm())) { - sLog.outError( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); + sLog.outError( "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() ); return; } @@ -596,7 +593,7 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid); if(!spellInfo) { - sLog.outError("WORLD: unknown PET spell id %i\n", spellid); + sLog.outError("WORLD: unknown PET spell id %i", spellid); return; } diff --git a/src/game/PetitionsHandler.cpp b/src/game/PetitionsHandler.cpp index 181c0556a..a3d50441f 100644 --- a/src/game/PetitionsHandler.cpp +++ b/src/game/PetitionsHandler.cpp @@ -26,7 +26,6 @@ #include "Opcodes.h" #include "Guild.h" #include "ArenaTeam.h" -#include "MapManager.h" #include "GossipDef.h" #include "SocialMgr.h" @@ -825,7 +824,7 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) if(type == 9) // create guild { Guild* guild = new Guild; - if(!guild->create(_player->GetGUID(), name)) + if(!guild->create(_player, name)) { delete guild; delete result; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 5dd08d383..1c54a9799 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -21,13 +21,13 @@ #include "Database/DatabaseEnv.h" #include "Log.h" #include "Opcodes.h" -#include "ObjectMgr.h" #include "SpellMgr.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" #include "UpdateMask.h" #include "Player.h" +#include "Vehicle.h" #include "SkillDiscovery.h" #include "QuestDef.h" #include "GossipDef.h" @@ -47,7 +47,6 @@ #include "Group.h" #include "Guild.h" #include "Pet.h" -#include "SpellAuras.h" #include "Util.h" #include "Transports.h" #include "Weather.h" @@ -348,8 +347,11 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this) m_regenTimer = 0; m_weaponChangeTimer = 0; - m_breathTimer = 0; - m_isunderwater = UNDERWATER_NONE; + for (int i=0; iSendPacket(&data); -} - -void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen) -{ - if(Type==BREATH_TIMER) - m_breathTimer = ((MaxValue + 1*IN_MILISECONDS) - CurrentValue) / Regen; - + if (MaxValue == DISABLED_MIRROR_TIMER) + { + if (CurrentValue!=DISABLED_MIRROR_TIMER) + StopMirrorTimer(Type); + return; + } WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); data << (uint32)Type; data << CurrentValue; @@ -825,9 +816,7 @@ void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 Cur void Player::StopMirrorTimer(MirrorTimerType Type) { - if(Type==BREATH_TIMER) - m_breathTimer = 0; - + m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER; WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4); data << (uint32)Type; GetSession()->SendPacket( &data ); @@ -838,12 +827,22 @@ void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 da if(!isAlive() || isGameMaster()) return; + // Absorb, resist some environmental damage type + uint32 absorb = 0; + uint32 resist = 0; + if (type == DAMAGE_LAVA) + CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist); + else if (type == DAMAGE_SLIME) + CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist); + + damage-=absorb+resist; + WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); data << (uint64)guid; data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL); data << (uint32)damage; - data << (uint32)0; - data << (uint32)0; + data << (uint32)absorb; // absorb + data << (uint32)resist; // resist SendMessageToSet(&data, true); DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); @@ -863,96 +862,153 @@ void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 da } } -void Player::HandleDrowning() +int32 Player::getMaxTimer(MirrorTimerType timer) { - if(!(m_isunderwater&~UNDERWATER_INLAVA)) - return; - - //if player is GM, have waterbreath, is dead or if breathing is disabled then return - if(isGameMaster() || !isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING)) + switch (timer) { - StopMirrorTimer(BREATH_TIMER); - // drop every flag _except_ LAVA - otherwise waterbreathing will prevent lava damage - m_isunderwater &= UNDERWATER_INLAVA; - return; - } - - uint32 UnderWaterTime = 3*MINUTE*IN_MILISECONDS; // default duration - - AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING); - for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) - UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f); - - if ((m_isunderwater & UNDERWATER_INWATER) && !(m_isunderwater & UNDERWATER_INLAVA) && isAlive()) - { - //single trigger timer - if (!(m_isunderwater & UNDERWATER_WATER_TRIGGER)) + case FATIGUE_TIMER: + return MINUTE*IN_MILISECONDS; + case BREATH_TIMER: { - m_isunderwater|= UNDERWATER_WATER_TRIGGER; - m_breathTimer = UnderWaterTime + 1*IN_MILISECONDS; + if (!isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING)) + return DISABLED_MIRROR_TIMER; + int32 UnderWaterTime = 3*MINUTE*IN_MILISECONDS; + AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING); + for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) + UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f); + return UnderWaterTime; } - //single trigger "show Breathbar" - if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & UNDERWATER_WATER_BREATHB)) + case FIRE_TIMER: { - m_isunderwater|= UNDERWATER_WATER_BREATHB; - StartMirrorTimer(BREATH_TIMER, UnderWaterTime); - } - //continuous trigger drowning "Damage" - if ((m_breathTimer == 0) && (m_isunderwater & UNDERWATER_INWATER)) - { - //TODO: Check this formula - uint64 guid = GetGUID(); - uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); - - EnvironmentalDamage(guid, DAMAGE_DROWNING,damage); - m_breathTimer = 2000; + if (!isAlive()) + return DISABLED_MIRROR_TIMER; + return 1*IN_MILISECONDS; } + default: + return 0; } - //single trigger retract bar - else if (!(m_isunderwater & UNDERWATER_INWATER) && (m_isunderwater & UNDERWATER_WATER_TRIGGER) && (m_breathTimer > 0) && isAlive()) - { - uint32 BreathRegen = 10; - // m_breathTimer will be reduced in ModifyMirrorTimer - ModifyMirrorTimer(BREATH_TIMER, UnderWaterTime, m_breathTimer,BreathRegen); - m_isunderwater = UNDERWATER_WATER_BREATHB_RETRACTING; - } - //remove bar - else if ((m_breathTimer < 50) && !(m_isunderwater & UNDERWATER_INWATER) && (m_isunderwater == UNDERWATER_WATER_BREATHB_RETRACTING)) - { - StopMirrorTimer(BREATH_TIMER); - m_isunderwater = UNDERWATER_NONE; - } + return 0; } -void Player::HandleLava() +void Player::UpdateMirrorTimers() { - if ((m_isunderwater & UNDERWATER_INLAVA) && isAlive()) + // Desync flags for update on next HandleDrowning + if (m_MirrorTimerFlags) + m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags; +} + +void Player::HandleDrowning(uint32 time_diff) +{ + if (!m_MirrorTimerFlags) + return; + + // In water + if (m_MirrorTimerFlags & UNDERWATER_INWATER) { - /* - * arrai: how is this supposed to work? UNDERWATER_INLAVA is always set in this scope! - // Single trigger Set BreathTimer - if (!(m_isunderwater & UNDERWATER_INLAVA)) + // Breath timer not activated - activate it + if (m_MirrorTimer[BREATH_TIMER] == DISABLED_MIRROR_TIMER) { - m_isunderwater|= UNDERWATER_WATER_BREATHB; - m_breathTimer = 1*IN_MILISECONDS; + m_MirrorTimer[BREATH_TIMER] = getMaxTimer(BREATH_TIMER); + SendMirrorTimer(BREATH_TIMER, m_MirrorTimer[BREATH_TIMER], m_MirrorTimer[BREATH_TIMER], -1); } - */ - // Reset BreathTimer and still in the lava - if (!m_breathTimer) + else // If activated - do tick { - uint64 guid = GetGUID(); - uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage - - EnvironmentalDamage(guid, DAMAGE_LAVA, damage); - - m_breathTimer = 1*IN_MILISECONDS; + m_MirrorTimer[BREATH_TIMER]-=time_diff; + // Timer limit - need deal damage + if (m_MirrorTimer[BREATH_TIMER] < 0) + { + m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILISECONDS; + // Calculate and deal damage + // TODO: Check this formula + uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); + EnvironmentalDamage(GetGUID(), DAMAGE_DROWNING, damage); + } + else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need + SendMirrorTimer(BREATH_TIMER, getMaxTimer(BREATH_TIMER), m_MirrorTimer[BREATH_TIMER], -1); } } - else if (!isAlive()) // Disable breath timer and reset underwater flags + else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer { - m_breathTimer = 0; - m_isunderwater = UNDERWATER_NONE; + int32 UnderWaterTime = getMaxTimer(BREATH_TIMER); + // Need breath regen + m_MirrorTimer[BREATH_TIMER]+=10*time_diff; + if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !isAlive()) + StopMirrorTimer(BREATH_TIMER); + else if (m_MirrorTimerFlagsLast & UNDERWATER_INWATER) + SendMirrorTimer(BREATH_TIMER, UnderWaterTime, m_MirrorTimer[BREATH_TIMER], 10); } + + // In dark water + if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER) + { + // Fatigue timer not activated - activate it + if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER) + { + m_MirrorTimer[FATIGUE_TIMER] = getMaxTimer(FATIGUE_TIMER); + SendMirrorTimer(FATIGUE_TIMER, m_MirrorTimer[FATIGUE_TIMER], m_MirrorTimer[FATIGUE_TIMER], -1); + } + else + { + m_MirrorTimer[FATIGUE_TIMER]-=time_diff; + // Timer limit - need deal damage or teleport ghost to graveyard + if (m_MirrorTimer[FATIGUE_TIMER] < 0) + { + m_MirrorTimer[FATIGUE_TIMER]+= 1*IN_MILISECONDS; + if (isAlive()) // Calculate and deal damage + { + uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); + EnvironmentalDamage(GetGUID(), DAMAGE_EXHAUSTED, damage); + } + else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard + RepopAtGraveyard(); + } + else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)) + SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1); + } + } + else if (m_MirrorTimer[FATIGUE_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer + { + int32 DarkWaterTime = getMaxTimer(FATIGUE_TIMER); + m_MirrorTimer[FATIGUE_TIMER]+=10*time_diff; + if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !isAlive()) + StopMirrorTimer(FATIGUE_TIMER); + else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER) + SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10); + } + + if (m_MirrorTimerFlags & (UNDERWATER_INLAVA|UNDERWATER_INSLIME)) + { + // Breath timer not activated - activate it + if (m_MirrorTimer[FIRE_TIMER] == DISABLED_MIRROR_TIMER) + m_MirrorTimer[FIRE_TIMER] = getMaxTimer(FIRE_TIMER); + else + { + m_MirrorTimer[FIRE_TIMER]-=time_diff; + if (m_MirrorTimer[FIRE_TIMER] < 0) + { + m_MirrorTimer[FIRE_TIMER]+= 1*IN_MILISECONDS; + // Calculate and deal damage + // TODO: Check this formula + uint32 damage = urand(600, 700); + if (m_MirrorTimerFlags&UNDERWATER_INLAVA) + EnvironmentalDamage(GetGUID(), DAMAGE_LAVA, damage); + else + EnvironmentalDamage(GetGUID(), DAMAGE_SLIME, damage); + } + } + } + else + m_MirrorTimer[FIRE_TIMER] = DISABLED_MIRROR_TIMER; + + // Recheck timers flag + m_MirrorTimerFlags&=~UNDERWATER_EXIST_TIMERS; + for (int i = 0; i< MAX_TIMERS; ++i) + if (m_MirrorTimer[i]!=DISABLED_MIRROR_TIMER) + { + m_MirrorTimerFlags|=UNDERWATER_EXIST_TIMERS; + break; + } + m_MirrorTimerFlagsLast = m_MirrorTimerFlags; } ///The player sobers by 256 every 10 seconds @@ -1182,14 +1238,15 @@ void Player::Update( uint32 p_time ) { if(p_time >= m_zoneUpdateTimer) { - uint32 newzone = GetZoneId(); + uint32 newzone, newarea; + GetZoneAndAreaId(newzone,newarea); + if( m_zoneUpdateId != newzone ) - UpdateZone(newzone); // also update area + UpdateZone(newzone,newarea); // also update area else { // use area updates as well // needed for free far all arenas for example - uint32 newarea = GetAreaId(); if( m_areaUpdateId != newarea ) UpdateArea(newarea); @@ -1224,21 +1281,8 @@ void Player::Update( uint32 p_time ) } } - //Breathtimer - if(m_breathTimer > 0) - { - if(p_time >= m_breathTimer) - m_breathTimer = 0; - else - m_breathTimer -= p_time; - - } - //Handle Water/drowning - HandleDrowning(); - - //Handle lava - HandleLava(); + HandleDrowning(p_time); //Handle detect stealth players if (m_DetectInvTimer > 0) @@ -1606,16 +1650,19 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati } } + uint32 newzone, newarea; + GetZoneAndAreaId(newzone,newarea); + if(!GetSession()->PlayerLogout()) { // don't reset teleport semaphore while logging out, otherwise m_teleport_dest won't be used in Player::SaveToDB SetSemaphoreTeleport(false); - UpdateZone(GetZoneId()); + UpdateZone(newzone,newarea); } // new zone - if(old_zone != GetZoneId()) + if(old_zone != newzone) { // honorless target if(pvpInfo.inHostileArea) @@ -2070,7 +2117,7 @@ void Player::UninviteFromGroup() group->RemoveInvite(this); - if(group->GetMembersCount() <= 1) // group has just 1 member => disband + if(group->GetMembersCount() <= 1) // group has just 1 member => disband { if(group->IsCreated()) { @@ -3883,7 +3930,9 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) } // trigger update zone for alive state zone updates - UpdateZone(GetZoneId()); + uint32 newzone, newarea; + GetZoneAndAreaId(newzone,newarea); + UpdateZone(newzone,newarea); // update visibility ObjectAccessor::UpdateVisibilityForPlayer(this); @@ -6318,13 +6367,16 @@ void Player::UpdateArea(uint32 newArea) UpdateAreaDependentAuras(newArea); } -void Player::UpdateZone(uint32 newZone) +void Player::UpdateZone(uint32 newZone, uint32 newArea) { + if(m_zoneUpdateId != newZone) + SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange... + m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; // zone changed, so area changed as well, update it - UpdateArea(GetAreaId()); + UpdateArea(newArea); AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone); if(!zone) @@ -7682,15 +7734,15 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value) GetSession()->SendPacket(&data); } -void Player::SendInitWorldStates() +void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) { // data depends on zoneid/mapid... BattleGround* bg = GetBattleGround(); uint16 NumberOfFields = 0; uint32 mapid = GetMapId(); - uint32 zoneid = GetZoneId(); - uint32 areaid = GetAreaId(); + sLog.outDebug("Sending SMSG_INIT_WORLD_STATES to Map:%u, Zone: %u", mapid, zoneid); + // may be exist better way to do this... switch(zoneid) { @@ -12658,8 +12710,8 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver ) SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true); if(saBounds.first != saBounds.second) { - uint32 zone = GetZoneId(); - uint32 area = GetAreaId(); + uint32 zone, area; + GetZoneAndAreaId(zone,area); for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area)) @@ -12873,8 +12925,7 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver SpellAreaForQuestMapBounds saEndBounds = spellmgr.GetSpellAreaForQuestEndMapBounds(quest_id); if(saEndBounds.first != saEndBounds.second) { - uint32 zone = GetZoneId(); - uint32 area = GetAreaId(); + GetZoneAndAreaId(zone,area); for(SpellAreaForAreaMap::const_iterator itr = saEndBounds.first; itr != saEndBounds.second; ++itr) if(!itr->second->IsFitToRequirements(this,zone,area)) @@ -12885,8 +12936,8 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,false); if(saBounds.first != saBounds.second) { - if(!zone) zone = GetZoneId(); - if(!area) area = GetAreaId(); + if(!zone || !area) + GetZoneAndAreaId(zone,area); for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) if(itr->second->autocast && itr->second->IsFitToRequirements(this,zone,area)) @@ -14297,7 +14348,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetBGTeam(bgteam); //join player to battleground group - currentBg->PlayerRelogin(this); + currentBg->EventPlayerLoggedIn(this, GetGUID()); currentBg->AddOrSetPlayerToCorrectBgGroup(this, GetGUID(), bgteam); SetInviteForBattleGroundQueueType(bgQueueTypeId,currentBg->GetInstanceID()); @@ -15635,7 +15686,7 @@ bool Player::_LoadHomeBind(QueryResult *result) CharacterDatabase.PExecute("INSERT INTO character_homebind (guid,map,zone,position_x,position_y,position_z) VALUES ('%u', '%u', '%u', '%f', '%f', '%f')", GetGUIDLow(), m_homebindMapId, (uint32)m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ); } - DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f\n", + DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f", m_homebindMapId, m_homebindZoneId, m_homebindX, m_homebindY, m_homebindZ); return true; @@ -18249,7 +18300,10 @@ void Player::SendInitialPacketsBeforeAddToMap() SendInitialReputations(); SendInitWorldStates(); m_achievementMgr.SendAllAchievementData(); - UpdateZone(GetZoneId()); + + uint32 newzone, newarea; + GetZoneAndAreaId(newzone,newarea); + UpdateZone(newzone,newarea); // also call SendInitWorldStates(); SendEquipmentSetList(); @@ -19297,21 +19351,48 @@ PartyResult Player::CanUninviteFromGroup() const void Player::UpdateUnderwaterState( Map* m, float x, float y, float z ) { - float water_z = m->GetWaterLevel(x,y); - float terrain_z = m->GetHeight(x,y,z, false); // use .map base surface height - uint8 flag1 = m->GetTerrainType(x,y); + LiquidData liquid_status; + ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) + { + m_MirrorTimerFlags &= ~(UNDERWATER_INWATER|UNDERWATER_INLAVA|UNDERWATER_INSLIME|UNDERWARER_INDARKWATER); + // Small hack for enable breath in WMO + if (IsInWater()) + m_MirrorTimerFlags|=UNDERWATER_INWATER; + return; + } - //!Underwater check, not in water if underground or above water level - take UC royal quater for example - if (terrain_z <= INVALID_HEIGHT || z < (terrain_z-2) || z > (water_z - 2) ) - m_isunderwater &= ~UNDERWATER_INWATER; - else if ((z < (water_z - 2)) && (flag1 & 0x01)) - m_isunderwater |= UNDERWATER_INWATER; + // All liquids type - check under water position + if (liquid_status.type&(MAP_LIQUID_TYPE_WATER|MAP_LIQUID_TYPE_OCEAN|MAP_LIQUID_TYPE_MAGMA|MAP_LIQUID_TYPE_SLIME)) + { + if ( res & LIQUID_MAP_UNDER_WATER) + m_MirrorTimerFlags |= UNDERWATER_INWATER; + else + m_MirrorTimerFlags &= ~UNDERWATER_INWATER; + } - //!in lava check, anywhere under lava level - if ((terrain_z <= INVALID_HEIGHT || z < (terrain_z - 0)) && (flag1 == 0x00) && IsInWater()) - m_isunderwater |= UNDERWATER_INLAVA; + // Allow travel in dark water on taxi or transport + if (liquid_status.type & MAP_LIQUID_TYPE_DARK_WATER && !isInFlight() && !(GetUnitMovementFlags()&MOVEMENTFLAG_ONTRANSPORT)) + m_MirrorTimerFlags |= UNDERWARER_INDARKWATER; else - m_isunderwater &= ~UNDERWATER_INLAVA; + m_MirrorTimerFlags &= ~UNDERWARER_INDARKWATER; + + // in lava check, anywhere in lava level + if (liquid_status.type&MAP_LIQUID_TYPE_MAGMA) + { + if (res & (LIQUID_MAP_UNDER_WATER|LIQUID_MAP_IN_WATER|LIQUID_MAP_WATER_WALK)) + m_MirrorTimerFlags |= UNDERWATER_INLAVA; + else + m_MirrorTimerFlags &= ~UNDERWATER_INLAVA; + } + // in slime check, anywhere in slime level + if (liquid_status.type&MAP_LIQUID_TYPE_SLIME) + { + if (res & (LIQUID_MAP_UNDER_WATER|LIQUID_MAP_IN_WATER|LIQUID_MAP_WATER_WALK)) + m_MirrorTimerFlags |= UNDERWATER_INSLIME; + else + m_MirrorTimerFlags &= ~UNDERWATER_INSLIME; + } } void Player::SetCanParry( bool value ) @@ -19341,13 +19422,22 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const return false; } -bool Player::isAllowUseBattleGroundObject() +bool Player::CanUseBattleGroundObject() { return ( //InBattleGround() && // in battleground - not need, check in other cases - !IsMounted() && // not mounted + //!IsMounted() && - not correct, player is dismounted when he clicks on flag !HasStealthAura() && // not stealthed !HasInvisibilityAura() && // not invisible !HasAura(SPELL_RECENTLY_DROPPED_FLAG, 0) && // can't pickup + //TODO player cannot use object when he is invulnerable (immune) - (ice block, divine shield, divine protection, divine intervention ...) + isAlive() // live player + ); +} + +bool Player::CanCaptureTowerPoint() +{ + return ( !HasStealthAura() && // not stealthed + !HasInvisibilityAura() && // not invisible isAlive() // live player ); } @@ -19814,6 +19904,11 @@ void Player::HandleFall(MovementInfo const& movementInfo) } } +void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ ) +{ + GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time); +} + void Player::BuildPlayerTalentsInfoData(WorldPacket *data) { *data << uint32(GetFreeTalentPoints()); // unspentTalentPoints @@ -20356,6 +20451,4 @@ void Player::DeleteEquipmentSet(uint64 setGuid) { itr->second.state = EQUIPMENT_SET_DELETED; break; - } - } } diff --git a/src/game/Player.h b/src/game/Player.h index d3ea09598..0f1fd16d6 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -69,10 +69,11 @@ enum PlayerUnderwaterState { UNDERWATER_NONE = 0x00, UNDERWATER_INWATER = 0x01, // terrain type is water and player is afflicted by it - UNDERWATER_WATER_TRIGGER = 0x02, // m_breathTimer has been initialized - UNDERWATER_WATER_BREATHB = 0x04, // breathbar has been send to client - UNDERWATER_WATER_BREATHB_RETRACTING = 0x10, // breathbar is currently refilling - the player is above water level - UNDERWATER_INLAVA = 0x80 // terrain type is lava and player is afflicted by it + UNDERWATER_INLAVA = 0x02, // terrain type is lava and player is afflicted by it + UNDERWATER_INSLIME = 0x04, // terrain type is lava and player is afflicted by it + UNDERWARER_INDARKWATER = 0x08, // terrain type is dark water and player is afflicted by it + + UNDERWATER_EXIST_TIMERS = 0x10 }; enum PlayerSpellState @@ -502,6 +503,8 @@ enum MirrorTimerType BREATH_TIMER = 1, FIRE_TIMER = 2 }; +#define MAX_TIMERS 3 +#define DISABLED_MIRROR_TIMER -1 // 2^n values enum PlayerExtraFlags @@ -1551,7 +1554,7 @@ class MANGOS_DLL_SPEC Player : public Unit PvPInfo pvpInfo; void UpdatePvP(bool state, bool ovrride=false); - void UpdateZone(uint32 newZone); + void UpdateZone(uint32 newZone,uint32 newArea); void UpdateArea(uint32 newArea); void UpdateZoneDependentAuras( uint32 zone_id ); // zones @@ -1727,6 +1730,7 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 DurabilityRepairAll(bool cost, float discountMod, bool guildBank); uint32 DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank); + void UpdateMirrorTimers(); void StopMirrorTimers() { StopMirrorTimer(FATIGUE_TIMER); @@ -1874,7 +1878,7 @@ class MANGOS_DLL_SPEC Player : public Unit void SetEquipmentSet(uint32 index, EquipmentSet eqset); void DeleteEquipmentSet(uint64 setGuid); - void SendInitWorldStates(); + void SendInitWorldStates(uint32 zone, uint32 area); void SendUpdateWorldState(uint32 Field, uint32 Value); void SendDirectMessage(WorldPacket *data); @@ -1995,7 +1999,8 @@ class MANGOS_DLL_SPEC Player : public Unit void ClearAfkReports() { m_bgAfkReporter.clear(); } bool GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const; - bool isAllowUseBattleGroundObject(); + bool CanUseBattleGroundObject(); + bool CanCaptureTowerPoint(); /*********************************************************/ /*** REST SYSTEM ***/ @@ -2041,8 +2046,6 @@ class MANGOS_DLL_SPEC Player : public Unit bool IsFlying() const { return HasUnitMovementFlag(MOVEMENTFLAG_FLYING); } bool IsAllowUseFlyMountsHere() const; - void HandleDrowning(); - void SetClientControl(Unit* target, uint8 allowMove); void EnterVehicle(Vehicle *vehicle); @@ -2171,6 +2174,7 @@ class MANGOS_DLL_SPEC Player : public Unit void AddRunePower(uint8 index); void InitRunes(); AchievementMgr& GetAchievementMgr() { return m_achievementMgr; } + void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0); bool HasTitle(uint32 bitIndex); bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } void SetTitle(CharTitlesEntry const* title); @@ -2256,12 +2260,14 @@ class MANGOS_DLL_SPEC Player : public Unit /*********************************************************/ /*** ENVIRONMENTAL SYSTEM ***/ /*********************************************************/ - void HandleLava(); void HandleSobering(); - void StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue); - void ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen); + void SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen); void StopMirrorTimer(MirrorTimerType Type); - uint8 m_isunderwater; + void HandleDrowning(uint32 time_diff); + int32 getMaxTimer(MirrorTimerType timer); + int32 m_MirrorTimer[MAX_TIMERS]; + uint8 m_MirrorTimerFlags; + uint8 m_MirrorTimerFlagsLast; bool m_isInWater; /*********************************************************/ @@ -2342,7 +2348,6 @@ class MANGOS_DLL_SPEC Player : public Unit bool m_DailyQuestChanged; time_t m_lastDailyQuestTime; - uint32 m_breathTimer; uint32 m_drunkTimer; uint16 m_drunk; uint32 m_weaponChangeTimer; diff --git a/src/game/PointMovementGenerator.cpp b/src/game/PointMovementGenerator.cpp index 5da26c9bf..fda73463c 100644 --- a/src/game/PointMovementGenerator.cpp +++ b/src/game/PointMovementGenerator.cpp @@ -20,7 +20,6 @@ #include "Errors.h" #include "Creature.h" #include "CreatureAI.h" -#include "MapManager.h" #include "DestinationHolderImp.h" //----- Point Movement Generator diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp index 0f18aee05..bd47c7b6a 100644 --- a/src/game/PoolHandler.cpp +++ b/src/game/PoolHandler.cpp @@ -17,10 +17,8 @@ */ #include "PoolHandler.h" -#include "World.h" #include "ObjectMgr.h" #include "ProgressBar.h" -#include "Language.h" #include "Log.h" #include "MapManager.h" #include "Policies/SingletonImp.h" diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp index 63376a88e..14fb7b443 100644 --- a/src/game/QueryHandler.cpp +++ b/src/game/QueryHandler.cpp @@ -29,7 +29,6 @@ #include "Player.h" #include "UpdateMask.h" #include "NPCHandler.h" -#include "ObjectAccessor.h" #include "Pet.h" #include "MapManager.h" diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index b4c2cfd55..1fb8090d1 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -1594,6 +1594,31 @@ enum CreatureEliteType CREATURE_UNKNOWN = 5 // found in 2.2.3 for 2 mobs }; +// values based at Holidays.dbc +enum HolidayIds +{ + HOLIDAY_FIREWORKS_SPECTACULAR = 62, + HOLIDAY_FEAST_OF_WINTER_VEIL = 141, + HOLIDAY_NOBLEGARDEN = 181, + HOLIDAY_CHILDRENS_WEEK = 201, + HOLIDAY_CALL_TO_ARMS_AV = 283, + HOLIDAY_CALL_TO_ARMS_WG = 284, + HOLIDAY_CALL_TO_ARMS_AB = 285, + HOLIDAY_FISHING_EXTRAVAGANZA = 301, + HOLIDAY_HARVEST_FESTIVAL = 321, + HOLIDAY_HALLOWS_END = 324, + HOLIDAY_LUNAR_FESTIVAL = 327, + HOLIDAY_LOVE_IS_IN_THE_AIR = 335, + HOLIDAY_FIRE_FESTIVAL = 341, + HOLIDAY_CALL_TO_ARMS_ES = 353, + HOLIDAY_BREWFEST = 372, + HOLIDAY_DARKMOON_FAIRE_ELWYNN = 374, + HOLIDAY_DARKMOON_FAIRE_THUNDER = 375, + HOLIDAY_DARKMOON_FAIRE_SHATTRATH = 376, + HOLIDAY_CALL_TO_ARMS_SA = 400, + HOLIDAY_WOTLK_LAUNCH = 406 +}; + // values based at QuestInfo.dbc enum QuestTypes { diff --git a/src/game/SkillDiscovery.cpp b/src/game/SkillDiscovery.cpp index 9e2ba8f6f..242487a38 100644 --- a/src/game/SkillDiscovery.cpp +++ b/src/game/SkillDiscovery.cpp @@ -20,7 +20,6 @@ #include "Log.h" #include "ProgressBar.h" #include "Policies/SingletonImp.h" -#include "ObjectAccessor.h" #include "World.h" #include "Util.h" #include "SkillDiscovery.h" diff --git a/src/game/SkillHandler.cpp b/src/game/SkillHandler.cpp index b2aeac58e..6698529be 100644 --- a/src/game/SkillHandler.cpp +++ b/src/game/SkillHandler.cpp @@ -21,12 +21,10 @@ #include "Opcodes.h" #include "Log.h" #include "Player.h" -#include "World.h" #include "WorldPacket.h" #include "WorldSession.h" #include "ObjectAccessor.h" #include "UpdateMask.h" -#include "SpellAuras.h" void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data ) { diff --git a/src/game/SocialMgr.cpp b/src/game/SocialMgr.cpp index 82cdf2e64..928411192 100644 --- a/src/game/SocialMgr.cpp +++ b/src/game/SocialMgr.cpp @@ -21,7 +21,6 @@ #include "Database/DatabaseEnv.h" #include "Opcodes.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "Player.h" #include "ObjectMgr.h" #include "World.h" diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index d341c80d8..1ce483bfb 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -33,7 +33,6 @@ #include "Unit.h" #include "Spell.h" #include "DynamicObject.h" -#include "SpellAuras.h" #include "Group.h" #include "UpdateData.h" #include "MapManager.h" @@ -2045,7 +2044,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list &TagUnitMap) } } else - sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); + sLog.outError( "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id ); }break; case TARGET_BEHIND_VICTIM: { @@ -3354,7 +3353,7 @@ uint8 Spell::CheckRuneCost(uint32 runeCostID) runeCost[i] = src->RuneCost[i]; } - runeCost[RUNE_DEATH] = 0; // calculated later + runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later for(uint32 i = 0; i < MAX_RUNES; ++i) { @@ -3373,7 +3372,7 @@ uint8 Spell::CheckRuneCost(uint32 runeCostID) } } - if(runeCost[RUNE_DEATH] > 0) + if(runeCost[RUNE_DEATH] > MAX_RUNES) return SPELL_FAILED_NO_POWER; // not sure if result code is correct return 0; @@ -3530,7 +3529,7 @@ void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTar EffectEnchantItemTmp(i); else { - sLog.outError("SPELL: unknown effect %u spell id %u\n", + sLog.outError("SPELL: unknown effect %u spell id %u", eff, m_spellInfo->Id); } } @@ -3756,7 +3755,10 @@ uint8 Spell::CanCast(bool strict) return SPELL_FAILED_NOT_IN_ARENA; // zone check - if (uint8 res= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId(), + uint32 zone, area; + m_caster->GetZoneAndAreaId(zone,area); + + if (uint8 res= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL)) return res; @@ -4108,7 +4110,7 @@ uint8 Spell::CanCast(bool strict) // In BattleGround players can use only flags and banners if( ((Player*)m_caster)->InBattleGround() && - !((Player*)m_caster)->isAllowUseBattleGroundObject() ) + !((Player*)m_caster)->CanUseBattleGroundObject() ) return SPELL_FAILED_TRY_AGAIN; // get the lock entry diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f776a53de..5574408f1 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -29,11 +29,9 @@ #include "Player.h" #include "Unit.h" #include "Spell.h" -#include "SpellAuras.h" #include "DynamicObject.h" #include "Group.h" #include "UpdateData.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "Policies/SingletonImp.h" #include "Totem.h" @@ -2396,8 +2394,8 @@ void Aura::HandleAuraDummy(bool apply, bool Real) SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId()); if(saBounds.first != saBounds.second) { - uint32 zone = m_target->GetZoneId(); - uint32 area = m_target->GetAreaId(); + uint32 zone, area; + m_target->GetZoneAndAreaId(zone,area); for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { @@ -2497,15 +2495,9 @@ void Aura::HandleAuraHover(bool apply, bool Real) void Aura::HandleWaterBreathing(bool apply, bool Real) { - if(!apply && !m_target->HasAuraType(SPELL_AURA_WATER_BREATHING)) - { - // update for enable timer in case not moving target - if(m_target->GetTypeId()==TYPEID_PLAYER && m_target->IsInWorld()) - { - ((Player*)m_target)->UpdateUnderwaterState(m_target->GetMap(),m_target->GetPositionX(),m_target->GetPositionY(),m_target->GetPositionZ()); - ((Player*)m_target)->HandleDrowning(); - } - } + // update timers in client + if(m_target->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_target)->UpdateMirrorTimers(); } void Aura::HandleAuraModShapeshift(bool apply, bool Real) @@ -3115,7 +3107,7 @@ void Aura::HandleModPossessPet(bool apply, bool Real) else pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); - ((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : NULL); + ((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : 0); ((Player*)caster)->SetCharm(apply ? pet : NULL); ((Player*)caster)->SetClientControl(pet, apply ? 1 : 0); @@ -4188,7 +4180,7 @@ void Aura::HandleAuraPeriodicDummy(bool apply, bool Real) { // Explosive Shot if (apply && !loading && caster) - m_modifier.m_amount +=caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 8 / 100; + m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 8 / 100); break; } } @@ -6691,8 +6683,8 @@ void Aura::HandlePhase(bool apply, bool Real) SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId()); if(saBounds.first != saBounds.second) { - uint32 zone = m_target->GetZoneId(); - uint32 area = m_target->GetAreaId(); + uint32 zone, area; + m_target->GetZoneAndAreaId(zone,area); for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 23ddedc2a..d754219d2 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -17,10 +17,8 @@ */ #include "Common.h" -#include "SharedDefines.h" #include "Database/DatabaseEnv.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "Opcodes.h" #include "Log.h" #include "UpdateMask.h" @@ -30,7 +28,6 @@ #include "Player.h" #include "SkillExtraItems.h" #include "Unit.h" -#include "CreatureAI.h" #include "Spell.h" #include "DynamicObject.h" #include "SpellAuras.h" @@ -56,6 +53,7 @@ #include "TemporarySummon.h" #include "ScriptCalls.h" #include "SkillDiscovery.h" +#include "Formulas.h" pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= { @@ -375,7 +373,7 @@ void Spell::EffectSchoolDMG(uint32 effect_idx) damage = uint32(damage * (m_caster->GetTotalAttackPowerValue(BASE_ATTACK)) / 100); } // Shield Slam - else if(m_spellInfo->SpellFamilyFlags & 0x100000000LL) + else if(m_spellInfo->SpellFamilyFlags & 0x0000020000000000LL) damage += int32(m_caster->GetShieldBlockValue()); // Victory Rush else if(m_spellInfo->SpellFamilyFlags & 0x10000000000LL) @@ -595,6 +593,11 @@ void Spell::EffectSchoolDMG(uint32 effect_idx) int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget); damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK); } + // Shield of Righteousness + else if(m_spellInfo->SpellFamilyFlags&0x0010000000000000LL) + { + damage+=int32(m_caster->GetShieldBlockValue()); + } break; } } @@ -808,7 +811,7 @@ void Spell::EffectDummy(uint32 i) creatureTarget->RemoveCorpse(); creatureTarget->SetHealth(0); // just for nice GM-mode view - DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy\n"); + DEBUG_LOG("AddObject at SpellEfects.cpp EffectDummy"); map->Add(pGameObj); WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); @@ -1261,7 +1264,7 @@ void Spell::EffectDummy(uint32 i) if (m_spellInfo->SpellFamilyFlags & 0x0000000000040000LL) { // In 303 exist spirit depend - uint32 spirit = m_caster->GetStat(STAT_SPIRIT); + uint32 spirit = uint32(m_caster->GetStat(STAT_SPIRIT)); switch (m_spellInfo->Id) { case 1454: damage+=spirit; break; @@ -1659,7 +1662,7 @@ void Spell::EffectDummy(uint32 i) if(!spellInfo) { - sLog.outError("WORLD: unknown spell id %i\n", spell_id); + sLog.outError("WORLD: unknown spell id %i", spell_id); return; } @@ -1758,7 +1761,7 @@ void Spell::EffectTriggerSpellWithValue(uint32 i) if(!spellInfo) { - sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id,triggered_spell_id); + sLog.outError("EffectTriggerSpellWithValue of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); return; } @@ -2021,7 +2024,7 @@ void Spell::EffectTeleportUnits(uint32 i) SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); if(!st) { - sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u\n", m_spellInfo->Id ); + sLog.outError( "Spell::EffectTeleportUnits - unknown Teleport coordinates for spell ID %u", m_spellInfo->Id ); return; } ((Player*)unitTarget)->TeleportTo(st->target_mapId,st->target_X,st->target_Y,st->target_Z,st->target_Orientation,unitTarget==m_caster ? TELE_TO_SPELL : 0); @@ -2061,7 +2064,7 @@ void Spell::EffectTeleportUnits(uint32 i) // If not exist data for dest location - return if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) { - sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u\n", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id ); + sLog.outError( "Spell::EffectTeleportUnits - unknown EffectImplicitTargetB[%u] = %u for spell ID %u", i, m_spellInfo->EffectImplicitTargetB[i], m_spellInfo->Id ); return; } // Init dest coordinates @@ -2922,7 +2925,7 @@ void Spell::EffectOpenLock(uint32 /*i*/) if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK ) { - //isAllowUseBattleGroundObject() already called in CanCast() + //CanUseBattleGroundObject() already called in CanCast() // in battleground check if(BattleGround *bg = player->GetBattleGround()) { @@ -2934,7 +2937,7 @@ void Spell::EffectOpenLock(uint32 /*i*/) } else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) { - //isAllowUseBattleGroundObject() already called in CanCast() + //CanUseBattleGroundObject() already called in CanCast() // in battleground check if(BattleGround *bg = player->GetBattleGround()) { @@ -3770,13 +3773,18 @@ void Spell::EffectAddHonor(uint32 /*i*/) if(unitTarget->GetTypeId() != TYPEID_PLAYER) return; - sLog.outDebug("SpellEffect::AddHonor called for spell_id %u , that rewards %d honor points to player: %u", m_spellInfo->Id, damage, ((Player*)unitTarget)->GetGUIDLow()); + uint32 honor_reward = MaNGOS::Honor::hk_honor_at_level(unitTarget->getLevel(), damage); + sLog.outDebug("SpellEffect::AddHonor called for spell_id %u, that rewards %u honor points to player: %u", m_spellInfo->Id, honor_reward, ((Player*)unitTarget)->GetGUIDLow()); - // TODO: find formula for honor reward based on player's level! - - // now fixed only for level 70 players: - if (((Player*)unitTarget)->getLevel() == 70) + // do not allow to add too many honor for player (50 * 21) = 1040 at level 70, or (50 * 31) = 1550 at level 80 + if( damage <= 50 ) + ((Player*)unitTarget)->RewardHonor(NULL, 1, honor_reward); + else + { + //maybe we have correct honor_gain in damage already ((Player*)unitTarget)->RewardHonor(NULL, 1, damage); + sLog.outError("SpellEffect::AddHonor called for spell_id %u, that rewards %d * honor for one honorable kill and it is too much (%u of honor) for player: %u", m_spellInfo->Id, damage, honor_reward, ((Player*)unitTarget)->GetGUIDLow()); + } } void Spell::EffectTradeSkill(uint32 /*i*/) @@ -4774,7 +4782,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) unitTarget->CastSpell(unitTarget, 25863, false); else unitTarget->CastSpell(unitTarget, 26655, false); - break; + return; } // Piccolo of the Flaming Fire case 17512: @@ -4782,7 +4790,14 @@ void Spell::EffectScriptEffect(uint32 effIndex) if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); - break; + return; + } + // Escape artist + case 20589: + { + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); + m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED); + return; } // Mirren's Drinking Hat case 29830: @@ -6297,7 +6312,7 @@ void Spell::EffectTransmitted(uint32 effIndex) pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() ); pGameObj->SetSpellId(m_spellInfo->Id); - DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted\n"); + DEBUG_LOG("AddObject at SpellEfects.cpp EffectTransmitted"); //m_caster->AddGameObject(pGameObj); //m_ObjToDel.push_back(pGameObj); diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 986c39908..89ce47123 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -20,15 +20,11 @@ #include "Database/DBCStores.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" #include "Log.h" #include "Opcodes.h" #include "Spell.h" -#include "SpellAuras.h" -#include "BattleGround.h" -#include "MapManager.h" #include "ScriptCalls.h" #include "Totem.h" diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp index e0a25477f..6f4aa4c73 100644 --- a/src/game/TargetedMovementGenerator.cpp +++ b/src/game/TargetedMovementGenerator.cpp @@ -20,7 +20,6 @@ #include "TargetedMovementGenerator.h" #include "Errors.h" #include "Creature.h" -#include "MapManager.h" #include "DestinationHolderImp.h" #include "World.h" diff --git a/src/game/TaxiHandler.cpp b/src/game/TaxiHandler.cpp index b8aa614db..166d833d0 100644 --- a/src/game/TaxiHandler.cpp +++ b/src/game/TaxiHandler.cpp @@ -22,7 +22,6 @@ #include "WorldSession.h" #include "Opcodes.h" #include "Log.h" -#include "World.h" #include "ObjectMgr.h" #include "Player.h" #include "UpdateMask.h" diff --git a/src/game/TemporarySummon.cpp b/src/game/TemporarySummon.cpp index d24e3ba83..293ac9d5c 100644 --- a/src/game/TemporarySummon.cpp +++ b/src/game/TemporarySummon.cpp @@ -17,8 +17,6 @@ */ #include "TemporarySummon.h" -#include "WorldPacket.h" -#include "MapManager.h" #include "Log.h" #include "ObjectAccessor.h" #include "CreatureAI.h" diff --git a/src/game/ThreatManager.cpp b/src/game/ThreatManager.cpp index 7932d46c4..66ab9c2a6 100644 --- a/src/game/ThreatManager.cpp +++ b/src/game/ThreatManager.cpp @@ -21,7 +21,6 @@ #include "Creature.h" #include "CreatureAI.h" #include "Map.h" -#include "MapManager.h" #include "Player.h" #include "ObjectAccessor.h" #include "UnitEvents.h" diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp index c5043a472..8f0fb902f 100644 --- a/src/game/Totem.cpp +++ b/src/game/Totem.cpp @@ -18,7 +18,6 @@ #include "Totem.h" #include "WorldPacket.h" -#include "MapManager.h" #include "Log.h" #include "Group.h" #include "Player.h" diff --git a/src/game/TotemAI.cpp b/src/game/TotemAI.cpp index e79804313..b91020a23 100644 --- a/src/game/TotemAI.cpp +++ b/src/game/TotemAI.cpp @@ -19,9 +19,7 @@ #include "TotemAI.h" #include "Totem.h" #include "Creature.h" -#include "Player.h" #include "Database/DBCStores.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "SpellMgr.h" diff --git a/src/game/Traveller.h b/src/game/Traveller.h index 6aa55eb14..c0531631c 100644 --- a/src/game/Traveller.h +++ b/src/game/Traveller.h @@ -19,7 +19,6 @@ #ifndef MANGOS_TRAVELLER_H #define MANGOS_TRAVELLER_H -#include "MapManager.h" #include "Creature.h" #include "Player.h" #include diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index b32e7003c..07138366c 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -889,7 +889,7 @@ void Unit::CastCustomSpell(Unit* Victim,uint32 spellId, int32 const* bp0, int32 if(!spellInfo) { - sLog.outError("CastCustomSpell: unknown spell id %i\n", spellId); + sLog.outError("CastCustomSpell: unknown spell id %i", spellId); return; } @@ -6017,7 +6017,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB //else if (auraSpellInfo->Id==47300) // Dark Flame Aura else if (auraSpellInfo->Id==57345) // Darkmoon Card: Greatness { - uint32 stat = 0; + float stat = 0.0f; // strength if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 60229;stat = GetStat(STAT_STRENGTH); } // agility @@ -6576,7 +6576,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB // Bloodthirst (($m/100)% of max health) case 23880: { - basepoints0 = int32(GetMaxHealth() * triggerAmount / 10000); + basepoints0 = int32(GetMaxHealth() * triggerAmount / 100); break; } // Shamanistic Rage triggered spell @@ -7606,10 +7606,12 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 coeff = bonus->dot_damage * LvlPenalty * stack; else coeff = bonus->direct_damage * LvlPenalty * stack; + if (bonus->ap_bonus) - DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack; - DoneTotal += DoneAdvertisedBenefit * coeff * SpellModSpellDamage; - TakenTotal+= TakenAdvertisedBenefit * coeff; + DoneTotal += int32(bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack); + + DoneTotal += int32(DoneAdvertisedBenefit * coeff * SpellModSpellDamage); + TakenTotal += int32(TakenAdvertisedBenefit * coeff); } // Default calculation else if (DoneAdvertisedBenefit || TakenAdvertisedBenefit) @@ -7659,8 +7661,8 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3 break; } } - DoneTotal += DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage; - TakenTotal+= TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty; + DoneTotal += int32(DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage); + TakenTotal+= int32(TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty); } float tmpDamage = (pdamage + DoneTotal) * DoneTotalMod; @@ -8022,10 +8024,12 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint coeff = bonus->dot_damage * LvlPenalty * stack; else coeff = bonus->direct_damage * LvlPenalty * stack; + if (bonus->ap_bonus) - DoneTotal+=bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack; - DoneTotal += DoneAdvertisedBenefit * coeff * SpellModSpellDamage; - TakenTotal+= TakenAdvertisedBenefit * coeff; + DoneTotal += int32(bonus->ap_bonus * GetTotalAttackPowerValue(BASE_ATTACK) * stack); + + DoneTotal += int32(DoneAdvertisedBenefit * coeff * SpellModSpellDamage); + TakenTotal += int32(TakenAdvertisedBenefit * coeff); } // Default calculation else if (DoneAdvertisedBenefit || TakenAdvertisedBenefit) @@ -8075,8 +8079,8 @@ uint32 Unit::SpellHealingBonus(Unit *pVictim, SpellEntry const *spellProto, uint break; } } - DoneTotal += DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage * 1.88f; - TakenTotal+= TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * 1.88f; + DoneTotal += int32(DoneAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * SpellModSpellDamage * 1.88f); + TakenTotal += int32(TakenAdvertisedBenefit * (CastingTime / 3500.0f) * DotFactor * LvlPenalty * 1.88f); } // use float as more appropriate for negative values and percent applying diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp index 2aa513e13..de587fcbe 100644 --- a/src/game/Vehicle.cpp +++ b/src/game/Vehicle.cpp @@ -18,13 +18,8 @@ #include "Common.h" #include "Log.h" -#include "WorldSession.h" -#include "WorldPacket.h" #include "ObjectMgr.h" -#include "SpellMgr.h" #include "Vehicle.h" -#include "MapManager.h" -#include "SpellAuras.h" #include "Unit.h" #include "Util.h" diff --git a/src/game/VoiceChatHandler.cpp b/src/game/VoiceChatHandler.cpp index 741957610..d3b614c52 100644 --- a/src/game/VoiceChatHandler.cpp +++ b/src/game/VoiceChatHandler.cpp @@ -19,7 +19,6 @@ #include "Common.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "World.h" #include "Opcodes.h" #include "Log.h" diff --git a/src/game/Weather.cpp b/src/game/Weather.cpp index be1aec79c..5065761fd 100644 --- a/src/game/Weather.cpp +++ b/src/game/Weather.cpp @@ -22,7 +22,6 @@ #include "Weather.h" #include "WorldPacket.h" -#include "WorldSession.h" #include "Player.h" #include "World.h" #include "Log.h" diff --git a/src/game/World.cpp b/src/game/World.cpp index 63c757a4e..f1d44a6ab 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -21,7 +21,6 @@ */ #include "Common.h" -//#include "WorldSocket.h" #include "Database/DatabaseEnv.h" #include "Config/ConfigEnv.h" #include "SystemConfig.h" @@ -31,6 +30,7 @@ #include "WorldPacket.h" #include "Weather.h" #include "Player.h" +#include "Vehicle.h" #include "SkillExtraItems.h" #include "SkillDiscovery.h" #include "World.h" @@ -52,7 +52,7 @@ #include "WaypointMovementGenerator.h" #include "VMapFactory.h" #include "GlobalEvents.h" -#include "GameEvent.h" +#include "GameEventMgr.h" #include "PoolHandler.h" #include "Database/DatabaseImpl.h" #include "GridNotifiersImpl.h" @@ -669,12 +669,12 @@ void World::LoadConfigSettings(bool reload) if(reload) { - uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 60); + uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 80); if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL]) sLog.outError("MaxPlayerLevel option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]); } else - m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 60); + m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 80); if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > MAX_LEVEL) { @@ -2271,58 +2271,80 @@ void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 te } } +namespace MaNGOS +{ + class WorldWorldTextBuilder + { + public: + typedef std::vector WorldPacketList; + explicit WorldWorldTextBuilder(int32 textId, va_list* args = NULL) : i_textId(textId), i_args(args) {} + void operator()(WorldPacketList& data_list, int32 loc_idx) + { + char const* text = objmgr.GetMangosString(i_textId,loc_idx); + + if(i_args) + { + // we need copy va_list before use or original va_list will corrupted + va_list ap; + va_copy(ap,*i_args); + + char str [2048]; + vsnprintf(str,2048,text, ap ); + va_end(ap); + + do_helper(data_list,&str[0]); + } + else + do_helper(data_list,(char*)text); + } + private: + char* lineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; } + void do_helper(WorldPacketList& data_list, char* text) + { + char* pos = text; + + while(char* line = lineFromMessage(pos)) + { + WorldPacket* data = new WorldPacket(); + + uint32 lineLength = (line ? strlen(line) : 0) + 1; + + data->Initialize(SMSG_MESSAGECHAT, 100); // guess size + *data << uint8(CHAT_MSG_SYSTEM); + *data << uint32(LANG_UNIVERSAL); + *data << uint64(0); + *data << uint32(0); // can be chat msg group or something + *data << uint64(0); + *data << uint32(lineLength); + *data << line; + *data << uint8(0); + + data_list.push_back(data); + } + } + + int32 i_textId; + va_list* i_args; + }; +} // namespace MaNGOS + /// Send a System Message to all players (except self if mentioned) void World::SendWorldText(int32 string_id, ...) { - std::vector > data_cache; // 0 = default, i => i-1 locale index + va_list ap; + va_start(ap, string_id); + MaNGOS::WorldWorldTextBuilder wt_builder(string_id, &ap); + MaNGOS::LocalizedPacketListDo wt_do(wt_builder); for(SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) { if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() ) continue; - uint32 loc_idx = itr->second->GetSessionDbLocaleIndex(); - uint32 cache_idx = loc_idx+1; - - std::vector* data_list; - - // create if not cached yet - if(data_cache.size() < cache_idx+1 || data_cache[cache_idx].empty()) - { - if(data_cache.size() < cache_idx+1) - data_cache.resize(cache_idx+1); - - data_list = &data_cache[cache_idx]; - - char const* text = objmgr.GetMangosString(string_id,loc_idx); - - char buf[1000]; - - va_list argptr; - va_start( argptr, string_id ); - vsnprintf( buf,1000, text, argptr ); - va_end( argptr ); - - char* pos = &buf[0]; - - while(char* line = ChatHandler::LineFromMessage(pos)) - { - WorldPacket* data = new WorldPacket(); - ChatHandler::FillMessageData(data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL); - data_list->push_back(data); - } - } - else - data_list = &data_cache[cache_idx]; - - for(int i = 0; i < data_list->size(); ++i) - itr->second->SendPacket((*data_list)[i]); + wt_do(itr->second->GetPlayer()); } - // free memory - for(int i = 0; i < data_cache.size(); ++i) - for(int j = 0; j < data_cache[i].size(); ++j) - delete data_cache[i][j]; + va_end(ap); } /// DEPRICATED, only for debug purpose. Send a System Message to all players (except self if mentioned) diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index ec71cedc6..36fbeb58e 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -20,12 +20,11 @@ \ingroup u2w */ -#include "WorldSocket.h" +#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it #include "Common.h" #include "Database/DatabaseEnv.h" #include "Log.h" #include "Opcodes.h" -#include "WorldSocket.h" #include "WorldPacket.h" #include "WorldSession.h" #include "Player.h" @@ -33,11 +32,8 @@ #include "Group.h" #include "Guild.h" #include "World.h" -#include "MapManager.h" #include "ObjectAccessor.h" #include "BattleGroundMgr.h" -#include "Language.h" // for CMSG_CANCEL_MOUNT_AURA handler -#include "Chat.h" #include "SocialMgr.h" /// WorldSession constructor @@ -305,7 +301,7 @@ void WorldSession::LogoutPlayer(bool Save) } //drop a flag if player is carrying it if(BattleGround *bg = _player->GetBattleGround()) - bg->EventPlayerDroppedFlag(_player); + bg->EventPlayerLoggedOut(_player); ///- Teleport to home if the player is in an invalid instance if(!_player->m_InstanceValid && !_player->isGameMaster()) diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index 5cf3b3abe..8e3ae2dc9 100644 --- a/src/game/WorldSocket.cpp +++ b/src/game/WorldSocket.cpp @@ -315,7 +315,7 @@ int WorldSocket::handle_input (ACE_HANDLE) } case 0: { - DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n"); + DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection"); errno = ECONNRESET; return -1; diff --git a/src/game/debugcmds.cpp b/src/game/debugcmds.cpp index d04cce6a2..6ff1a90bf 100644 --- a/src/game/debugcmds.cpp +++ b/src/game/debugcmds.cpp @@ -19,17 +19,14 @@ #include "Common.h" #include "Database/DatabaseEnv.h" #include "WorldPacket.h" -#include "WorldSession.h" -#include "World.h" +#include "Vehicle.h" #include "Player.h" #include "Opcodes.h" #include "Chat.h" #include "Log.h" #include "Unit.h" -#include "ObjectAccessor.h" #include "GossipDef.h" #include "Language.h" -#include "MapManager.h" #include "BattleGroundMgr.h" #include #include "ObjectMgr.h" diff --git a/src/mangosd/WorldRunnable.cpp b/src/mangosd/WorldRunnable.cpp index 929463503..cf652d673 100644 --- a/src/mangosd/WorldRunnable.cpp +++ b/src/mangosd/WorldRunnable.cpp @@ -87,7 +87,7 @@ void WorldRunnable::run() sWorld.UpdateSessions( 1 ); // real players unload required UpdateSessions call // unload battleground templates before different singletons destroyed - sBattleGroundMgr.DeleteAlllBattleGrounds(); + sBattleGroundMgr.DeleteAllBattleGrounds(); sWorldSocketMgr->StopNetwork(); diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index a6a7f29bd..86c600194 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -219,8 +219,9 @@ AddonChannel = 1 # 0 = Minimum; 1 = Error; 2 = Detail; 3 = Full/Debug # Default: 0 # -# LogFilter_TransportMoves +# LogFilter_AchievementUpdates # LogFilter_CreatureMoves +# LogFilter_TransportMoves # LogFilter_VisibilityChanges # Log filters # Default: 1 - not include with any log level @@ -288,8 +289,9 @@ LogTime = 0 LogFile = "Server.log" LogTimestamp = 0 LogFileLevel = 0 -LogFilter_TransportMoves = 1 +LogFilter_AchievementUpdates = 1 LogFilter_CreatureMoves = 1 +LogFilter_TransportMoves = 1 LogFilter_VisibilityChanges = 1 WorldLogFile = "" DBErrorLogFile = "DBErrors.log" diff --git a/src/shared/Database/DBCStores.cpp b/src/shared/Database/DBCStores.cpp index 2cb2d729a..dade62657 100644 --- a/src/shared/Database/DBCStores.cpp +++ b/src/shared/Database/DBCStores.cpp @@ -75,6 +75,7 @@ DBCStorage sGtOCTRegenHPStore(GtOCTRegenHPfmt); //DBCStorage sGtOCTRegenMPStore(GtOCTRegenMPfmt); -- not used currently DBCStorage sGtRegenHPPerSptStore(GtRegenHPPerSptfmt); DBCStorage sGtRegenMPPerSptStore(GtRegenMPPerSptfmt); +DBCStorage sHolidaysStore(Holidaysfmt); DBCStorage sItemStore(Itemfmt); //DBCStorage sItemCondExtCostsStore(ItemCondExtCostsEntryfmt); //DBCStorage sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently @@ -190,7 +191,7 @@ void LoadDBCStores(const std::string& dataPath) { std::string dbcPath = dataPath+"dbc/"; - const uint32 DBCFilesCount = 72; + const uint32 DBCFilesCount = 73; barGoLink bar( DBCFilesCount ); @@ -263,6 +264,7 @@ void LoadDBCStores(const std::string& dataPath) //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtOCTRegenMPStore, dbcPath,"gtOCTRegenMP.dbc"); -- not used currently LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenHPPerSptStore, dbcPath,"gtRegenHPPerSpt.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sGtRegenMPPerSptStore, dbcPath,"gtRegenMPPerSpt.dbc"); + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sHolidaysStore, dbcPath,"Holidays.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemStore, dbcPath,"Item.dbc"); //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemDisplayInfoStore, dbcPath,"ItemDisplayInfo.dbc"); -- not used currently //LoadDBC(availableDbcLocales,bar,bad_dbc_files,sItemCondExtCostsStore, dbcPath,"ItemCondExtCosts.dbc"); diff --git a/src/shared/Database/DBCStores.h b/src/shared/Database/DBCStores.h index e2e3dac6e..69b4c30bc 100644 --- a/src/shared/Database/DBCStores.h +++ b/src/shared/Database/DBCStores.h @@ -165,6 +165,7 @@ extern DBCStorage sGtOCTRegenHPStore; //extern DBCStorage sGtOCTRegenMPStore; -- not used currently extern DBCStorage sGtRegenHPPerSptStore; extern DBCStorage sGtRegenMPPerSptStore; +extern DBCStorage sHolidaysStore; extern DBCStorage sItemStore; //extern DBCStorage sItemDisplayInfoStore; -- not used currently extern DBCStorage sItemExtendedCostStore; diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h index daf4849cc..42ea449ae 100644 --- a/src/shared/Database/DBCStructure.h +++ b/src/shared/Database/DBCStructure.h @@ -356,7 +356,8 @@ struct AchievementCriteriaEntry // TODO: where is the information about the target stored? struct { - uint32 emoteID; // 3 + uint32 emoteID; // 3 enum TextEmotes + uint32 count; // 4 count of emotes, always required special target or requirements } do_emote; // ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13 // ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55 @@ -854,6 +855,40 @@ struct GtRegenMPPerSptEntry float ratio; }; +/* no used +struct HolidayDescriptionsEntry +{ + uint32 ID; // 0, this is NOT holiday id + //char* name[16] // 1-16 m_name_lang + // 17 name flags +}; +*/ + +/* no used +struct HolidayNamesEntry +{ + uint32 ID; // 0, this is NOT holiday id + //char* name[16] // 1-16 m_name_lang + // 17 name flags +}; +*/ + +struct HolidaysEntry +{ + uint32 ID; // 0, holiday id + //uint32 unk1; // 1 + //uint32 unk2; // 2 + //uint32 unk3[8] // 3-10, empty fields + //uint32 unk11[13] // 11-23, some unknown data (bit strings?) + //uint32 unk11[13] // 24-36, some empty fields (continue prev?) + //uint32 unk11[12] // 37-48, counters? + //uint32 holidayNameId; // 49, id for HolidayNames.dbc + //uint32 holidayDescriptionId; // 50, id for HolidayDescriptions.dbc + //uint32 unk51; // 51 + //uint32 unk52; // 52 + //uint32 unk53; // 53 +}; + struct ItemEntry { uint32 ID; // 0 diff --git a/src/shared/Database/DBCfmt.cpp b/src/shared/Database/DBCfmt.cpp index b271d59d9..422b8c043 100644 --- a/src/shared/Database/DBCfmt.cpp +++ b/src/shared/Database/DBCfmt.cpp @@ -53,6 +53,7 @@ const char GtOCTRegenHPfmt[]="f"; //const char GtOCTRegenMPfmt[]="f"; const char GtRegenHPPerSptfmt[]="f"; const char GtRegenMPPerSptfmt[]="f"; +const char Holidaysfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const char Itemfmt[]="nixiiiii"; //const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx"; //const char ItemCondExtCostsEntryfmt[]="xiii"; diff --git a/src/shared/Database/dbcfile.cpp b/src/shared/Database/dbcfile.cpp index 0cfc7ada3..519e77de7 100644 --- a/src/shared/Database/dbcfile.cpp +++ b/src/shared/Database/dbcfile.cpp @@ -37,23 +37,35 @@ bool DBCFile::Load(const char *filename, const char *fmt) delete [] data; data=NULL; } + FILE * f=fopen(filename,"rb"); if(!f)return false; - fread(&header,4,1,f); // Number of records + if(fread(&header,4,1,f)!=1) // Number of records + return false; + EndianConvert(header); if(header!=0x43424457) - { - //printf("not dbc file"); return false; //'WDBC' - } - fread(&recordCount,4,1,f); // Number of records + + if(fread(&recordCount,4,1,f)!=1) // Number of records + return false; + EndianConvert(recordCount); - fread(&fieldCount,4,1,f); // Number of fields + + if(fread(&fieldCount,4,1,f)!=1) // Number of fields + return false; + EndianConvert(fieldCount); - fread(&recordSize,4,1,f); // Size of a record + + if(fread(&recordSize,4,1,f)!=1) // Size of a record + return false; + EndianConvert(recordSize); - fread(&stringSize,4,1,f); // String size + + if(fread(&stringSize,4,1,f)!=1) // String size + return false; + EndianConvert(stringSize); fieldsOffset = new uint32[fieldCount]; @@ -69,7 +81,10 @@ bool DBCFile::Load(const char *filename, const char *fmt) data = new unsigned char[recordSize*recordCount+stringSize]; stringTable = data + recordSize*recordCount; - fread(data,recordSize*recordCount+stringSize,1,f); + + if(fread(data,recordSize*recordCount+stringSize,1,f)!=1) + return false; + fclose(f); return true; } diff --git a/src/shared/Log.cpp b/src/shared/Log.cpp index 904ac704a..97c2e7164 100644 --- a/src/shared/Log.cpp +++ b/src/shared/Log.cpp @@ -243,6 +243,8 @@ void Log::Initialize() m_logFilter |= LOG_FILTER_CREATURE_MOVES; if(sConfig.GetBoolDefault("LogFilter_VisibilityChanges", true)) m_logFilter |= LOG_FILTER_VISIBILITY_CHANGES; + if(sConfig.GetBoolDefault("LogFilter_AchievementUpdates", true)) + m_logFilter |= LOG_FILTER_ACHIEVEMENT_UPDATES; // Char log settings m_charLog_Dump = sConfig.GetBoolDefault("CharLogDump", false); diff --git a/src/shared/Log.h b/src/shared/Log.h index 85fac5ed3..0c637b975 100644 --- a/src/shared/Log.h +++ b/src/shared/Log.h @@ -29,7 +29,8 @@ enum LogFilters { LOG_FILTER_TRANSPORT_MOVES = 1, LOG_FILTER_CREATURE_MOVES = 2, - LOG_FILTER_VISIBILITY_CHANGES = 4 + LOG_FILTER_VISIBILITY_CHANGES = 4, + LOG_FILTER_ACHIEVEMENT_UPDATES= 8 }; enum Color diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 160925670..96986cb2e 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7387" + #define REVISION_NR "7440" #endif // __REVISION_NR_H__ diff --git a/win/VC71/ACE_vc71.vcproj b/win/VC71/ACE_vc71.vcproj index 862ef1a83..9ab6be08d 100644 --- a/win/VC71/ACE_vc71.vcproj +++ b/win/VC71/ACE_vc71.vcproj @@ -45,7 +45,7 @@ Name="VCLinkerTool" AdditionalDependencies="" OutputFile="$(OutDir)\ACEd.dll" - LinkIncremental="2" + LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="" GenerateDebugInformation="TRUE" diff --git a/win/VC71/game.vcproj b/win/VC71/game.vcproj index 0643908d5..da274a1f5 100644 --- a/win/VC71/game.vcproj +++ b/win/VC71/game.vcproj @@ -276,10 +276,10 @@ RelativePath="..\..\src\game\DuelHandler.cpp">
+ RelativePath="..\..\src\game\GameEventMgr.cpp"> + RelativePath="..\..\src\game\GameEventMgr.h"> diff --git a/win/VC71/realmd.vcproj b/win/VC71/realmd.vcproj index 1eb41decc..e6edec8e4 100644 --- a/win/VC71/realmd.vcproj +++ b/win/VC71/realmd.vcproj @@ -112,7 +112,7 @@ AdditionalOptions="/MACHINE:I386" AdditionalDependencies="zthread.lib libmySQL.lib libeay32.lib ws2_32.lib winmm.lib odbc32.lib odbccp32.lib advapi32.lib dbghelp.lib" OutputFile="..\..\bin\$(PlatformName)_$(ConfigurationName)\realmd.exe" - LinkIncremental="2" + LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories=""..\..\dep\lib\$(PlatformName)_$(ConfigurationName)";".\zthread__$(PlatformName)_$(ConfigurationName)"" GenerateDebugInformation="TRUE" diff --git a/win/VC71/script.vcproj b/win/VC71/script.vcproj index a88a9dd07..617991188 100644 --- a/win/VC71/script.vcproj +++ b/win/VC71/script.vcproj @@ -35,7 +35,7 @@ Name="VCLinkerTool" AdditionalDependencies="mangosd.lib zlib.lib zthread.lib libmySQL.lib libeay32.lib ws2_32.lib winmm.lib odbc32.lib odbccp32.lib" OutputFile="..\..\bin\$(PlatformName)_$(ConfigurationName)\MaNGOSScript.dll" - LinkIncremental="2" + LinkIncremental="1" AdditionalLibraryDirectories="".\mangosd__$(PlatformName)_$(ConfigurationName)";"..\..\dep\lib\$(PlatformName)_$(ConfigurationName)";".\zlib__$(PlatformName)_$(ConfigurationName)";".\zthread__$(PlatformName)_$(ConfigurationName)"" GenerateDebugInformation="TRUE" ProgramDatabaseFile="$(OutDir)/MaNGOSScript.pdb" diff --git a/win/VC80/ACE_vc8.vcproj b/win/VC80/ACE_vc8.vcproj index 767a03b43..c948be1a7 100644 --- a/win/VC80/ACE_vc8.vcproj +++ b/win/VC80/ACE_vc8.vcproj @@ -77,7 +77,7 @@ Name="VCLinkerTool" AdditionalDependencies="" OutputFile="$(OutDir)\ACEd.dll" - LinkIncremental="2" + LinkIncremental="1" SuppressStartupBanner="true" AdditionalLibraryDirectories="" GenerateDebugInformation="true" @@ -171,7 +171,7 @@ AdditionalOptions="/machine:AMD64" AdditionalDependencies="" OutputFile="$(OutDir)\ACEd.dll" - LinkIncremental="2" + LinkIncremental="1" SuppressStartupBanner="true" AdditionalLibraryDirectories="" GenerateDebugInformation="true" diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index 0ac846d64..7e4cc1413 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -539,11 +539,11 @@ >