Eye of the Beholder Decorations Format

From ModdingWiki
Jump to navigation Jump to search
Edge of map!

! Wikify formatting

! Add infobox

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;