SubSpace Map File Format ----------------------- Copyright © 1999 by Ravi I ===================== Introduction ===================== Map files are divided into two major sections. The first, which is optional, contains a standard Windows bitamp describing the tileset. The second is what contains the actual map. While the format for map files has changed in the past, there is no indication that it will again. It became especially unlikely when the US branch of VIE ceased to exist. Just in case, this documents the format as it stood for version 1.34. This would be an appropriate time to recognize ljc and Pastor of Muppets (authors of SSME and SSLEd respectively), both of who worked with map files long before me. Their tools were quite helpful in writing this. Also helpful was the TileEdit utility, which appears to be unsigned. The fact that it installs to the SSME directory makes me think it may have been written by ljc. I'm sure many people know more about it, and if one of them could contact me I'd appreciate it. ===================== Tileset ===================== The tileset, if included in the file, is saved as a 304x160 256 color bitmap. Tiles are 16x16, for a total of 190 tiles arraged in a 19x10 grid. The bitmap is a standard Windows BMP, complete with header, and you can easily find bitmap specifications lying around. I won't add to their number here. One place to look if you're interested is Wotsit's File Format Archive. If the file does not contain a custom tileset, SubSpace has a default: When using custom tilesets, you should take care with your palette. SubSpace converts the tileset's palette to the standard internal palette, which can induce color shifts. The effect is especially noticeable for gradients not found inside the game. If you design a tileset with your own palette, I would highly reccomend that you either use a graphics program to adjust it before saving or check to make sure the map looks okay when loaded into the game. I don't often work with computer graphics packages, and am not familiar with how different programs import colors. Here's a blank bitmap with the standard palette, for those who want to see it. ===================== Tiles ===================== Each tile is saved in a 4 byte structure that holds an x-value, a y-value, and a tile index. These structures come one after another at the beginning of the file if there is no tileset or directly after the bitmap if there is. The x and y values form an ordered pair in or on the rectangle from (0,0) to (1023,1023). The tile index specifies which tile goes on that square. Normal tiles range from 1 to 190 inclusive and represent the 190 tiles in the tileset. Tile 1 is in the upper left corner, tile 19 is in the upper right corner, tile 172 is in the lower left corner, and tile 190 is in the lower right corner. In addition to those there are 4 special tiles: small asteroid 216 medium asteroid 217 station 219 wormhole 220 Tile 218 had been the large asteroid, but it was removed from the game. Current versions of SubSpace treat instances of 218 exactly like 216 (small asteroid). For the medium asteroid, the station, and the wormhole, the (x,y) coordinate specifies the top left corner. Clever things like putting tiles in the middle of a station make invalid maps that can easily crash SubSpace. Utilities should be careful to ensure that any maps it saves make sense. The 4 byte structures are not broken along byte boundaries, which would waste space. This table shows how the bits would be used, MSB on the left, if you were to read the structure as a 32 bit integer. tile number 8 bits y-coord 12 bits x-coord 12 bits These structures can be created and interpreted with simple bit-string flicking when typed as integers: intstruct = (tile << 24) | (y << 12) | x; tile = intstruct >> 24; y = (intstruct >> 12) & 0x03FF; x = intstruct & 0x03FF; Note the use of 0x03FF here. Although the x and y components each use 12 bits, they may not exceed 1023, which only uses 10 bits. Invalid values from 0x0400 to 0x0FFF are automatically clipped at file load. Alternatively, a program could use bit-fields in a struct: struct tilerecord { unsigned x : 12; unsigned y : 12; unsigned tile : 8; } Using the bit-fields makes pretty, readable code without strange #define's, but will require extra clipping code later. Yes, I could have called x and y 10 bits and inserted two 2 bit unused fileds. However, there's a flaw in that logic. Suppose my program reads in an invalid file that has tiles at x = 1024. If I used the 10 - 2 division, my x would be 0 and my unused would be 1. My program would display the tile at x = 0, but the unused is not 0 like it should be! When I save the file, I would still save the unused portion as 1, and my file would still be invalid. An easy compromise is to save and load files with integers but store them in structures. The internal structures need not even use bit-fields, and probably shouldn't.