Eye of the Beholder DAT File Format

This document describes the decoration rectangle data files (.dat) that are bundled with each decoration image file.

In EOB2 they have the filename extension .dec


All unsigned short are big endian! They are little endian in the PC version.


File Format

struct Decoration

{

   unsigned short nbrDecorations;

   struct Decoration decorations[nbrDecorations]; /* Indexed into by the WallMapping in the [[eob.inf|.inf]] file. */

   unsigned short nbrDecorationRectangles;

   struct DecorationRectangle rectangles[nbrDecorationRectangles];

};


Sub structures

struct Decoration

{

   unsigned char rectangleIndices[10]; /* indices into DecorationData.rectangles */

   unsigned char linkToNextDecoration; /* index into DecorationData.decorations */

   unsigned char flags;

   unsigned short xCoords[10]; /* coordinate in the game view, where to render the overlay */

   unsigned short yCoords[10];

};

If rectangle index is 0xFF, there isn't a decoration for that view position.

Each of these 10 indices in the arrays corresponds to the 10 possible overlay graphics positions in the viewport.

TODO: Describe linkToNextDecoration, flags and the coordinate system. (JackAsser will fix this)


struct DecorationRectangle

{

   unsigned short x; /* Multiply by 8 to get actual screen coord */

   unsigned short y;

   unsigned short w; /* Multiply by 8 to get actual width */

   unsigned short h;

};

Each rectangle describes an area in the .cps graphics file stated by the 0xec command code in the .inf file.



Drawing a decoration + Pseudocode(EOB2)

(what about EOB1?)


decoration wall positions (0..9):

9 7 3 7 9

 8 6 2 6 8

 8 5 1 5 8

   4 0 4

     ^=party pos.


The following table contains drawing information for each view position:

xflip: for side walls: 0=left, 1=right

wall: decoration position number, -1=none available for this position

xdelta: horizontal shift (decoration on wall only) in render window for this wall position (multiply with 8)


CDecPos: array [0 .. 25] of TPos = (

   (XFlip: 0; Wall: -1; XDelta: 0),

   (XFlip: 0; Wall: 9; XDelta: 0),

   (XFlip: 0; Wall: 7; XDelta: 0),

 

   (XFlip: 1; Wall: 7; XDelta: 0),

   (XFlip: 1; Wall: 9; XDelta: 0),

   (XFlip: 0; Wall: -1; XDelta: 0),

 

   (XFlip: 0; Wall: 3; XDelta: -12),

   (XFlip: 0; Wall: 3; XDelta: -6),

   (XFlip: 0; Wall: 3; XDelta: 12),

   (XFlip: 0; Wall: 3; XDelta: 6),

   (XFlip: 0; Wall: 3; XDelta: 0),    //middle front wall

 

   (XFlip: 0; Wall: 8; XDelta: 0),

   (XFlip: 0; Wall: 6; XDelta: 0),

 

   (XFlip: 1; Wall: 6; XDelta: 0),

   (XFlip: 1; Wall: 8; XDelta: 0),

 

   (XFlip: 0; Wall: 2; XDelta: -10),

   (XFlip: 0; Wall: 2; XDelta: 10),

   (XFlip: 0; Wall: 2; XDelta: 0),   //middle front wall

 

   (XFlip: 0; Wall: 5; XDelta: 0),

 

   (XFlip: 1; Wall: 5; XDelta: 0),

 

   (XFlip: 0; Wall: 1; XDelta: -16),

   (XFlip: 0; Wall: 1; XDelta: 16),

   (XFlip: 0; Wall: 1; XDelta: 0),    //middle front wall

 

   (XFlip: 0; Wall: 4; XDelta: 0),

 

   (XFlip: 1; Wall: 4; XDelta: 0),

   (XFlip: 0; Wall: 0; XDelta: 0)

 );

Decorations can consist of more than one rectangle, which are drawn together.

They are given as a list:

procedure DrawCompleteDecoration(GFXIndex, DecNumber, Position:longint; isAtWall:boolean);

begin

 repeat

  DrawDecorationPart(GFXIndex, DecNumber, Position, isAtWall); // draw a part of the decoration

  DecNumber:= Decoration[DecNumber].NextDecoration; // go to next part

 until DecNumber = 0;

end;


GFXIndex points to the data file where the decoration resides: for example mezz2.cps

DecNumber is the number of the Decoration.

Position (range 0..25) is the wall position (side and front walls).

isAtWall tells if the decoration is at a wall, this is true if the walltype in the

decoration mapping definition in the .inf file is unequal zero.


procedure DrawDecorationPart(GFXIndex, DecNumber, Position:longint; isAtWall:boolean);

 

var

 i,j,            //pos in cps graphics

 s,t:longint;    //pos on screen

 q:byte;

 dx,pos : longint;

 mirrored : boolean;

begin

 

 //get the horizontal shift for the decoration according to its position.

 //if the decoration is drawn at a wall, we use the table above.

 //otherwise the decoration is placed in the middle of a field,

 // for example a pit or pressure plate...

 dx := 0;

 if isAtWall then

  dx := 8*CDecPos[Position].XDelta

 else

  case Position of

   6 : dx := -88;

   7 : dx := -40;

   8 : dx := 88;

   9 : dx := 40;

 

   15 : dx := -59;

   16 : dx := 59;

 

   20 : dx := -98;

   21 : dx := 98;

  end;

 

 //translate view positions (0..25) to decoration view position (0..9)

 pos := CDecPos[Position].Wall;

 

 if pos >= 0 then

 begin

 

  //get the number of the decoration rectangle for the corresponding view position

  q := Decoration[DecNumber].RectangleIndices[pos];

 

  //if rectangle index is $FF, then there doesn't exist a decoration for this view position

  if q <> $FF then

  begin

 

   //Bit 0 in Flags: for front walls (and not for side walls):

   // for example, a decoration consists of two parts,

   // and the second part is the first one, but mirrored..

   mirrored := false;

   case Position of

   6..10, 15..17, 20..22, 25: mirrored := boolean(Decoration[DecNumber].Flags and $01);

   end;

 

    t:= Decoration[DecNumber].YCoords[pos];

 

    for j:= Rectangles[q].y to Rectangles[q].y+Rectangles[q].Height-1 do

    begin

 

      if mirrored then

       s := 22*8 - Decoration[DecNumber].XCoords[pos] - 1

      else

       s := Decoration[DecNumber].XCoords[pos];

 

     for i := Rectangles[q].x*8 to Rectangles[q].x*8+Rectangles[q].Width*8-1 do

     begin

 

       if mirrored then

       begin

        PutPixel(s+dx, t, Graphics[GFXIndex][320*j + i]);

        Dec(s);

       end else

       begin

         if CDecPos[Position].XFlip = 0 then

          PutPixel(s+dx, t, Graphics[GFXIndex][320*j + i]) //left side walls; front walls

         else

          PutPixel(22*8-(s+dx), t, Graphics[GFXIndex][320*j + i]); //right side walls only

         Inc(s);

       end;

 

     end; //for i

 

     Inc(t);

    end; //for j

 

 

  end; // q<>$FF

 

 end; //pos>0

 

end;

Discussions

inigomartinez

PC EOB1/2

inigomartinez 08 November 2009 12:19:42

Looks like Neither EOB1 and EOB2 seems to have the unsigned short values in Big Endian. Is this annotation about the Amiga version ?

JackAsser

JackAsser 08 November 2009 15:51:06

Yes. The PC version is little-endian afaik.

inigomartinez

flags field

inigomartinez 06 September 2010 17:21:24

Looking below, I have seen that the first bit of the flags does mean that the decoration should be mirrored.

I have been checking more files and I have seen that the third bit is used sometimes too. Any idea about its meaning ? Is any other bit used.

inigomartinez

inigomartinez 20 September 2010 07:32:43

As a side note, I have noticed that the decorations with this bit active are mainly, floor and ceil decorations like holes and similar.

In my tests they look correct without doing anything special. Maybe, they have something to do with scripts data.

inigomartinez

No decoration ID

inigomartinez 09 September 2010 14:06:55

Looking to INF files, I have seen that some wall mapping commands have a decoration id of 0xFF.

Knowing that 0xFF is used to suggest that no rectangle exist for a given position, shouldn't 0xFF mean no decoration too ?

Could anyone confirm this ?

PS: Is anyone still around ?

badut

badut 09 September 2010 23:27:23

I'm still around. But sorry I can not answer your question.
My EOB project is hibernating at the moment but I hope to find time to awaken it soon ;)