Free Hero Mesh

mbform.doc at [ef8fe744ff]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.

File misc/mbform.doc artifact 810ca18dc0 part of check-in ef8fe744ff


** Hero Mesh File Format **

This describes the file format of the Windows version of Hero Mesh. (Free
Hero Mesh uses a different file format described in a different file.)

All numbers are small-endian and unsigned. WORD is 16-bits, and DWORD is
32-bits, and BYTE is 8-bits.


=== Header ===

At the beginning of the file is the following:

Offset  Type      Description
0       WORD      File version
2       CHAR(4)   ASCII characters "MESH"
6       DWORD     Puzzle set number
10      WORD      Number of picture sizes
12      WORD(8)   Picture sizes
28      WORD      Number of words in picture allocation table

File version is 15 for Hero Mesh version 1.1c, and is 16 for Hero Mesh
version 2.0. Other versions (if any) are unknown. The rest of this
document is applicable to file version 16 (differences, if any, are
unknown; file version 15 does not seem to have any differences as far
as I can tell).

Puzzle set number is a number that can be read by the class codes but
otherwise does nothing. It is used by the Hero Hearts puzzle sets to
determine which puzzle set to link to after completing the last level.

The picture sizes are all square; the numbers given are the width (which
is equal to the height) of that picture size. For example, if it says 24
then the pictures are 24x24.

After this comes the picture allocation table, which specifies which
pictures are allocated. The first word of the allocation table is for the
first sixteen pictures; the low bit is for the first picture, and the high
bit is for the sixteenth picture.


=== Pictures ===

Picture data comes next. The encoding is like this C code:

  // nsizes = number of picture sizes (1 to 8; normally 3)
  // nalloc = number of words in picture allocation table
  // sizes[s] = width or height of picture size s (where s is 0 to 7)
  for(s=0;s<nsizes;s++) {
    for(i=0;i<nalloc;i++) {
      for(y=0;y<sizes[s];y++) {
        for(j=0;j<16;j++) {
          @< Read (sizes[s]) bytes from file into
             scanline y of size s of picture 16*i+j
             (one byte per pixel; zero = transparent) @>
        }
      }
    }
  }
  // Unallocated pictures are still read, even though they aren't used.

(This may also be considered as one large picture per size; where the
pictures are tile sets with sixteen tiles across.)

Next comes the picture availability table, which controls which pictures
are available for selection in the level editor. There are always 512
bytes, one byte per picture. The byte value is 1 if it is available or 0
if it is not available.


=== User Message Table ===

Next is the user message table. It starts with a WORD which is the number
of user messages. User message numbers start with 20; messages 0 to 19 are
the built-in messages. For each user message there is a BYTE giving the
length of the message name, followed by the message name. (There seems to
be always one extra message name at the end which is blank and is unused.
The reason for this is currently unknown.) If the name is empty then that
user message does not exist (it may have been deleted).

The standard messages are as follows:
 0 = INIT
 1 = CREATE
 2 = DESTROY
 3 = BEGIN_TURN
 4 = ARRIVED
 5 = DEPARTED
 6 = LASTIMAGE
 7 = MOVED
 8 = JUMPED
 9 = KEY
 10 = MOVING
 11 = SUNK
 12 = FLOATED
 13 = PLAYERMOVING
 14 = HIT
 15 = HITBY
 16 = DESTROYED
 17 = CREATED
 18 = POSTINIT
 19 = END_TURN


=== Classes ===

After the user message table comes the classes. This starts with a WORD
specifying the number of classes. Classes then follow.

Each class consists of the following:

* Name: A BYTE giving the length of the name, followed by the name.

* ID number: A WORD giving the zero-based class ID number (class ID
numbers are sometimes one-based, but here they are zero-based).

* Description: One or three bytes for length, followed by the plain text
(using CRLF for line endings). If length is less than 255 then it is one
byte. Otherwise, the first byte is 255 and then a WORD follows which gives
the length of the description. The description isn't null terminated. Any
escapes in the description are interpreted at runtime; they are not stored
with the control codes mentioned for special texts.

* Attributes: See attribute table below.

* Number of pictures (WORD)

* List of pictures. Each is a WORD, and is a zero-based number of the
picture from the picture area; after this, all further picture numbers in
the file are zero-based indexing into this table.

* Number of user variables (WORD)

* User variable names; each is eight bytes long and is padded with nulls.
(Variable names are actually limited to seven characters.)

* Number of subroutine labels (WORD)

* Label names; each is ten bytes long, and is a eight-byte null terminated
string, with junk in the remaining bytes; the final two bytes are a word
address into the sobroutine or message section.

* Subroutine program codes

* Number of message labels (WORD) (these aren't the message names; these
are labels outside of the subroutine section).

* Message label names; stored like the subroutine label names.

* Message program codes

Attribute Table
     0    BYTE     ???
     1    BYTE     Flag
     2    WORD     Misc4
     4    WORD     Misc5
     6    WORD     Misc6
     8    WORD     Misc7
    10    WORD     Shovable
    12    BYTE(5)  Arrivals
    17    BYTE(5)  Departures
    22    WORD     Density
    24    WORD     Volume
    26    WORD     Strength
    28    WORD     Weight
    30    WORD     HardE
    32    WORD     HardN
    34    WORD     HardW
    36    WORD     HardS
    38    WORD     SharpE
    40    WORD     SharpN
    42    WORD     SharpW
    44    WORD     SharpS
    46    WORD     Height
    48    WORD     Climb
    50    WORD     Temperature
    52    WORD     Shape
    54    WORD     ???
    56    WORD     ???
    58    WORD     ???
    60    WORD     ???

The flag byte has bit0 set for "receives keys" and has bit7 set for "is
the player". Other flags (if any) are unknown, they appear to be unset.

The arrivals and departures are stored each as five bytes, each byte for
one row, with the first byte corresponding to the top row. In each byte,
the rightmost column is the low bit; only the low 5-bits are used. (This
is not the same as the representation used in class codes!)

The last four attributes seem to have something to do with the program
length, but it is unknown. However, it is not necessary to read these in
order to figure out the program length (see below for details).


=== Program ===

Each class has program codes; this section describes how the program codes
are encoded in the file.

The first WORD of the subroutine section is the number of WORDs that make
up the the subroutine section, including the count itself. After that one
WORD header comes the instructions.

Each message block in the message section then consists of the header and
then the instructions. The header of each message block consists of two
WORDs, the first being the message number, and the second being the length
(in WORDs) of this message block, including the header.

The program is terminated by a header with both WORDs zero.

Program instructions are executed using a stack-based virtual machine.
Each instruction is normally one WORD; see below section for the opcodes.


=== Program Opcodes ===

The first byte is opcode byte (the major code). The second byte is the
minor code, the meaning depending on the opcode. In the descriptions
below, if it says / and a number, it is how many taken from stack. If
there is * then it pushes to stack, ! means end block, - means no effect
on data stack.

[1*] Local variables: 0=Class, 1=Temperature, 2=Shape, 4=Xloc, 5=Yloc,
6=LastDir, 7=CurImage, 8=Inertia, 9=Misc1, 10=Misc2, 11=Misc3, 12=Misc4,
13=Misc5, 14=Misc6, 15=Misc7, 16=Arrived, 17=Departed, 18=Arrivals,
19=Departures, 32=Busy, 33=Invisible, 34=UserSignal, 35=UserState,
36=KeyCleared, 37=IsPlayer, 38=Destroyed, 39=Stealthy, 40=VisualOnly,
48=Msg, 49=MsgFrom, 50=MsgArg1, 51=MsgArg2, 64=Density, 65=Volume,
66=Strength, 67=Weight, 68=Distance, 69=Height, 70=Climb, 72=HardE,
73=HardN, 74=HardW, 75=HardS, 76=SharpE, 77=SharpN, 78=SharpW, 79=SharpS,
80=ShapeE, 81=ShapeN, 82=ShapeW, 83=ShapeS, 84=Shovable

[2/1*] Retrieve local variable from other object. Local variable numbers
are the same as opcode 1.

[3/1] Assignment to standard local variables of current object.

[4/2] Assignment to standard local variable of other object (the first
(top) value taken from the stack is the value, and second is the object).

[5*] User-defined local variable; the second byte is zero-based local
variable number.

[6/1] Assignment to user-defined variable; the second byte is the
zero-based local variable number to write to.

[7*] Short decimal constant; the second byte is the 8-bit value.

[8*] Long decimal constant. The next two words are the small-endian 32-bit
number that it represents.

[9*] Short class constant; the second byte is a zero-based class number
(the class number is one-based at runtime).

[11*] Message constant; the second byte is the message number.

[13*] String literal. Follow by one WORD giving number of bytes of string
(including null terminator, always even), and then null-terminated special
text. There may be two null terminators if needed to make it even.

[14*] Direction constant (0-7 for absolute, 8-15 for relative)

[16/1*] Unary operator: 0=negative, 1=bitwise NOT, 2=logical NOT

[17/2*] Binary operator: 0=multiply, 1=divide, 2=modulo

[18/2*] Binary operator: 0=add, 1=subtract, 2=AND, 3=OR, 4=XOR

[19/2*] Bit shift operator: 0=left, 1=right

[20/2*] Comparison operator: 0=equal, 1=unequal, 2=less, 3=greater, 4=less
or equal, 5=greater or equal

[21/2*] Logical operator: 0=AND, 1=OR, 2=XOR (not short-circuiting)

[32] ObjDir

[34] ObjAbove

[36] ObjBelow

[38/2*] 0=ObjTopAt, 1=ObjBottomAt, 2=VolumeAt, 3=HeightAt, 4=Delta

[39*] Self

[40/3*] ObjClassAt

[47*] Array reference; next word is the array address.

[48*] Key

[49*] Animation constant: 0=STOP, 1=ONCE, 2=LOOP, 8=OSC

[50*] Keyboard constant: See section about key codes.

[51*] Short hexadecimal constant; second byte is the 8-bit value.

[52*] Long hexadecimal constant. Next two words are the small-endian
32-bit number that it represents.

[53*] Global variable: 0=Level, 1=LevelCount, 2=AltImage, 3=ExplainDeath,
4=GlobalBool, 5=PuzzleSetNumber, 6=MoveNumber

[54] XDir

[56] YDir

[58] 0=NewX, 1=NewY

[59*] Bit constant 0-31; the second byte is the number 0-31, and at
runtime it is replaced by the relevant 32-bit number.

[60*] Sound constant (see section about user sounds)

[61] 0=ClassCount/1* (I don't know what this does), 1=GetArray

[64/3*] SendMessage (to Self)

[65/4*] SendMessage

[66/3*] Broadcast; second byte is zero-based class number

[67/4*] Broadcast

[68/1*] Move(Self, ...); minor code is 255 to take the value from the
stack, or is another number for a direction constant (in this latter case
the same bug occurs as with opcode 84).

[69/2*] Move; minor code is same as opcode 68, but the bug with opcode 84
does not occur, regardless of the minor code.

[70/2*] JumpTo(Self, ...)

[71/3*] JumpTo

[72/5*] Create

[74*] Destroy(Self)

[75/1*] Destroy

[80/3] SendMessage(Self, ...)

[81/4] SendMessage

[82/3] Broadcast; second byte is zero-based class number

[83/4] Broadcast

[84] Move(Self, dir). The second byte is the direction to move. Unlike
the normal Move() function, this one adds Strength to Inertia instead of
setting Inertia equal to Strength (this seems to be a bug). If the minor
code is 255 then takes direction from stack and does not have this bug.

[85] Move. The second byte is the same as for opcode 84; if 255 then it
takes from the stack (before taking the object to move). In this case the
bug mentioned above does not occur regardless of what the minor code is.

[88/5] Create

[96] Comment. Has one WORD giving length of the comment text (including
the null terminator), and then the plain text of the comment (with CRLF
line endings), null terminated.

[97] Popup setting. Second byte is 0 for PopupColor or 1 for PopupLoc.

[98] Destroy(Self)

[99/1] Destroy

[100] CallSub

[101-] Goto; next WORD is address to branch to unconditionally

[102] Return. Second byte is 0 for implicit end of SUBS block, 1 for
return from a subroutine, 2 for the end of a message block.

[103-] Return short constant. Second byte is return value.

[104/1] Return

[105/1] If. Second byte is zero for block-if or one for inline-if. The
next word is the number of words to skip (including the count itself) if
the condition is false.

[106] Else

[107/3] ImageSeq (seems to do nothing?)

[108/3] ImageLoop (seems to do nothing?)

[109] PopUp. Values taken from the stack is one plus the minor code.

[110/2] JumpTo(Self, ...)

[111/3] JumpTo

[112] Sound

[114] Array operations. Second byte: 0 = definition of an array, 1 =
SetArray, 2 = InitArray.

[126] Animate

[127] Link

[128] GotoLevel

[129-] 0=WinLevel, 1=LocateMe, 2=IgnoreKey, 3=PopupMisc, 4=UpdateScreen
(I don't know what UpdateScreen means?)

[130] FlushClass

[131] FlushObj

[132] SetInventory

[133] DelInventory

[134] ForEachObjAt

[240] Trace


=== Levels ===

After all classes are the levels. Before the levels comes a header of four
bytes that consists of:

* Number of levels (WORD)

* Two null bytes with unknown meaning

Each level consists of:

* Zero-based level number (WORD)

* Level description length, including the null terminator (WORD)

* Level description; a null-terminated special text

* Border colours, outer to inner (BYTE(32))

* Background colour (BYTE)

* Null byte (maybe the high byte of the background colour)

* Number of objects (WORD)

* Objects, in ordinary progressive television order; within each cell they
go bottom to top. See information about object records below.

* Number of level strings (WORD)

* Level strings; each one WORD length (the length includes the null
terminator), followed by the null-terminated special text.

An object record is sixteen bytes long, and consists of:
    0   WORD    Class (zero-based)
    2   WORD    CurImage (zero-based)
    4   BYTE    LastDir (zero-based; 0=east, 1=northeast, etc)
    5   BYTE    Data types for Misc vars
    6   WORD    X coordinate (one-based)
    8   WORD    Y coordinate (one-based)
   10   WORD    Misc1
   12   WORD    Misc2
   14   WORD    Misc3

The data types are as follows:
 0 = Number
 1 = Class (one-based)
 2 = Message
 3 = String
Data type for Misc1 is in bit1 and bit0, data type for Misc2 is in bit3
and bit2, data type for Misc3 is in bit5 and bit4. Bit7 and bit6 are
always zero.

The data type is used only in the editor and is irrelevant at run time.


=== Special Text ===

Level data may contain special text. This is text using the following
control codes (escapes have already been interpreted):

1 = Black (\0)
2 = Blue (\1)
3 = Green (\2)
4 = Cyan (\3)
5 = Red (\4)
6 = Purple (\5)
7 = Yellow (\6)
8 = White (\7)
10 = Line break (\n)
11 = Left (\l)
12 = Center (\c)
14 = Picture (\i); followed by two WORDs: zero-based class and image
15 = Horizontal line (\b)
16 = Quiz button (\q); followed by one byte key code


=== Solutions ===

After the levels come the solutions. There is first one WORD which is the
number of solutions, and then the solutions. Each solution consists of:

* Zero-based level number (WORD)

* Number of keys in solution (WORD)

* User name (BYTE(9)); the user name is null terminated, although there
may be junk after the null terminator.

* Key codes; one byte each.


=== User Sounds ===

Finally, the user sounds come last. One WORD gives the number of user
sounds. And then each sound consists of:

* Sound ID number (zero-based) (WORD)

* Name length (BYTE)

* Name (not terminated; length is given instead)

* Data length (WORD)

* Data (a RIFF WAVE file)

The built-in sounds are as follows:
 SPLASH
 POUR
 DOOR
 GLASS
 BANG
 UNHH
 UH_OH
 FROG
 THWIT
 KLINKK
 POWER
 KLECK
 CLICK
 SMALL_POP
 DINK
 TICK
 CHYEW
 CHEEP
 ANHH
 BRRRT
 BRRREEET
 BWEEP
 DRLRLRINK
 FFFFTT
 WAHOO
 YEEHAW
 OLDPHONE
 RATTLE
 BEEDEEP
 THMP_thmp
 BEDOINGNG
 HEARTBEAT
 LOCK
 TAHTASHH
 BOOOM
 VACUUM
 RATCHET2
 DYUPE
 UNCORK
 BOUNCE
 JAYAYAYNG
 DEEP_POP
 RATCHET1
 GLISSANT
 BUZZER
 FAROUT
 KEWEL
 WHACK
 STEAM
 HAWK


=== Key codes ===

   8  BACK
   9  TAB
  12  CENTER (number pad 5 when numlock is off)
  13  ENTER
  16  SHIFT
  17  CTRL
  19  BREAK
  20  CAPSLOCK
  32  SPACE
  33  PGUP
  34  PGDN
  35  END
  36  HOME
  37  LEFT
  38  UP
  39  RIGHT
  40  DOWN
  48  0 (the top row zero)
  57  9 (the top row nine; 1-8 are in between 0 and 9)
  65  A
  90  Z (letters B-Y are in between A and Z)
  96  NUMPAD0
 105  NUMPAD9 (number pad 1-8 are in between)
 106  MULTIPLY (the number pad "*" key)
 110  DECIMAL (the number pad "." key)
 111  DIVIDE (the number pad "/" key)
 120  F9
 121  F10
 122  F11
 123  F12
 144  NUMLOCK
 145  SCRLOCK
 186  SEMICOLON
 187  EQUALS
 188  COMMA
 189  MINUS
 190  PERIOD
 191  SLASH
 192  TILDE
 219  OBRACKET
 220  BACKSLASH
 221  CBRACKET
 222  QUOTE

The number pad and main enter keys have the same key code. When num lock
is off, the number pad keys have the same codes as the other arrow keys.
The NUMPAD codes are only when numlock is on.