Test of Time Sprite File Format
Many thanks to Apolyton's Zarion (DracoOmega) and Angelo Scotto. I would never have been able to decipher the sprite file format without them.
Jorrit "Mercator" Vermeiren
STATIC.SPR
FILE HEADER
ID bytes: value
----------------------------------------
HEADER
1 4 bytes: 0, due to absence of Animation Section
2 4 bytes: 12, offset of Image Offsets
3 4 bytes: Offset of the first image
IMAGE OFFSETS
406 x 4 bytes: Image offsets relative to start of image section, so the first
image has offset 0. They refer to the 5 facing directions
(N, NE, E, SE, S) of all 81 units. The last offset is EOF
(5 x 81 + 1 = 406). The order is first all directions of the
first unit, then the second unit etc. The NW, W and SW facing
images are created by mirroring the images for NE, E and SE,
respectively.
* What happens if there are MORE or LESS offsets?
IMAGES
ID bytes: value
----------------------------------------
IMAGE HEADER
1 16 bytes: 0, doesn't seem to have any effect
2 4 bytes: Image width
3 4 bytes: Image height
4 4 bytes: Number of leading empty columns
5 4 bytes: Number of leading empty rows
6 4 bytes: Number of columns (i.e. width up to the last non-empty pixel)
7 4 bytes: Number of rows (i.e. height up to the last non-empty pixel)
8 1 byte : 0xFD, this controls which color is treated as transparent.
This only applies to the pixels actually present in the image
encoding, not the "assumed" transparent pixels outside of the
image's bounding box.
The first 5 bits must be 1. The last 3 bits are in the order
BGR (blue, green, red) and reflect the RGB values of the
transparent color.
For example, if the last 3 bits are 111, the transparent color
is white. If the last 3 bits are 001 the transparent color is
red. The default is 101 which makes the transparent color
magenta. 0xFD is 11111101 in binary.
9 4 bytes: image body size
IMAGE BODY ([Image Header value 7] - [Image Header value 5] rows)
1 4 bytes: Number of empty bytes. This number of bytes corresponds to
half this number of transparent pixels. That is because the
image is 16-bit, so it takes 2 bytes per pixel.
2 4 bytes: Row data size: N bytes, or N/2 pixels.
3 N bytes: Row image data. This image data is in 15+1 bit format (in Big
endian byte order that would be: 1-5-5-5). The first bit
indicates whether the pixel's shade is changed to the civ color
(1) or not (0). The other 15 bits are 5 bits each in the order
R-G-B. Transparent pixels are represented by magenta (Little
endian 0x1F7C or Big endian 0111110000011111). This depends on
Image Header value 8.
IMAGE FOOTER
1 10 bytes: 0, doesn't seem to have any effect
UNITXX.SPR
FILE HEADER
ID bytes: value
----------------------------------------
HEADER
1 4 bytes: 12, offset of Animation Section
2 4 bytes: Offset of Image Offsets
3 4 bytes: Offset of first image
ANIMATION SECTION
Animation Header:
1 32 x 4 bytes: Offsets of information for each animation
(8 facing directions x 4 actions = 32 animations)
The actions are, in order: Attack, Die, Idle, Move. The
directions start at North, continuing clockwise to end at
Northwest. The offsets indicate first all directions of
Attack, then the animations for Die, then Idle and Move.
Unit99.spr, used for the train animation, has exactly the same
header. Since its Attack and Die animations are never used
their offsets always point to an empty animation.
NOTE: These offsets need not necessarily be in ascending order
or even different. You could let the file contain only one
animation, with all actions and directions using the same one.
Animation Information:
1 X x 4 bytes: For each frame in an animation...
(probably one long integer "bitmasked" into separate values)
1. Points to the Nth (zero-based) image in the file. This
index actually uses 10 bits! The last two bits in the
second byte are also part of this index.
That means two things: there can't be more than 1024
images in an animation file, and more interestingly, you
can reuse frames.
2. ..1. .... "Start loop" frame
.1.. .... "End loop" frame (back to last start)
1... .... Mirrors a frame (horizontally)
...x xx.. These 3 bits control transparency:
000 = fully visible ...
111 = fully transparent
(used for fading out dying units)
.... ..xx Part of the image index from byte 1!
3. Byte 3 is almost always 06 but doesn't seem to be used
for aything. Perhaps it was originally meant for
controlling animation frame rate.
4. .... ...1 End animation/Don't display frame ???
.... ..1. Loop frame
.xxx xx.. Not used (?)
1... .... Not used (hangs Civ2)
DISCUSSION
The 01 and 02 values only seem to occur in Resource.spr.
It seems as if a fade-out animation must end with the byte
sequence 0000 0001. It doesn't seem to be possible to control
frame rate, e.g. Die animations often have two of the same
frames following each other, which makes the animation twice
as "slow" as the others.
Animations that start with the "start loop", end with the
"end loop" and are all marked with the byte 4 value 02 will
play continuously (like the oil resources). Any frame in a
loop that isn't marked with 02 will not be displayed, but WILL
take up time. The tile won't be refreshed though, unless
something else does refresh it (e.g. the blinking cursor).
What that means is, the last visible frame will remain on-
screen during the invisible frames' display time, EXCEPT when
the cursor is over it. In that case, the animation will really
disappear for the duration of the invisible frames...
Even more, the cursor is a 64x64 pixel box, aligned to the
bottom-left corner of the enclosing box of the tile it's on.
Anything within that box will be refreshed, so it can also
(partially) affect resource animations above or below it.
An animation MUST either end with [XX XX XX01] (no loop) or
with [XX 40 XX 02] (continuous loop). All frames in a loop
must have their 4th byte on 02.
In determining what to play, Civ2 will start at the header
offset and continue until the first end loop/animation
(Byte 2, bit 2/Byte 4 bit 8).
It will then search back to the nearest start loop (B2b3) and
animate up until the next end frame. E.g. if you remove the
starting frame's B2b3, you will actually get to see the
animation that's stored before it in the file. It will either
play that once (ends with B4b8, otherwise byte 4 is 00) or
play it forever (all frames B4b7, first frame B2b3, last
frame B2b2).
A value of 03 for byte 4 will make the entire resource
invisible, until the screen is refreshed.
If the end frame of an otherwise proper loop has 01 rather
than 02, the end frame is not displayed, but the animation
still loops.
IMAGE OFFSETS
X x 4 bytes: Image offsets (from start of image section), the last one of
these offsets points to the end of the file.
IMAGES
As in Static.spr
RESOURCE.SPR
This one's pretty much the same as the units sprite files. Some extra notes:
If a resource doesn't have animation, the corresponding header value points it
to an empty animation (hex sequence 0020 0001, 0001 probably means something to
the effect of "don't display me", the 20 part is the "start loop" flag).
While the unitXX.spr has the first part of the animation header nicely in
ascending order of offset, the resource.spr has that section in pretty random
order. Plus, a lot of the animations are empty, so the animation "summary"
points all of those to a final entry in the frame information part.
The first part of the animation header is obviously different from the units:
1 88 x 4 bytes: (4 maps x 11 terrain types x 2 resources)
In the following order: first resources of first map
(following regular terrain order from Desert through to
Ocean), second resources of first map, first resources of
second map etc. In fact, that's exactly the order of the
resources in the rules.
Last updated: 26 November 2007







