OregonCore  revision be9e804-git
Your Favourite TBC server
System.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #define _CRT_SECURE_NO_DEPRECATE
19 
20 #include <stdio.h>
21 #include <deque>
22 #include <set>
23 #include <cstdlib>
24 
25 #ifdef WIN32
26 #include "direct.h"
27 #else
28 #include <sys/stat.h>
29 #endif
30 
31 #include "dbcfile.h"
32 #include "mpq_libmpq.h"
33 
34 #include "loadlib/adt.h"
35 #include "loadlib/wdt.h"
36 #include <fcntl.h>
37 
38 #if defined( __GNUC__ )
39 #include <unistd.h>
40 #define _open open
41 #define _close close
42 #ifndef O_BINARY
43 #define O_BINARY 0
44 #endif
45 #else
46 #include <io.h>
47 #endif
48 
49 #ifdef O_LARGEFILE
50 #define OPEN_FLAGS (O_RDONLY | O_BINARY | O_LARGEFILE)
51 #else
52 #define OPEN_FLAGS (O_RDONLY | O_BINARY)
53 #endif
55 
56 typedef struct
57 {
58  char name[64];
60 } map_id;
61 
65 #define MAX_PATH_LENGTH 128
69 
70 // **************************************************
71 // Extractor options
72 // **************************************************
73 enum Extract
74 {
78 
79 };
80 
81 // Select data for extract
83 // This option allow limit minimum height to some value (Allow save some memory)
85 float CONF_use_minHeight = -500.0f;
86 
87 // This option allow use float to int conversion
89 float CONF_float_to_int8_limit = 2.0f; // Max accuracy = val/256
90 float CONF_float_to_int16_limit = 2048.0f; // Max accuracy = val/65536
91 float CONF_flat_height_delta_limit = 0.005f; // If max - min less this value - surface is flat
92 float CONF_flat_liquid_delta_limit = 0.001f; // If max - min less this value - liquid surface is flat
93 
94 // List MPQ for extract from
95 const char *CONF_mpq_list[]={
96  "common.MPQ",
97  "common-2.MPQ",
98  "lichking.MPQ",
99  "expansion.MPQ",
100  "patch.MPQ",
101  "patch-2.MPQ",
102  "patch-3.MPQ",
103  "patch-4.MPQ",
104  "patch-5.MPQ",
105 };
106 
107 static const char* const langs[] = {"enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" };
108 #define LANG_COUNT 12
109 
110 void CreateDir( const std::string& Path )
111 {
112  #ifdef WIN32
113  _mkdir( Path.c_str());
114  #else
115  mkdir( Path.c_str(), 0777 );
116  #endif
117 }
118 
119 bool FileExists( const char* FileName )
120 {
121  int fp = _open(FileName, OPEN_FLAGS);
122  if (fp != -1)
123  {
124  _close(fp);
125  return true;
126  }
127 
128  return false;
129 }
130 
131 void Usage(char* prg)
132 {
133  printf(
134  "Usage:\n"\
135  "%s -[var] [value]\n"\
136  "-i set input path (max %d characters)\n"\
137  "-o set output path (max %d characters)\n"\
138  "-e extract only MAP(1)/DBC(2)/Camera(4) - standard: all(7)\n"\
139  "-f height stored as int (less map size but lost some accuracy) 1 by default\n"\
140  "Example: %s -f 0 -i \"c:\\games\\game\"", prg, MAX_PATH_LENGTH - 1, MAX_PATH_LENGTH - 1, prg);
141  exit(1);
142 }
143 
144 void HandleArgs(int argc, char* arg[])
145 {
146  for (int c = 1; c < argc; ++c)
147  {
148  // i - input path
149  // o - output path
150  // e - extract only MAP(1)/DBC(2) - standard both(3)
151  // f - use float to int conversion
152  // h - limit minimum height
153  if (arg[c][0] != '-')
154  Usage(arg[0]);
155 
156  switch (arg[c][1])
157  {
158  case 'i':
159  if (c + 1 < argc) // all ok
160  strcpy(input_path, arg[(c++) + 1]);
161  else
162  Usage(arg[0]);
163  break;
164  case 'o':
165  if (c + 1 < argc) // all ok
166  strcpy(output_path, arg[(c++) + 1]);
167  else
168  Usage(arg[0]);
169  break;
170  case 'f':
171  if (c + 1 < argc) // all ok
172  CONF_allow_float_to_int = atoi(arg[(c++) + 1]) != 0;
173  else
174  Usage(arg[0]);
175  break;
176  case 'e':
177  if (c + 1 < argc) // all ok
178  {
179  CONF_extract = atoi(arg[(c++) + 1]);
180  if (!(CONF_extract > 0 && CONF_extract < 8))
181  Usage(arg[0]);
182  }
183  else
184  Usage(arg[0]);
185  break;
186  }
187  }
188 }
189 
190 uint32 ReadBuild(int locale)
191 {
192  // include build info file also
193  std::string filename = std::string("component.wow-") + langs[locale] + ".txt";
194  //printf("Read %s file... ", filename.c_str());
195 
196  MPQFile m(filename.c_str());
197  if (m.isEof())
198  {
199  printf("Fatal error: Not found %s file!\n", filename.c_str());
200  exit(1);
201  }
202 
203  std::string text = std::string(m.getPointer(), m.getSize());
204  m.close();
205 
206  size_t pos = text.find("version=\"");
207  size_t pos1 = pos + strlen("version=\"");
208  size_t pos2 = text.find("\"", pos1);
209  if (pos == text.npos || pos2 == text.npos || pos1 >= pos2)
210  {
211  printf("Fatal error: Invalid %s file format!\n", filename.c_str());
212  exit(1);
213  }
214 
215  std::string build_str = text.substr(pos1, pos2 - pos1);
216 
217  int build = atoi(build_str.c_str());
218  if (build <= 0)
219  {
220  printf("Fatal error: Invalid %s file format!\n", filename.c_str());
221  exit(1);
222  }
223 
224  return build;
225 }
226 
228 {
229  printf("Read Map.dbc file... ");
230  DBCFile dbc("DBFilesClient\\Map.dbc");
231 
232  if (!dbc.open())
233  {
234  printf("Fatal error: Invalid Map.dbc file format!\n");
235  exit(1);
236  }
237 
238  size_t map_count = dbc.getRecordCount();
239  map_ids = new map_id[map_count];
240  for (uint32 x = 0; x < map_count; ++x)
241  {
242  map_ids[x].id = dbc.getRecord(x).getUInt(0);
243  strcpy(map_ids[x].name, dbc.getRecord(x).getString(1));
244  }
245  printf("Done! (%lu maps loaded)\n", map_count);
246  return map_count;
247 }
248 
250 {
251  printf("Read AreaTable.dbc file...");
252  DBCFile dbc("DBFilesClient\\AreaTable.dbc");
253 
254  if (!dbc.open())
255  {
256  printf("Fatal error: Invalid AreaTable.dbc file format!\n");
257  exit(1);
258  }
259 
260  size_t area_count = dbc.getRecordCount();
261  size_t maxid = dbc.getMaxId();
262  areas = new uint16[maxid + 1];
263  memset(areas, 0xff, (maxid + 1) * sizeof(uint16));
264 
265  for (uint32 x = 0; x < area_count; ++x)
266  areas[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
267 
268  maxAreaId = dbc.getMaxId();
269 
270  printf("Done! (%lu areas loaded)\n", area_count);
271 }
272 
274 {
275  printf("Read LiquidType.dbc file...");
276  DBCFile dbc("DBFilesClient\\LiquidType.dbc");
277  if (!dbc.open())
278  {
279  printf("Fatal error: Invalid LiquidType.dbc file format!\n");
280  exit(1);
281  }
282 
283  size_t LiqType_count = dbc.getRecordCount();
284  size_t LiqType_maxid = dbc.getMaxId();
285  LiqType = new uint16[LiqType_maxid + 1];
286  memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16));
287 
288  for (uint32 x = 0; x < LiqType_count; ++x)
289  LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3);
290 
291  printf("Done! (%lu LiqTypes loaded)\n", LiqType_count);
292 }
293 
294 //
295 // Adt file convertor function and data
296 //
297 
298 // Map file format data
299 static char const* MAP_MAGIC = "MAPS";
300 static char const* MAP_VERSION_MAGIC = "v1.3";
301 static char const* MAP_AREA_MAGIC = "AREA";
302 static char const* MAP_HEIGHT_MAGIC = "MHGT";
303 static char const* MAP_LIQUID_MAGIC = "MLIQ";
304 
305 struct map_fileheader
306 {
318 };
319 
320 #define MAP_AREA_NO_AREA 0x0001
321 
322 struct map_areaHeader
323 {
324  uint32 fourcc;
325  uint16 flags;
326  uint16 gridArea;
327 };
328 
329 #define MAP_HEIGHT_NO_HEIGHT 0x0001
330 #define MAP_HEIGHT_AS_INT16 0x0002
331 #define MAP_HEIGHT_AS_INT8 0x0004
332 
333 struct map_heightHeader
334 {
335  uint32 fourcc;
336  uint32 flags;
337  float gridHeight;
338  float gridMaxHeight;
339 };
340 
341 #define MAP_LIQUID_TYPE_NO_WATER 0x00
342 #define MAP_LIQUID_TYPE_MAGMA 0x01
343 #define MAP_LIQUID_TYPE_OCEAN 0x02
344 #define MAP_LIQUID_TYPE_SLIME 0x04
345 #define MAP_LIQUID_TYPE_WATER 0x08
346 
347 #define MAP_LIQUID_TYPE_DARK_WATER 0x10
348 #define MAP_LIQUID_TYPE_WMO_WATER 0x20
349 
350 
351 #define MAP_LIQUID_NO_TYPE 0x0001
352 #define MAP_LIQUID_NO_HEIGHT 0x0002
353 
354 struct map_liquidHeader
355 {
356  uint32 fourcc;
357  uint16 flags;
358  uint16 liquidType;
359  uint8 offsetX;
360  uint8 offsetY;
361  uint8 width;
362  uint8 height;
363  float liquidLevel;
364 };
365 
366 float selectUInt8StepStore(float maxDiff)
367 {
368  return 255 / maxDiff;
369 }
370 
371 float selectUInt16StepStore(float maxDiff)
372 {
373  return 65535 / maxDiff;
374 }
375 // Temporary grid data store
377 
384 
389 
390 bool ConvertADT(char* filename, char* filename2, int /*cell_y*/, int /*cell_x*/, uint32 build)
391 {
392  ADT_file adt;
393 
394  if (!adt.loadFile(filename))
395  return false;
396 
397  adt_MCIN* cells = adt.a_grid->getMCIN();
398  if (!cells)
399  {
400  printf("Can't find cells in '%s'\n", filename);
401  return false;
402  }
403 
404  memset(liquid_show, 0, sizeof(liquid_show));
405  memset(liquid_flags, 0, sizeof(liquid_flags));
406  memset(liquid_entry, 0, sizeof(liquid_entry));
407 
408  // Prepare map header
409  map_fileheader map;
410  map.mapMagic = *reinterpret_cast<uint32 const*>(MAP_MAGIC);
411  map.versionMagic = *reinterpret_cast<uint32 const*>(MAP_VERSION_MAGIC);
412  map.buildMagic = build;
413 
414  // Get area flags data
415  for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
416  {
417  for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
418  {
419  adt_MCNK* cell = cells->getMCNK(i, j);
420  uint32 areaid = cell->areaid;
421  if (areaid && areaid <= maxAreaId)
422  {
423  if (areas[areaid] != 0xffff)
424  {
425  area_flags[i][j] = areas[areaid];
426  continue;
427  }
428  printf("File: %s\nCan't find area flag for areaid %u [%d, %d].\n", filename, areaid, cell->ix, cell->iy);
429  }
430  area_flags[i][j] = 0xffff;
431  }
432  }
433  //============================================
434  // Try pack area data
435  //============================================
436  bool fullAreaData = false;
437  uint32 areaflag = area_flags[0][0];
438  for (int y = 0; y < ADT_CELLS_PER_GRID; y++)
439  {
440  for (int x = 0; x < ADT_CELLS_PER_GRID; x++)
441  {
442  if (area_flags[y][x] != areaflag)
443  {
444  fullAreaData = true;
445  break;
446  }
447  }
448  }
449 
450  map.areaMapOffset = sizeof(map);
451  map.areaMapSize = sizeof(map_areaHeader);
452 
453  map_areaHeader areaHeader;
454  areaHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_AREA_MAGIC);
455  areaHeader.flags = 0;
456  if (fullAreaData)
457  {
458  areaHeader.gridArea = 0;
459  map.areaMapSize += sizeof(area_flags);
460  }
461  else
462  {
463  areaHeader.flags |= MAP_AREA_NO_AREA;
464  areaHeader.gridArea = static_cast<uint16>(areaflag);
465  }
466 
467  //
468  // Get Height map from grid
469  //
470  for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
471  {
472  for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
473  {
474  adt_MCNK* cell = cells->getMCNK(i, j);
475  if (!cell)
476  continue;
477  // Height values for triangles stored in order:
478  // 1 2 3 4 5 6 7 8 9
479  // 10 11 12 13 14 15 16 17
480  // 18 19 20 21 22 23 24 25 26
481  // 27 28 29 30 31 32 33 34
482  // . . . . . . . .
483  // For better get height values merge it to V9 and V8 map
484  // V9 height map:
485  // 1 2 3 4 5 6 7 8 9
486  // 18 19 20 21 22 23 24 25 26
487  // . . . . . . . .
488  // V8 height map:
489  // 10 11 12 13 14 15 16 17
490  // 27 28 29 30 31 32 33 34
491  // . . . . . . . .
492 
493  // Set map height as grid height
494  for (int y = 0; y <= ADT_CELL_SIZE; y++)
495  {
496  int cy = i * ADT_CELL_SIZE + y;
497  for (int x = 0; x <= ADT_CELL_SIZE; x++)
498  {
499  int cx = j * ADT_CELL_SIZE + x;
500  V9[cy][cx] = cell->ypos;
501  }
502  }
503  for (int y = 0; y < ADT_CELL_SIZE; y++)
504  {
505  int cy = i * ADT_CELL_SIZE + y;
506  for (int x = 0; x < ADT_CELL_SIZE; x++)
507  {
508  int cx = j * ADT_CELL_SIZE + x;
509  V8[cy][cx] = cell->ypos;
510  }
511  }
512  // Get custom height
513  adt_MCVT* v = cell->getMCVT();
514  if (!v)
515  continue;
516  // get V9 height map
517  for (int y = 0; y <= ADT_CELL_SIZE; y++)
518  {
519  int cy = i * ADT_CELL_SIZE + y;
520  for (int x = 0; x <= ADT_CELL_SIZE; x++)
521  {
522  int cx = j * ADT_CELL_SIZE + x;
523  V9[cy][cx] += v->height_map[y * (ADT_CELL_SIZE * 2 + 1) + x];
524  }
525  }
526  // get V8 height map
527  for (int y = 0; y < ADT_CELL_SIZE; y++)
528  {
529  int cy = i * ADT_CELL_SIZE + y;
530  for (int x = 0; x < ADT_CELL_SIZE; x++)
531  {
532  int cx = j * ADT_CELL_SIZE + x;
533  V8[cy][cx] += v->height_map[y * (ADT_CELL_SIZE * 2 + 1) + ADT_CELL_SIZE + 1 + x];
534  }
535  }
536  }
537  }
538  //============================================
539  // Try pack height data
540  //============================================
541  float maxHeight = -20000;
542  float minHeight = 20000;
543  for (int y = 0; y < ADT_GRID_SIZE; y++)
544  {
545  for (int x = 0; x < ADT_GRID_SIZE; x++)
546  {
547  float h = V8[y][x];
548  if (maxHeight < h) maxHeight = h;
549  if (minHeight > h) minHeight = h;
550  }
551  }
552  for (int y = 0; y <= ADT_GRID_SIZE; y++)
553  {
554  for (int x = 0; x <= ADT_GRID_SIZE; x++)
555  {
556  float h = V9[y][x];
557  if (maxHeight < h) maxHeight = h;
558  if (minHeight > h) minHeight = h;
559  }
560  }
561 
562  // Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
563  if (CONF_allow_height_limit && minHeight < CONF_use_minHeight)
564  {
565  for (int y = 0; y < ADT_GRID_SIZE; y++)
566  for (int x = 0; x < ADT_GRID_SIZE; x++)
567  if (V8[y][x] < CONF_use_minHeight)
568  V8[y][x] = CONF_use_minHeight;
569  for (int y = 0; y <= ADT_GRID_SIZE; y++)
570  for (int x = 0; x <= ADT_GRID_SIZE; x++)
571  if (V9[y][x] < CONF_use_minHeight)
572  V9[y][x] = CONF_use_minHeight;
573  if (minHeight < CONF_use_minHeight)
574  minHeight = CONF_use_minHeight;
575  if (maxHeight < CONF_use_minHeight)
576  maxHeight = CONF_use_minHeight;
577  }
578 
579  map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
580  map.heightMapSize = sizeof(map_heightHeader);
581 
582  map_heightHeader heightHeader;
583  heightHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_HEIGHT_MAGIC);
584  heightHeader.flags = 0;
585  heightHeader.gridHeight = minHeight;
586  heightHeader.gridMaxHeight = maxHeight;
587 
588  if (maxHeight == minHeight)
589  heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
590 
591  // Not need store if flat surface
592  if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit)
593  heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT;
594 
595  // Try store as packed in uint16 or uint8 values
596  if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
597  {
598  float step = 0;
599  // Try Store as uint values
601  {
602  float diff = maxHeight - minHeight;
603  if (diff < CONF_float_to_int8_limit) // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
604  {
605  heightHeader.flags |= MAP_HEIGHT_AS_INT8;
606  step = selectUInt8StepStore(diff);
607  }
608  else if (diff < CONF_float_to_int16_limit) // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
609  {
610  heightHeader.flags |= MAP_HEIGHT_AS_INT16;
611  step = selectUInt16StepStore(diff);
612  }
613  }
614 
615  // Pack it to int values if need
616  if (heightHeader.flags & MAP_HEIGHT_AS_INT8)
617  {
618  for (int y = 0; y < ADT_GRID_SIZE; y++)
619  for (int x = 0; x < ADT_GRID_SIZE; x++)
620  uint8_V8[y][x] = uint8((V8[y][x] - minHeight) * step + 0.5f);
621  for (int y = 0; y <= ADT_GRID_SIZE; y++)
622  for (int x = 0; x <= ADT_GRID_SIZE; x++)
623  uint8_V9[y][x] = uint8((V9[y][x] - minHeight) * step + 0.5f);
624  map.heightMapSize += sizeof(uint8_V9) + sizeof(uint8_V8);
625  }
626  else if (heightHeader.flags & MAP_HEIGHT_AS_INT16)
627  {
628  for (int y = 0; y < ADT_GRID_SIZE; y++)
629  for (int x = 0; x < ADT_GRID_SIZE; x++)
630  uint16_V8[y][x] = uint16((V8[y][x] - minHeight) * step + 0.5f);
631  for (int y = 0; y <= ADT_GRID_SIZE; y++)
632  for (int x = 0; x <= ADT_GRID_SIZE; x++)
633  uint16_V9[y][x] = uint16((V9[y][x] - minHeight) * step + 0.5f);
634  map.heightMapSize += sizeof(uint16_V9) + sizeof(uint16_V8);
635  }
636  else
637  map.heightMapSize += sizeof(V9) + sizeof(V8);
638  }
639 
640  // Get from MCLQ chunk (old)
641  for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
642  {
643  for(int j = 0; j < ADT_CELLS_PER_GRID; j++)
644  {
645  adt_MCNK *cell = cells->getMCNK(i, j);
646  if (!cell)
647  continue;
648 
649  adt_MCLQ *liquid = cell->getMCLQ();
650  int count = 0;
651  if (!liquid || cell->sizeMCLQ <= 8)
652  continue;
653 
654  for (int y = 0; y < ADT_CELL_SIZE; y++)
655  {
656  int cy = i * ADT_CELL_SIZE + y;
657  for (int x = 0; x < ADT_CELL_SIZE; x++)
658  {
659  int cx = j * ADT_CELL_SIZE + x;
660  if (liquid->flags[y][x] != 0x0F)
661  {
662  liquid_show[cy][cx] = true;
663  if (liquid->flags[y][x] & (1<<7))
665  ++count;
666  }
667  }
668  }
669 
670  uint32 c_flag = cell->flags;
671  if (c_flag & (1<<2))
672  {
673  liquid_entry[i][j] = 1;
674  liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; // water
675  }
676  if (c_flag & (1<<3))
677  {
678  liquid_entry[i][j] = 2;
679  liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; // ocean
680  }
681  if (c_flag & (1<<4))
682  {
683  liquid_entry[i][j] = 3;
684  liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime
685  }
686 
687  if (!count && liquid_flags[i][j])
688  fprintf(stderr, "Wrong liquid detect in MCLQ chunk");
689 
690  for (int y = 0; y <= ADT_CELL_SIZE; y++)
691  {
692  int cy = i * ADT_CELL_SIZE + y;
693  for (int x = 0; x <= ADT_CELL_SIZE; x++)
694  {
695  int cx = j * ADT_CELL_SIZE + x;
696  liquid_height[cy][cx] = liquid->liquid[y][x].height;
697  }
698  }
699  }
700  }
701 
702  // Get liquid map for grid (in WOTLK used MH2O chunk)
703  adt_MH2O* h2o = adt.a_grid->getMH2O();
704  if (h2o)
705  {
706  for (int i = 0; i < ADT_CELLS_PER_GRID; i++)
707  {
708  for (int j = 0; j < ADT_CELLS_PER_GRID; j++)
709  {
710  adt_liquid_header* h = h2o->getLiquidData(i, j);
711  if (!h)
712  continue;
713 
714  int count = 0;
715  uint64 show = h2o->getLiquidShowMap(h);
716  for (int y = 0; y < h->height; y++)
717  {
718  int cy = i * ADT_CELL_SIZE + y + h->yOffset;
719  for (int x = 0; x < h->width; x++)
720  {
721  int cx = j * ADT_CELL_SIZE + x + h->xOffset;
722  if (show & 1)
723  {
724  liquid_show[cy][cx] = true;
725  ++count;
726  }
727  show >>= 1;
728  }
729  }
730 
731  liquid_entry[i][j] = h->liquidType;
732  switch (LiqType[h->liquidType])
733  {
738  default:
739  printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, filename, i, j);
740  break;
741  }
742  // Dark water detect
744  {
745  uint8* lm = h2o->getLiquidLightMap(h);
746  if (!lm)
748  }
749 
750  if (!count && liquid_flags[i][j])
751  printf("Wrong liquid detect in MH2O chunk");
752 
753  float* height = h2o->getLiquidHeightMap(h);
754  int pos = 0;
755  for (int y = 0; y <= h->height; y++)
756  {
757  int cy = i * ADT_CELL_SIZE + y + h->yOffset;
758  for (int x = 0; x <= h->width; x++)
759  {
760  int cx = j * ADT_CELL_SIZE + x + h->xOffset;
761  if (height)
762  liquid_height[cy][cx] = height[pos];
763  else
764  liquid_height[cy][cx] = h->heightLevel1;
765  pos++;
766  }
767  }
768  }
769  }
770  }
771 
772  //============================================
773  // Pack liquid data
774  //============================================
775  uint8 type = liquid_flags[0][0];
776  bool fullType = false;
777  for (int y = 0; y < ADT_CELLS_PER_GRID; y++)
778  {
779  for (int x = 0; x < ADT_CELLS_PER_GRID; x++)
780  {
781  if (liquid_flags[y][x] != type)
782  {
783  fullType = true;
784  y = ADT_CELLS_PER_GRID;
785  break;
786  }
787  }
788  }
789 
790  map_liquidHeader liquidHeader;
791 
792  // no water data (if all grid have 0 liquid type)
793  if (type == 0 && !fullType)
794  {
795  // No liquid data
796  map.liquidMapOffset = 0;
797  map.liquidMapSize = 0;
798  }
799  else
800  {
801  int minX = 255, minY = 255;
802  int maxX = 0, maxY = 0;
803  maxHeight = -20000;
804  minHeight = 20000;
805  for (int y = 0; y < ADT_GRID_SIZE; y++)
806  {
807  for (int x = 0; x < ADT_GRID_SIZE; x++)
808  {
809  if (liquid_show[y][x])
810  {
811  if (minX > x) minX = x;
812  if (maxX < x) maxX = x;
813  if (minY > y) minY = y;
814  if (maxY < y) maxY = y;
815  float h = liquid_height[y][x];
816  if (maxHeight < h) maxHeight = h;
817  if (minHeight > h) minHeight = h;
818  }
819  else
821  }
822  }
824  map.liquidMapSize = sizeof(map_liquidHeader);
825  liquidHeader.fourcc = *reinterpret_cast<uint32 const*>(MAP_LIQUID_MAGIC);
826  liquidHeader.flags = 0;
827  liquidHeader.liquidType = 0;
828  liquidHeader.offsetX = minX;
829  liquidHeader.offsetY = minY;
830  liquidHeader.width = maxX - minX + 1 + 1;
831  liquidHeader.height = maxY - minY + 1 + 1;
832  liquidHeader.liquidLevel = minHeight;
833 
834  if (maxHeight == minHeight)
835  liquidHeader.flags |= MAP_LIQUID_NO_HEIGHT;
836 
837  // Not need store if flat surface
838  if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_liquid_delta_limit)
839  liquidHeader.flags |= MAP_LIQUID_NO_HEIGHT;
840 
841  if (!fullType)
842  liquidHeader.flags |= MAP_LIQUID_NO_TYPE;
843 
844  if (liquidHeader.flags & MAP_LIQUID_NO_TYPE)
845  liquidHeader.liquidType = type;
846  else
847  map.liquidMapSize += sizeof(liquid_entry) + sizeof(liquid_flags);
848 
849  if (!(liquidHeader.flags & MAP_LIQUID_NO_HEIGHT))
850  map.liquidMapSize += sizeof(float) * liquidHeader.width * liquidHeader.height;
851  }
852 
853  // map hole info
855 
856  if (map.liquidMapOffset)
857  map.holesOffset = map.liquidMapOffset + map.liquidMapSize;
858  else
859  map.holesOffset = map.heightMapOffset + map.heightMapSize;
860 
861  memset(holes, 0, sizeof(holes));
862  bool hasHoles = false;
863 
864  for (int i = 0; i < ADT_CELLS_PER_GRID; ++i)
865  {
866  for (int j = 0; j < ADT_CELLS_PER_GRID; ++j)
867  {
868  adt_MCNK* cell = cells->getMCNK(i, j);
869  if (!cell)
870  continue;
871  holes[i][j] = cell->holes;
872  if (!hasHoles && cell->holes != 0)
873  hasHoles = true;
874  }
875  }
876 
877  if (hasHoles)
878  map.holesSize = sizeof(holes);
879  else
880  map.holesSize = 0;
881 
882  // Ok all data prepared - store it
883 
884  FILE* output = fopen(filename2, "wb");
885  if (!output)
886  {
887  printf("Can't create the output file '%s'\n", filename2);
888  return false;
889  }
890 
891  fwrite(&map, sizeof(map), 1, output);
892  // Store area data
893  fwrite(&areaHeader, sizeof(areaHeader), 1, output);
894  if (!(areaHeader.flags & MAP_AREA_NO_AREA))
895  fwrite(area_flags, sizeof(area_flags), 1, output);
896 
897  // Store height data
898  fwrite(&heightHeader, sizeof(heightHeader), 1, output);
899  if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT))
900  {
901  if (heightHeader.flags & MAP_HEIGHT_AS_INT16)
902  {
903  fwrite(uint16_V9, sizeof(uint16_V9), 1, output);
904  fwrite(uint16_V8, sizeof(uint16_V8), 1, output);
905  }
906  else if (heightHeader.flags & MAP_HEIGHT_AS_INT8)
907  {
908  fwrite(uint8_V9, sizeof(uint8_V9), 1, output);
909  fwrite(uint8_V8, sizeof(uint8_V8), 1, output);
910  }
911  else
912  {
913  fwrite(V9, sizeof(V9), 1, output);
914  fwrite(V8, sizeof(V8), 1, output);
915  }
916  }
917 
918  // Store liquid data if need
919  if (map.liquidMapOffset)
920  {
921  fwrite(&liquidHeader, sizeof(liquidHeader), 1, output);
922 
923  if (!(liquidHeader.flags & MAP_LIQUID_NO_TYPE))
924  {
925  fwrite(liquid_entry, sizeof(liquid_entry), 1, output);
926  fwrite(liquid_flags, sizeof(liquid_flags), 1, output);
927  }
928  if (!(liquidHeader.flags & MAP_LIQUID_NO_HEIGHT))
929  {
930  for (int y = 0; y < liquidHeader.height; y++)
931  fwrite(&liquid_height[y + liquidHeader.offsetY][liquidHeader.offsetX], sizeof(float), liquidHeader.width, output);
932  }
933  }
934 
935  // store hole data
936  if (hasHoles)
937  fwrite(holes, map.holesSize, 1, output);
938 
939  fclose(output);
940  return true;
941 }
942 
944 {
945  char mpq_filename[1024];
946  char output_filename[1024];
947  char mpq_map_name[1024];
948 
949  printf("Extracting maps...\n");
950 
952 
955 
956  std::string path = output_path;
957  path += "/maps/";
958  CreateDir(path);
959 
960  printf("Convert map files\n");
961  for (uint32 z = 0; z < map_count; ++z)
962  {
963  printf("Extract %s (%d/%d) \n", map_ids[z].name, z + 1, map_count);
964  // Loadup map grid data
965  sprintf(mpq_map_name, "World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name);
966  WDT_file wdt;
967  if (!wdt.loadFile(mpq_map_name, false))
968  {
969  // printf("Error loading %s map wdt data\n", map_ids[z].name);
970  continue;
971  }
972 
973  for (uint32 y = 0; y < WDT_MAP_SIZE; ++y)
974  {
975  for (uint32 x = 0; x < WDT_MAP_SIZE; ++x)
976  {
977  if (!wdt.main->adt_list[y][x].exist)
978  continue;
979  sprintf(mpq_filename, "World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y);
980  sprintf(output_filename, "%s/maps/%03u%02u%02u.map", output_path, map_ids[z].id, y, x);
981  ConvertADT(mpq_filename, output_filename, y, x, build);
982  }
983  // draw progress bar
984  printf("Processing........................%d%%\r", (100 * (y + 1)) / WDT_MAP_SIZE);
985  }
986  }
987  delete [] areas;
988  delete [] map_ids;
989 }
990 
991 bool ExtractFile( char const* mpq_name, std::string const& filename )
992 {
993  FILE* output = fopen(filename.c_str(), "wb");
994  if (!output)
995  {
996  printf("Can't create the output file '%s'\n", filename.c_str());
997  return false;
998  }
999  MPQFile m(mpq_name);
1000  if (!m.isEof())
1001  fwrite(m.getPointer(), 1, m.getSize(), output);
1002 
1003  fclose(output);
1004  return true;
1005 }
1006 
1007 void ExtractDBCFiles(int locale, bool basicLocale)
1008 {
1009  printf("Extracting dbc files...\n");
1010 
1011  std::set<std::string> dbcfiles;
1012 
1013  // get DBC file list
1014  for (ArchiveSet::iterator i = gOpenArchives.begin(); i != gOpenArchives.end(); ++i)
1015  {
1016  vector<string> files;
1017  (*i)->GetFileListTo(files);
1018  for (vector<string>::iterator iter = files.begin(); iter != files.end(); ++iter)
1019  if (iter->rfind(".dbc") == iter->length() - strlen(".dbc"))
1020  dbcfiles.insert(*iter);
1021  }
1022 
1023  std::string path = output_path;
1024  path += "/dbc/";
1025  CreateDir(path);
1026  if (!basicLocale)
1027  {
1028  path += langs[locale];
1029  path += "/";
1030  CreateDir(path);
1031  }
1032 
1033  // extract Build info file
1034  {
1035  string mpq_name = std::string("component.wow-") + langs[locale] + ".txt";
1036  string filename = path + mpq_name;
1037 
1038  ExtractFile(mpq_name.c_str(), filename);
1039  }
1040 
1041  // extract DBCs
1042  int count = 0;
1043  for (set<string>::iterator iter = dbcfiles.begin(); iter != dbcfiles.end(); ++iter)
1044  {
1045  string filename = path;
1046  filename += (iter->c_str() + strlen("DBFilesClient\\"));
1047 
1048  if (ExtractFile(iter->c_str(), filename))
1049  ++count;
1050  }
1051  printf("Extracted %u DBC files\n\n", count);
1052 }
1053 
1054 void ExtractCameraFiles(int locale, bool basicLocale)
1055 {
1056  printf("Extracting camera files...\n");
1057  DBCFile camdbc("DBFilesClient\\CinematicCamera.dbc");
1058 
1059  if (!camdbc.open())
1060  {
1061  printf("Unable to open CinematicCamera.dbc. Camera extract aborted.\n");
1062  return;
1063  }
1064 
1065  // get camera file list from DBC
1066  std::vector<std::string> camerafiles;
1067  size_t cam_count = camdbc.getRecordCount();
1068 
1069  for (uint32 i = 0; i < cam_count; ++i)
1070  {
1071  std::string camFile(camdbc.getRecord(i).getString(1));
1072  size_t loc = camFile.find(".mdx");
1073  if (loc != std::string::npos)
1074  camFile.replace(loc, 4, ".m2");
1075  camerafiles.push_back(std::string(camFile));
1076  }
1077 
1078  std::string path = output_path;
1079  path += "/Cameras/";
1080  CreateDir(path);
1081  if (!basicLocale)
1082  {
1083  path += langs[locale];
1084  path += "/";
1085  CreateDir(path);
1086  }
1087 
1088  // extract M2s
1089  uint32 count = 0;
1090  for (std::string thisFile : camerafiles)
1091  {
1092  std::string filename = path;
1093  filename += (thisFile.c_str() + strlen("Cameras\\"));
1094 
1095  if (FileExists(filename.c_str()))
1096  continue;
1097 
1098  if (ExtractFile(thisFile.c_str(), filename))
1099  ++count;
1100  }
1101  printf("Extracted %u camera files\n", count);
1102 }
1103 
1104 void LoadLocaleMPQFiles(int const locale)
1105 {
1106  char filename[512];
1107 
1108  sprintf(filename, "%s/Data/%s/locale-%s.MPQ", input_path, langs[locale], langs[locale]);
1109  new MPQArchive(filename);
1110 
1111  for (int i = 1; i < 5; ++i)
1112  {
1113  char ext[3] = "";
1114  if (i > 1)
1115  sprintf(ext, "-%i", i);
1116 
1117  sprintf(filename, "%s/Data/%s/patch-%s%s.MPQ", input_path, langs[locale], langs[locale], ext);
1118  if (FileExists(filename))
1119  new MPQArchive(filename);
1120  }
1121 }
1122 
1124 {
1125  char filename[512];
1126  int count = sizeof(CONF_mpq_list) / sizeof(char*);
1127  for (int i = 0; i < count; ++i)
1128  {
1129  sprintf(filename, "%s/Data/%s", input_path, CONF_mpq_list[i]);
1130  if (FileExists(filename))
1131  new MPQArchive(filename);
1132  }
1133 }
1134 
1135 inline void CloseMPQFiles()
1136 {
1137  for (ArchiveSet::iterator j = gOpenArchives.begin(); j != gOpenArchives.end(); ++j) (*j)->close();
1138  gOpenArchives.clear();
1139 }
1140 
1141 int main(int argc, char* arg[])
1142 {
1143  printf("Map & DBC Extractor\n");
1144  printf("===================\n\n");
1145 
1146  HandleArgs(argc, arg);
1147 
1148  int FirstLocale = -1;
1149  uint32 build = 0;
1150 
1151  for (int i = 0; i < LANG_COUNT; i++)
1152  {
1153  char tmp1[512];
1154  sprintf(tmp1, "%s/Data/%s/locale-%s.MPQ", input_path, langs[i], langs[i]);
1155  if (FileExists(tmp1))
1156  {
1157  printf("Detected locale: %s\n", langs[i]);
1158 
1159  //Open MPQs
1160  LoadLocaleMPQFiles(i);
1161 
1162  if ((CONF_extract & EXTRACT_DBC) == 0)
1163  {
1164  FirstLocale = i;
1165  build = ReadBuild(FirstLocale);
1166  printf("Detected client build: %u\n", build);
1167  break;
1168  }
1169 
1170  //Extract DBC files
1171  if (FirstLocale < 0)
1172  {
1173  FirstLocale = i;
1174  build = ReadBuild(FirstLocale);
1175  printf("Detected client build: %u\n", build);
1176  ExtractDBCFiles(i, true);
1177  }
1178  else
1179  ExtractDBCFiles(i, false);
1180 
1181  //Close MPQs
1182  CloseMPQFiles();
1183  }
1184  }
1185 
1186  if (FirstLocale < 0)
1187  {
1188  printf("No locales detected\n");
1189  return 0;
1190  }
1191 
1193  {
1194  printf("Using locale: %s\n", langs[FirstLocale]);
1195 
1196  // Open MPQs
1197  LoadLocaleMPQFiles(FirstLocale);
1199 
1200  ExtractCameraFiles(FirstLocale, true);
1201  // Close MPQs
1202  CloseMPQFiles();
1203  }
1204 
1205  if (CONF_extract & EXTRACT_MAP)
1206  {
1207  printf("Using locale: %s\n", langs[FirstLocale]);
1208 
1209  // Open MPQs
1210  LoadLocaleMPQFiles(FirstLocale);
1212 
1213  // Extract maps
1214  ExtractMapsFromMpq(build);
1215 
1216  // Close MPQs
1217  CloseMPQFiles();
1218  }
1219 
1220  return 0;
1221 }
adt_liquid_header * getLiquidData(int x, int y)
Definition: adt.h:220
uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE]
Definition: adt.h:85
uint16 uint16_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition: System.cpp:380
bool loadFile(char *filename, bool log=true)
Definition: loadlib.cpp:39
uint32 sizeMCLQ
Definition: adt.h:128
uint8 offsetY
Definition: Map.h:120
uint64 getLiquidShowMap(adt_liquid_header *h)
Definition: adt.h:262
Record getRecord(size_t id)
Definition: dbcfile.cpp:71
uint8 height
Definition: Map.h:122
uint16 * areas
Definition: System.cpp:63
float CONF_float_to_int8_limit
Definition: System.cpp:89
uint32 fourcc
Definition: Map.h:105
bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition: System.cpp:387
#define OPEN_FLAGS
Definition: System.cpp:52
uint16 flags
Definition: Map.h:117
uint32 areaMapSize
Definition: Map.h:81
uint32 map_count
Definition: vmapexport.cpp:68
adt_MCLQ * getMCLQ()
Definition: adt.h:143
#define MAP_LIQUID_TYPE_SLIME
Definition: System.cpp:344
#define ADT_GRID_SIZE
Definition: adt.h:40
void LoadCommonMPQFiles()
Definition: System.cpp:1123
bool ExtractFile(char const *mpq_name, std::string const &filename)
Definition: System.cpp:991
Definition: adt.h:62
void ExtractMapsFromMpq(uint32 build)
Definition: System.cpp:943
#define MAP_LIQUID_TYPE_OCEAN
Definition: System.cpp:343
float ypos
Definition: adt.h:131
void Usage(char *prg)
Definition: System.cpp:131
uint16 holes
Definition: adt.h:117
float CONF_flat_height_delta_limit
Definition: System.cpp:91
float gridMaxHeight
Definition: Map.h:108
bool open()
Definition: dbcfile.cpp:29
Definition: adt.h:154
uint8 offsetX
Definition: Map.h:119
uint32 ReadMapDBC()
Definition: System.cpp:227
adt_MH2O * getMH2O()
Definition: adt.h:307
uint32 flags
Definition: Map.h:106
float CONF_float_to_int16_limit
Definition: System.cpp:90
uint32 fourcc
Definition: Map.h:116
bool FileExists(const char *FileName)
Definition: System.cpp:119
uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition: System.cpp:386
uint32 areaMapOffset
Definition: Map.h:80
#define MAP_LIQUID_NO_TYPE
Definition: System.cpp:351
#define MAP_LIQUID_TYPE_WATER
Definition: System.cpp:345
uint16 uint16_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition: System.cpp:381
bool isEof()
Definition: mpq_libmpq.h:90
size_t getSize()
Definition: mpq_libmpq.h:86
uint32 ix
Definition: adt.h:103
void ReadLiquidTypeTableDBC()
Definition: System.cpp:273
float height_map[(ADT_CELL_SIZE+1)*(ADT_CELL_SIZE+1)+ADT_CELL_SIZE *ADT_CELL_SIZE]
Definition: adt.h:54
uint8 uint8_V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition: System.cpp:383
bool CONF_allow_height_limit
Definition: System.cpp:84
void CreateDir(const std::string &Path)
Definition: System.cpp:110
struct wdt_MAIN::adtData adt_list[64][64]
uint16 gridArea
Definition: Map.h:96
float selectUInt16StepStore(float maxDiff)
Definition: System.cpp:371
uint32 id
Definition: System.cpp:59
void ExtractDBCFiles(int locale, bool basicLocale)
Definition: System.cpp:1007
void LoadLocaleMPQFiles(int const locale)
Definition: System.cpp:1104
map_id * map_ids
Definition: System.cpp:62
uint16 liquidType
Definition: Map.h:118
uint8 width
Definition: Map.h:121
float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition: System.cpp:388
#define MAP_HEIGHT_AS_INT8
Definition: System.cpp:331
char output_path[MAX_PATH_LENGTH]
Definition: System.cpp:66
float liquidLevel
Definition: Map.h:123
#define MAP_LIQUID_TYPE_DARK_WATER
Definition: System.cpp:347
uint32 ReadBuild(int locale)
Definition: System.cpp:190
uint16 * LiqType
Definition: System.cpp:64
adt_MCNK * getMCNK(int x, int y)
Definition: adt.h:173
uint16 area_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition: System.cpp:376
size_t getMaxId()
Definition: dbcfile.cpp:77
const char * CONF_mpq_list[]
Definition: System.cpp:95
ACE_UINT8 uint8
Definition: Define.h:73
uint32 heightMapOffset
Definition: Map.h:82
Definition: Path.h:32
void ReadAreaTableDBC()
Definition: System.cpp:249
#define MAX_PATH_LENGTH
Definition: System.cpp:65
void ExtractCameraFiles(int locale, bool basicLocale)
Definition: System.cpp:1054
float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]
Definition: System.cpp:379
float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition: System.cpp:378
#define ADT_CELLS_PER_GRID
Definition: adt.h:38
Definition: adt.h:314
float CONF_flat_liquid_delta_limit
Definition: System.cpp:92
#define LANG_COUNT
Definition: System.cpp:108
void HandleArgs(int argc, char *arg[])
Definition: System.cpp:144
uint32 holesOffset
Definition: Map.h:86
#define MAP_LIQUID_TYPE_MAGMA
Definition: System.cpp:342
uint8 * getLiquidLightMap(adt_liquid_header *h)
Definition: adt.h:236
uint8 yOffset
Definition: adt.h:191
float selectUInt8StepStore(float maxDiff)
Definition: System.cpp:366
const char * getString(size_t field) const
Definition: dbcfile.h:73
adt_MCIN * getMCIN()
Definition: adt.h:303
#define MAP_HEIGHT_AS_INT16
Definition: System.cpp:330
uint32 liquidMapOffset
Definition: Map.h:84
uint8 width
Definition: adt.h:192
float * getLiquidHeightMap(adt_liquid_header *h)
Definition: adt.h:227
uint32 liquidMapSize
Definition: Map.h:85
uint16 flags
Definition: Map.h:95
#define ADT_CELL_SIZE
Definition: adt.h:39
uint32 exist
Definition: wdt.h:72
char * getPointer()
Definition: mpq_libmpq.h:89
float gridHeight
Definition: Map.h:107
uint32 heightMapSize
Definition: Map.h:83
float CONF_use_minHeight
Definition: System.cpp:85
ACE_UINT64 uint64
Definition: Define.h:70
Definition: adt.h:45
bool CONF_allow_float_to_int
Definition: System.cpp:88
std::deque< MPQArchive * > ArchiveSet
Definition: mpq_libmpq.h:69
int CONF_extract
Definition: System.cpp:82
#define MAP_LIQUID_NO_HEIGHT
Definition: System.cpp:352
unsigned int getUInt(size_t field) const
Definition: dbcfile.h:63
#define MAP_AREA_NO_AREA
Definition: System.cpp:320
uint32 fourcc
Definition: Map.h:94
uint16 liquidType
Definition: adt.h:186
size_t getRecordCount() const
Trivial.
Definition: dbcfile.h:130
struct adt_MCLQ::liquid_data liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1]
char input_path[MAX_PATH_LENGTH]
Definition: System.cpp:67
adt_MCVT * getMCVT()
Definition: adt.h:137
ArchiveSet gOpenArchives
Definition: mpq_libmpq.cpp:22
float heightLevel1
Definition: adt.h:188
adt_MHDR * a_grid
Definition: adt.h:322
uint8 uint8_V8[ADT_GRID_SIZE][ADT_GRID_SIZE]
Definition: System.cpp:382
int main(int argc, char *arg[])
Definition: System.cpp:1141
Definition: wdt.h:79
Extract
Definition: System.cpp:73
uint32 mapMagic
Definition: Map.h:77
uint32 flags
Definition: adt.h:102
uint8 xOffset
Definition: adt.h:190
ACE_UINT16 uint16
Definition: Define.h:72
bool ConvertADT(char *filename, char *filename2, int, int, uint32 build)
Definition: System.cpp:390
ACE_UINT32 uint32
Definition: Define.h:71
uint32 iy
Definition: adt.h:104
Definition: adt.h:93
#define WDT_MAP_SIZE
Definition: wdt.h:25
uint8 height
Definition: adt.h:193
wdt_MAIN * main
Definition: wdt.h:89
uint32 holesSize
Definition: Map.h:87
uint32 buildMagic
Definition: Map.h:79
uint16 liquid_entry[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]
Definition: System.cpp:385
#define MAP_HEIGHT_NO_HEIGHT
Definition: System.cpp:329
void CloseMPQFiles()
Definition: System.cpp:1135
uint32 areaid
Definition: adt.h:115
uint32 versionMagic
Definition: Map.h:78
Definition: adt.h:201
uint32 maxAreaId
Definition: System.cpp:68