7 #include "../clib/Program/ProgramMain.h" 8 #include "../clib/cfgelem.h" 9 #include "../clib/cfgfile.h" 10 #include "../clib/fileutil.h" 11 #include "../clib/logfacility.h" 12 #include "../clib/passert.h" 13 #include "../clib/rawtypes.h" 14 #include "../clib/stlutil.h" 15 #include "../clib/timer.h" 16 #include "../plib/mapcell.h" 17 #include "../plib/mapfunc.h" 18 #include "../plib/mapshape.h" 19 #include "../plib/mapsolid.h" 20 #include "../plib/maptile.h" 21 #include "../plib/mapwriter.h" 22 #include "../plib/realmdescriptor.h" 23 #include "../plib/systemstate.h" 24 #include "../plib/uopreader/uop.h" 25 #include "../plib/uopreader/uophash.h" 26 #include "../pol/clidata.h" 27 #include "../pol/objtype.h" 28 #include "../pol/polfile.h" 29 #include "../pol/udatfile.h" 30 #include "../pol/uofile.h" 31 #include "../pol/uofilei.h" 32 #include "../pol/ustruct.h" 56 <<
" UOCONVERT command [options ...]\n" 59 <<
" map {uodata=Dir} {maxtileid=0x3FFF/0x7FFF} {realm=realmname} {width=Width}" 60 <<
" {height=Height} {mapid=0} {readuop=1} {x=X} {y=Y}\n" 61 <<
" statics {uodata=Dir} {maxtileid=0x3FFF/0x7FFF} {realm=realmname}\n" 62 <<
" maptile {uodata=Dir} {maxtileid=0x3FFF/0x7FFF} {realm=realmname}\n" 63 <<
" multis {uodata=Dir} {maxtileid=0x3FFF/0x7FFF}\n" 64 <<
" tiles {uodata=Dir} {maxtileid=0x3FFF/0x7FFF}\n" 65 <<
" landtiles {uodata=Dir} {maxtileid=0x3FFF/0x7FFF}\n";
79 void create_map(
const std::string& realm,
unsigned short width,
unsigned short height );
80 void update_map(
const std::string& realm,
unsigned short x,
unsigned short y );
89 for (
unsigned blocking = 0; blocking <= 1; ++blocking )
91 for (
unsigned platform = 0; platform <= 1; ++platform )
93 for (
unsigned walk = 0; walk <= 1; ++walk )
95 for (
unsigned wall = 0; wall <= 1; ++wall )
97 for (
unsigned half = 0; half <= 1; ++half )
99 for (
unsigned floor = 0; floor <= 1; ++floor )
116 0x4000, flags, cfg_use_no_shoot, cfg_LOS_through_windows );
118 INFO_PRINT.Format(
"{} {} {} {} {} {}: {}\n" )
119 << blocking << platform << walk << wall << half << floor << moveland;
132 unsigned int polflags =
134 return static_cast<unsigned char>( polflags );
145 <<
" Realm: " << realmname <<
"\n" 146 <<
" Map ID: " << descriptor.
uomapid <<
"\n" 147 <<
" Use Dif files: " << ( descriptor.
uodif ?
"Yes" :
"No" ) <<
"\n" 151 writer->OpenExistingFiles( realmname );
161 unsigned short x = x_base + x_add;
162 unsigned short y = y_base + y_add;
170 INFO_PRINT.Format(
"Tile 0x{:X} at ({},{},{}) is an invalid ID!\n" )
179 cell.
z =
static_cast<signed char>( z );
180 writer->SetMapTile( x, y, cell );
184 INFO_PRINT <<
"\rConverting: " << y_base * 100 / uo_map_height <<
"%";
200 bool flags_match(
unsigned int f1,
unsigned int f2,
unsigned char bits_compare )
202 return ( f1 & bits_compare ) == ( f2 & bits_compare );
207 return ( f1 & ~bits_exclude ) == ( f2 & ~bits_exclude );
212 return ( ( f1 ^ f2 ) == bits );
221 void update_map(
const std::string& realm,
unsigned short x,
unsigned short y )
233 <<
"with more_solids: " << with_more_solids <<
"\n" 234 <<
"total statics=" << total_statics <<
"\n";
237 void create_map(
const std::string& realm,
unsigned short width,
unsigned short height )
240 INFO_PRINT <<
"Creating map base and solids files.\n" 241 <<
" Realm: " << realm <<
"\n" 243 <<
" Reading UOP file: " << (
uo_readuop ?
"Yes" :
"No" ) <<
"\n" 244 <<
" Use Dif files: " << (
uo_usedif ?
"Yes" :
"No" ) <<
"\n" 246 <<
"Initializing files: ";
253 for (
unsigned short y_base = 0; y_base < height; y_base +=
SOLIDX_Y_SIZE )
255 for (
unsigned short x_base = 0; x_base < width; x_base +=
SOLIDX_X_SIZE )
259 INFO_PRINT <<
"\rConverting: " << y_base * 100 / height <<
"%";
267 <<
"Conversion details:\n" 268 <<
" Total blocks: " << empty +
nonempty <<
"\n" 269 <<
" Blocks with solids: " <<
nonempty <<
" (" 272 <<
" Blocks without solids: " << empty <<
" (" 273 << ( empty * 100 / ( empty +
nonempty ) ) <<
"%)" 275 <<
" Locations with solids: " << with_more_solids <<
"\n" 276 <<
" Total number of solids: " << total_statics <<
"\n" 277 <<
" Elapsed time: " << timer.
ellapsed() <<
" ms.\n";
310 bool cave_override =
false;
312 if ( ( x - 1 >= 0 ) && ( y - 1 >= 0 ) )
320 cave_override =
true;
336 cave_override =
true;
352 cave_override =
true;
368 cave_override =
true;
384 cave_override =
true;
400 cave_override =
true;
416 cave_override =
true;
432 cave_override =
true;
448 unsigned int idx2_offset = 0;
450 memset( &idx2_elem, 0,
sizeof idx2_elem );
459 for (
unsigned short x_add = 0; x_add < x_add_max; ++x_add )
461 for (
unsigned short y_add = 0; y_add < y_add_max; ++y_add )
463 unsigned short x = x_base + x_add;
464 unsigned short y = y_base + y_add;
475 INFO_PRINT.Format(
"Tile 0x{:X} at ({},{},{}) is an invalid ID!\n" )
483 short lt_height = z - low_z;
487 INFO_PRINT.Format(
"Tile 0x{:X} at ({},{},{}) is an invalid ID!\n" )
512 for (
unsigned i = 0; i < statics.size(); ++i )
517 cfg_LOS_through_windows );
524 statics.erase( statics.begin() + i );
527 if ( ( ~srec.
flags & USTRUCT_TILE::FLAG_BLOCKING ) &&
535 statics.erase( statics.begin() + i );
542 for (
const auto& srec : statics )
545 if ( z + lt_height <= srec.z &&
546 ( ( srec.z - ( z + lt_height ) ) <=
548 srec.graphic >= 0x1796 &&
549 srec.graphic <= 0x17B2 )
556 if ( ( lt_flags & USTRUCT_TILE::FLAG_WALL ) &&
557 z <= srec.z && srec.z - z <= lt_height )
559 lt_height = srec.z - z;
570 if ( mi.
landtile == 2 && !statics.empty() )
574 statics.push_back(
StaticRec( 0, static_cast<signed char>( z ), lt_flags,
575 static_cast<char>( lt_height ) ) );
577 sort( statics.begin(), statics.end(),
StaticsByZ() );
578 reverse( statics.begin(), statics.end() );
580 std::vector<MapShape> shapes;
583 while ( !statics.empty() )
589 cfg_LOS_through_windows );
597 if ( ( ~srec.
flags & USTRUCT_TILE::FLAG_BLOCKING ) &&
608 if ( shapes.empty() )
615 shape.
flags =
static_cast<unsigned char>( polflags );
618 shapes.push_back( shape );
627 _shape.
flags = polflags;
628 shapes.push_back( _shape );
638 shape.
flags = polflags;
641 if ( shapes.size() == 1 )
643 shapes.push_back( shape );
647 if ( shape.
z < prev.
z + prev.
height )
652 short height_remove = prev.
z + prev.
height - shape.
z;
653 if ( height_remove <= shape.
height )
655 shape.
z += height_remove;
656 shape.
height -= height_remove;
667 if ( ( prev.
flags & FLAG::MOVESEA ) && ( shape.
z > prev.
z + prev.
height ) &&
668 ( shape.
z <= prev.
z + prev.
height + 4 ) )
670 short height_add = shape.
z - prev.
z - prev.
height;
671 shape.
z -= height_add;
672 shape.
height += height_add;
674 if ( ( prev.
flags & FLAG::MOVESEA ) && ( prev.
z + prev.
height == -5 ) &&
675 ( shape.
flags & FLAG::MOVESEA ) && ( shape.
z == 25 ) )
686 if ( shape.
z > prev.
z + prev.
height )
692 shapes.push_back( shape );
698 if ( shape.
z == prev.
z + prev.
height )
709 if ( prev.
flags & FLAG::MOVELAND && ~shape.
flags & FLAG::BLOCKING &&
710 ~shape.
flags & FLAG::MOVELAND )
722 shapes.push_back( shape );
730 shapes.erase( shapes.begin() );
733 cell.
z =
static_cast<signed char>(
736 if ( !shapes.empty() )
741 if ( !shapes.empty() )
744 total_statics +=
static_cast<unsigned int>( shapes.size() );
745 if ( idx2_offset == 0 )
749 if ( addindex > std::numeric_limits<unsigned short>::max() )
750 throw std::runtime_error(
"addoffset overflow" );
751 idx2_elem.
addindex[x_add][y_add] =
static_cast<unsigned short>( addindex );
752 int count =
static_cast<int>( shapes.size() );
753 for (
int j = 0; j < count; ++j )
756 char _z, height, flags;
757 _z =
static_cast<char>( shapes[j].z );
758 height =
static_cast<char>( shape.
height );
759 flags =
static_cast<u8>( shape.
flags );
766 if ( j != count - 1 )
789 void write_multi( FILE* multis_cfg,
unsigned id, FILE* multi_mul,
unsigned int offset,
790 unsigned int length )
797 count = length /
sizeof elem;
799 std::string type, mytype;
800 if ( BoatTypes.count(
id ) )
802 else if ( HouseTypes.count(
id ) )
804 else if ( StairTypes.count(
id ) )
809 <<
" not found in uoconvert.cfg, assuming \"House\" type.\n";
814 fprintf( multis_cfg,
"%s 0x%x\n", type.c_str(), id );
815 fprintf( multis_cfg,
"{\n" );
817 if ( fseek( multi_mul, offset, SEEK_SET ) != 0 )
819 throw std::runtime_error(
"write_multi(): fseek() failed" );
826 if ( fread( &elem,
sizeof elem, 1, multi_mul ) != 1 )
828 throw std::runtime_error(
"write_multi(): fread() failed" );
833 if ( fseek( multi_mul, 4, SEEK_CUR ) != 0 )
834 throw std::runtime_error(
"write_multi(): fseek() failed" );
846 if ( mytype ==
"Boat" )
848 if ( first && elem.
graphic != 1 )
856 comment.assign( tile.
name,
sizeof( tile.
name ) );
862 comment.assign( tile.
name,
sizeof( tile.
name ) );
864 fprintf( multis_cfg,
" %-7s 0x%04x %4d %4d %4d // %s\n", type.c_str(), elem.
graphic,
865 elem.
x, elem.
y, elem.
z, comment.c_str() );
868 fprintf( multis_cfg,
"}\n" );
869 fprintf( multis_cfg,
"\n" );
874 if ( fseek( multi_idx, 0, SEEK_SET ) != 0 )
875 throw std::runtime_error(
"create_multis_cfg: fseek failed" );
878 for (
int i = 0; fread( &idxrec,
sizeof idxrec, 1, multi_idx ) == 1; ++i )
889 if ( idxrec.
offset == 0xFFffFFffLu )
896 INFO_PRINT << count <<
" multi definitions written to multis.cfg\n";
904 FILE* multis_cfg = fopen(
"multis.cfg",
"wt" );
908 fclose( multis_cfg );
916 fprintf( fp,
" MoveLand 1\n" );
918 fprintf( fp,
" MoveSea 1\n" );
920 fprintf( fp,
" BlockSight 1\n" );
922 fprintf( fp,
" OverFlight 0\n" );
924 fprintf( fp,
" AllowDropOn 1\n" );
926 fprintf( fp,
" Gradual 1\n" );
928 fprintf( fp,
" Stackable 1\n" );
930 fprintf( fp,
" Blocking 1\n" );
932 fprintf( fp,
" Movable 1\n" );
934 fprintf( fp,
" Equippable 1\n" );
936 fprintf( fp,
" DescPrependA 1\n" );
938 fprintf( fp,
" DescPrependAn 1\n" );
943 FILE* fp = fopen(
"tiles.cfg",
"wt" );
950 u16 graphic =
static_cast<u16>( graphic_i );
971 mountCount =
static_cast<int>( MountTypes.count( graphic ) );
980 if ( mountCount != 0 )
986 memset( name, 0,
sizeof name );
987 memcpy( name, tile.
name,
sizeof tile.
name );
989 fprintf( fp,
"tile 0x%x\n", graphic );
990 fprintf( fp,
"{\n" );
991 fprintf( fp,
" Desc %s\n", name );
992 fprintf( fp,
" UoFlags 0x%08lx\n", static_cast<unsigned long>( tile.
flags ) );
994 fprintf( fp,
" Layer %u\n", tile.
layer );
995 fprintf( fp,
" Height %u\n", tile.
height );
996 fprintf( fp,
" Weight %u\n", tile.
weight );
998 fprintf( fp,
"}\n" );
1004 INFO_PRINT << count <<
" tile definitions written to tiles.cfg\n";
1009 FILE* fp = fopen(
"landtiles.cfg",
"wt" );
1012 for (
u16 i = 0; i <= 0x3FFF; ++i )
1020 landtile.
unk = newlandtile.
unk;
1021 memcpy( landtile.
name, newlandtile.
name,
sizeof landtile.
name );
1026 if ( landtile.
name[0] || landtile.
flags )
1028 fprintf( fp,
"landtile 0x%x\n", i );
1029 fprintf( fp,
"{\n" );
1030 fprintf( fp,
" Name %s\n", landtile.
name );
1031 fprintf( fp,
" UoFlags 0x%08lx\n", static_cast<unsigned long>( landtile.
flags ) );
1034 flags &= ~
FLAG::MOVABLE;
1036 fprintf( fp,
"}\n" );
1037 fprintf( fp,
"\n" );
1043 INFO_PRINT << count <<
" landtile definitions written to landtiles.cfg\n";
1048 const std::vector<std::string>& binArgs =
programArgs();
1053 if ( binArgs.size() == 1 )
1064 if ( !argvalue.empty() )
1081 unsigned short max_tile = elem.
remove_ushort(
"MaxTileID", 0x0 );
1087 unsigned short max_tile =
1093 std::string main_cfg =
"uoconvert.cfg";
1100 while ( cf_main.read( elem ) )
1102 if ( elem.
type_is(
"MultiTypes" ) )
1106 std::string graphicnum;
1107 while ( is_boats >> graphicnum )
1112 while ( is_houses >> graphicnum )
1117 while ( is_stairs >> graphicnum )
1120 else if ( elem.
type_is(
"LOSOptions" ) )
1122 if ( elem.
has_prop(
"UseNoShoot" ) )
1125 if ( elem.
has_prop(
"LOSThroughWindows" ) )
1128 else if ( elem.
type_is(
"Mounts" ) )
1130 std::string graphicnum;
1133 while ( is_mounts >> graphicnum )
1138 else if ( elem.
type_is(
"StaticOptions" ) )
1140 if ( elem.
has_prop(
"MaxStaticsPerBlock" ) )
1147 INFO_PRINT <<
"max. Statics per Block limited to " 1154 if ( elem.
has_prop(
"WarningStaticsPerBlock" ) )
1161 INFO_PRINT <<
"max. Statics per Block for Warning limited to " 1168 if ( elem.
has_prop(
"ShowIllegalGraphicWarning" ) )
1172 else if ( elem.
type_is(
"TileOptions" ) )
1174 if ( elem.
has_prop(
"ShowRoofAndPlatformWarning" ) )
1178 else if ( elem.
type_is(
"ClientOptions" ) )
1180 if ( elem.
has_prop(
"UseNewHSAFormat" ) )
1186 std::string command = binArgs[1];
1187 if ( command ==
"uoptomul" )
1192 std::string mul_mapfile =
"map" + to_string(
uo_mapid ) +
".mul";
1193 std::string uop_mapfile =
"map" + to_string(
uo_mapid ) +
"LegacyMUL.uop";
1195 auto maphash = [](
int mapid,
size_t chunkidx ) {
1197 tmp <<
"build/map" << mapid <<
"legacymul/" << fmt::pad(chunkidx,8,
'0') <<
".dat";
1204 ERROR_PRINT <<
"Error when opening mapfile: " << uop_mapfile <<
'\n';
1208 kaitai::kstream ks( &ifs );
1209 uop_t uopfile( &ks );
1212 std::map<uint64_t, uop_t::file_t*> filemap;
1216 if ( file ==
nullptr )
1218 if ( file->decompressed_size() == 0 )
1220 filemap[file->filehash()] = file;
1224 INFO_PRINT <<
"Warning: not all chunks read (" << filemap.size() <<
"/" 1228 for (
size_t i = 0; i < filemap.size(); i++ )
1230 auto fileitr = filemap.find( maphash(
uo_mapid, i ) );
1231 if ( fileitr == filemap.end() )
1237 auto file = fileitr->second;
1238 ofs << file->data()->filebytes();
1239 INFO_PRINT <<
"Wrote: " << i + 1 <<
"/" << filemap.size() <<
'\n';
1243 else if ( command ==
"map" )
1250 int default_width = 6144;
1251 int default_height = 4096;
1258 default_width = 2304;
1259 default_height = 1600;
1262 default_width = 2560;
1263 default_height = 2048;
1266 default_width = 1448;
1267 default_height = 1448;
1270 default_width = 1280;
1271 default_height = 4096;
1291 if ( x >= 0 && y >= 0 )
1298 static_cast<unsigned short>( height ) );
1301 else if ( command ==
"statics" )
1316 else if ( command ==
"multis" )
1322 else if ( command ==
"tiles" )
1328 else if ( command ==
"landtiles" )
1334 else if ( command ==
"maptile" )
1349 else if ( command ==
"flags" )
1371 UoConvertMain->
start( argc, argv );
void create_maptile(const std::string &realmname)
void AppendSolid(const SOLIDS_ELEM &solid)
static RealmDescriptor Load(const std::string &realm_name, const std::string &realm_path="")
void readtile(unsigned short tilenum, USTRUCT_TILE *tile)
std::string remove_string(const char *propname)
const std::vector< std::string > & programArgs() const
bool operator()(const StaticRec &a, const StaticRec &b)
std::vector< StaticRec > StaticList
void readstatics(StaticList &vec, unsigned short x, unsigned short y)
bool is_no_draw(USTRUCT_MAPINFO &mi)
void open_uo_data_files(void)
unsigned with_more_solids
char * binary(unsigned int val, int nbits)
bool cfg_show_illegal_graphic_warning
std::set< unsigned int > HouseTypes
bool flags_match(unsigned int f1, unsigned int f2, unsigned char bits_compare)
void read_objinfo(u16 graphic, struct USTRUCT_TILE &objinfo)
std::set< unsigned int > MountTypes
int remove_int(const char *propname)
bool is_cave_exit(USTRUCT_MAPINFO &mi)
void start(int argc, char *argv[])
std::set< unsigned int > BoatTypes
bool cfg_show_roof_and_platform_warning
bool differby_exactly(unsigned char f1, unsigned char f2, unsigned char bits)
unsigned short addindex[SOLIDX_X_SIZE][SOLIDX_Y_SIZE]
bool cfg_use_new_hsa_format
void readlandtile(unsigned short tilenum, USTRUCT_LAND_TILE *landtile)
void readraw(ConfigElem &elem)
bool check_verdata(unsigned int file, unsigned int block, const Core::USTRUCT_VERSION *&vrec)
#define VERFILE_MULTI_MUL
void write_flags(FILE *fp, unsigned int flags)
std::vector< file_t * > * files() const
unsigned int landtile_uoflags(unsigned short landtile)
void safe_getmapinfo(unsigned short x, unsigned short y, short *z, USTRUCT_MAPINFO *mi)
short get_lowestadjacentz(unsigned short x, unsigned short y, short z)
unsigned int NextSolidIndex()
int cfg_max_statics_per_block
u32 polflags_from_tileflags(unsigned short tile, u32 uoflags, bool use_no_shoot, bool LOS_through_windows)
void write_multi(FILE *multis_cfg, unsigned id, FILE *multi_mul, unsigned int offset, unsigned int length)
void AppendSolidx2Elem(const SOLIDX2_ELEM &elem)
void create_landtiles_cfg()
u32 polflags_from_landtileflags(unsigned short tile, u32 lt_flags)
#define MAX_STATICS_PER_BLOCK
unsigned short uo_map_height
uint64_t HashLittle2(std::string s)
void SetMapCell(unsigned short x, unsigned short y, MAPCELL cell)
std::set< unsigned int > StairTypes
bool is_cave_shadow(USTRUCT_MAPINFO &mi)
const unsigned MAPTILE_CHUNK
block_body_t * block_body()
bool type_is(const char *name) const
bool has_prop(const char *propname) const
unsigned short remove_ushort(const char *propname)
FILE * open_uo_file(const std::string &filename_part)
unsigned short uo_map_width
void update_map(const std::string &realm, unsigned short x, unsigned short y)
void SetSolidx2Offset(unsigned short x_base, unsigned short y_base, unsigned int offset)
std::string programArgsFindEquals(const std::string &filter, std::string defaultVal) const
void ProcessSolidBlock(unsigned short x_base, unsigned short y_base, MapWriter &mapwriter)
unsigned char polmap_flags_from_landtile(unsigned short landtile)
std::string normalized_dir_form(const std::string &istr)
std::string uo_datafile_root
bool FileExists(const char *filename)
bool cfg_LOS_through_windows
void CreateNewFiles(const std::string &realm_name, unsigned short width, unsigned short height)
#define passert_always(exp)
unsigned int NextSolidx2Offset()
bool otherflags_match(unsigned char f1, unsigned char f2, unsigned char bits_exclude)
void create_map(const std::string &realm, unsigned short width, unsigned short height)
int write_pol_static_files(const std::string &realm)
bool remove_bool(const char *propname)
void OpenExistingFiles(const std::string &realm_name)
header_t * header() const
int cfg_warning_statics_per_block