/*========================================================================= EXPORT.CPP Author: Created: Project: Purpose: Copyright (c) 1998 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ /* Std Lib ------- */ #include "mapread.h" /* Glib ---- */ #include <tquant.h> /* Local ----- */ /* Graphics -------- */ /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ #define TILE_SHIFT 8 /*---------------------------------------------------------------------- Structure defintions -------------------- */ /*---------------------------------------------------------------------- Positional Vars --------------- */ /*---------------------------------------------------------------------- Function Prototypes ------------------- */ /*---------------------------------------------------------------------- Vars ---- */ /*---------------------------------------------------------------------- Data ---- */ /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CMapFile::GetVersion( char * version ) { int ret = 0; int len; char whole[8]; char frac[8]; len = strlen(version); if (len) { int pos = 0; int opos = 0; while (version[pos] != '.') { whole[pos] = version[pos]; pos++; if (pos > len) GObject::Error(ERR_FATAL,"Corrupt Version - %s\n", version); } pos++; while (version[pos]) { frac[opos] = version[pos]; pos++; opos++; if (pos > len) GObject::Error(ERR_FATAL,"Corrupt Version - %s\n", version); } } ret = atoi( whole ); ret *= 100; ret += atoi( frac ); GObject::Error(ERR_WARNING, "Map Version %d\n", ret ); return ret; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CMapFile::FindFrame( const char * frame ) { char InFile[_MAX_FNAME]; char CompFile[_MAX_FNAME]; _splitpath( frame, NULL, NULL, InFile, NULL ); for (int f=0;f<RepItems.size();f++) { _splitpath( RepItems[f].m_texName, NULL, NULL, CompFile, NULL ); if (!strcmp( InFile, CompFile )) return f; } if (m_errorOnMissingFile) GObject::Error(ERR_FATAL,"Missing bmp - %s\n", frame); return -1; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CMapFile::Parse() { int i; int version; int x, y; float lowestY; TILE_PACKET * t; MapFile.Seek( 0 ); MapFile.Read( VersionText, 4 ); version = GetVersion( (char *)VersionText ); // READ GLOBAL TILE NAMES MapFile.Read( &nbTiles ); TileNames = (CFileName *)malloc( nbTiles * sizeof(CFileName) ); for (i=0;i<nbTiles;i++) { MapFile.Read( &TileNames[i], sizeof(CFileName) ); } // READ GLOBAL OBJECT INFO MapFile.Read( &nbObjects ); Objects = (CObject *)malloc( nbObjects * sizeof(CObject) ); for (i=0;i<nbObjects;i++) { MapFile.Read( &Objects[i].Name, sizeof(CFileName) ); if (version < 104) { MapFile.Read( &Objects[i].Width ); MapFile.Read( &Objects[i].Height ); MapFile.Read( &Objects[i].Depth ); MapFile.Read( &Objects[i].Mask, (sizeof(bool) * MAX_MASKX * MAX_MASKY) ); } } // READ TILE MAP MapFile.Read( &MapWidth ); MapFile.Read( &MapHeight ); MapFile.Read( &TileSize ); if (TileSize > sizeof(MapCTile)) GObject::Error(ERR_FATAL, "MapCTile STRUCT MISMATCH" ); Tiles = (TILE_PACKET *)malloc( (MapWidth * MapHeight * sizeof( TILE_PACKET )) ); if (!Tiles) GObject::Error(ERR_FATAL, "can't allocate tiles" ); t = Tiles; nbSpawnPoints=0; lowestY = 65536; for (y=0;y<MapHeight;y++) { for (x=0;x<MapWidth;x++) { MapCTile tile; int frame = 0; int angle = 0; MapFile.Read( &tile, TileSize ); strlwr( tile.FrameName ); for (int l=0;l<strlen(tile.FrameName);l++) { if (tile.FrameName[l] == '\\') tile.FrameName[l] = '/'; } if (tile.frame) frame = FindFrame( tile.FrameName ); else frame = 0; angle = (int)tile.angle; angle++; angle &= 0x3; if (angle == 2) angle = 0; else if (angle == 0) angle = 2; t->frame = tile.frame; t->r = (u8)(tile.r * 255.f); t->g = (u8)(tile.g * 255.f); t->b = (u8)(tile.b * 255.f); t->pad = 0; if (tile.flag&TF_SPAWN) { if (nbSpawnPoints>=MAX_SPAWNING_TILES) { GObject::Error(ERR_FATAL, "Max Spawning Positions exceeded for level" ); } Spawn[nbSpawnPoints].x = x; Spawn[nbSpawnPoints].y = y; nbSpawnPoints++; } t->angle = angle; t->flags = (int)(tile.flag&(~TF_SPAWN)); t->height = (int)tile.py; t->frame = frame; t->xflip = tile.xflip; t->yflip = tile.yflip; t->type = tile.type; // if (t->flags & TF_NO_BUILD) // GObject::Error(ERR_WARNING, "No build flag found\n" ); if (frame < 0) t->flags |= TF_HIDDEN; if (!(tile.flag & TF_HIDDEN) && (x < MapWidth-1) && (y < MapHeight-1)) { if (lowestY > tile.py) lowestY = tile.py; } t++; } } GObject::Error( ERR_WARNING, "Lowest land height = %f\n", lowestY ); t = Tiles; for (y=0;y<MapHeight;y++) { for (x=0;x<MapWidth;x++) { t->height -= (int)lowestY; if (t->height < 0) t->height = 0; // if (t->height > sizeof(u16)) // { // GObject::Error( ERR_FATAL, "Land height overflow - %d\n", t->height ); // } t++; } } // READ OBJECT LIST MapFile.Read( &nbModels ); MapFile.Read( &ModelSize ); if (ModelSize > sizeof(CModel)) GObject::Error(ERR_FATAL, "Struct mismatch in CModel" ); Models = (MODEL_PACKET *)malloc( nbModels * sizeof(MODEL_PACKET) ); if (!Models) GObject::Error(ERR_FATAL, "Can't allocate models\n" ); MODEL_PACKET * m = Models; for (i=0;i<nbModels;i++) { u32 animflag; u16 angle; CModel model; char MyDir[_MAX_DIR]; char MyFile[_MAX_FNAME]; MapFile.Read( &model, ModelSize ); _splitpath( model.MeshName, NULL, MyDir, MyFile, NULL ); angle = (u16)model.AngY; if (angle == 1) angle = 3; else if (angle == 3) angle = 1; animflag = FindFileEquate( MyFile ); animflag &= ~MODEL_FLAGS_MASK; if (model.m_Animates) animflag |= MODEL_ANIMATE_FLAG; if (model.m_Busstop) animflag |= MODEL_BUSSTOP_FLAG; if (model.m_Booth) animflag |= MODEL_BOOTH_FLAG; if (model.m_OtherAnim) animflag |= MODEL_OTHERANIM_FLAG; if (model.m_Entrance) animflag |= MODEL_ENTRANCE_FLAG; m->AnimAndFlags = animflag; m->xp = (u16)(model.PosX / (1 << TILE_SHIFT)); m->yp = (u16)(model.PosY - lowestY); m->zp = (u16)(model.PosZ / (1 << TILE_SHIFT)); m->ya = (u16)angle; // if (m->yp > sizeof(u16)) // { // GObject::Error( ERR_FATAL, "Object Y position overflow - %d\n", m->yp ); // } m++; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CMapFile::FindFileEquate( char * name ) { strupr( name ); for (int i=0;i<AnimItems.size();i++) { if (!strcmp( AnimItems[i].m_AnimName, name )) return( AnimItems[i].m_Frame ); } if (AnimHeaderFile) { GObject::Error( ERR_WARNING, "Could not find anim %s in anim header %s\n", name, AnimHeaderFile ); } else { GObject::Error( ERR_WARNING, "Could not find anim %s - anim header not loaded\n", name ); } return (-1); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CMapFile::MakeMapPalette(void) { using namespace std; vector<u8> SourcePal; vector<u8> DestPal; SourcePal.resize(MapWidth*MapHeight*3); TileToPalNum.resize(MapWidth*MapHeight); DestPal.resize(NUM_OF_PAL_ENTRIES*3); MapPal.resize(NUM_OF_PAL_ENTRIES); for (int f=0;f<MapWidth*MapHeight;f++) { SourcePal[f*3+0]=Tiles[f].r; SourcePal[f*3+1]=Tiles[f].g; SourcePal[f*3+2]=Tiles[f].b; } tquant(&SourcePal[0],&TileToPalNum[0],&DestPal[0],NUM_OF_PAL_ENTRIES,MapWidth*MapHeight); for (int c=0;c<NUM_OF_PAL_ENTRIES;c++) { MapPal[c].r=DestPal[c*3+0]; MapPal[c].g=DestPal[c*3+1]; MapPal[c].b=DestPal[c*3+2]; } } void CMapFile::WriteMapPalette(FILE * F) { int count = NUM_OF_PAL_ENTRIES; fwrite( &count, sizeof(u32), 1,F); for (int f=0;f<count;f++) { u8 Dummy = 0; fwrite( &MapPal[f].r, sizeof(u8), 1,F); fwrite( &MapPal[f].g, sizeof(u8), 1,F); fwrite( &MapPal[f].b, sizeof(u8), 1,F); fwrite( &Dummy,sizeof(u8),1,F); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CMapFile::SetInfoOut( int x, int y, TILE_PACKET * T, OUT_TILE_PACKET * O ) { O->mType = 0; if (T->height<0) { O->ypos = 0; // printf("low height %d\n", T->height); } else if (T->height>255*4.f) { O->ypos = 255; // printf("hi height %d\n", T->height); } else { O->ypos = (T->height/4.f); } O->mNeighbours = 0; O->mDirection = 0; if (T->frame > 4095) GObject::Error(ERR_FATAL, "Tile index overflow" ); O->mTileIndex = T->frame; O->mTileIndex |= (T->angle << 12); // STUFF ANGLE IN TOP BITS OF TILE INDEX O->ColIdx = GetPalNum( x, y ); O->mFlags = T->flags; if (T->xflip) O->mTileIndex |= (1 << 15); // SET X/Y FLIP IN TOP BITS OF TILE INDEX if (T->yflip) O->mTileIndex |= (1 << 14); switch(T->type) { case TT_VOID: O->mType = (u8)CELL_Void; break; case TT_PATH: O->mType = (u8)CELL_Path; break; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CMapFile::Export( const char * file ) { FILE * level; MakeMapPalette(); level = fopen( file, "wb" ); if (level) { WriteMapPalette( level ); fwrite( &MapWidth, sizeof( int ), 1, level ); fwrite( &MapHeight, sizeof( int ), 1, level ); for (int y=0;y<MapHeight;y++) { for (int x=0;x<MapWidth;x++) { TILE_PACKET * tile; OUT_TILE_PACKET out; tile = &Tiles[x + (y * MapWidth)]; SetInfoOut( x, y, tile, &out ); fwrite( &out, sizeof(OUT_TILE_PACKET), 1, level ); } } fwrite( &nbModels, sizeof( int ), 1, level ); for (int i=0;i<nbModels;i++) { fwrite( &Models[i], sizeof(MODEL_PACKET), 1, level ); } fwrite( &nbSpawnPoints, sizeof(int), 1, level ); for (i=0; i<nbSpawnPoints; i++) { fwrite( &Spawn[i], sizeof(SPAWNPOS), 1, level); } // printf( "WRITTEN %s\n", file ); } else { GObject::Error(ERR_FATAL, "Could not save lvl file - %s", file ); } } /*=========================================================================== end */