omega-rpg/map.c

211 lines
4.7 KiB
C

/* Copyright 2000 William D. Tanksley Jr., licensed under the terms of the
* Omega license as part of Omega. */
#include "glob.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#define MAP_VERSION 2
#define MAP_HEADER_SIZE 3
#define MAP_ITEM_SIZE 9
/* I plan to eventually make this code handle ALL map loading, since map
* loading is largely similar. However, to keep from biting off more than
* I can chew, I'm going to start by doing just a little bit at a time.
*
* For starters, I'm just going to have this load the map, and that's all. */
struct symbolMapping
{
/* Which L_* to assign this character to. */
int locationFunction;
/* What argument (if any) to give to the function which constructs that
* location. */
int argument;
};
struct map_type
{
int length, width, depth, offset;
char *sites;
#if 0
struct symbolMapping symbols[128-32]; /* Only printable characters.
* This does assume ASCII. */
#endif
};
void error(char *explanation, ...)
{
va_list ap;
va_start (ap, explanation);
vfprintf (stderr, explanation, ap);
va_end (ap);
abort();
}
int fgetint(FILE *f)
{
int x;
assert(sizeof(int) == 4); /* This assumption is explicit here, but it's
* also elsewhere. */
x = fgetc(f) &0x000000FF;
x|= (fgetc(f) << 8) &0x0000FF00;
x|= (fgetc(f) <<16) &0x00FF0000;
x|= (fgetc(f) <<24) &0xFF000000;
if ( feof(f) )
error("Unexpected end of file while parsing binary file.");
return x;
}
int fgetshort(FILE *f)
{
int x;
assert(sizeof(int) == 4); /* This assumption is explicit here, but it's
* also elsewhere. */
x = fgetc(f) &0x000000FF;
x|= (fgetc(f) << 8) &0x0000FF00;
if ( feof(f) )
error("Unexpected end of file while parsing binary file.");
return x;
}
void decode(char **data, int *length)
{
/* just testing... Place a sophisticated BWT here. */
}
int map_getWidth(map *m)
{
return m->width;
}
int map_getLength(map *m)
{
return m->length;
}
int map_getDepth(map *m)
{
return m->depth;
}
/* Read in the indicated sublevel of the current map. Called from
* map_setLevel. */
void map_read(map *m, FILE *in, int subLevel)
{
int size;
if ( subLevel > m->depth || subLevel < 0 )
error("map has only %d levels; game requested level %d.\n",
m->depth, subLevel);
/* Seek to the location of the data (as previously calculated). */
fseek(in,m->offset,SEEK_SET);
do {
/* Read in the size of the next submap, and if it wasn't the one
* we're looking for, skip past it. */
size = fgetshort(in);
if ( subLevel )
fseek(in, size, SEEK_CUR);
} while ( subLevel-- );
/* We now know that we're looking at the right map, and we know its size. */
/* Read the encoding of the level into a buffer. */
m->sites = malloc(size);
fread(m->sites,size,1,in);
/* Decode the level. */
decode(&m->sites,&size);
if ( size != m->length*m->width )
error("Map had invalid size: expected %d, got %d.\n",
m->length*m->width, size);
}
/* Read the map info out of the header of the mapfile, and load it into
* the map. */
void map_readDimensions(map *m, FILE *in, enum map_identifier map)
{
int version, maps, items, this_map;
version = fgetc(in); /* The file version */
if ( version != MAP_VERSION )
error("Mapfile version mismatch: expected %d, got %d.\n",
MAP_VERSION, version);
maps = fgetshort(in); /* The number of maps it's supposed to contain */
items = 0;
do {
this_map = fgetshort(in);
m->width = fgetc(in); m->length = fgetc(in); m->depth = fgetc(in);
m->offset = fgetint(in);
items++;
} while (this_map != map && items < maps);
if ( (items == maps) && (this_map != map) )
error("Map #%d was not found in mapfile.\n", map );
/* The offset stored in the file was the offset from the end of the table of
* contents. Fix that to be an absolute offset. */
m->offset += MAP_HEADER_SIZE + maps*MAP_ITEM_SIZE;
}
map *map_open(enum map_identifier mapNumber)
{
map *m = malloc( sizeof(map) );
FILE *fd;
strcpy(Str3,Omegalib);
strcat(Str3,"maps.dat");
fd = checkfopen(Str3,"rb");
map_readDimensions(m,fd,mapNumber);
fclose(fd);
return m;
}
void map_setLevel(map *m, int levelNumber)
{
FILE *fd;
strcpy(Str3,Omegalib);
strcat(Str3,"maps.dat");
fd = checkfopen(Str3,"rb");
map_read(m,fd,levelNumber);
fclose(fd);
}
void map_close(map *m)
{
free(m->sites);
free(m);
}
#if 0
/* Using the mappings given in this map structure, build an Omega
* level, using appropriate terrain. */
void map_buildLevel(map *m, Level *lev)
{
}
#endif
char map_getSiteChar(map *m, int i, int j)
{
assert(i < m->width);
assert(j < m->length);
assert(m->sites[j*m->width + i]);
return m->sites[j*m->width + i];
}