The El-Fish .FSH file format

Contact information

All this was done by Vidar Holen (mail). Send me questions or comments, especially if you piece together something I have not.

Pre-rant

El-Fish, the wonderful fish simulator by Animatek/Maxis, has long been a love of mine. Unfortunately, I haven't actually been able to run the program for years since it's very picky with what it will run on. My dream has long been an xscreensaver with elfish fishies, but Maxis turned down my plea to open source it (2002-08-01), so I decided to try to reverse engineer it. Two years later, after on and off (mostly off, obviously; most of it was done in two days) hacking, I can extract the frames.

How much can you do with these specs?

I'm currently able to extract animation frames (and description/icon view) but I haven't been able to piece together fluid animations. This same file format is used for .mvy (animations like the crab) and .isb (custom art). Even .aqu (aquariums) and .iso (image libraries) use it to some extent, but I haven't studied it closely.

The format

Each file is encoded in streams, each stream has a number of frames. All integers are little-endian. The .fsh file:
8 bytes   Unknown (magic?)
2 bytes   Unknown (zero)

--(offset now 0A)--
8 bytes   Fish name, zero-padded at end.
4 bytes   Unknown (zero)
2 bytes   Unknown (rendering progress?)
2 bytes   Unknown (rendering total?)
2 bytes   Unknown (Total number of animation frames + 7 ?)
4 bytes   Unknown

--(offset now 20)--
4 bytes   Total file length
103 bytes Unknown

--(offset now 8B)--
4 bytes   Stream offset - Detailed frame
4 bytes   Stream offset - Icon frame
4 bytes   Stream offset - Animation frames
Each stream is a linked list of frames. Each frame has a 30 byte header:
4 bytes   Frame length (from start of header)
4 bytes   Frame number
4 bytes   Previous entry (absolute seek), or 0 if first frame in the series
4 bytes   Next entry (absolute seek), or 0 if last frame in the series
4 bytes   Unknown (same as frame length)
2 bytes   Unknown (movement increment?)
2 bytes   X offset (?)
2 bytes   Y offset (?)
2 bytes   Frame width
2 bytes   Frame height
Then follows frame data. Each frame is encoded in lines, each line is built up from plot sections. Each plot section has a length, position, and pixels:
      2 bytes      2 bytes     'Length' bytes
  [ Data length  | Position  |  Pixel data (1 byte per) ]
If the position is positive (two's complement), this is the start of a line. If it's negative, take its absolute value and plot on the current line (the first line only have negative sections). Simply put the pixel data in the line buffer linearly at the specified position. Any part of a line that is not explicitly colored is transparent. Each pixel is encoded in a fixed palette, which can be extracted from an elfish screenshot or downloaded here.

Animation

This isn't perfect, but it's what I have so far: The frame number from the frame header, when encoded in decimal, is on the form 'DANN' where D is the direction, A is the action, and NN is the position of this frame within the sequence. Some fish have six directions, others have four:

Direction:  4-dir:   6-dir:
    0        Right    Right
    1        Up       Up-right
    2        Left     Up-left
    3        Down     Left
    4                 Down-left
    5                 Down-right
The only way I know to determine if a fish has 4 or 6 directions is to count. The actions are as follows:
Action: 
    0 Swim 
    1 First section in Turn from dir to dir+1 
    2 Middle section in Turn from dir-1 to dir+1
    3 Last section in Turn from dir+1 to dir
    4 Paddle
    5 Idle
    6 Stop (Swim to Idle)
As you can see, there are only left turns. Fish rely on their symmetry for complete animation. Swin animations are done by first playing Swim Right then mirroring Swim Left. The X/Y offsets from the frame header is probably the relative position in which to paint the frame (since each has a varying width and height depending on fin positions and such).

Sample code

I don't know what will be useful (read: I don't want to sort), so I'll just tar up all of the java code I wrote while reverse engineering it (GPL): Fetch! Interesting ones are ExtractFrames to dump all the frames, CountFrames to walk the .fsh file and print out structure information, and Swim to show animations

Amusing stuff

Here are some progress screenshots:
It's a fish allright
Kind of mushed, but alteast linebroken.
Head's ok
Tail's ok
Perfect frame
Animation!
And here is the game itself: PC Version (thanks to Scootie and the El-Fish, which seems to be down): Disk 1 , 2 , 3 , 4 , 5 . There's also an svga patch to run the game at 640x480.

Links

Contributed material