534 lines
11 KiB
C++
534 lines
11 KiB
C++
/*=========================================================================
|
|
|
|
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 */
|