Pol  Revision:b38175a
uotool/uotool.cpp
Go to the documentation of this file.
00001 /*
00002 History
00003 =======
00004 2009/09/03 MuadDib:   Relocation of multi related cpp/h
00005 2009/11/23 Turley:    added staticdefrag to defrag/remove duplicate statics
00006 2009/12/02 Turley:    added config.max_tile_id - Tomi
00007 
00008 Notes
00009 =======
00010 
00011 */
00012 
00013 #include "../pol/uofile.h"
00014 #include "../pol/polcfg.h"
00015 #include "../pol/polfile.h"
00016 #include "../pol/uofilei.h"
00017 #include "../pol/multi/multidef.h"
00018 #include "../pol/globals/multidefs.h"
00019 #include "../pol/objtype.h"
00020 #include "../pol/poltype.h"
00021 
00022 #include "../plib/realmdescriptor.h"
00023 #include "../plib/staticblock.h"
00024 #include "../plib/systemstate.h"
00025 
00026 #include "../clib/strutil.h"
00027 #include "../clib/stlutil.h"
00028 
00029 #include "../clib/cfgelem.h"
00030 #include "../clib/cfgfile.h"
00031 #include "../clib/cmdargs.h"
00032 #include "../clib/fileutil.h"
00033 #include "../clib/logfacility.h"
00034 #include "../clib/fdump.h"
00035 #include "../clib/passert.h"
00036 
00037 #ifdef _MSC_VER
00038 #pragma warning(disable:4996) // deprecation warning for fopen, sprintf, stricmp
00039 #endif
00040 
00041 namespace Pol {
00042   namespace Multi {
00043     void read_multidefs();
00044     bool BoatShapeExists( unsigned short /*graphic*/ )
00045     {
00046       return true;
00047     }
00048   }
00049   namespace Core {
00050     void safe_getmapinfo( unsigned short x, unsigned short y, short* z, USTRUCT_MAPINFO* mi );
00051     void staticsmax();
00052     void readwater();
00053   }
00054   namespace Uotool {
00055 
00056     int keyid[] = {
00057       0x0002, 0x01f5, 0x0226, 0x0347, 0x0757, 0x0286, 0x03b6, 0x0327,
00058       0x0e08, 0x0628, 0x0567, 0x0798, 0x19d9, 0x0978, 0x02a6, 0x0577,
00059       0x0718, 0x05b8, 0x1cc9, 0x0a78, 0x0257, 0x04f7, 0x0668, 0x07d8,
00060       0x1919, 0x1ce9, 0x03f7, 0x0909, 0x0598, 0x07b8, 0x0918, 0x0c68,
00061       0x02d6, 0x1869, 0x06f8, 0x0939, 0x1cca, 0x05a8, 0x1aea, 0x1c0a,
00062       0x1489, 0x14a9, 0x0829, 0x19fa, 0x1719, 0x1209, 0x0e79, 0x1f3a,
00063       0x14b9, 0x1009, 0x1909, 0x0136, 0x1619, 0x1259, 0x1339, 0x1959,
00064       0x1739, 0x1ca9, 0x0869, 0x1e99, 0x0db9, 0x1ec9, 0x08b9, 0x0859,
00065       0x00a5, 0x0968, 0x09c8, 0x1c39, 0x19c9, 0x08f9, 0x18f9, 0x0919,
00066       0x0879, 0x0c69, 0x1779, 0x0899, 0x0d69, 0x08c9, 0x1ee9, 0x1eb9,
00067       0x0849, 0x1649, 0x1759, 0x1cd9, 0x05e8, 0x0889, 0x12b9, 0x1729,
00068       0x10a9, 0x08d9, 0x13a9, 0x11c9, 0x1e1a, 0x1e0a, 0x1879, 0x1dca,
00069       0x1dfa, 0x0747, 0x19f9, 0x08d8, 0x0e48, 0x0797, 0x0ea9, 0x0e19,
00070       0x0408, 0x0417, 0x10b9, 0x0b09, 0x06a8, 0x0c18, 0x0717, 0x0787,
00071       0x0b18, 0x14c9, 0x0437, 0x0768, 0x0667, 0x04d7, 0x08a9, 0x02f6,
00072       0x0c98, 0x0ce9, 0x1499, 0x1609, 0x1baa, 0x19ea, 0x39fa, 0x0e59,
00073       0x1949, 0x1849, 0x1269, 0x0307, 0x06c8, 0x1219, 0x1e89, 0x1c1a,
00074       0x11da, 0x163a, 0x385a, 0x3dba, 0x17da, 0x106a, 0x397a, 0x24ea,
00075       0x02e7, 0x0988, 0x33ca, 0x32ea, 0x1e9a, 0x0bf9, 0x3dfa, 0x1dda,
00076       0x32da, 0x2eda, 0x30ba, 0x107a, 0x2e8a, 0x3dea, 0x125a, 0x1e8a,
00077       0x0e99, 0x1cda, 0x1b5a, 0x1659, 0x232a, 0x2e1a, 0x3aeb, 0x3c6b,
00078       0x3e2b, 0x205a, 0x29aa, 0x248a, 0x2cda, 0x23ba, 0x3c5b, 0x251a,
00079       0x2e9a, 0x252a, 0x1ea9, 0x3a0b, 0x391b, 0x23ca, 0x392b, 0x3d5b,
00080       0x233a, 0x2cca, 0x390b, 0x1bba, 0x3a1b, 0x3c4b, 0x211a, 0x203a,
00081       0x12a9, 0x231a, 0x3e0b, 0x29ba, 0x3d7b, 0x202a, 0x3adb, 0x213a,
00082       0x253a, 0x32ca, 0x23da, 0x23fa, 0x32fa, 0x11ca, 0x384a, 0x31ca,
00083       0x17ca, 0x30aa, 0x2e0a, 0x276a, 0x250a, 0x3e3b, 0x396a, 0x18fa,
00084       0x204a, 0x206a, 0x230a, 0x265a, 0x212a, 0x23ea, 0x3acb, 0x393b,
00085       0x3e1b, 0x1dea, 0x3d6b, 0x31da, 0x3e5b, 0x3e4b, 0x207a, 0x3c7b,
00086       0x277a, 0x3d4b, 0x0c08, 0x162a, 0x3daa, 0x124a, 0x1b4a, 0x264a,
00087       0x33da, 0x1d1a, 0x1afa, 0x39ea, 0x24fa, 0x373b, 0x249a, 0x372b,
00088       0x1679, 0x210a, 0x23aa, 0x1b8a, 0x3afb, 0x18ea, 0x2eca, 0x0627,
00089       0x00d4 // terminator
00090     };
00091 
00092     /* transforms table above into:
00093         { nbits, bits_reversed [[ LSB .. MSB ]] },
00094         */
00095     int print_ctable()
00096     {
00097       INFO_PRINT << "#include \"ctable.h\"\n\n"
00098         << "SVR_KEYDESC keydesc[ 257 ] = {\n";
00099       fmt::Writer _tmp;
00100       for ( int i = 0; i <= 256; i++ )
00101       {
00102         int nbits = keyid[i] & 0x0F;
00103         unsigned short inmask = 0x10;
00104         const unsigned short val = static_cast<const unsigned short>( keyid[i] );
00105         unsigned short valout = 0;
00106         while ( nbits-- )
00107         {
00108           valout <<= 1;
00109           if ( val & inmask )
00110             valout |= 1;
00111           inmask <<= 1;
00112         }
00113         _tmp.Format( "    {{ {:>2}, 0x{:04X}, 0x{:04X}}},\n" )
00114           << ( keyid[i] & 0x0F )
00115           << ( keyid[i] >> 4 )
00116           << valout;
00117       }
00118       _tmp << "};\n";
00119       INFO_PRINT << _tmp.str();
00120       return 0;
00121     }
00122 
00123     unsigned char buffer[10000];
00124 
00125     int Usage( int ret )
00126     {
00127       ERROR_PRINT << "Usage: uotool func [params ...]\n"
00128         << "  Functions:\n"
00129         << "    tiledump filename        Dump object information\n"
00130         << "    vertile                  Dump updated object info\n"
00131         << "    rawdump filename hdrlen reclen\n"
00132         << "    ctable                   Print Server encryption table\n"
00133         << "    findgraphic graphic      finds coords of statics with graphic\n"
00134         << "    findlandtileflags flags  finds landtiles with flags\n"
00135         << "    contour                  write binary file 6144x4096 z heights\n"
00136         << "    mapdump x1 y1 [x2 y2]    dumps map+statics info to html tables\n"
00137         << "    landtileflagsearch flags [notflags]  prints landtiles matching args\n"
00138         << "    flagsearch flags [notflags]          prints tiles matching flags\n"
00139         << "    landtilehist             prints landtile histogram\n"
00140         << "    staticshist              histogram of number of statics at a location\n"
00141         << "    zhist                    histogram of map z\n"
00142         << "    multis                   prints multi definitions \n"
00143         << "    verdata                  prints verdata info\n"
00144         << "    statics                  prints statics info\n"
00145         << "    sndlist                  prints sound list info\n"
00146         << "    verlandtile              prints verdata landtile info\n"
00147         << "    loschange                prints differences in LOS handling \n"
00148         << "    staticdefrag [realm]     recreates static files {default britannia} \n"
00149         << "    formatdesc name          prints plural and singular form of name \n"
00150         << "    checkmultis              prints infos about multi center items \n";
00151       return ret;
00152     }
00153 #define TILES_START 0x68800
00154 
00155     void display_tileinfo( unsigned short objtype, const Core::USTRUCT_TILE& tile )
00156     {
00157       fmt::Writer _tmp;
00158       _tmp.Format( "objtype:  0x{:04X}\n" ) << objtype;
00159       _tmp << "  name:   " << tile.name << "\n";
00160       if ( tile.flags )  _tmp.Format( "  flags:  0x{:08X}\n" ) << static_cast<unsigned long>( tile.flags );
00161       if ( tile.weight ) _tmp.Format( "  weight: 0x{:02X}\n" ) << (int)tile.weight;
00162       if ( tile.layer )  _tmp.Format( "  layer:  0x{:02X}\n" ) << (int)tile.layer;
00163       if ( tile.unk6 )   _tmp.Format( "  unk6:   0x{:02X}\n" ) << (int)tile.unk6;
00164       if ( tile.unk7 )   _tmp.Format( "  unk7:   0x{:02X}\n" ) << (int)tile.unk7;
00165       if ( tile.unk8 )   _tmp.Format( "  unk8:   0x{:02X}\n" ) << (int)tile.unk8;
00166       if ( tile.unk9 )   _tmp.Format( "  unk9:   0x{:02X}\n" ) << (int)tile.unk9;
00167       if ( tile.anim )   _tmp.Format( "  anim:   0x{:08X}\n" ) << static_cast<unsigned long>( tile.anim );
00168       if ( tile.height ) _tmp.Format( "  height: 0x{:02X}\n" ) << (int)tile.height;
00169       if ( tile.unk14 )  _tmp.Format( "  unk14:  0x{:02X}\n" ) << (int)tile.unk14;
00170       if ( tile.unk15 )  _tmp.Format( "  unk15:  0x{:02X}\n" ) << (int)tile.unk15;
00171     }
00172 
00173     int tiledump( int argc, char **argv )
00174     {
00175       Core::USTRUCT_TILE tile;
00176       u32 version;
00177       if ( argc != 3 )
00178         return Usage( 1 );
00179 
00180       FILE *fp = fopen( argv[2], "rb" );
00181       fseek( fp, TILES_START, SEEK_SET );
00182       int recnum = 0;
00183       unsigned short objtype = 0;
00184       for ( ;; )
00185       {
00186         if ( recnum == 0 )
00187         {
00188           if ( fread( &version, sizeof version, 1, fp ) != 1 )
00189             break;
00190           INFO_PRINT.Format( "Block Version: {:08X}\n" ) << static_cast<unsigned long>( version );
00191         }
00192         if ( fread( &tile, sizeof tile, 1, fp ) != 1 )
00193           break;
00194         display_tileinfo( objtype, tile );
00195 
00196 
00197         ++objtype;
00198         ++recnum;
00199         if ( recnum == 32 )
00200           recnum = 0;
00201 
00202       }
00203       fclose( fp );
00204       return 0;
00205     }
00206 
00207     int vertile( int /*argc*/, char ** /*argv*/ )
00208     {
00209       Core::USTRUCT_TILE tile;
00210 
00211       Core::open_uo_data_files();
00212       Core::read_uo_data( );
00213 
00214       int i;
00215       for ( i = 0; i <= 0xFFFF; i++ )
00216       {
00217         unsigned short objtype = (unsigned short)i;
00218         read_objinfo( objtype, tile );
00219         display_tileinfo( objtype, tile );
00220       }
00221       Core::clear_tiledata( );
00222       return 0;
00223     }
00224 
00225     int verlandtile( int /*argc*/, char ** /*argv*/ )
00226     {
00227       Core::USTRUCT_LAND_TILE landtile;
00228 
00229       Core::open_uo_data_files( );
00230       Core::read_uo_data( );
00231 
00232       int i;
00233       for ( i = 0; i <= 0x3FFF; i++ )
00234       {
00235         unsigned short objtype = (unsigned short)i;
00236         readlandtile( objtype, &landtile );
00237         if ( landtile.flags || landtile.unk || landtile.name[0] )
00238         {
00239           INFO_PRINT << "Land Tile: 0x" << fmt::hexu(objtype) << "\n"
00240           << "\tflags: 0x" << fmt::hexu( landtile.flags ) << "\n"
00241           << "\t  unk: 0x" << fmt::hexu( landtile.unk ) << "\n"
00242           << "\t name: " << landtile.name << "\n";
00243         }
00244       }
00245       Core::clear_tiledata( );
00246       return 0;
00247     }
00248 
00249     int landtilehist( int /*argc*/, char** /*argv*/ )
00250     {
00251       Core::USTRUCT_LAND_TILE landtile;
00252 
00253       Core::open_uo_data_files( );
00254       Core::read_uo_data( );
00255 
00256       typedef std::map<std::string, unsigned> M;
00257       M tilecount;
00258 
00259       int i;
00260       for ( i = 0; i < 0x4000; i++ )
00261       {
00262         unsigned short objtype = (unsigned short)i;
00263         readlandtile( objtype, &landtile );
00264         tilecount[landtile.name] = tilecount[landtile.name] + 1;
00265       }
00266 
00267       fmt::Writer tmp;
00268       for ( const auto &elem : tilecount )
00269       {
00270         tmp << elem.first << ": " << elem.second << "\n";
00271       }
00272       INFO_PRINT << tmp.str();
00273       Core::clear_tiledata( );
00274       return 0;
00275     }
00276 
00277     int landtilecfg( int /*argc*/, char** /*argv*/ )
00278     {
00279       Core::USTRUCT_LAND_TILE landtile;
00280 
00281       Core::open_uo_data_files( );
00282       Core::read_uo_data( );
00283 
00284       typedef std::map<std::string, unsigned> M;
00285       M tilecount;
00286 
00287       int i;
00288       for ( i = 0; i < 0x4000; i++ )
00289       {
00290         unsigned short objtype = (unsigned short)i;
00291         readlandtile( objtype, &landtile );
00292         tilecount[landtile.name] = tilecount[landtile.name] + 1;
00293       }
00294 
00295       fmt::Writer tmp;
00296       for ( const auto &elem : tilecount )
00297       {
00298         tmp << elem.first << ": " << elem.second << "\n";
00299       }
00300       INFO_PRINT << tmp.str();
00301       Core::clear_tiledata( );
00302       return 0;
00303     }
00304 
00305     int flagsearch( int argc, char **argv )
00306     {
00307       Core::USTRUCT_TILE tile;
00308 
00309       Core::open_uo_data_files( );
00310       Core::read_uo_data( );
00311 
00312       if ( argc < 3 ) return 1;
00313 
00314       unsigned int flags = strtoul( argv[2], NULL, 0 );
00315       unsigned int notflags = 0;
00316       if ( argc >= 4 )
00317         notflags = strtoul( argv[3], NULL, 0 );
00318 
00319       int i;
00320       for ( i = 0; i <= 0xFFFF; i++ )
00321       {
00322         unsigned short objtype = (unsigned short)i;
00323         read_objinfo( objtype, tile );
00324         if ( ( ( tile.flags & flags ) == flags ) &&
00325              ( ( ~tile.flags & notflags ) == notflags ) )
00326         {
00327           display_tileinfo( objtype, tile );
00328         }
00329       }
00330       Core::clear_tiledata( );
00331       return 0;
00332     }
00333 
00334     int landtileflagsearch( int argc, char **argv )
00335     {
00336 
00337       Core::open_uo_data_files( );
00338       Core::read_uo_data( );
00339 
00340       if ( argc < 3 ) return 1;
00341 
00342       unsigned int flags = strtoul( argv[2], NULL, 0 );
00343       unsigned int notflags = 0;
00344       if ( argc >= 4 )
00345         notflags = strtoul( argv[3], NULL, 0 );
00346 
00347       Core::USTRUCT_LAND_TILE landtile;
00348 
00349       int i;
00350       for ( i = 0; i < 0x4000; i++ )
00351       {
00352         unsigned short objtype = (unsigned short)i;
00353         readlandtile( objtype, &landtile );
00354         if ( ( landtile.flags & flags ) == flags &&
00355              ( ~landtile.flags & notflags ) == notflags )
00356         {
00357           INFO_PRINT << "Land Tile: 0x" << fmt::hexu( objtype ) << "\n"
00358             << "\tflags: 0x" << fmt::hexu( landtile.flags ) << "\n"
00359             << "\t  unk: 0x" << fmt::hexu( landtile.unk ) << "\n"
00360             << "\t name: " << landtile.name << "\n";
00361         }
00362       }
00363       Core::clear_tiledata( );
00364       return 0;
00365     }
00366 
00367     int loschange( int /*argc*/, char** /*argv*/ )
00368     {
00369       Core::USTRUCT_TILE tile;
00370 
00371       Core::open_uo_data_files( );
00372       Core::read_uo_data( );
00373 
00374       for ( int i = 0; i <= 0xFFFF; i++ )
00375       {
00376         unsigned short objtype = (unsigned short)i;
00377         read_objinfo( objtype, tile );
00378 
00379         bool old_lostest = ( tile.flags & Core::USTRUCT_TILE::FLAG_WALKBLOCK ) != 0;
00380 
00381         bool new_lostest = ( tile.flags & ( Core::USTRUCT_TILE::FLAG_WALKBLOCK | Core::USTRUCT_TILE::FLAG_NO_SHOOT ) ) != 0;
00382 
00383 
00384         if ( old_lostest != new_lostest )
00385         {
00386           display_tileinfo( objtype, tile );
00387           INFO_PRINT.Format( " Old LOS: %s\n New LOS: %s\n" ) << ( old_lostest ? "true" : "false" )
00388             << ( new_lostest ? "true" : "false" );
00389 
00390         }
00391 
00392       }
00393       Core::clear_tiledata( );
00394       return 0;
00395     }
00396 
00397     int print_verdata_info()
00398     {
00399       Core::open_uo_data_files( );
00400       Core::read_uo_data( );
00401       int num_version_records;
00402       Core::USTRUCT_VERSION vrec;
00403 
00404       // FIXME: should read this once per run, per file.
00405       fseek( Core::verfile, 0, SEEK_SET );
00406       fread( &num_version_records, sizeof num_version_records, 1, Core::verfile ); // ENDIAN-BROKEN
00407 
00408       INFO_PRINT << "There are " << num_version_records << " version records.\n";
00409 
00410       int filecount[32];
00411       int inv_filecount = 0;
00412       memset( filecount, 0, sizeof filecount );
00413 
00414       for ( int i = 0; i < num_version_records; i++ )
00415       {
00416         fread( &vrec, sizeof vrec, 1, Core::verfile );
00417         if ( vrec.file < 32 )
00418           ++filecount[vrec.file];
00419         else
00420           ++inv_filecount;
00421       }
00422       for ( int i = 0; i < 32; ++i )
00423       {
00424         if ( filecount[i] )
00425           INFO_PRINT << "File 0x" << fmt::hexu( i ) << ": " << filecount[i] << " versioned blocks.\n";
00426       }
00427       if ( inv_filecount )
00428         INFO_PRINT << inv_filecount << " invalid file indexes\n";
00429       Core::clear_tiledata( );
00430       return 0;
00431     }
00432 
00433     int print_statics()
00434     {
00435       INFO_PRINT << "Reading UO data..\n";
00436       Core::open_uo_data_files( );
00437       Core::read_uo_data( );
00438       int water = 0;
00439       int strange_water = 0;
00440       int cnt = 0;
00441       for ( u16 y = 30; y < 50; y++ )
00442       {
00443         for ( u16 x = 5900; x < 5940; x++ )
00444         {
00445           std::vector<Core::StaticRec> vec;
00446           Core::readallstatics( vec, x, y );
00447 
00448           if ( !vec.empty() )
00449           {
00450             bool hdrshown = false;
00451             for ( const auto &elem : vec )
00452             {
00453               int height = Core::tileheight( elem.graphic );
00454               if ( elem.graphic >= 0x1796 && elem.graphic <= 0x17b2 )
00455               {
00456                 if ( elem.z == -5 && height == 0 )
00457                   water++;
00458                 else
00459                   strange_water++;
00460                 continue;
00461               }
00462               if ( !hdrshown )
00463                 INFO_PRINT << x << "," << y << ":\n";
00464               hdrshown = true;
00465               INFO_PRINT << "\tOBJT= 0x" << fmt::hexu( elem.graphic )
00466                 << "  Z=" << int( elem.z ) << "  HT=" << height
00467                 << "  FLAGS=0x" << fmt::hexu( Core::tile_uoflags( elem.graphic ) ) << "\n";
00468               ++cnt;
00469             }
00470           }
00471         }
00472       }
00473       INFO_PRINT << cnt << " statics exist.\n"
00474         << water << " water tiles exist.\n"
00475         << strange_water << " strange water tiles exist.\n";
00476       Core::clear_tiledata( );
00477       return 0;
00478     }
00479 
00480 
00481 
00482     void elimdupes( Core::StaticList& list )
00483     {
00484       bool any = true;
00485       do
00486       {
00487         any = false;
00488         for ( unsigned i = 0; !any && ( i < list.size() ); ++i )
00489         {
00490           for ( unsigned j = 0; !any && ( j < list.size() ); ++j )
00491           {
00492             if ( i == j )
00493               continue;
00494             if ( Core::tile_uoflags( list[i].graphic ) == Core::tile_uoflags( list[j].graphic ) &&
00495                  Core::tileheight( list[i].graphic ) == Core::tileheight( list[j].graphic ) &&
00496                  list[i].z == list[j].z )
00497             {
00498               list[i] = list.back();
00499               list.pop_back();
00500               any = true;
00501             }
00502           }
00503         }
00504       } while ( any );
00505     }
00506 
00507 #if 0
00508     int test_new_statics()
00509     {
00510       INFO_PRINT << "Reading UO data..\n";
00511       open_uo_data_files();
00512       read_uo_data();
00513       load_pol_static_files();
00514 
00515       for( unsigned x = 0; x < 6144; ++x )
00516       {
00517         for( unsigned y = 0; y < 4096; ++y )
00518         {
00519           StaticList list1, list2;
00520           readstatics( list1, x, y );
00521           readstatics2( list2, x, y );
00522 
00523           for( unsigned i = 0; i < list1.size(); ++i )
00524           {
00525             StaticRec& r1 = list1[i];
00526             // see if this is represented
00527             // really should check that there aren't any extras, too!
00528             bool found = false;
00529             for( unsigned j = 0; j < list2.size(); ++j )
00530             {
00531               StaticRec& r2 = list2[j];
00532               if (tileheight(r1.graphic) == tileheight(r2.graphic) &&
00533                    r1.z == r2.z)
00534               {
00535                 found = true;
00536                 break;
00537               }
00538             }
00539             if (!found)
00540             {
00541               INFO_PRINT << "elem not found: x=" << x << ", y=" << y << ",i=" << i
00542                 << ", r1.graphic=" << r1.graphic << ", r1.z=" << int(r1.z)
00543                 << "\n";
00544               INFO_PRINT << "list1:\n";
00545               for( unsigned j = 0; j < list1.size(); ++j )
00546               {
00547                 INFO_PRINT << "gid=" << list1[j].graphic 
00548                   << " z=" << int(list1[j].z) 
00549                   << " ht=" << int(tileheight(list1[j].graphic))
00550                   << "\n";
00551               }
00552               INFO_PRINT << "list2:\n";
00553               for( unsigned j = 0; j < list2.size(); ++j )
00554               {
00555                 INFO_PRINT << "gid=" << list2[j].graphic 
00556                   << " z=" << int(list2[j].z) 
00557                   << " ht=" << int(tileheight(list2[j].graphic))
00558                   << "\n";
00559               }
00560             }
00561           }
00562         }
00563       }
00564       clear_tiledata();
00565       return 0;
00566     }
00567 #endif
00568 
00569     int rawdump( int argc, char **argv )
00570     {
00571       if ( argc != 5 )
00572         return Usage( 1 );
00573 
00574       FILE *fp = fopen( argv[2], "rb" );
00575       int hdrlen = atoi( argv[3] );
00576       int reclen = atoi( argv[4] );
00577       int recnum = 0;
00578       if ( !fp )
00579         return 1;
00580 
00581       if ( hdrlen )
00582       {
00583         if ( fread( buffer, hdrlen, 1, fp ) != 1 )
00584         {
00585           fclose( fp );
00586           return 1;
00587         }
00588         fmt::Writer tmp;
00589         tmp << "Header:\n";
00590         Clib::fdump( tmp, buffer, hdrlen );
00591         INFO_PRINT << tmp.str() << "\n";
00592       }
00593 
00594       while ( fread( buffer, reclen, 1, fp ) == 1 )
00595       {
00596         fmt::Writer tmp;
00597         tmp.Format( "Record {} (0x{:X}):\n" ) << recnum << recnum;
00598         Clib::fdump( tmp, buffer, reclen );
00599         INFO_PRINT << tmp.str( ) << "\n";
00600 
00601         ++recnum;
00602       }
00603       INFO_PRINT << recnum << " records read.\n";
00604       fclose( fp );
00605       return 0;
00606     }
00607 
00608     unsigned int read_ulong( std::istream& is )
00609     {
00610       unsigned char a[4];
00611       is.read( (char *)a, sizeof a );
00612       return ( a[3] << 24 ) | ( a[2] << 16 ) | ( a[1] << 8 ) | a[0];
00613     }
00614 
00615     int print_sndlist( int /*argc*/, char** /*argv*/ )
00616     {
00617       unsigned int offset;
00618       unsigned int length;
00619       unsigned int serial;
00620       char filename[15];
00621 
00622       std::string soundidxname = Plib::systemstate.config.uo_datafile_root + "soundidx.mul";
00623       std::string soundname = Plib::systemstate.config.uo_datafile_root + "sound.mul";
00624       std::ifstream soundidx(soundidxname.c_str(), std::ios::in | std::ios::binary);
00625       std::ifstream sound(soundname.c_str(), std::ios::in | std::ios::binary);
00626       int i;
00627       i = 0;
00628       while ( soundidx.good() )
00629       {
00630         ++i;
00631         offset = read_ulong( soundidx );
00632         length = read_ulong( soundidx );
00633         serial = read_ulong( soundidx );
00634         if ( !soundidx.good() )
00635           break;
00636 
00637         if ( offset == 0xFFffFFffLu )
00638           continue;
00639 
00640         sound.seekg(offset, std::ios::beg);
00641         if ( !sound.good() )
00642           break;
00643 
00644         sound.read( filename, sizeof filename );
00645         INFO_PRINT << "0x" << fmt::hexu( i ) << ", 0x" << fmt::hexu( serial ) << ": " << filename << "\n"
00646           << "len " << length << "\n";
00647       }
00648       return 0;
00649     }
00650 
00651     void print_multihull( u16 i, Multi::MultiDef* multi )
00652     {
00653       if ( multi->hull.empty() )
00654         return;
00655 
00656       Core::USTRUCT_TILE tile;
00657       read_objinfo( static_cast<u16>( i + ( Plib::systemstate.config.max_tile_id + 1 ) ), tile );
00658       INFO_PRINT << "Multi 0x" << fmt::hexu (i + i + ( Plib::systemstate.config.max_tile_id + 1 ) )
00659         << " -- " << tile.name << ":\n";
00660       fmt::Writer tmp;
00661       for ( short y = multi->minry; y <= multi->maxry; ++y )
00662       {
00663         for ( short x = multi->minrx; x <= multi->maxrx; ++x )
00664         {
00665           unsigned short key = multi->getkey( x, y );
00666           bool external = multi->hull2.count( key ) != 0;
00667           bool internal = multi->internal_hull2.count( key ) != 0;
00668           bool origin = ( x == 0 && y == 0 );
00669 
00670           if ( external && !internal )
00671             tmp << 'H';
00672           else if ( !external && internal )
00673             tmp << 'i';
00674           else if ( external && internal )
00675             tmp << 'I';
00676           else if ( origin )
00677             tmp << '*';
00678           else
00679             tmp << ' ';
00680         }
00681         tmp << "\n";
00682       }
00683       tmp << "\n";
00684       INFO_PRINT << tmp.str( );
00685     }
00686 
00687     void print_widedata( u16 i, Multi::MultiDef* multi )
00688     {
00689       if ( multi->hull.empty() )
00690         return;
00691 
00692       Core::USTRUCT_TILE tile;
00693       read_objinfo( static_cast<u16>( i + ( Plib::systemstate.config.max_tile_id + 1 ) ), tile );
00694       INFO_PRINT << "Multi 0x" << fmt::hexu( i + ( Plib::systemstate.config.max_tile_id + 1 ) )
00695         << " -- " << tile.name << ":\n";
00696       fmt::Writer tmp;
00697       for ( short y = multi->minry; y <= multi->maxry; ++y )
00698       {
00699         for ( short x = multi->minrx; x <= multi->maxrx; ++x )
00700         {
00701           const Multi::MULTI_ELEM* elem = multi->find_component( x, y );
00702           if ( elem != NULL )
00703           {
00704             tmp << "0x" << fmt::pad( fmt::hexu( elem->is_static ), 6 ) << ":";
00705           }
00706           else
00707           {
00708             tmp << "        " << ":";
00709           }
00710         }
00711         tmp << "\n";
00712       }
00713       tmp << "\n";
00714       INFO_PRINT << tmp.str();
00715     }
00716 
00717     void print_multidata( u16 i, Multi::MultiDef* multi )
00718     {
00719       if ( multi->hull.empty() )
00720         return;
00721 
00722       Core::USTRUCT_TILE tile;
00723       read_objinfo( static_cast<u16>( i + ( Plib::systemstate.config.max_tile_id + 1 ) ), tile );
00724       INFO_PRINT << "Multi 0x" << fmt::hexu( i + ( Plib::systemstate.config.max_tile_id + 1 ) )
00725         << " -- " << tile.name << ":\n";
00726       fmt::Writer tmp;
00727       for ( const auto &_itr : multi->components )
00728       {
00729         const Multi::MULTI_ELEM* elem = _itr.second;
00730         tmp << "0x" << fmt::hexu( elem->objtype)
00731           << " 0x" << fmt::hexu((int)elem->is_static)
00732           << ":"  << elem->x << "," << elem->y << "," << elem->z << "\n";
00733       }
00734       INFO_PRINT << tmp.str();
00735     }
00736 
00737     int print_multis( void )
00738     {
00739       INFO_PRINT << "Reading UO data..\n";
00740       Core::open_uo_data_files( );
00741       Core::read_uo_data( );
00742       Multi::read_multidefs();
00743 
00744       for ( u16 i = 0; i < 0x1000; ++i )
00745       {
00746         if ( Multi::multidef_buffer.multidefs_by_multiid[i] )
00747         {
00748           print_multihull( i, Multi::multidef_buffer.multidefs_by_multiid[i] );
00749           print_multidata( i, Multi::multidef_buffer.multidefs_by_multiid[i] );
00750         }
00751       }
00752       Core::clear_tiledata( );
00753       return 0;
00754 
00755     }
00756 
00757     int z_histogram()
00758     {
00759       unsigned int zcount[256];
00760       memset(zcount, 0, sizeof(zcount));
00761 
00762       INFO_PRINT << "Reading UO data..\n";
00763       Core::open_uo_data_files( );
00764       Core::read_uo_data( );
00765       for ( u16 x = 0; x < 6143; ++x )
00766       {
00767         INFO_PRINT << ".";
00768         for ( u16 y = 0; y < 4095; ++y )
00769         {
00770           Core::USTRUCT_MAPINFO mi;
00771           short z;
00772           getmapinfo( x, y, &z, &mi );
00773           assert( z >= Core::ZCOORD_MIN && z <= Core::ZCOORD_MAX );
00774           ++zcount[z + 128];
00775         }
00776       }
00777       INFO_PRINT << "\n";
00778       for ( int i = 0; i < 256; ++i )
00779       {
00780         if ( zcount[i] )
00781           INFO_PRINT << i - 128 << ": " << zcount[i] << "\n";
00782       }
00783       Core::clear_tiledata( );
00784       return 0;
00785     }
00786 
00787     int statics_histogram()
00788     {
00789       unsigned int counts[1000];
00790       memset( counts, 0, sizeof counts );
00791       INFO_PRINT << "Reading UO data..\n";
00792       Core::open_uo_data_files( );
00793       Core::read_uo_data( );
00794       for ( u16 x = 0; x < 6143; x += 8 )
00795       {
00796         INFO_PRINT << ".";
00797         for ( u16 y = 0; y < 4095; y += 8 )
00798         {
00799           std::vector<Core::USTRUCT_STATIC> p;
00800           int count;
00801 
00802           readstaticblock( &p, &count, x, y );
00803           if ( count < 1000 )
00804               ++counts[count];
00805           else
00806               ERROR_PRINT << "doh: count=" << count << "\n";
00807         }
00808       }
00809       INFO_PRINT << "\n";
00810       for ( int i = 0; i < 1000; ++i )
00811       {
00812         if ( counts[i] )
00813           INFO_PRINT << i << ": " << counts[i] << "\n";
00814       }
00815       Core::clear_tiledata( );
00816       return 0;
00817     }
00818 
00819     int write_polmap( const char* filename, unsigned short xbegin, unsigned short xend )
00820     {
00821       INFO_PRINT << "Writing " << filename << "\n";
00822       FILE* fp = fopen( filename, "wb" );
00823       int num = xend + 1 - xbegin;
00824       for ( u16 xs = xbegin; xs < xend; xs += 8 )
00825       {
00826         int percent = ( xs - xbegin ) * 100 / num;
00827         INFO_PRINT << "\r" << percent << "%";
00828         for ( u16 ys = 0; ys < 4096; ys += 8 )
00829         {
00830           short z;
00831           Core::USTRUCT_POL_MAPINFO_BLOCK blk;
00832           memset( &blk, 0, sizeof blk );
00833           for ( u16 xi = 0; xi < 8; ++xi )
00834           {
00835             for ( u16 yi = 0; yi < 8; ++yi )
00836             {
00837               u16 x = xs + xi;
00838               u16 y = ys + yi;
00839               if ( x == 6143 ) x = 6142;
00840               if ( y == 4095 ) y = 4094;
00841               bool walkok = Core::groundheight( x, y, &z );
00842               blk.z[xi][yi] = static_cast<signed char>( z );
00843               if ( walkok )
00844                 blk.walkok[xi] |= ( 1 << yi );
00845             }
00846           }
00847           fwrite( &blk, sizeof blk, 1, fp );
00848         }
00849       }
00850       fclose( fp );
00851       return 0;
00852     }
00853 
00854     int write_polmap()
00855     {
00856       INFO_PRINT << "Reading UO data..\n";
00857       Core::open_uo_data_files( );
00858       Core::read_uo_data( );
00859       write_polmap( "dngnmap0.pol", 5120, 6144 );
00860       write_polmap( "map0.pol", 0, 6144 );
00861       Core::clear_tiledata( );
00862       return 0;
00863     }
00864 
00865     int print_water_data()
00866     {
00867       Core::open_uo_data_files( );
00868       Core::readwater( );
00869       return 0;
00870     }
00871 
00872     inline bool is_water( u16 objtype )
00873     {
00874       return ( objtype >= 0x1796 && objtype <= 0x17b2 );
00875     }
00876     bool has_water( u16 x, u16 y )
00877     {
00878       Core::StaticList vec;
00879       vec.clear();
00880       Core::readstatics( vec, x, y );
00881       for ( const auto &rec : vec )
00882       {
00883         if ( is_water( rec.graphic ) )
00884           return true;
00885       }
00886       return false;
00887     }
00888 
00889     int water_search( int /*argc*/, char** /*argv*/ )
00890     {
00891       u16 wxl = 1420, wxh = 1480, wyl = 1760, wyh = 1780;
00892       Core::open_uo_data_files( );
00893       for ( u16 y = wyl; y < wyh; y++ )
00894       {
00895         for ( u16 x = wxl; x < wxh; x++ )
00896         {
00897           if ( has_water( x, y ) )
00898             INFO_PRINT << "W";
00899           else
00900             INFO_PRINT << ".";
00901         }
00902         INFO_PRINT << "\n";
00903       }
00904       INFO_PRINT << "\n";
00905       return 0;
00906     }
00907 
00908     int mapdump( int argc, char* argv[] )
00909     {
00910       u16 wxl = 5485, wxh = 5500, wyl = 0, wyh = 30;
00911 
00912       if ( argc >= 4 )
00913       {
00914         wxl = wxh = static_cast<u16>( atoi( argv[2] ) );
00915         wyl = wyh = static_cast<u16>( atoi( argv[3] ) );
00916       }
00917       if ( argc >= 6 )
00918       {
00919         wxh = static_cast<u16>( atoi( argv[4] ) );
00920         wyh = static_cast<u16>( atoi( argv[5] ) );
00921       }
00922 
00923       Core::open_uo_data_files( );
00924       Core::read_uo_data( );
00925 
00926       std::ofstream ofs( "mapdump.html" );
00927 
00928       ofs << "<table border=1 cellpadding=5 cellspacing=0>" << std::endl;
00929       ofs << "<tr><td>&nbsp;</td>";
00930       for ( u16 x = wxl; x <= wxh; ++x )
00931       {
00932         ofs << "<td align=center>" << x << "</td>";
00933       }
00934       ofs << "</tr>" << std::endl;
00935       for ( u16 y = wyl; y <= wyh; ++y )
00936       {
00937           ofs << "<tr><td valign=center>" << y << "</td>" << std::endl;
00938         for ( u16 x = wxl; x <= wxh; ++x )
00939         {
00940           ofs << "<td align=left valign=top>";
00941           short z;
00942           Core::USTRUCT_MAPINFO mi;
00943           safe_getmapinfo( x, y, &z, &mi );
00944           Core::USTRUCT_LAND_TILE landtile;
00945           readlandtile( mi.landtile, &landtile );
00946           ofs << "z=" << z << "<br>";
00947           ofs << "landtile=" << Clib::hexint( mi.landtile ) << " " << landtile.name << "<br>";
00948           ofs << "&nbsp;flags=" << Clib::hexint( landtile.flags ) << "<br>";
00949           ofs << "mapz=" << (int)mi.z << "<br>";
00950 
00951           Core::StaticList statics;
00952           readallstatics( statics, x, y );
00953           if ( !statics.empty() )
00954           {
00955               ofs << "<table border=1 cellpadding=5 cellspacing=0>" << std::endl;
00956               ofs << "<tr><td>graphic</td><td>z</td><td>flags</td><td>ht</td>" << std::endl;
00957             for ( const auto &rec : statics )
00958             {
00959               ofs << "<tr>";
00960               ofs << "<td>" << Clib::hexint( rec.graphic ) << "</td>";
00961               ofs << "<td>" << int( rec.z ) << "</td>";
00962               ofs << "<td>" << Clib::hexint( rec.flags ) << "</td>";
00963               ofs << "<td>" << int( rec.height ) << "</td>";
00964               ofs << "</tr>" << std::endl;
00965             }
00966             ofs << "</table>" << std::endl;
00967           }
00968           ofs << "</td>" << std::endl;
00969         }
00970         ofs << "</tr>" << std::endl;
00971       }
00972       ofs << "</table>" << std::endl;
00973       Core::clear_tiledata( );
00974       return 0;
00975     }
00976 
00977     struct MapContour
00978     {
00979       signed char z[6144][4096];
00980     };
00981 
00982     int contour( int /*argc*/, char** /*argv*/ )
00983     {
00984       Core::open_uo_data_files( );
00985       Core::read_uo_data( );
00986 
00987       auto mc = new MapContour;
00988       for ( u16 y = 0; y < 4095; ++y )
00989       {
00990         for ( u16 x = 0; x < 6143; ++x )
00991         {
00992           static Core::StaticList vec;
00993 
00994           vec.clear();
00995 
00996           readstatics( vec, x, y );
00997 
00998           bool result;
00999           short newz;
01000           standheight( Core::MOVEMODE_LAND, vec, x, y, 127,
01001                        &result, &newz );
01002           if ( result )
01003           {
01004             mc->z[x][y] = static_cast<signed char>( newz );
01005           }
01006           else
01007           {
01008             mc->z[x][y] = 127;
01009           }
01010         }
01011       }
01012 
01013       std::ofstream ofs("contour.dat", std::ios::trunc | std::ios::out | std::ios::binary);
01014       ofs.write( reinterpret_cast<const char*>( mc ), sizeof( MapContour ) );
01015       Core::clear_tiledata( );
01016       delete mc;
01017       return 0;
01018     }
01019 
01020     int findlandtile( int /*argc*/, char **argv )
01021     {
01022       int landtile = strtoul( argv[1], NULL, 0 );
01023       Core::open_uo_data_files( );
01024       Core::read_uo_data( );
01025 
01026       for ( u16 y = 0; y < 4095; ++y )
01027       {
01028         for ( u16 x = 0; x < 6143; ++x )
01029         {
01030           short z;
01031           Core::USTRUCT_MAPINFO mi;
01032           safe_getmapinfo( x, y, &z, &mi );
01033           if ( mi.landtile == landtile )
01034           {
01035             INFO_PRINT << x << "," << y << "," << (int)mi.z;
01036             if ( mi.z != z )
01037               INFO_PRINT << " (" << z << ")";
01038             INFO_PRINT << "\n";
01039           }
01040         }
01041       }
01042 
01043       Core::clear_tiledata( );
01044       return 0;
01045     }
01046 
01047     int findgraphic( int /*argc*/, char **argv )
01048     {
01049       int graphic = strtoul( argv[1], NULL, 0 );
01050       INFO_PRINT << "Searching map for statics with graphic=0x" << fmt::hexu( graphic ) << "\n";
01051 
01052       Core::open_uo_data_files( );
01053       Core::read_uo_data( );
01054 
01055       for ( u16 y = 0; y < 4095; ++y )
01056       {
01057         for ( u16 x = 0; x < 6143; ++x )
01058         {
01059           Core::StaticList statics;
01060           readallstatics( statics, x, y );
01061           for ( const auto &rec : statics )
01062           {
01063             if ( rec.graphic == graphic )
01064             {
01065               INFO_PRINT << x << "," << y << "," << rec.z << "\n";
01066             }
01067           }
01068         }
01069       }
01070       Core::clear_tiledata( );
01071       return 0;
01072     }
01073 
01074     int findlandtileflags( int /*argc*/, char **argv )
01075     {
01076       unsigned int flags = strtoul( argv[1], NULL, 0 );
01077       Core::open_uo_data_files( );
01078       Core::read_uo_data( );
01079 
01080       for ( u16 y = 0; y < 4095; ++y )
01081       {
01082         for ( u16 x = 0; x < 6143; ++x )
01083         {
01084           short z;
01085           Core::USTRUCT_MAPINFO mi;
01086           safe_getmapinfo( x, y, &z, &mi );
01087           if ( Core::landtile_uoflags( mi.landtile ) & flags )
01088           {
01089             INFO_PRINT << x << "," << y << "," << (int)mi.z
01090               << ": landtile 0x" << fmt::hexu( mi.landtile )
01091               << ", flags 0x" << fmt::hexu( Core::landtile_uoflags( mi.landtile ) )
01092               << "\n";
01093           }
01094         }
01095       }
01096 
01097       Core::clear_tiledata( );
01098       return 0;
01099     }
01100 
01101     int defragstatics( int argc, char **argv )
01102     {
01103       const char* realm;
01104       if ( argc < 2 )
01105         realm = "britannia";
01106       else
01107         realm = argv[1];
01108 
01109       Plib::RealmDescriptor descriptor = Plib::RealmDescriptor::Load( realm );
01110 
01111       Core::uo_mapid = descriptor.uomapid;
01112       Core::uo_usedif = descriptor.uodif;
01113       Core::uo_map_width = static_cast<unsigned short>( descriptor.width );
01114       Core::uo_map_height = static_cast<unsigned short>( descriptor.height );
01115 
01116       Core::open_uo_data_files( );
01117       Core::read_uo_data( );
01118 
01119       std::string statidx = "staidx" + Clib::tostring(Core::uo_mapid) + ".mul";
01120       std::string statics = "statics" + Clib::tostring(Core::uo_mapid) + ".mul";
01121       Clib::RemoveFile( statidx );
01122       Clib::RemoveFile( statics );
01123 
01124       FILE* fidx = fopen( statidx.c_str(), "wb" );
01125       FILE* fmul = fopen( statics.c_str(), "wb" );
01126 
01127       int lastprogress = -1;
01128       for ( u16 x = 0; x < descriptor.width; x += Plib::STATICBLOCK_CHUNK )
01129       {
01130         int progress = x * 100L / descriptor.width;
01131         if ( progress != lastprogress )
01132         {
01133           INFO_PRINT << "\rRewriting statics files: " << progress << "%";
01134           lastprogress = progress;
01135         }
01136         for ( u16 y = 0; y < descriptor.height; y += Plib::STATICBLOCK_CHUNK )
01137         {
01138             std::vector<Core::USTRUCT_STATIC> pstat;
01139           int num;
01140           std::vector<Core::USTRUCT_STATIC> tilelist;
01141           readstaticblock( &pstat, &num, x, y );
01142           if ( num>0 )
01143           {
01144             int currwritepos = ftell( fmul );
01145             for ( int i = 0; i < num; ++i )
01146             {
01147               Core::USTRUCT_STATIC& tile = pstat[i];
01148               if ( tile.graphic < 0x4000 )
01149               {
01150                 bool first = true;
01151                 for ( const auto &stile : tilelist )
01152                 {
01153                   if ( ( tile.graphic == stile.graphic )
01154                        && ( tile.x_offset == stile.x_offset )
01155                        && ( tile.y_offset == stile.y_offset )
01156                        && ( tile.z == stile.z )
01157                        && ( tile.hue == stile.hue ) )
01158                   {
01159                     first = false;
01160                     break;
01161                   }
01162                 }
01163                 if ( first )
01164                 {
01165                   Core::USTRUCT_STATIC newtile;
01166                   newtile.graphic = tile.graphic;
01167                   newtile.x_offset = tile.x_offset;
01168                   newtile.y_offset = tile.y_offset;
01169                   newtile.z = tile.z;
01170                   newtile.hue = tile.hue;
01171                   tilelist.push_back( newtile );
01172                 }
01173               }
01174             }
01175             Core::USTRUCT_IDX idx;
01176             idx.offset = ~0u;
01177             idx.length = ~0u;
01178             idx.unknown = ~0u;
01179             if ( !tilelist.empty() )
01180             {
01181               idx.offset = currwritepos;
01182               for ( const auto &elem : tilelist )
01183               {
01184                 fwrite( &elem, sizeof( Core::USTRUCT_STATIC ), 1, fmul );
01185               }
01186               currwritepos = ftell( fmul ) - currwritepos;
01187               idx.length = currwritepos;
01188               idx.unknown = 0;
01189               tilelist.clear();
01190             }
01191             fwrite( &idx, sizeof idx, 1, fidx );
01192           }
01193           else
01194           {
01195             Core::USTRUCT_IDX idx;
01196             idx.offset = ~0u;
01197             idx.length = ~0u;
01198             idx.unknown = ~0u;
01199             fwrite( &idx, sizeof idx, 1, fidx );
01200           }
01201         }
01202       }
01203 
01204       INFO_PRINT << "\rRewriting statics files: Complete\n";
01205       fclose( fidx );
01206       fclose( fmul );
01207       return 0;
01208     }
01209 
01210     int format_description( int argc, char **argv )
01211     {
01212       std::string name = "";
01213       for ( int i = 1; i < argc; ++i )
01214       {
01215         name.append( argv[i] );
01216         if ( i < ( argc - 1 ) )
01217           name.append( " " );
01218       }
01219       if ( name.length() == 0 )
01220         return Usage( 1 );
01221       for ( unsigned short amount = 1; amount <= 2; ++amount )
01222       {
01223         const char *src = name.c_str();
01224 
01225         std::string desc;
01226 
01227         if ( amount != 1 )
01228         {
01229           char s[15];
01230           sprintf( s, "%hu ", amount );
01231           desc = s;
01232         }
01233 
01234         int singular = ( amount == 1 );
01235         int plural_handled = 0;
01236         int phase = 0; /* 0= first part, 1=plural part, 2=singular part, 3=rest */
01237         char ch;
01238         while ( '\0' != ( ch = *src ) )
01239         {
01240           if ( phase == 0 )
01241           {
01242             if ( ch == '%' )
01243             {
01244               plural_handled = 1;
01245               phase = 1;
01246             }
01247             else
01248             {
01249               desc += ch;
01250             }
01251           }
01252           else if ( phase == 1 )
01253           {
01254             if ( ch == '%' )
01255               phase = 3;
01256             else if ( ch == '/' )
01257               phase = 2;
01258             else if ( !singular )
01259               desc += ch;
01260           }
01261           else if ( phase == 2 )
01262           {
01263             if ( ch == '%' )
01264               phase = 3;
01265             else if ( singular )
01266               desc += ch;
01267           }
01268           // if phase == 3 that means there are more words to come, 
01269           // lets loop through them to support singular/plural stuff in more than just the first word of the desc.
01270           else
01271           {
01272             desc += ch;
01273             phase = 0;
01274           }
01275           ++src;
01276         }
01277 
01278         if ( !singular && !plural_handled )
01279           desc += 's';
01280 
01281         if ( amount == 1 )
01282           INFO_PRINT << "Singular: " << desc << "\n";
01283         else
01284           INFO_PRINT << "Plural: " << desc << "\n";
01285       }
01286       return 0;
01287     }
01288 
01289     int checkmultis()
01290     {
01291       FILE *multi_idx = Core::open_uo_file( "multi.idx" );
01292       FILE *multi_mul = Core::open_uo_file( "multi.mul" );
01293       if ( fseek( multi_idx, 0, SEEK_SET ) != 0 )
01294       {
01295         fclose( multi_idx );
01296         fclose( multi_mul );
01297         INFO_PRINT << "Failed seek check\n";
01298         return 0;
01299       }
01300       unsigned count = 0;
01301       unsigned warnings = 0;
01302       unsigned errors = 0;
01303       unsigned invisitems = 0;
01304       Core::USTRUCT_IDX idxrec;
01305       for ( int i = 0; fread( &idxrec, sizeof idxrec, 1, multi_idx ) == 1; ++i )
01306       {
01307         if ( idxrec.offset == 0xFFffFFffLu )
01308           continue;
01309         fseek( multi_mul, idxrec.offset, SEEK_SET );
01310         Core::USTRUCT_MULTI_ELEMENT elem;
01311         fread( &elem, sizeof elem, 1, multi_mul );
01312         if ( elem.x != 0 || elem.y != 0 || elem.z != 0 )
01313         {
01314           INFO_PRINT << "ERROR: First tile not in center: " << elem.x << " " << elem.y << " " << elem.z << " (" << elem.flags << ") MultiID: 0x" << fmt::hexu( i ) << "\n";
01315           ++errors;
01316         }
01317         else if ( elem.graphic == 0x0001 )
01318         {
01319           ++invisitems;
01320           unsigned int itemcount = idxrec.length / sizeof elem;
01321           --itemcount;
01322           while ( itemcount-- )
01323           {
01324             fread( &elem, sizeof elem, 1, multi_mul );
01325             if ( elem.x == 0 && elem.y == 0 && elem.z == 0 && elem.graphic != 0x0001 && elem.flags )
01326             {
01327               INFO_PRINT << "Warning: Found invis tile as center, but could use 0x" << fmt::hexu( elem.graphic ) << " at 0 0 0 MultiID: 0x" << fmt::hexu( i ) << "\n";
01328               ++warnings;
01329               break;
01330             }
01331           }
01332         }
01333         ++count;
01334       }
01335       INFO_PRINT << "Checked Multis: " << count << " with invis center: " << invisitems << " Warnings: " << warnings << " Errors: " << errors << "\n";
01336       fclose( multi_idx );
01337       fclose( multi_mul );
01338       return 1;
01339     }
01340 
01341   }
01342 
01343   int xmain( int argc, char* argv[] )
01344   {
01345     Clib::StoreCmdArgs( argc, argv );
01346     Clib::ConfigFile cf( "pol.cfg" );
01347     Clib::ConfigElem elem;
01348 
01349     cf.readraw( elem );
01350 
01351     Plib::systemstate.config.uo_datafile_root = elem.remove_string( "UoDataFileRoot" );
01352     Plib::systemstate.config.uo_datafile_root = Clib::normalized_dir_form( Plib::systemstate.config.uo_datafile_root );
01353 
01354     unsigned short max_tile = elem.remove_ushort( "MaxTileID", UOBJ_DEFAULT_MAX );
01355 
01356     if ( max_tile != UOBJ_DEFAULT_MAX && max_tile != UOBJ_SA_MAX && max_tile != UOBJ_HSA_MAX )
01357       Plib::systemstate.config.max_tile_id = UOBJ_DEFAULT_MAX;
01358     else
01359       Plib::systemstate.config.max_tile_id = max_tile;
01360 
01361     if ( argc <= 1 )
01362       return Uotool::Usage( 1 );
01363 
01364     if ( argv[1][0] == '/' || argv[1][1] == ':' )
01365     {
01366       Plib::systemstate.config.uo_datafile_root = argv[1];
01367       --argc;
01368       ++argv;
01369     }
01370 
01371     if ( stricmp( argv[1], "tiledump" ) == 0 )
01372     {
01373       return Uotool::tiledump( argc, argv );
01374     }
01375     else if ( stricmp( argv[1], "vertile" ) == 0 )
01376     {
01377       return Uotool::vertile( argc, argv );
01378     }
01379     else if ( stricmp( argv[1], "verlandtile" ) == 0 )
01380     {
01381       return Uotool::verlandtile( argc, argv );
01382     }
01383     else if ( stricmp( argv[1], "landtilehist" ) == 0 )
01384     {
01385       return Uotool::landtilehist( argc, argv );
01386     }
01387     else if ( stricmp( argv[1], "flagsearch" ) == 0 )
01388     {
01389       return Uotool::flagsearch( argc, argv );
01390     }
01391     else if ( stricmp( argv[1], "landtileflagsearch" ) == 0 )
01392     {
01393       return Uotool::landtileflagsearch( argc, argv );
01394     }
01395     else if ( stricmp( argv[1], "loschange" ) == 0 )
01396     {
01397       return Uotool::loschange( argc, argv );
01398     }
01399     else if ( stricmp( argv[1], "rawdump" ) == 0 )
01400     {
01401       return Uotool::rawdump( argc, argv );
01402     }
01403     else if ( stricmp( argv[1], "ctable" ) == 0 )
01404     {
01405       return Uotool::print_ctable();
01406     }
01407     else if ( stricmp( argv[1], "sndlist" ) == 0 )
01408     {
01409       return Uotool::print_sndlist( argc, argv );
01410     }
01411     else if ( stricmp( argv[1], "statics" ) == 0 )
01412     {
01413       return Uotool::print_statics();
01414     }
01415     else if ( stricmp( argv[1], "verdata" ) == 0 )
01416     {
01417       return Uotool::print_verdata_info();
01418     }
01419     else if ( stricmp( argv[1], "multis" ) == 0 )
01420     {
01421       return Uotool::print_multis();
01422     }
01423     else if ( stricmp( argv[1], "water" ) == 0 )
01424     {
01425       return Uotool::print_water_data();
01426     }
01427     else if ( stricmp( argv[1], "newstatics" ) == 0 )
01428     {
01429       return Core::write_pol_static_files( "main" );
01430     }
01431     else if ( stricmp( argv[1], "staticsmax" ) == 0 )
01432     {
01433       Core::open_uo_data_files();
01434       Core::staticsmax();
01435       return 0;
01436     }
01437     else if ( stricmp( argv[1], "watersearch" ) == 0 )
01438     {
01439       return Uotool::water_search( argc, argv );
01440     }
01441     else if ( stricmp( argv[1], "zhist" ) == 0 )
01442     {
01443       return Uotool::z_histogram();
01444     }
01445     else if ( stricmp( argv[1], "staticshist" ) == 0 )
01446     {
01447       return Uotool::statics_histogram();
01448     }
01449     else if ( stricmp( argv[1], "writedungmap" ) == 0 )
01450     {
01451       return Uotool::write_polmap();
01452     }
01453     else if ( stricmp( argv[1], "writekeys" ) == 0 )
01454     {
01455       INFO_PRINT << "Keys written to current.key\n";
01456       return 0;
01457     }
01458     else if ( stricmp( argv[1], "mapdump" ) == 0 )
01459     {
01460       return Uotool::mapdump( argc, argv );
01461     }
01462     else if ( stricmp( argv[1], "contour" ) == 0 )
01463     {
01464       return Uotool::contour( argc, argv );
01465     }
01466     else if ( stricmp( argv[1], "findlandtile" ) == 0 )
01467     {
01468       return Uotool::findlandtile( argc - 1, argv + 1 );
01469     }
01470     else if ( stricmp( argv[1], "findlandtileflags" ) == 0 )
01471     {
01472       return Uotool::findlandtileflags( argc - 1, argv + 1 );
01473     }
01474     else if ( stricmp( argv[1], "findgraphic" ) == 0 )
01475     {
01476       return Uotool::findgraphic( argc - 1, argv + 1 );
01477     }
01478     else if ( stricmp( argv[1], "defragstatics" ) == 0 )
01479     {
01480       return Uotool::defragstatics( argc - 1, argv + 1 );
01481     }
01482     else if ( stricmp( argv[1], "formatdesc" ) == 0 )
01483     {
01484       return Uotool::format_description( argc - 1, argv + 1 );
01485     }
01486     else if ( stricmp( argv[1], "checkmultis" ) == 0 )
01487     {
01488       return Uotool::checkmultis();
01489     }
01490 
01491     return Uotool::Usage( 0 );
01492   }
01493 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines