warzone2100/tools/map/mapload.c

185 lines
4.6 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "mapload.h"
#define MAX_PLAYERS 8
#define MAP_MAXAREA (256 * 256)
#define debug(z, ...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
void mapFree(GAMEMAP *map)
{
free(map->mGateways);
free(map->mMapTiles);
free(map);
}
/* Initialise the map structure */
GAMEMAP *mapLoad(char *filename)
{
char path[PATH_MAX];
GAMEMAP *map = malloc(sizeof(*map));
uint32_t gwVersion, i, j, gameVersion, gameTime, gameType, featVersion;
char aFileType[4];
bool littleEndian = true;
PHYSFS_file *fp = NULL;
// this cries out for a class based design
#define readU8(v) ( littleEndian ? PHYSFS_readULE8(fp, v) : PHYSFS_readUBE8(fp, v) )
#define readU16(v) ( littleEndian ? PHYSFS_readULE16(fp, v) : PHYSFS_readUBE16(fp, v) )
#define readU32(v) ( littleEndian ? PHYSFS_readULE32(fp, v) : PHYSFS_readUBE32(fp, v) )
#define readS8(v) ( littleEndian ? PHYSFS_readSLE8(fp, v) : PHYSFS_readSBE8(fp, v) )
#define readS16(v) ( littleEndian ? PHYSFS_readSLE16(fp, v) : PHYSFS_readSBE16(fp, v) )
#define readS32(v) ( littleEndian ? PHYSFS_readSLE32(fp, v) : PHYSFS_readSBE32(fp, v) )
/* === Load map data === */
strcpy(path, filename);
strcat(path, "/game.map");
fp = PHYSFS_openRead(path);
if (!fp)
{
debug(LOG_ERROR, "Map file %s not found", path);
return NULL;
}
else if (PHYSFS_read(fp, aFileType, 4, 1) != 1
|| !readU32(&map->version)
|| !readU32(&map->width)
|| !readU32(&map->height)
|| aFileType[0] != 'm'
|| aFileType[1] != 'a'
|| aFileType[2] != 'p')
{
debug(LOG_ERROR, "Bad header in %s", path);
return NULL;
}
else if (map->version <= 9)
{
debug(LOG_ERROR, "%s: Unsupported save format version %u", path, map->version);
return NULL;
}
else if (map->version > 36)
{
debug(LOG_ERROR, "%s: Undefined save format version %u", path, map->version);
return NULL;
}
else if (map->width * map->height > MAP_MAXAREA)
{
debug(LOG_ERROR, "Map %s too large : %d %d", path, map->width, map->height);
return NULL;
}
/* Allocate the memory for the map */
map->mMapTiles = calloc(map->width * map->height, sizeof(*map->mMapTiles));
if (!map->mMapTiles)
{
debug(LOG_ERROR, "Out of memory");
return NULL;
}
/* Load in the map data */
for (i = 0; i < map->width * map->height; i++)
{
uint16_t texture;
uint8_t height;
if (!readU16(&texture) || !readU8(&height))
{
debug(LOG_ERROR, "%s: Error during savegame load", path);
return NULL;
}
map->mMapTiles[i].texture = texture;
map->mMapTiles[i].height = height;
for (j = 0; j < MAX_PLAYERS; j++)
{
map->mMapTiles[i].tileVisBits = (uint8_t)(map->mMapTiles[i].tileVisBits &~ (uint8_t)(1 << j));
}
}
if (!readU32(&gwVersion) || !readU32(&map->numGateways) || gwVersion != 1)
{
debug(LOG_ERROR, "Bad gateway in %s", path);
return NULL;
}
map->mGateways = calloc(map->numGateways, sizeof(*map->mGateways));
for (i = 0; i < map->numGateways; i++)
{
if (!readU8(&map->mGateways[i].x1) || !readU8(&map->mGateways[i].y1)
|| !readU8(&map->mGateways[i].x2) || !readU8(&map->mGateways[i].y2))
{
debug(LOG_ERROR, "%s: Failed to read gateway info", path);
return NULL;
}
}
PHYSFS_close(fp);
/* === Load game data === */
strcpy(path, filename);
strcat(path, ".gam");
fp = PHYSFS_openRead(path);
if (!fp)
{
debug(LOG_ERROR, "Game file %s not found", path);
return NULL;
}
else if (PHYSFS_read(fp, aFileType, 4, 1) != 1
|| aFileType[0] != 'g'
|| aFileType[1] != 'a'
|| aFileType[2] != 'm'
|| aFileType[3] != 'e'
|| !readU32(&gameVersion))
{
debug(LOG_ERROR, "Bad header in %s", path);
return NULL;
}
if (gameVersion > 35) // big-endian
{
littleEndian = false;
}
if (!readU32(&gameTime)
|| !readU32(&gameType)
|| !readS32(&map->scrollMinX)
|| !readS32(&map->scrollMinY)
|| !readU32(&map->scrollMaxX)
|| !readU32(&map->scrollMaxY)
|| PHYSFS_read(fp, map->levelName, 20, 1) != 1)
{
debug(LOG_ERROR, "Bad data in %s", filename);
return NULL;
}
PHYSFS_close(fp);
/* === Load game data === */
littleEndian = true;
strcpy(path, filename);
strcat(path, "/feat.bjo");
fp = PHYSFS_openRead(path);
if (!fp)
{
debug(LOG_ERROR, "Feature file %s not found", path);
return NULL;
}
else if (PHYSFS_read(fp, aFileType, 4, 1) != 1
|| aFileType[0] != 'f'
|| aFileType[1] != 'e'
|| aFileType[2] != 'a'
|| aFileType[3] != 't'
|| !readU32(&featVersion)
|| !readU32(&map->numFeatures))
{
debug(LOG_ERROR, "Bad features header in %s", path);
return NULL;
}
PHYSFS_close(fp);
return map;
}