rnd-20031208-1-src
[rocksndiamonds.git] / src / tools.c
index 0d1f8b910314491db687c2059f612c7dc9e81e57..cb473ce77e96463fa140c24d7da0bf2ac276036a 100644 (file)
@@ -1,35 +1,24 @@
 /***********************************************************
-*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
 *----------------------------------------------------------*
-*  (c) 1995-98 Artsoft Entertainment                       *
-*              Holger Schemel                              *
-*              Oststrasse 11a                              *
-*              33604 Bielefeld                             *
-*              phone: ++49 +521 290471                     *
-*              email: aeglos@valinor.owl.de                *
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
 *----------------------------------------------------------*
-*  tools.c                                                 *
+* tools.c                                                  *
 ***********************************************************/
 
-#include <stdarg.h>
-
-#ifdef __FreeBSD__
-#include <machine/joystick.h>
-#endif
+#include "libgame/libgame.h"
 
 #include "tools.h"
 #include "game.h"
 #include "events.h"
-#include "sound.h"
-#include "misc.h"
-#include "buttons.h"
-#include "joystick.h"
 #include "cartoons.h"
 #include "network.h"
-
-#ifdef MSDOS
-extern boolean wait_for_vsync;
-#endif
+#include "tape.h"
 
 /* tool button identifiers */
 #define TOOL_CTRL_ID_YES       0
@@ -45,6 +34,8 @@ extern boolean wait_for_vsync;
 /* forward declaration for internal use */
 static void UnmapToolButtons();
 static void HandleToolButtons(struct GadgetInfo *);
+static int el_act_dir2crm(int, int, int);
+static int el_act2crm(int, int);
 
 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
 static int request_gadget_id = -1;
@@ -79,12 +70,57 @@ void SetDrawtoField(int mode)
   }
 }
 
+void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
+{
+  if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
+  {
+    if (force_redraw)
+    {
+      x = gfx.sx - TILEX;
+      y = gfx.sy - TILEY;
+      width = gfx.sxsize + 2 * TILEX;
+      height = gfx.sysize + 2 * TILEY;
+    }
+
+    if (force_redraw || setup.direct_draw)
+    {
+      int xx, yy;
+      int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
+      int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
+
+      if (setup.direct_draw)
+       SetDrawtoField(DRAW_BACKBUFFER);
+
+      for (xx = BX1; xx <= BX2; xx++)
+       for (yy = BY1; yy <= BY2; yy++)
+         if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
+           DrawScreenField(xx, yy);
+      DrawAllPlayers();
+
+      if (setup.direct_draw)
+       SetDrawtoField(DRAW_DIRECT);
+    }
+
+    if (setup.soft_scrolling)
+    {
+      int fx = FX, fy = FY;
+
+      fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
+      fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
+
+      BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
+    }
+  }
+
+  BlitBitmap(drawto, window, x, y, width, height, x, y);
+}
+
 void BackToFront()
 {
   int x,y;
-  Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
+  DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
 
-  if (setup.direct_draw && game_status == PLAYING)
+  if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
     redraw_mask &= ~REDRAW_MAIN;
 
   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
@@ -93,43 +129,59 @@ void BackToFront()
   if (redraw_mask & REDRAW_FIELD)
     redraw_mask &= ~REDRAW_TILES;
 
-  /*
-  if (redraw_mask & REDRAW_FIELD ||
-      (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING))
-    redraw_mask &= ~REDRAW_TILES;
-  */
-
-  if (!redraw_mask)
+  if (redraw_mask == REDRAW_NONE)
     return;
 
+  if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
+  {
+    static boolean last_frame_skipped = FALSE;
+    boolean skip_even_when_not_scrolling = TRUE;
+    boolean just_scrolling = (ScreenMovDir != 0);
+    boolean verbose = FALSE;
+
+    if (global.fps_slowdown_factor > 1 &&
+       (FrameCounter % global.fps_slowdown_factor) &&
+       (just_scrolling || skip_even_when_not_scrolling))
+    {
+      redraw_mask &= ~REDRAW_MAIN;
+
+      last_frame_skipped = TRUE;
+
+      if (verbose)
+       printf("FRAME SKIPPED\n");
+    }
+    else
+    {
+      if (last_frame_skipped)
+       redraw_mask |= REDRAW_FIELD;
+
+      last_frame_skipped = FALSE;
+
+      if (verbose)
+       printf("frame not skipped\n");
+    }
+  }
+
   /* synchronize X11 graphics at this point; if we would synchronize the
      display immediately after the buffer switching (after the XFlush),
      this could mean that we have to wait for the graphics to complete,
      although we could go on doing calculations for the next frame */
 
-  XSync(display, FALSE);
-
-  /*
-#ifdef MSDOS
-  wait_for_vsync = TRUE;
-#endif
-  */
+  SyncDisplay();
 
   if (redraw_mask & REDRAW_ALL)
   {
-    XCopyArea(display, backbuffer, window, gc,
-             0, 0, WIN_XSIZE, WIN_YSIZE,
-             0, 0);
+    BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
     redraw_mask = 0;
   }
 
   if (redraw_mask & REDRAW_FIELD)
   {
-    if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
+    if (game_status != GAME_MODE_PLAYING ||
+       redraw_mask & REDRAW_FROM_BACKBUFFER)
     {
-      XCopyArea(display, backbuffer, window, gc,
-               REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
-               REAL_SX, REAL_SY);
+      BlitBitmap(backbuffer, window,
+                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
     }
     else
     {
@@ -146,7 +198,7 @@ void BackToFront()
          ABS(ScreenMovPos) == ScrollStepSize ||
          redraw_tiles > REDRAWTILES_THRESHOLD)
       {
-       XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
+       BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
 
 #ifdef DEBUG
 #if 0
@@ -163,307 +215,408 @@ void BackToFront()
 #endif
       }
     }
+
     redraw_mask &= ~REDRAW_MAIN;
   }
 
   if (redraw_mask & REDRAW_DOORS)
   {
     if (redraw_mask & REDRAW_DOOR_1)
-      XCopyArea(display, backbuffer, window, gc,
-               DX, DY, DXSIZE, DYSIZE,
-               DX, DY);
+      BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
     if (redraw_mask & REDRAW_DOOR_2)
     {
       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
-       XCopyArea(display,backbuffer,window,gc,
-                 VX,VY, VXSIZE,VYSIZE,
-                 VX,VY);
+       BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
       else
       {
        if (redraw_mask & REDRAW_VIDEO_1)
-         XCopyArea(display,backbuffer,window,gc,
-                   VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
-                   VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
-                   VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
+         BlitBitmap(backbuffer, window,
+                    VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
+                    VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
+                    VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
        if (redraw_mask & REDRAW_VIDEO_2)
-         XCopyArea(display,backbuffer,window,gc,
-                   VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
-                   VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
-                   VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
+         BlitBitmap(backbuffer, window,
+                    VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
+                    VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
+                    VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
        if (redraw_mask & REDRAW_VIDEO_3)
-         XCopyArea(display,backbuffer,window,gc,
-                   VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
-                   VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
-                   VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
+         BlitBitmap(backbuffer, window,
+                    VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
+                    VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
+                    VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
       }
     }
+
     if (redraw_mask & REDRAW_DOOR_3)
-      XCopyArea(display, backbuffer, window, gc,
-               EX, EY, EXSIZE, EYSIZE,
-               EX, EY);
+      BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
+
     redraw_mask &= ~REDRAW_DOORS;
   }
 
   if (redraw_mask & REDRAW_MICROLEVEL)
   {
-    XCopyArea(display,backbuffer,window,gc,
-             MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
-             MICROLEV_XPOS, MICROLEV_YPOS);
-    XCopyArea(display,backbuffer,window,gc,
-             SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
-             SX, MICROLABEL_YPOS);
+    BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
+              SX, SY + 10 * TILEY);
+
     redraw_mask &= ~REDRAW_MICROLEVEL;
   }
 
   if (redraw_mask & REDRAW_TILES)
   {
-    for(x=0; x<SCR_FIELDX; x++)
-      for(y=0; y<SCR_FIELDY; y++)
+    for (x = 0; x < SCR_FIELDX; x++)
+      for (y =0 ; y < SCR_FIELDY; y++)
        if (redraw[redraw_x1 + x][redraw_y1 + y])
-         XCopyArea(display, buffer, window, gc,
-                   FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
-                   SX + x * TILEX, SY + y * TILEY);
+         BlitBitmap(buffer, window,
+                    FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
+                    SX + x * TILEX, SY + y * TILEY);
+  }
+
+  if (redraw_mask & REDRAW_FPS)                /* display frames per second */
+  {
+    char text[100];
+    char info1[100];
+
+    sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
+    if (!global.fps_slowdown)
+      info1[0] = '\0';
+
+    sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
+    DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
   }
 
-  XFlush(display);
+  FlushDisplay();
 
-  for(x=0; x<MAX_BUF_XSIZE; x++)
-    for(y=0; y<MAX_BUF_YSIZE; y++)
+  for (x = 0; x < MAX_BUF_XSIZE; x++)
+    for (y = 0; y < MAX_BUF_YSIZE; y++)
       redraw[x][y] = 0;
   redraw_tiles = 0;
-  redraw_mask = 0;
+  redraw_mask = REDRAW_NONE;
 }
 
 void FadeToFront()
 {
-/*
+#if 0
   long fading_delay = 300;
 
   if (setup.fading && (redraw_mask & REDRAW_FIELD))
   {
-*/
+#endif
 
-/*
+#if 0
     int x,y;
 
-    XFillRectangle(display,window,gc,
-                  REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
-    XFlush(display);
+    ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
+    FlushDisplay();
 
-    for(i=0;i<2*FULL_SYSIZE;i++)
+    for (i = 0; i < 2 * FULL_SYSIZE; i++)
     {
-      for(y=0;y<FULL_SYSIZE;y++)
+      for (y = 0; y < FULL_SYSIZE; y++)
       {
-       XCopyArea(display,backbuffer,window,gc,
-                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
+       BlitBitmap(backbuffer, window,
+                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
       }
-      XFlush(display);
+      FlushDisplay();
       Delay(10);
     }
-*/
+#endif
 
-/*
-    for(i=1;i<FULL_SYSIZE;i+=2)
-      XCopyArea(display,backbuffer,window,gc,
-               REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
-    XFlush(display);
+#if 0
+    for (i = 1; i < FULL_SYSIZE; i+=2)
+      BlitBitmap(backbuffer, window,
+                REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
+    FlushDisplay();
     Delay(fading_delay);
-*/
+#endif
 
-/*
-    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
-    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
-             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
-    XFlush(display);
+#if 0
+    SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
+    BlitBitmapMasked(backbuffer, window,
+                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
+                    REAL_SX,REAL_SY);
+    FlushDisplay();
     Delay(fading_delay);
 
-    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
-    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
-             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
-    XFlush(display);
+    SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
+    BlitBitmapMasked(backbuffer, window,
+                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
+                    REAL_SX,REAL_SY);
+    FlushDisplay();
     Delay(fading_delay);
 
-    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
-    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
-             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
-    XFlush(display);
+    SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
+    BlitBitmapMasked(backbuffer, window,
+                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
+                    REAL_SX,REAL_SY);
+    FlushDisplay();
     Delay(fading_delay);
 
-    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
-    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
-             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
-    XFlush(display);
+    SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
+    BlitBitmapMasked(backbuffer, window,
+                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
+                    REAL_SX,REAL_SY);
+    FlushDisplay();
     Delay(fading_delay);
 
     redraw_mask &= ~REDRAW_MAIN;
   }
-*/
+#endif
 
   BackToFront();
 }
 
+void SetMainBackgroundImage(int graphic)
+{
+  SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                         graphic_info[graphic].bitmap ?
+                         graphic_info[graphic].bitmap :
+                         graphic_info[IMG_BACKGROUND].bitmap);
+}
+
+void SetDoorBackgroundImage(int graphic)
+{
+  SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                         graphic_info[graphic].bitmap ?
+                         graphic_info[graphic].bitmap :
+                         graphic_info[IMG_BACKGROUND].bitmap);
+}
+
+void DrawBackground(int dest_x, int dest_y, int width, int height)
+{
+  ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
+
+  redraw_mask |= REDRAW_FIELD;
+}
+
 void ClearWindow()
 {
-  XFillRectangle(display, backbuffer, gc,
-                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+  DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
 
-  if (setup.soft_scrolling && game_status == PLAYING)
+  if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
   {
-    XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
+    ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
     SetDrawtoField(DRAW_BUFFERED);
   }
   else
     SetDrawtoField(DRAW_BACKBUFFER);
 
-  if (setup.direct_draw && game_status == PLAYING)
+  if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
   {
-    XFillRectangle(display, window, gc,
-                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+    ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
     SetDrawtoField(DRAW_DIRECT);
   }
+}
 
-  redraw_mask |= REDRAW_FIELD;
+void MarkTileDirty(int x, int y)
+{
+  int xx = redraw_x1 + x;
+  int yy = redraw_y1 + y;
+
+  if (!redraw[xx][yy])
+    redraw_tiles++;
+
+  redraw[xx][yy] = TRUE;
+  redraw_mask |= REDRAW_TILES;
 }
 
-void DrawTextFCentered(int y, int font_type, char *format, ...)
+void SetBorderElement()
 {
-  char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
-  int font_xsize;
-  va_list ap;
+  int x, y;
 
-  font_xsize = (font_type < FC_SPECIAL1 ? FONT2_XSIZE :
-               font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
+  BorderElement = EL_EMPTY;
 
-  va_start(ap, format);
-  vsprintf(buffer, format, ap);
-  va_end(ap);
+  for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
+  {
+    for (x = 0; x < lev_fieldx; x++)
+    {
+      if (!IS_INDESTRUCTIBLE(Feld[x][y]))
+       BorderElement = EL_STEELWALL;
 
-  DrawText(SX + (SXSIZE - strlen(buffer) * font_xsize) / 2, SY + y,
-          buffer, FS_SMALL, font_type);
+      if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
+       x = lev_fieldx - 2;
+    }
+  }
+}
+
+void SetRandomAnimationValue(int x, int y)
+{
+  gfx.anim_random_frame = GfxRandom[x][y];
 }
 
-void DrawTextF(int x, int y, int font_type, char *format, ...)
+inline int getGraphicAnimationFrame(int graphic, int sync_frame)
 {
-  char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
-  va_list ap;
+  /* animation synchronized with global frame counter, not move position */
+  if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
+    sync_frame = FrameCounter;
+
+  return getAnimationFrame(graphic_info[graphic].anim_frames,
+                          graphic_info[graphic].anim_delay,
+                          graphic_info[graphic].anim_mode,
+                          graphic_info[graphic].anim_start_frame,
+                          sync_frame);
+}
 
-  va_start(ap, format);
-  vsprintf(buffer, format, ap);
-  va_end(ap);
+inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
+                                   int graphic, int sync_frame, int mask_mode)
+{
+  int frame = getGraphicAnimationFrame(graphic, sync_frame);
 
-  DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
+  if (mask_mode == USE_MASKING)
+    DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
+  else
+    DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
 }
 
-void DrawText(int x, int y, char *text, int font_size, int font_type)
+inline void DrawGraphicAnimation(int x, int y, int graphic)
 {
-  DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
+  int lx = LEVELX(x), ly = LEVELY(y);
 
-  if (x < DX)
-    redraw_mask |= REDRAW_FIELD;
-  else if (y < VY)
-    redraw_mask |= REDRAW_DOOR_1;
+  if (!IN_SCR_FIELD(x, y))
+    return;
+
+  DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
+                         graphic, GfxFrame[lx][ly], NO_MASKING);
+  MarkTileDirty(x, y);
 }
 
-void DrawTextExt(Drawable d, GC gc, int x, int y,
-                char *text, int font_size, int font_type)
+void DrawLevelGraphicAnimation(int x, int y, int graphic)
 {
-  int font_width, font_height, font_start;
-  int font_pixmap;
-  boolean print_inverse = FALSE;
+  DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
+}
 
-  if (font_size != FS_SMALL && font_size != FS_BIG)
-    font_size = FS_SMALL;
-  if (font_type < FC_RED || font_type > FC_SPECIAL2)
-    font_type = FC_RED;
+void DrawLevelElementAnimation(int x, int y, int element)
+{
+#if 1
+  int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
 
-  font_width = (font_size == FS_BIG ? FONT1_XSIZE :
-               font_type < FC_SPECIAL1 ? FONT2_XSIZE :
-               font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
-  font_height = (font_size == FS_BIG ? FONT1_XSIZE :
-                font_type < FC_SPECIAL2 ? FONT2_XSIZE : FONT4_XSIZE);
-  font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
-  font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
-               FONT_LINES_PER_FONT);
+  DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
+#else
+  DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
+#endif
+}
 
-  while (*text)
-  {
-    char c = *text++;
+inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
+{
+  int sx = SCREENX(x), sy = SCREENY(y);
 
-    if (c == '~' && font_size == FS_SMALL && font_type <= FC_YELLOW)
-    {
-      print_inverse = TRUE;
-      continue;
-    }
+  if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
+    return;
+
+  if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    return;
+
+  DrawGraphicAnimation(sx, sy, graphic);
+
+  if (GFX_CRUMBLED(Feld[x][y]))
+    DrawLevelFieldCrumbledSand(x, y);
+}
+
+void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
+{
+  int sx = SCREENX(x), sy = SCREENY(y);
+  int graphic;
+
+  if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
+    return;
 
-    if (c >= 'a' && c <= 'z')
-      c = 'A' + (c - 'a');
-    else if (c == 'ä' || c == 'Ä')
-      c = 91;
-    else if (c == 'ö' || c == 'Ö')
-      c = 92;
-    else if (c == 'ü' || c == 'Ãœ')
-      c = 93;
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
 
-    if (c >= 32 && c <= 95)
+  if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    return;
+
+  DrawGraphicAnimation(sx, sy, graphic);
+
+  if (GFX_CRUMBLED(element))
+    DrawLevelFieldCrumbledSand(x, y);
+}
+
+static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
+{
+  if (player->use_murphy_graphic)
+  {
+    /* this works only because currently only one player can be "murphy" ... */
+    static int last_horizontal_dir = MV_LEFT;
+    int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
+
+    if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
+      last_horizontal_dir = move_dir;
+
+    if (graphic == IMG_SP_MURPHY)      /* undefined => use special graphic */
     {
-      int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
-      int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
-      int dest_x = x, dest_y = y;
+      int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
 
-      if (print_inverse)
-      {
-       XCopyArea(display, pix[font_pixmap], d, gc,
-                 FONT_CHARS_PER_LINE * font_width,
-                 3 * font_height + font_start,
-                 font_width, font_height, x, y);
-
-       XSetClipOrigin(display, clip_gc[font_pixmap],
-                      dest_x - src_x, dest_y - src_y);
-       XCopyArea(display, pix[font_pixmap], d, clip_gc[font_pixmap],
-                 0, 0, font_width, font_height, dest_x, dest_y);
-      }
-      else
-       XCopyArea(display, pix[font_pixmap], d, gc,
-                 src_x, src_y, font_width, font_height, dest_x, dest_y);
+      graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
     }
 
-    x += font_width;
+    return graphic;
   }
+  else
+    return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
+}
+
+static boolean equalGraphics(int graphic1, int graphic2)
+{
+  struct GraphicInfo *g1 = &graphic_info[graphic1];
+  struct GraphicInfo *g2 = &graphic_info[graphic2];
+
+  return (g1->bitmap      == g2->bitmap &&
+         g1->src_x       == g2->src_x &&
+         g1->src_y       == g2->src_y &&
+         g1->anim_frames == g2->anim_frames &&
+         g1->anim_delay  == g2->anim_delay &&
+         g1->anim_mode   == g2->anim_mode);
 }
 
 void DrawAllPlayers()
 {
   int i;
 
-  for(i=0; i<MAX_PLAYERS; i++)
+  for (i = 0; i < MAX_PLAYERS; i++)
     if (stored_player[i].active)
       DrawPlayer(&stored_player[i]);
 }
 
 void DrawPlayerField(int x, int y)
 {
-  if (!IS_PLAYER(x,y))
+  if (!IS_PLAYER(x, y))
     return;
 
-  DrawPlayer(PLAYERINFO(x,y));
+  DrawPlayer(PLAYERINFO(x, y));
 }
 
 void DrawPlayer(struct PlayerInfo *player)
 {
-  int jx = player->jx, jy = player->jy;
-  int last_jx = player->last_jx, last_jy = player->last_jy;
-  int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
+  int jx = player->jx;
+  int jy = player->jy;
+  int move_dir = player->MovDir;
+#if 0
+  int last_jx = player->last_jx;
+  int last_jy = player->last_jy;
+  int next_jx = jx + (jx - last_jx);
+  int next_jy = jy + (jy - last_jy);
+  boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
+#else
+  int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
+  int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
+  int last_jx = (player->is_moving ? jx - dx : jx);
+  int last_jy = (player->is_moving ? jy - dy : jy);
+  int next_jx = jx + dx;
+  int next_jy = jy + dy;
+  boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
+#endif
   int sx = SCREENX(jx), sy = SCREENY(jy);
   int sxx = 0, syy = 0;
-  int element = Feld[jx][jy];
-  int graphic, phase;
+  int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
+  int graphic;
+  int action = ACTION_DEFAULT;
+  int last_player_graphic = getPlayerGraphic(player, move_dir);
+  int last_player_frame = player->Frame;
+  int frame = 0;
 
-  if (!player->active || player->gone ||
-      !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
+  if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
     return;
 
 #if DEBUG
-  if (!IN_LEV_FIELD(jx,jy))
+  if (!IN_LEV_FIELD(jx, jy))
   {
     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
@@ -472,35 +625,89 @@ void DrawPlayer(struct PlayerInfo *player)
   }
 #endif
 
-  if (element == EL_EXPLODING)
+  if (element == EL_EXPLOSION)
     return;
 
-  /* draw things in the field the player is leaving, if needed */
+#if 1
+
+  action = GetPlayerAction(player, move_dir);
+
+#else
+
+  action = (player->is_pushing   ? ACTION_PUSHING    :
+           player->is_digging    ? ACTION_DIGGING    :
+           player->is_collecting ? ACTION_COLLECTING :
+           player->is_moving     ? ACTION_MOVING     :
+           player->is_snapping   ? ACTION_SNAPPING   :
+           player->is_sleeping   ? ACTION_SLEEPING   :
+           player->is_bored      ? ACTION_BORING     :
+           player->is_waiting    ? ACTION_WAITING    : ACTION_DEFAULT);
 
-  if (last_jx != jx || last_jy != jy)
+  if (player->is_bored && player->num_special_action_bored > 0)
   {
-    if (Store[last_jx][last_jy])
+    if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
     {
-      DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
-      DrawLevelFieldThruMask(last_jx, last_jy);
+      int graphic_waiting;
+
+      action = ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
+      special_graphic = el_act_dir2img(EL_SP_MURPHY, action, move_dir);
+
+      player->anim_delay_counter =
+       graphic_info[special_graphic].anim_delay_fixed +
+       SimpleRND(graphic_info[special_graphic].anim_delay_random);
+      player->post_delay_counter =
+       graphic_info[special_graphic].post_delay_fixed +
+       SimpleRND(graphic_info[special_graphic].post_delay_random);
+      player->special_action_bored = action;
     }
-    else if (Feld[last_jx][last_jy] == EL_DYNAMIT)
-      DrawDynamite(last_jx, last_jy);
-    else
-      DrawLevelField(last_jx, last_jy);
 
-    if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
+    if (player->anim_delay_counter > 0)
     {
-      if (player->GfxPos)
-      {
-       if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
-         DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
-       else
-         DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
-      }
+      action = player->special_action_bored;
+      player->anim_delay_counter--;
+    }
+
+    if (player->post_delay_counter > 0)
+    {
+      player->post_delay_counter--;
+    }
+  }
+#endif
+
+#if 0
+  printf("::: '%s'\n", element_action_info[action].suffix);
+#endif
+
+  InitPlayerGfxAnimation(player, action, move_dir);
+
+  /* ----------------------------------------------------------------------- */
+  /* draw things in the field the player is leaving, if needed               */
+  /* ----------------------------------------------------------------------- */
+
+#if 1
+  if (player->is_moving)
+#else
+  if (player_is_moving)
+#endif
+  {
+    if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
+    {
+      DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
+
+      if (last_element == EL_DYNAMITE_ACTIVE ||
+         last_element == EL_SP_DISK_RED_ACTIVE)
+       DrawDynamite(last_jx, last_jy);
       else
-       DrawLevelField(next_jx, next_jy);
+       DrawLevelFieldThruMask(last_jx, last_jy);
     }
+    else if (last_element == EL_DYNAMITE_ACTIVE ||
+            last_element == EL_SP_DISK_RED_ACTIVE)
+      DrawDynamite(last_jx, last_jy);
+    else
+      DrawLevelField(last_jx, last_jy);
+
+    if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
+      DrawLevelElement(next_jx, next_jy, EL_EMPTY);
   }
 
   if (!IN_SCR_FIELD(sx, sy))
@@ -509,108 +716,78 @@ void DrawPlayer(struct PlayerInfo *player)
   if (setup.direct_draw)
     SetDrawtoField(DRAW_BUFFERED);
 
-  /* draw things behind the player, if needed */
-
-  if (Store[jx][jy])
-    DrawLevelElement(jx, jy, Store[jx][jy]);
-  else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
-    DrawLevelField(jx, jy);
+  /* ----------------------------------------------------------------------- */
+  /* draw things behind the player, if needed                                */
+  /* ----------------------------------------------------------------------- */
 
-  /* draw player himself */
-
-  if (game_emulation == EMU_SUPAPLEX)
+  if (Back[jx][jy])
+    DrawLevelElement(jx, jy, Back[jx][jy]);
+  else if (IS_ACTIVE_BOMB(element))
+    DrawLevelElement(jx, jy, EL_EMPTY);
+  else
   {
-#if 0
-    if (player->MovDir == MV_LEFT)
-      graphic =
-       (player->Pushing ? GFX_MURPHY_PUSH_LEFT : GFX_MURPHY_LEFT);
-    else if (player->MovDir == MV_RIGHT)
-      graphic =
-       (player->Pushing ? GFX_MURPHY_PUSH_RIGHT : GFX_MURPHY_RIGHT);
-    else if (player->MovDir == MV_UP)
-      graphic = GFX_MURPHY_UP;
-    else if (player->MovDir == MV_DOWN)
-      graphic = GFX_MURPHY_DOWN;
-    else       /* MV_NO_MOVING */
-      graphic = GFX_SP_MURPHY;
-
-
-    /*
-    if (player->snapped)
-      graphic = GFX_SPIELER1_PUSH_LEFT;
-    else
-      graphic = GFX_SPIELER1_PUSH_RIGHT;
-    */
-#endif
-
-    static last_dir = MV_LEFT;
-
-    if (player->Pushing)
+    if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
     {
-      if (player->MovDir == MV_LEFT)
-       graphic = GFX_MURPHY_PUSH_LEFT;
-      else if (player->MovDir == MV_RIGHT)
-       graphic = GFX_MURPHY_PUSH_RIGHT;
-      else if (last_dir == MV_LEFT)
-       graphic = GFX_MURPHY_ANY_LEFT;
-      else if (last_dir == MV_RIGHT)
-       graphic = GFX_MURPHY_ANY_RIGHT;
+      if (GFX_CRUMBLED(GfxElement[jx][jy]))
+       DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
       else
-       graphic = GFX_SP_MURPHY;
-    }
-    else if (player->snapped)
-    {
-      if (player->MovDir == MV_LEFT)
-       graphic = GFX_MURPHY_SNAP_LEFT;
-      else if (player->MovDir == MV_RIGHT)
-       graphic = GFX_MURPHY_SNAP_RIGHT;
-      else if (player->MovDir == MV_UP)
-       graphic = GFX_MURPHY_SNAP_UP;
-      else if (player->MovDir == MV_DOWN)
-       graphic = GFX_MURPHY_SNAP_DOWN;
-      else
-       graphic = GFX_SP_MURPHY;
+      {
+       int old_element = GfxElement[jx][jy];
+       int old_graphic = el_act_dir2img(old_element, action, move_dir);
+       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
+
+       DrawGraphic(sx, sy, old_graphic, frame);
+      }
     }
     else
     {
-      if (player->MovDir == MV_LEFT)
-       graphic = GFX_MURPHY_ANY_LEFT;
-      else if (player->MovDir == MV_RIGHT)
-       graphic = GFX_MURPHY_ANY_RIGHT;
-      else if (last_dir == MV_LEFT)
-       graphic = GFX_MURPHY_ANY_LEFT;
-      else if (last_dir == MV_RIGHT)
-       graphic = GFX_MURPHY_ANY_RIGHT;
-      else
-       graphic = GFX_SP_MURPHY;
+      GfxElement[jx][jy] = EL_UNDEFINED;
+
+      DrawLevelField(jx, jy);
     }
+  }
 
-    if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
-      last_dir = player->MovDir;
+  /* ----------------------------------------------------------------------- */
+  /* draw player himself                                                     */
+  /* ----------------------------------------------------------------------- */
 
-    if (!player->Pushing && !player->snapped && player->MovDir != MV_NO_MOVING)
-      graphic -= player->Frame % 2;
-  }
-  else
+#if 1
+
+  graphic = getPlayerGraphic(player, move_dir);
+
+  /* in the case of changed player action or direction, prevent the current
+     animation frame from being restarted for identical animations */
+  if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
+    player->Frame = last_player_frame;
+
+#else
+
+  if (player->use_murphy_graphic)
   {
-    if (player->MovDir == MV_LEFT)
-      graphic =
-       (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
-    else if (player->MovDir == MV_RIGHT)
-      graphic =
-       (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
-    else if (player->MovDir == MV_UP)
-      graphic = GFX_SPIELER1_UP;
-    else       /* MV_DOWN || MV_NO_MOVING */
-      graphic = GFX_SPIELER1_DOWN;
+    static int last_horizontal_dir = MV_LEFT;
+
+    if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
+      last_horizontal_dir = move_dir;
+
+    graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
 
-    graphic += player->index_nr * 3 * HEROES_PER_LINE;
-    graphic += player->Frame;
+    if (graphic == IMG_SP_MURPHY)      /* undefined => use special graphic */
+    {
+      int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
+
+      graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
+    }
   }
+  else
+    graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
+
+#endif
+
+  frame = getGraphicAnimationFrame(graphic, player->Frame);
 
   if (player->GfxPos)
   {
-    if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
+    if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
       sxx = player->GfxPos;
     else
       syy = player->GfxPos;
@@ -619,69 +796,98 @@ void DrawPlayer(struct PlayerInfo *player)
   if (!setup.soft_scrolling && ScreenMovPos)
     sxx = syy = 0;
 
-  DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
+  DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
 
-  if (player->Pushing && player->GfxPos)
+  if (SHIELD_ON(player))
+  {
+    int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
+                  IMG_SHIELD_NORMAL_ACTIVE);
+    int frame = getGraphicAnimationFrame(graphic, -1);
+
+    DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
+  }
+
+  /* ----------------------------------------------------------------------- */
+  /* draw things the player is pushing, if needed                            */
+  /* ----------------------------------------------------------------------- */
+
+#if 0
+  printf("::: %d, %d [%d, %d] [%d]\n",
+        player->is_pushing, player_is_moving, player->GfxAction,
+        player->is_moving, player_is_moving);
+#endif
+
+#if 1
+  if (player->is_pushing && player->is_moving)
+#else
+  if (player->is_pushing && player_is_moving)
+#endif
   {
     int px = SCREENX(next_jx), py = SCREENY(next_jy);
 
-    if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER ||
-       Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
-      DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
+    if (Back[next_jx][next_jy])
+      DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+
+    if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
+      DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
                                 NO_CUTTING);
     else
     {
-      int element = Feld[next_jx][next_jy];
-      int graphic = el2gfx(element);
-
-      if (element == EL_FELSBROCKEN && sxx)
-      {
-       int phase = (player->GfxPos / (TILEX/4));
-
-       if (player->MovDir == MV_LEFT)
-         graphic += phase;
-       else
-         graphic += (phase+4)%4;
-      }
+      int element = MovingOrBlocked2Element(next_jx, next_jy);
+      int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
+#if 1
+      int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
+#else
+      int frame = getGraphicAnimationFrame(graphic, player->Frame);
+#endif
 
-      DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
+      DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
+                        NO_CUTTING, NO_MASKING);
     }
   }
 
-  /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
+  /* ----------------------------------------------------------------------- */
+  /* draw things in front of player (active dynamite or dynabombs)           */
+  /* ----------------------------------------------------------------------- */
 
-  if (element == EL_DYNAMIT || element == EL_DYNABOMB)
+  if (IS_ACTIVE_BOMB(element))
   {
-    graphic = el2gfx(element);
+    graphic = el2img(element);
+    frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
 
-    if (element == EL_DYNAMIT)
-    {
-      if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
-       phase = 6;
-    }
+    if (game.emulation == EMU_SUPAPLEX)
+      DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
     else
-    {
-      if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
-       phase = 7 - phase;
-    }
-
-    if (game_emulation == EMU_SUPAPLEX)
-      DrawGraphic(sx, sy, GFX_SP_DISK_RED);
-    else
-      DrawGraphicThruMask(sx, sy, graphic + phase);
+      DrawGraphicThruMask(sx, sy, graphic, frame);
   }
 
-  if ((last_jx != jx || last_jy != jy) &&
-      Feld[last_jx][last_jy] == EL_EXPLODING)
+  if (player_is_moving && last_element == EL_EXPLOSION)
   {
-    int phase = Frame[last_jx][last_jy];
-    int delay = 2;
+    int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
+    int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
+    int phase = ExplodePhase[last_jx][last_jy] - 1;
+    int frame = getGraphicAnimationFrame(graphic, phase - delay);
 
-    if (phase > 2)
-      DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
-                         GFX_EXPLOSION + ((phase - 1) / delay - 1));
+    if (phase >= delay)
+      DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
   }
 
+  /* ----------------------------------------------------------------------- */
+  /* draw elements the player is just walking/passing through/under          */
+  /* ----------------------------------------------------------------------- */
+
+  /* handle the field the player is leaving ... */
+  if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
+    DrawLevelField(last_jx, last_jy);
+  else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
+    DrawLevelFieldThruMask(last_jx, last_jy);
+
+  /* ... and the field the player is entering */
+  if (IS_ACCESSIBLE_INSIDE(element))
+    DrawLevelField(jx, jy);
+  else if (IS_ACCESSIBLE_UNDER(element))
+    DrawLevelFieldThruMask(jx, jy);
+
   if (setup.direct_draw)
   {
     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
@@ -689,171 +895,70 @@ void DrawPlayer(struct PlayerInfo *player)
     int x_size = TILEX * (1 + ABS(jx - last_jx));
     int y_size = TILEY * (1 + ABS(jy - last_jy));
 
-    XCopyArea(display, drawto_field, window, gc,
-             dest_x, dest_y, x_size, y_size, dest_x, dest_y);
+    BlitBitmap(drawto_field, window,
+              dest_x, dest_y, x_size, y_size, dest_x, dest_y);
     SetDrawtoField(DRAW_DIRECT);
   }
 
   MarkTileDirty(sx,sy);
 }
 
-static int getGraphicAnimationPhase(int frames, int delay, int mode)
+void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
 {
-  int phase;
+  struct GraphicInfo *g = &graphic_info[graphic];
 
-  if (mode == ANIM_OSCILLATE)
-  {
-    int max_anim_frames = 2 * frames - 2;
-    phase = (FrameCounter % (delay * max_anim_frames)) / delay;
-    phase = (phase < frames ? phase : max_anim_frames - phase);
-  }
-  else
-    phase = (FrameCounter % (delay * frames)) / delay;
-
-  if (mode == ANIM_REVERSE)
-    phase = -phase;
-
-  return(phase);
-}
-
-void DrawGraphicAnimationExt(int x, int y, int graphic,
-                            int frames, int delay, int mode, int mask_mode)
-{
-  int phase = getGraphicAnimationPhase(frames, delay, mode);
+  *bitmap = g->bitmap;
 
-  if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+  if (g->offset_y == 0)                /* frames are ordered horizontally */
   {
-    if (mask_mode == USE_MASKING)
-      DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
-    else
-      DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
-  }
-}
-
-void DrawGraphicAnimation(int x, int y, int graphic,
-                         int frames, int delay, int mode)
-{
-  DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
-}
-
-void DrawGraphicAnimationThruMask(int x, int y, int graphic,
-                                 int frames, int delay, int mode)
-{
-  DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
-}
+    int max_width = g->anim_frames_per_line * g->width;
 
-void getGraphicSource(int graphic, int *pixmap_nr, int *x, int *y)
-{
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    graphic -= GFX_START_ROCKSSCREEN;
-    *pixmap_nr = PIX_BACK;
-    *x = SX + (graphic % GFX_PER_LINE) * TILEX;
-    *y = SY + (graphic / GFX_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    *pixmap_nr = PIX_MORE;
-    *x = (graphic % MORE_PER_LINE) * TILEX;
-    *y = (graphic / MORE_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
-  {
-    graphic -= GFX_START_ROCKSHEROES;
-    *pixmap_nr = PIX_HEROES;
-    *x = (graphic % HEROES_PER_LINE) * TILEX;
-    *y = (graphic / HEROES_PER_LINE) * TILEY;
+    *x = (g->src_x + frame * g->offset_x) % max_width;
+    *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
   }
-  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
+  else if (g->offset_x == 0)   /* frames are ordered vertically */
   {
-    graphic -= GFX_START_ROCKSFONT;
-    *pixmap_nr = PIX_BIGFONT;
-    *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
-    *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
-         FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
+    int max_height = g->anim_frames_per_line * g->height;
+
+    *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
+    *y = (g->src_y + frame * g->offset_y) % max_height;
   }
-  else
+  else                         /* frames are ordered diagonally */
   {
-    *pixmap_nr = PIX_MORE;
-    *x = 0;
-    *y = 0;
+    *x = g->src_x + frame * g->offset_x;
+    *y = g->src_y + frame * g->offset_y;
   }
 }
 
-void DrawGraphic(int x, int y, int graphic)
+void DrawGraphic(int x, int y, int graphic, int frame)
 {
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
-    printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
+    printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
     printf("DrawGraphic(): This should never happen!\n");
     return;
   }
 #endif
 
-  DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
-  MarkTileDirty(x,y);
+  DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
+  MarkTileDirty(x, y);
 }
 
-void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
+void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
+                   int frame)
 {
-
-#if 1
-
-  int pixmap_nr;
+  Bitmap *src_bitmap;
   int src_x, src_y;
 
-  getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
-  XCopyArea(display, pix[pixmap_nr], d, gc,
-           src_x, src_y, TILEX, TILEY, x, y);
-
-#else
-
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    graphic -= GFX_START_ROCKSSCREEN;
-    XCopyArea(display, pix[PIX_BACK], d, gc,
-             SX + (graphic % GFX_PER_LINE) * TILEX,
-             SY + (graphic / GFX_PER_LINE) * TILEY,
-             TILEX, TILEY, x, y);
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    XCopyArea(display, pix[PIX_MORE], d, gc,
-             (graphic % MORE_PER_LINE) * TILEX,
-             (graphic / MORE_PER_LINE) * TILEY,
-             TILEX, TILEY, x, y);
-  }
-  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
-  {
-    graphic -= GFX_START_ROCKSHEROES;
-    XCopyArea(display, pix[PIX_HEROES], d, gc,
-             (graphic % HEROES_PER_LINE) * TILEX,
-             (graphic / HEROES_PER_LINE) * TILEY,
-             TILEX, TILEY, x, y);
-  }
-  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
-  {
-    graphic -= GFX_START_ROCKSFONT;
-    XCopyArea(display, pix[PIX_BIGFONT], d, gc,
-             (graphic % FONT_CHARS_PER_LINE) * TILEX,
-             (graphic / FONT_CHARS_PER_LINE) * TILEY +
-             FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
-             TILEX, TILEY, x, y);
-  }
-  else
-    XFillRectangle(display, d, gc, x, y, TILEX, TILEY);
-
-#endif
-
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+  BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
 }
 
-void DrawGraphicThruMask(int x, int y, int graphic)
+void DrawGraphicThruMask(int x, int y, int graphic, int frame)
 {
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
     printf("DrawGraphicThruMask(): This should never happen!\n");
@@ -861,213 +966,109 @@ void DrawGraphicThruMask(int x, int y, int graphic)
   }
 #endif
 
-  DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
-  MarkTileDirty(x,y);
+  DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
+                        frame);
+  MarkTileDirty(x, y);
 }
 
-void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
+void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
+                           int frame)
 {
-
 #if 1
-
-  int tile = graphic;
-  int pixmap_nr;
+  Bitmap *src_bitmap;
   int src_x, src_y;
-  Pixmap src_pixmap;
   GC drawing_gc;
 
-  getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
-  src_pixmap = pix[pixmap_nr];
-  drawing_gc = clip_gc[pixmap_nr];
-
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+  drawing_gc = src_bitmap->stored_clip_gc;
 #else
+  GC drawing_gc = src_bitmap->stored_clip_gc;
+  Bitmap *src_bitmap = graphic_info[graphic].bitmap;
+  int src_x = graphic_info[graphic].src_x;
+  int src_y = graphic_info[graphic].src_y;
+  int offset_x = graphic_info[graphic].offset_x;
+  int offset_y = graphic_info[graphic].offset_y;
 
-  int src_x, src_y;
-  int tile = graphic;
-  Pixmap src_pixmap;
-  GC drawing_gc;
-
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    src_pixmap = pix[PIX_BACK];
-    drawing_gc = clip_gc[PIX_BACK];
-    graphic -= GFX_START_ROCKSSCREEN;
-    src_x  = SX + (graphic % GFX_PER_LINE) * TILEX;
-    src_y  = SY + (graphic / GFX_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    src_pixmap = pix[PIX_MORE];
-    drawing_gc = clip_gc[PIX_MORE];
-    graphic -= GFX_START_ROCKSMORE;
-    src_x  = (graphic % MORE_PER_LINE) * TILEX;
-    src_y  = (graphic / MORE_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
-  {
-    src_pixmap = pix[PIX_HEROES];
-    drawing_gc = clip_gc[PIX_HEROES];
-    graphic -= GFX_START_ROCKSHEROES;
-    src_x  = (graphic % HEROES_PER_LINE) * TILEX;
-    src_y  = (graphic / HEROES_PER_LINE) * TILEY;
-  }
-  else
-  {
-    DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
-    return;
-  }
-
-#endif
-
+  src_x += frame * offset_x;
+  src_y += frame * offset_y;
 
-  if (tile_clipmask[tile] != None)
-  {
-    XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
-    XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
-    XCopyArea(display, src_pixmap, d, tile_clip_gc,
-             src_x, src_y, TILEX, TILEY, dest_x, dest_y);
-  }
-  else
-  {
-#if DEBUG
-    printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
 #endif
 
-    XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
-    XCopyArea(display, src_pixmap, d, drawing_gc,
-             src_x, src_y, TILEX, TILEY, dest_x, dest_y);
-  }
+  SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
+  BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
 }
 
 void DrawMiniGraphic(int x, int y, int graphic)
 {
-  DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
-  MarkTileDirty(x/2, y/2);
+  DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
+  MarkTileDirty(x / 2, y / 2);
 }
 
-void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
+void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
 {
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    graphic -= GFX_START_ROCKSSCREEN;
-    *pixmap = pix[PIX_BACK];
-    *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
-    *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    *pixmap = pix[PIX_MORE];
-    *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
-    *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
-  {
-    graphic -= GFX_START_ROCKSFONT;
-    *pixmap = pix[PIX_SMALLFONT];
-    *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
-    *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
-             FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
-  }
-  else
-  {
-    *pixmap = pix[PIX_MORE];
-    *x = MINI_MORE_STARTX;
-    *y = MINI_MORE_STARTY;
-  }
+  struct GraphicInfo *g = &graphic_info[graphic];
+  int mini_startx = 0;
+  int mini_starty = g->bitmap->height * 2 / 3;
+
+  *bitmap = g->bitmap;
+  *x = mini_startx + g->src_x / 2;
+  *y = mini_starty + g->src_y / 2;
 }
 
-void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
+void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
 {
-
-#if 1
-
-  Pixmap pixmap;
+  Bitmap *src_bitmap;
   int src_x, src_y;
 
-  getMiniGraphicSource(graphic, &pixmap, &src_x, &src_y);
-  XCopyArea(display, pixmap, d, gc,
-           src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
-
-#else
-
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    graphic -= GFX_START_ROCKSSCREEN;
-    XCopyArea(display, pix[PIX_BACK], d, gc,
-             MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
-             MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
-             MINI_TILEX, MINI_TILEY, x, y);
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    XCopyArea(display, pix[PIX_MORE], d, gc,
-             MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
-             MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
-             MINI_TILEX, MINI_TILEY, x, y);
-  }
-  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
-  {
-    graphic -= GFX_START_ROCKSFONT;
-    XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
-             (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
-             (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
-             FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
-             MINI_TILEX, MINI_TILEY, x, y);
-  }
-  else
-    XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
-
-#endif
-
+  getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+  BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
 }
 
-void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
+void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
                        int cut_mode, int mask_mode)
 {
+  Bitmap *src_bitmap;
+  GC drawing_gc;
+  int src_x, src_y;
   int width = TILEX, height = TILEY;
   int cx = 0, cy = 0;
-  int src_x, src_y, dest_x, dest_y;
-  int tile = graphic;
-  Pixmap src_pixmap;
-  GC drawing_gc;
+  int dest_x, dest_y;
 
   if (graphic < 0)
   {
-    DrawGraphic(x, y, graphic);
+    DrawGraphic(x, y, graphic, frame);
     return;
   }
 
-  if (dx || dy)                        /* Verschiebung der Grafik? */
+  if (dx || dy)                        /* shifted graphic */
   {
-    if (x < BX1)               /* Element kommt von links ins Bild */
+    if (x < BX1)               /* object enters playfield from the left */
     {
       x = BX1;
       width = dx;
       cx = TILEX - dx;
       dx = 0;
     }
-    else if (x > BX2)          /* Element kommt von rechts ins Bild */
+    else if (x > BX2)          /* object enters playfield from the right */
     {
       x = BX2;
       width = -dx;
       dx = TILEX + dx;
     }
-    else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */
+    else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
     {
       width += dx;
       cx = -dx;
       dx = 0;
     }
-    else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */
+    else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
       width -= dx;
-    else if (dx)               /* allg. Bewegung in x-Richtung */
+    else if (dx)               /* general horizontal movement */
       MarkTileDirty(x + SIGN(dx), y);
 
-    if (y < BY1)               /* Element kommt von oben ins Bild */
+    if (y < BY1)               /* object enters playfield from the top */
     {
-      if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */
+      if (cut_mode==CUT_BELOW) /* object completely above top border */
        return;
 
       y = BY1;
@@ -1075,13 +1076,13 @@ void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
       cy = TILEY - dy;
       dy = 0;
     }
-    else if (y > BY2)          /* Element kommt von unten ins Bild */
+    else if (y > BY2)          /* object enters playfield from the bottom */
     {
       y = BY2;
       height = -dy;
       dy = TILEY + dy;
     }
-    else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */
+    else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
     {
       height += dy;
       cy = -dy;
@@ -1089,46 +1090,37 @@ void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
     }
     else if (dy > 0 && cut_mode == CUT_ABOVE)
     {
-      if (y == BY2)            /* Element unterhalb des Bildes */
+      if (y == BY2)            /* object completely above bottom border */
        return;
 
       height = dy;
       cy = TILEY - dy;
       dy = TILEY;
       MarkTileDirty(x, y + 1);
-    }                          /* Element verläßt unten das Bild */
+    }                          /* object leaves playfield to the bottom */
     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
       height -= dy;
-    else if (dy)               /* allg. Bewegung in y-Richtung */
+    else if (dy)               /* general vertical movement */
       MarkTileDirty(x, y + SIGN(dy));
   }
 
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    src_pixmap = pix[PIX_BACK];
-    drawing_gc = clip_gc[PIX_BACK];
-    graphic -= GFX_START_ROCKSSCREEN;
-    src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
-    src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    src_pixmap = pix[PIX_MORE];
-    drawing_gc = clip_gc[PIX_MORE];
-    graphic -= GFX_START_ROCKSMORE;
-    src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
-    src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
-  }
-  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
-  {
-    src_pixmap = pix[PIX_HEROES];
-    drawing_gc = clip_gc[PIX_HEROES];
-    graphic -= GFX_START_ROCKSHEROES;
-    src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
-    src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
-  }
-  else /* big font graphics currently not allowed (and not needed) */
-    return;
+#if 1
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+#else
+  src_bitmap = graphic_info[graphic].bitmap;
+  src_x = graphic_info[graphic].src_x;
+  src_y = graphic_info[graphic].src_y;
+  offset_x = graphic_info[graphic].offset_x;
+  offset_y = graphic_info[graphic].offset_y;
+
+  src_x += frame * offset_x;
+  src_y += frame * offset_y;
+#endif
+
+  drawing_gc = src_bitmap->stored_clip_gc;
+
+  src_x += cx;
+  src_y += cy;
 
   dest_x = FX + x * TILEX + dx;
   dest_y = FY + y * TILEY + dy;
@@ -1144,147 +1136,72 @@ void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
 
   if (mask_mode == USE_MASKING)
   {
-    if (tile_clipmask[tile] != None)
-    {
-      XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
-      XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
-      XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
-               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
-    }
-    else
-    {
-#if DEBUG
-      printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
-#endif
-
-      XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
-      XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
-               src_x, src_y, width, height, dest_x, dest_y);
-    }
+    SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
+    BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
+                    dest_x, dest_y);
   }
   else
-    XCopyArea(display, src_pixmap, drawto_field, gc,
-             src_x, src_y, width, height, dest_x, dest_y);
+    BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
+              dest_x, dest_y);
 
   MarkTileDirty(x,y);
 }
 
-void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
-                               int cut_mode)
+void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
+                               int frame, int cut_mode)
 {
-  DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
+  DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
 }
 
 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
                          int cut_mode, int mask_mode)
 {
-  int ux = LEVELX(x), uy = LEVELY(y);
-  int graphic = el2gfx(element);
-  int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
-  int phase4 = phase8 / 2;
-  int phase2  = phase8 / 4;
-  int dir = MovDir[ux][uy];
-
-  if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
-  {
-    graphic += 4 * !phase2;
+  int lx = LEVELX(x), ly = LEVELY(y);
+  int graphic;
+  int frame;
 
-    if (dir == MV_UP)
-      graphic += 1;
-    else if (dir == MV_LEFT)
-      graphic += 2;
-    else if (dir == MV_DOWN)
-      graphic += 3;
-  }
-  else if (element == EL_SP_SNIKSNAK)
+  if (IN_LEV_FIELD(lx, ly))
   {
-    if (dir == MV_LEFT)
-      graphic = GFX_SP_SNIKSNAK_LEFT;
-    else if (dir == MV_RIGHT)
-      graphic = GFX_SP_SNIKSNAK_RIGHT;
-    else if (dir == MV_UP)
-      graphic = GFX_SP_SNIKSNAK_UP;
-    else
-      graphic = GFX_SP_SNIKSNAK_DOWN;
+    SetRandomAnimationValue(lx, ly);
 
-    graphic += (phase8 < 4 ? phase8 : 7 - phase8);
+    graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
+    frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
   }
-  else if (element == EL_SP_ELECTRON)
+  else /* border element */
   {
-    graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
+    graphic = el2img(element);
+    frame = getGraphicAnimationFrame(graphic, -1);
   }
-  else if (element == EL_MAULWURF || element == EL_PINGUIN ||
-          element == EL_SCHWEIN || element == EL_DRACHE)
-  {
-    if (dir == MV_LEFT)
-      graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
-                element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
-    else if (dir == MV_RIGHT)
-      graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
-                element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
-    else if (dir == MV_UP)
-      graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
-                element == EL_PINGUIN ? GFX_PINGUIN_UP :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
-    else
-      graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
-                element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
 
-    graphic += phase4;
-  }
-  else if (element == EL_SONDE)
-  {
-    graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
-  }
-  else if (element == EL_SALZSAEURE)
-  {
-    graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
-  }
-  else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
-  {
-    graphic += !phase2;
-  }
-  else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
-  {
-    if (element != EL_SP_INFOTRON)
-      graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
-  }
-  else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
-          element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
+  if (element == EL_EXPANDABLE_WALL)
   {
-    graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
-  }
-  else if (IS_AMOEBOID(element))
-  {
-    graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
-    graphic += (x + 2 * y + 4) % 4;
-  }
-  else if (element == EL_MAUER_LEBT)
-  {
-    boolean links_massiv = FALSE, rechts_massiv = FALSE;
+    boolean left_stopped = FALSE, right_stopped = FALSE;
 
-    if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
-      links_massiv = TRUE;
-    if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
-      rechts_massiv = TRUE;
+    if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
+      left_stopped = TRUE;
+    if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
+      right_stopped = TRUE;
 
-    if (links_massiv && rechts_massiv)
-      graphic = GFX_MAUERWERK;
-    else if (links_massiv)
-      graphic = GFX_MAUER_R;
-    else if (rechts_massiv)
-      graphic = GFX_MAUER_L;
+    if (left_stopped && right_stopped)
+      graphic = IMG_WALL;
+    else if (left_stopped)
+    {
+      graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
+      frame = graphic_info[graphic].anim_frames - 1;
+    }
+    else if (right_stopped)
+    {
+      graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
+      frame = graphic_info[graphic].anim_frames - 1;
+    }
   }
 
   if (dx || dy)
-    DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
+    DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
   else if (mask_mode == USE_MASKING)
-    DrawGraphicThruMask(x, y, graphic);
+    DrawGraphicThruMask(x, y, graphic, frame);
   else
-    DrawGraphic(x, y, graphic);
+    DrawGraphic(x, y, graphic, frame);
 }
 
 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
@@ -1307,11 +1224,6 @@ void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
 }
 
-void DrawScreenElementThruMask(int x, int y, int element)
-{
-  DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
-}
-
 void DrawLevelElementThruMask(int x, int y, int element)
 {
   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
@@ -1322,12 +1234,18 @@ void DrawLevelFieldThruMask(int x, int y)
   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
 }
 
-void ErdreichAnbroeckeln(int x, int y)
+static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
 {
-  int i, width, height, cx,cy;
-  int ux = LEVELX(x), uy = LEVELY(y);
-  int element, graphic;
-  int snip = 4;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int sx = SCREENX(x), sy = SCREENY(y);
+  int element;
+  int width, height, cx, cy, i;
+#if 1
+  int crumbled_border_size = graphic_info[graphic].border_size;
+#else
+  int snip = TILEX / 8;        /* number of border pixels from "crumbled graphic" */
+#endif
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -1336,101 +1254,204 @@ void ErdreichAnbroeckeln(int x, int y)
     { 0, +1 }
   };
 
-  if (!IN_LEV_FIELD(ux, uy))
+#if 0
+  if (x == 0 && y == 7)
+    printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
+          crumbled_border_size);
+#endif
+
+  if (!IN_LEV_FIELD(x, y))
     return;
 
-  element = Feld[ux][uy];
+  element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
+            GfxElement[x][y] : Feld[x][y]);
 
-  if (element == EL_ERDREICH)
+  /* crumble field itself */
+  if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
   {
-    if (!IN_SCR_FIELD(x, y))
+    if (!IN_SCR_FIELD(sx, sy))
       return;
 
-    graphic = GFX_ERDENRAND;
+    getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
 
-    for(i=0; i<4; i++)
+    for (i = 0; i < 4; i++)
     {
-      int uxx, uyy;
+      int xx = x + xy[i][0];
+      int yy = y + xy[i][1];
 
-      uxx = ux + xy[i][0];
-      uyy = uy + xy[i][1];
-      if (!IN_LEV_FIELD(uxx, uyy))
-       element = EL_BETON;
-      else
-       element = Feld[uxx][uyy];
+      element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
 
-      if (element == EL_ERDREICH)
+      /* check if neighbour field is of same type */
+      if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
        continue;
 
+#if 0
+      if (Feld[x][y] == EL_CUSTOM_START + 123)
+       printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
+              i, Feld[x][y], element,
+              GFX_CRUMBLED(element), IS_MOVING(x, y));
+#endif
+
       if (i == 1 || i == 2)
       {
-       width = snip;
+       width = crumbled_border_size;
        height = TILEY;
-       cx = (i == 2 ? TILEX - snip : 0);
+       cx = (i == 2 ? TILEX - crumbled_border_size : 0);
        cy = 0;
       }
       else
       {
        width = TILEX;
-       height = snip;
+       height = crumbled_border_size;
        cx = 0;
-       cy = (i == 3 ? TILEY - snip : 0);
+       cy = (i == 3 ? TILEY - crumbled_border_size : 0);
       }
 
-      XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
-               SX + (graphic % GFX_PER_LINE) * TILEX + cx,
-               SY + (graphic / GFX_PER_LINE) * TILEY + cy,
-               width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
+      BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
+                width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
     }
 
-    MarkTileDirty(x, y);
+    MarkTileDirty(sx, sy);
   }
-  else
+  else         /* crumble neighbour fields */
   {
-    graphic = GFX_ERDENRAND;
+#if 0
+    getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+#endif
 
-    for(i=0; i<4; i++)
+    for (i = 0; i < 4; i++)
     {
-      int xx, yy, uxx, uyy;
+      int xx = x + xy[i][0];
+      int yy = y + xy[i][1];
+      int sxx = sx + xy[i][0];
+      int syy = sy + xy[i][1];
+
+      if (!IN_LEV_FIELD(xx, yy) ||
+         !IN_SCR_FIELD(sxx, syy) ||
+         !GFX_CRUMBLED(Feld[xx][yy]) ||
+         IS_MOVING(xx, yy))
+       continue;
 
-      xx = x + xy[i][0];
-      yy = y + xy[i][1];
-      uxx = ux + xy[i][0];
-      uyy = uy + xy[i][1];
+#if 1
+      graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
+      crumbled_border_size = graphic_info[graphic].border_size;
 
-      if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
-         !IN_SCR_FIELD(xx, yy))
-       continue;
+      getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+#endif
 
       if (i == 1 || i == 2)
       {
-       width = snip;
+       width = crumbled_border_size;
        height = TILEY;
-       cx = (i == 1 ? TILEX - snip : 0);
+       cx = (i == 1 ? TILEX - crumbled_border_size : 0);
        cy = 0;
       }
       else
       {
        width = TILEX;
-       height = snip;
+       height = crumbled_border_size;
        cx = 0;
-       cy = (i==0 ? TILEY-snip : 0);
+       cy = (i == 0 ? TILEY - crumbled_border_size : 0);
       }
 
-      XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
-               SX + (graphic % GFX_PER_LINE) * TILEX + cx,
-               SY + (graphic / GFX_PER_LINE) * TILEY + cy,
-               width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
+      BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
+                width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
 
-      MarkTileDirty(xx, yy);
+      MarkTileDirty(sxx, syy);
     }
   }
 }
 
+void DrawLevelFieldCrumbledSand(int x, int y)
+{
+#if 1
+  int graphic;
+
+  if (!IN_LEV_FIELD(x, y))
+    return;
+
+  graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
+
+  DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
+#else
+  DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
+#endif
+}
+
+void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
+                                      int step_frame)
+{
+#if 1
+  int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
+  int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
+#else
+  int graphic1 = el_act_dir2img(EL_SAND,          ACTION_DIGGING, direction);
+  int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
+#endif
+  int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
+  int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
+  int sx = SCREENX(x), sy = SCREENY(y);
+
+  DrawGraphic(sx, sy, graphic1, frame1);
+  DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
+}
+
+void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
+{
+  int sx = SCREENX(x), sy = SCREENY(y);
+  static int xy[4][2] =
+  {
+    { 0, -1 },
+    { -1, 0 },
+    { +1, 0 },
+    { 0, +1 }
+  };
+  int i;
+
+  for (i = 0; i < 4; i++)
+  {
+    int xx = x + xy[i][0];
+    int yy = y + xy[i][1];
+    int sxx = sx + xy[i][0];
+    int syy = sy + xy[i][1];
+
+    if (!IN_LEV_FIELD(xx, yy) ||
+       !IN_SCR_FIELD(sxx, syy) ||
+       !GFX_CRUMBLED(Feld[xx][yy]) ||
+       IS_MOVING(xx, yy))
+      continue;
+
+    DrawLevelField(xx, yy);
+  }
+}
+
+static int getBorderElement(int x, int y)
+{
+  int border[7][2] =
+  {
+    { EL_STEELWALL_TOPLEFT,            EL_INVISIBLE_STEELWALL_TOPLEFT     },
+    { EL_STEELWALL_TOPRIGHT,           EL_INVISIBLE_STEELWALL_TOPRIGHT    },
+    { EL_STEELWALL_BOTTOMLEFT,         EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
+    { EL_STEELWALL_BOTTOMRIGHT,                EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
+    { EL_STEELWALL_VERTICAL,           EL_INVISIBLE_STEELWALL_VERTICAL    },
+    { EL_STEELWALL_HORIZONTAL,         EL_INVISIBLE_STEELWALL_HORIZONTAL  },
+    { EL_STEELWALL,                    EL_INVISIBLE_STEELWALL             }
+  };
+  int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
+  int steel_position = (x == -1                && y == -1              ? 0 :
+                       x == lev_fieldx && y == -1              ? 1 :
+                       x == -1         && y == lev_fieldy      ? 2 :
+                       x == lev_fieldx && y == lev_fieldy      ? 3 :
+                       x == -1         || x == lev_fieldx      ? 4 :
+                       y == -1         || y == lev_fieldy      ? 5 : 6);
+
+  return border[steel_position][steel_type];
+}
+
 void DrawScreenElement(int x, int y, int element)
 {
   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
-  ErdreichAnbroeckeln(x, y);
+  DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
 }
 
 void DrawLevelElement(int x, int y, int element)
@@ -1441,81 +1462,92 @@ void DrawLevelElement(int x, int y, int element)
 
 void DrawScreenField(int x, int y)
 {
-  int ux = LEVELX(x), uy = LEVELY(y);
-  int element;
+  int lx = LEVELX(x), ly = LEVELY(y);
+  int element, content;
 
-  if (!IN_LEV_FIELD(ux, uy))
+  if (!IN_LEV_FIELD(lx, ly))
   {
-    if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
-      element = EL_LEERRAUM;
+    if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
+      element = EL_EMPTY;
     else
-      element = BorderElement;
+      element = getBorderElement(lx, ly);
 
     DrawScreenElement(x, y, element);
     return;
   }
 
-  element = Feld[ux][uy];
+  element = Feld[lx][ly];
+  content = Store[lx][ly];
 
-  if (IS_MOVING(ux, uy))
+  if (IS_MOVING(lx, ly))
   {
-    int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
+    int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
     boolean cut_mode = NO_CUTTING;
 
-    if (Store[ux][uy] == EL_MORAST_LEER ||
-       Store[ux][uy] == EL_SIEB_LEER ||
-       Store[ux][uy] == EL_SIEB2_LEER ||
-       Store[ux][uy] == EL_AMOEBE_NASS)
+    if (element == EL_QUICKSAND_EMPTYING ||
+       element == EL_MAGIC_WALL_EMPTYING ||
+       element == EL_BD_MAGIC_WALL_EMPTYING ||
+       element == EL_AMOEBA_DROPPING)
       cut_mode = CUT_ABOVE;
-    else if (Store[ux][uy] == EL_MORAST_VOLL ||
-            Store[ux][uy] == EL_SIEB_VOLL ||
-            Store[ux][uy] == EL_SIEB2_VOLL)
+    else if (element == EL_QUICKSAND_FILLING ||
+            element == EL_MAGIC_WALL_FILLING ||
+            element == EL_BD_MAGIC_WALL_FILLING)
       cut_mode = CUT_BELOW;
 
     if (cut_mode == CUT_ABOVE)
-      DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
+      DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
     else
-      DrawScreenElement(x, y, EL_LEERRAUM);
+      DrawScreenElement(x, y, EL_EMPTY);
 
     if (horiz_move)
-      DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
+      DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
+    else if (cut_mode == NO_CUTTING)
+      DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
     else
-      DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
+      DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
 
-    if (Store[ux][uy] == EL_SALZSAEURE)
-      DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
+    if (content == EL_ACID)
+      DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
   }
-  else if (IS_BLOCKED(ux, uy))
+  else if (IS_BLOCKED(lx, ly))
   {
     int oldx, oldy;
     int sx, sy;
     int horiz_move;
     boolean cut_mode = NO_CUTTING;
+    int element_old, content_old;
 
-    Blocked2Moving(ux, uy, &oldx, &oldy);
+    Blocked2Moving(lx, ly, &oldx, &oldy);
     sx = SCREENX(oldx);
     sy = SCREENY(oldy);
     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
                  MovDir[oldx][oldy] == MV_RIGHT);
 
-    if (Store[oldx][oldy] == EL_MORAST_LEER ||
-       Store[oldx][oldy] == EL_SIEB_LEER ||
-       Store[oldx][oldy] == EL_SIEB2_LEER ||
-       Store[oldx][oldy] == EL_AMOEBE_NASS)
+    element_old = Feld[oldx][oldy];
+    content_old = Store[oldx][oldy];
+
+    if (element_old == EL_QUICKSAND_EMPTYING ||
+       element_old == EL_MAGIC_WALL_EMPTYING ||
+       element_old == EL_BD_MAGIC_WALL_EMPTYING ||
+       element_old == EL_AMOEBA_DROPPING)
       cut_mode = CUT_ABOVE;
 
-    DrawScreenElement(x, y, EL_LEERRAUM);
-    element = Feld[oldx][oldy];
+    DrawScreenElement(x, y, EL_EMPTY);
 
     if (horiz_move)
-      DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
+      DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
+                              NO_CUTTING);
+    else if (cut_mode == NO_CUTTING)
+      DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
+                              cut_mode);
     else
-      DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
+      DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
+                              cut_mode);
   }
   else if (IS_DRAWABLE(element))
     DrawScreenElement(x, y, element);
   else
-    DrawScreenElement(x, y, EL_LEERRAUM);
+    DrawScreenElement(x, y, EL_EMPTY);
 }
 
 void DrawLevelField(int x, int y)
@@ -1544,13 +1576,7 @@ void DrawMiniElement(int x, int y, int element)
 {
   int graphic;
 
-  if (!element)
-  {
-    DrawMiniGraphic(x, y, -1);
-    return;
-  }
-
-  graphic = el2gfx(element);
+  graphic = el2edimg(element);
   DrawMiniGraphic(x, y, graphic);
 }
 
@@ -1559,100 +1585,191 @@ void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
   int x = sx + scroll_x, y = sy + scroll_y;
 
   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
-    DrawMiniElement(sx, sy, EL_LEERRAUM);
+    DrawMiniElement(sx, sy, EL_EMPTY);
   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
     DrawMiniElement(sx, sy, Feld[x][y]);
   else
+    DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
+}
+
+void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
+                           int x, int y, int xsize, int ysize, int font_nr)
+{
+  int font_width  = getFontWidth(font_nr);
+  int font_height = getFontHeight(font_nr);
+  int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int dst_x = SX + startx + x * font_width;
+  int dst_y = SY + starty + y * font_height;
+  int width  = graphic_info[graphic].width;
+  int height = graphic_info[graphic].height;
+  int inner_width  = MAX(width  - 2 * font_width,  font_width);
+  int inner_height = MAX(height - 2 * font_height, font_height);
+  int inner_sx = (width >= 3 * font_width ? font_width : 0);
+  int inner_sy = (height >= 3 * font_height ? font_height : 0);
+  boolean draw_masked = graphic_info[graphic].draw_masked;
+
+  getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+
+  if (src_bitmap == NULL || width < font_width || height < font_height)
   {
-    int steel_type, steel_position;
-    int border[6][2] =
-    {
-      { GFX_VSTEEL_UPPER_LEFT, GFX_ISTEEL_UPPER_LEFT  },
-      { GFX_VSTEEL_UPPER_RIGHT,        GFX_ISTEEL_UPPER_RIGHT },
-      { GFX_VSTEEL_LOWER_LEFT, GFX_ISTEEL_LOWER_LEFT  },
-      { GFX_VSTEEL_LOWER_RIGHT,        GFX_ISTEEL_LOWER_RIGHT },
-      { GFX_VSTEEL_VERTICAL,   GFX_ISTEEL_VERTICAL    },
-      { GFX_VSTEEL_HORIZONTAL, GFX_ISTEEL_HORIZONTAL  }
-    };
-
-    steel_type = (BorderElement == EL_BETON ? 0 : 1);
-    steel_position = (x == -1 && y == -1                       ? 0 :
-                     x == lev_fieldx && y == -1                ? 1 :
-                     x == -1 && y == lev_fieldy                ? 2 :
-                     x == lev_fieldx && y == lev_fieldy        ? 3 :
-                     x == -1 || x == lev_fieldx                ? 4 :
-                     y == -1 || y == lev_fieldy                ? 5 : -1);
-
-    if (steel_position != -1)
-      DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
+    ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
+    return;
+  }
 
+  src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - font_width  :
+           inner_sx + (x - 1) * font_width  % inner_width);
+  src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
+           inner_sy + (y - 1) * font_height % inner_height);
 
-#if 0
-    if (x == -1 && y == -1)
-      DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_LEFT);
-    else if (x == lev_fieldx && y == -1)
-      DrawMiniGraphic(sx, sy, GFX_STEEL_UPPER_RIGHT);
-    else if (x == -1 && y == lev_fieldy)
-      DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_LEFT);
-    else if (x == lev_fieldx && y == lev_fieldy)
-      DrawMiniGraphic(sx, sy, GFX_STEEL_LOWER_RIGHT);
-    else if (x == -1 || x == lev_fieldx)
-      DrawMiniGraphic(sx, sy, GFX_STEEL_VERTICAL);
-    else if (y == -1 || y == lev_fieldy)
-      DrawMiniGraphic(sx, sy, GFX_STEEL_HORIZONTAL);
-#endif
+  if (draw_masked)
+  {
+    SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+                 dst_x - src_x, dst_y - src_y);
+    BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
+                    dst_x, dst_y);
+  }
+  else
+    BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
+              dst_x, dst_y);
+}
+
+void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
+{
+  int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+  boolean draw_masked = graphic_info[graphic].draw_masked;
+  int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
+  boolean ffwd_delay = (tape.playing && tape.fast_forward);
+  unsigned long anim_delay = 0;
+  int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+  int font_nr = FONT_ENVELOPE_1 + envelope_nr;
+  int font_width = getFontWidth(font_nr);
+  int font_height = getFontHeight(font_nr);
+  int max_xsize = level.envelope_xsize[envelope_nr];
+  int max_ysize = level.envelope_ysize[envelope_nr];
+  int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
+  int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
+  int xend = max_xsize;
+  int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
+  int xstep = (xstart < xend ? 1 : 0);
+  int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
+  int x, y;
+
+  for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
+  {
+    int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
+    int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
+    int sx = (SXSIZE - xsize * font_width)  / 2;
+    int sy = (SYSIZE - ysize * font_height) / 2;
+    int xx, yy;
+
+    SetDrawtoField(DRAW_BUFFERED);
+
+    BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+    SetDrawtoField(DRAW_BACKBUFFER);
+
+    for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
+      DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
+
+    DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
+                      level.envelope_text[envelope_nr], font_nr, max_xsize,
+                      xsize - 2, ysize - 2, mask_mode);
+
+    redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+    BackToFront();
+
+    WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
+  }
+}
 
+void ShowEnvelope(int envelope_nr)
+{
+  int element = EL_ENVELOPE_1 + envelope_nr;
+  int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+  int sound_opening = element_info[element].sound[ACTION_OPENING];
+  int sound_closing = element_info[element].sound[ACTION_CLOSING];
+  boolean ffwd_delay = (tape.playing && tape.fast_forward);
+  int wait_delay_value = (ffwd_delay ? 500 : 1000);
+  int anim_mode = graphic_info[graphic].anim_mode;
+  int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
+                       anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
+
+  game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
+
+  PlaySoundStereo(sound_opening, SOUND_MIDDLE);
+
+  if (anim_mode == ANIM_DEFAULT)
+    AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
+
+  AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
+
+  if (tape.playing)
+    Delay(wait_delay_value);
+  else
+    WaitForEventToContinue();
+
+  PlaySoundStereo(sound_closing, SOUND_MIDDLE);
+
+  if (anim_mode != ANIM_NONE)
+    AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
+
+  if (anim_mode == ANIM_DEFAULT)
+    AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
+
+  game.envelope_active = FALSE;
+
+  SetDrawtoField(DRAW_BUFFERED);
+
+  redraw_mask |= REDRAW_FIELD;
+  BackToFront();
+}
 
-  }
+void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
+{
+  Bitmap *src_bitmap = graphic_info[graphic].bitmap;
+  int mini_startx = src_bitmap->width * 3 / 4;
+  int mini_starty = src_bitmap->height * 2 / 3;
+  int src_x = mini_startx + graphic_info[graphic].src_x / 8;
+  int src_y = mini_starty + graphic_info[graphic].src_y / 8;
+
+  *bitmap = src_bitmap;
+  *x = src_x;
+  *y = src_y;
 }
 
 void DrawMicroElement(int xpos, int ypos, int element)
 {
-  int graphic;
-
-  if (element == EL_LEERRAUM)
-    return;
-
-  graphic = el2gfx(element);
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int graphic = el2preimg(element);
 
-  if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    XCopyArea(display, pix[PIX_MORE], drawto, gc,
-             MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
-             MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
-             MICRO_TILEX, MICRO_TILEY, xpos, ypos);
-  }
-  else
-    XCopyArea(display, pix[PIX_BACK], drawto, gc,
-             MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
-             MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
-             MICRO_TILEX, MICRO_TILEY, xpos, ypos);
+  getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+  BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
+            xpos, ypos);
 }
 
 void DrawLevel()
 {
   int x,y;
 
+  SetDrawBackgroundMask(REDRAW_NONE);
   ClearWindow();
 
-  for(x=BX1; x<=BX2; x++)
-    for(y=BY1; y<=BY2; y++)
+  for (x = BX1; x <= BX2; x++)
+    for (y = BY1; y <= BY2; y++)
       DrawScreenField(x, y);
 
-  if (setup.soft_scrolling)
-    XCopyArea(display, fieldbuffer, backbuffer, gc,
-             FX, FY, SXSIZE, SYSIZE, SX, SY);
-
-  redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
+  redraw_mask |= REDRAW_FIELD;
 }
 
 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
 {
   int x,y;
 
-  for(x=0; x<size_x; x++)
-    for(y=0; y<size_y; y++)
+  for (x = 0; x < size_x; x++)
+    for (y = 0; y < size_y; y++)
       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
 
   redraw_mask |= REDRAW_FIELD;
@@ -1662,11 +1779,7 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 {
   int x, y;
 
-  /* determine border element for this level */
-  SetBorderElement();
-
-  XFillRectangle(display, drawto, gc,
-                xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
+  DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
 
   if (lev_fieldx < STD_LEV_FIELDX)
     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
@@ -1676,46 +1789,60 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
   xpos += MICRO_TILEX;
   ypos += MICRO_TILEY;
 
-  for(x=-1; x<=STD_LEV_FIELDX; x++)
+  for (x = -1; x <= STD_LEV_FIELDX; x++)
   {
-    for(y=-1; y<=STD_LEV_FIELDY; y++)
+    for (y = -1; y <= STD_LEV_FIELDY; y++)
     {
       int lx = from_x + x, ly = from_y + y;
 
       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
-                        Ur[lx][ly]);
-      else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
+                        level.field[lx][ly]);
+      else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
+              && BorderElement != EL_EMPTY)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
-                        BorderElement);
+                        getBorderElement(lx, ly));
     }
   }
 
   redraw_mask |= REDRAW_MICROLEVEL;
 }
 
+#define MICROLABEL_EMPTY               0
+#define MICROLABEL_LEVEL_NAME          1
+#define MICROLABEL_CREATED_BY          2
+#define MICROLABEL_LEVEL_AUTHOR                3
+#define MICROLABEL_IMPORTED_FROM       4
+#define MICROLABEL_LEVEL_IMPORT_INFO   5
+
 static void DrawMicroLevelLabelExt(int mode)
 {
-  char label_text[100];
+  char label_text[MAX_OUTPUT_LINESIZE + 1];
+  int max_len_label_text;
+  int font_nr = FONT_TEXT_2;
 
-  XFillRectangle(display, drawto,gc,
-                SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
+  if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
+    font_nr = FONT_TEXT_3;
 
-  strcpy(label_text, (mode == 1 ? level.name :
-                     mode == 2 ? "created by" :
-                     mode == 3 ? level.author : ""));
+  max_len_label_text = SXSIZE / getFontWidth(font_nr);
 
-  if (strlen(label_text) > 0)
-  {
-    int size, lxpos, lypos;
+  DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
 
-    label_text[SXSIZE / FONT4_XSIZE] = '\0';
+  strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
+                      mode == MICROLABEL_CREATED_BY ? "created by" :
+                      mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
+                      mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
+                      mode == MICROLABEL_LEVEL_IMPORT_INFO ?
+                      leveldir_current->imported_from : ""),
+         max_len_label_text);
+  label_text[max_len_label_text] = '\0';
 
-    size = strlen(label_text);
-    lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
-    lypos = MICROLABEL_YPOS;
+  if (strlen(label_text) > 0)
+  {
+    int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
+    int lypos = MICROLABEL_YPOS;
 
-    DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
+    DrawText(lxpos, lypos, label_text, font_nr);
   }
 
   redraw_mask |= REDRAW_MICROLEVEL;
@@ -1727,6 +1854,10 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
   static unsigned long label_delay = 0;
   static int from_x, from_y, scroll_direction;
   static int label_state, label_counter;
+  int last_game_status = game_status;  /* save current game status */
+
+  /* force PREVIEW font on preview level */
+  game_status = GAME_MODE_PSEUDO_PREVIEW;
 
   if (restart)
   {
@@ -1742,6 +1873,17 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
     DelayReached(&scroll_delay, 0);
     DelayReached(&label_delay, 0);
 
+    if (leveldir_current->name)
+    {
+      int text_width = getTextWidth(leveldir_current->name, FONT_TEXT_1);
+      int lxpos = SX + (SXSIZE - text_width) / 2;
+      int lypos = SY + 352;
+
+      DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
+    }
+
+    game_status = last_game_status;    /* restore current game status */
+
     return;
   }
 
@@ -1789,114 +1931,173 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
   /* redraw micro level label, if needed */
   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
-      strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
+      strcmp(level.author, leveldir_current->name) != 0 &&
       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
   {
-    label_counter = (label_counter + 1) % 23;
-    label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
-                  label_counter >= 9 && label_counter <= 12 ? 2 :
-                  label_counter >= 14 && label_counter <= 21 ? 3 : 0);
+    int max_label_counter = 23;
+
+    if (leveldir_current->imported_from != NULL)
+      max_label_counter += 14;
+
+    label_counter = (label_counter + 1) % max_label_counter;
+    label_state = (label_counter >= 0 && label_counter <= 7 ?
+                  MICROLABEL_LEVEL_NAME :
+                  label_counter >= 9 && label_counter <= 12 ?
+                  MICROLABEL_CREATED_BY :
+                  label_counter >= 14 && label_counter <= 21 ?
+                  MICROLABEL_LEVEL_AUTHOR :
+                  label_counter >= 23 && label_counter <= 26 ?
+                  MICROLABEL_IMPORTED_FROM :
+                  label_counter >= 28 && label_counter <= 35 ?
+                  MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
     DrawMicroLevelLabelExt(label_state);
   }
+
+  game_status = last_game_status;      /* restore current game status */
 }
 
-int REQ_in_range(int x, int y)
+void WaitForEventToContinue()
 {
-  if (y > DY+249 && y < DY+278)
+  boolean still_wait = TRUE;
+
+  /* simulate releasing mouse button over last gadget, if still pressed */
+  if (button_status)
+    HandleGadgets(-1, -1, 0);
+
+  button_status = MB_RELEASED;
+
+  while (still_wait)
   {
-    if (x > DX+1 && x < DX+48)
-      return 1;
-    else if (x > DX+51 && x < DX+98) 
-      return 2;
+    if (PendingEvent())
+    {
+      Event event;
+
+      NextEvent(&event);
+
+      switch (event.type)
+      {
+       case EVENT_BUTTONPRESS:
+       case EVENT_KEYPRESS:
+         still_wait = FALSE;
+         break;
+
+       case EVENT_KEYRELEASE:
+         ClearPlayerAction();
+         break;
+
+       default:
+         HandleOtherEvents(&event);
+         break;
+      }
+    }
+    else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
+    {
+      still_wait = FALSE;
+    }
+
+    DoAnimation();
+
+    /* don't eat all CPU time */
+    Delay(10);
   }
-  return 0;
 }
 
+#define MAX_REQUEST_LINES              13
+#define MAX_REQUEST_LINE_FONT1_LEN     7
+#define MAX_REQUEST_LINE_FONT2_LEN     10
+
 boolean Request(char *text, unsigned int req_state)
 {
   int mx, my, ty, result = -1;
   unsigned int old_door_state;
+  int last_game_status = game_status;  /* save current game status */
+  int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
+  int font_nr = FONT_TEXT_2;
+  int max_word_len = 0;
+  char *text_ptr;
+
+  for (text_ptr = text; *text_ptr; text_ptr++)
+  {
+    max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
+
+    if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
+    {
+      max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
+      font_nr = FONT_LEVEL_NUMBER;
 
-#ifndef MSDOS
+      break;
+    }
+  }
+
+#if 1
+  SetMouseCursor(CURSOR_DEFAULT);
+#endif
+
+#if defined(PLATFORM_UNIX)
   /* pause network game while waiting for request to answer */
   if (options.network &&
-      game_status == PLAYING &&
+      game_status == GAME_MODE_PLAYING &&
       req_state & REQUEST_WAIT_FOR)
     SendToServer_PausePlaying();
 #endif
 
   old_door_state = GetDoorState();
 
+  /* simulate releasing mouse button over last gadget, if still pressed */
+  if (button_status)
+    HandleGadgets(-1, -1, 0);
+
   UnmapAllGadgets();
 
   CloseDoor(DOOR_CLOSE_1);
 
   /* save old door content */
-  XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
-           DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
-           DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
+  BlitBitmap(bitmap_db_door, bitmap_db_door,
+            DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
+            DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
+
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
 
   /* clear door drawing field */
-#if 0
-  XFillRectangle(display, pix[PIX_DB_DOOR], gc,
-                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
-#else
-  XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
-#endif
+  DrawBackground(DX, DY, DXSIZE, DYSIZE);
+
+  /* force DOOR font on preview level */
+  game_status = GAME_MODE_PSEUDO_DOOR;
 
   /* write text for request */
-  for(ty=0; ty<13; ty++)
+  for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
   {
+    char text_line[max_request_line_len + 1];
     int tx, tl, tc;
-    char txt[256];
 
     if (!*text)
       break;
 
-    for(tl=0,tx=0; tx<7; tl++,tx++)
+    for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
     {
       tc = *(text + tx);
-      if (!tc || tc == 32)
+      if (!tc || tc == ' ')
        break;
     }
+
     if (!tl)
     { 
       text++; 
       ty--; 
       continue; 
     }
-    sprintf(txt, text); 
-    txt[tl] = 0;
-#if 0
-    DrawTextExt(pix[PIX_DB_DOOR], gc,
-               DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
-               txt, FS_SMALL, FC_YELLOW);
-#else
-    DrawTextExt(drawto, gc,
-               DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
-               txt, FS_SMALL, FC_YELLOW);
-#endif
-    text += tl + (tc == 32 ? 1 : 0);
-  }
 
-#if 0
-  if (req_state & REQ_ASK)
-  {
-    DrawYesNoButton(BUTTON_OK, DB_INIT);
-    DrawYesNoButton(BUTTON_NO, DB_INIT);
-  }
-  else if (req_state & REQ_CONFIRM)
-  {
-    DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
-  }
-  else if (req_state & REQ_PLAYER)
-  {
-    DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
-    DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
-    DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
-    DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
+    strncpy(text_line, text, tl);
+    text_line[tl] = 0;
+
+    DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
+            DY + 8 + ty * (getFontHeight(font_nr) + 2),
+            text_line, font_nr);
+
+    text += tl + (tc == ' ' ? 1 : 0);
   }
-#else
+
+  game_status = last_game_status;      /* restore current game status */
 
   if (req_state & REQ_ASK)
   {
@@ -1916,113 +2117,73 @@ boolean Request(char *text, unsigned int req_state)
   }
 
   /* copy request gadgets to door backbuffer */
-  XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
-           DX, DY, DXSIZE, DYSIZE,
-           DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
-
-#endif
+  BlitBitmap(drawto, bitmap_db_door,
+            DX, DY, DXSIZE, DYSIZE,
+            DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
   OpenDoor(DOOR_OPEN_1);
+
+#if 0
   ClearEventQueue();
+#endif
 
   if (!(req_state & REQUEST_WAIT_FOR))
-    return(FALSE);
+  {
+    SetDrawBackgroundMask(REDRAW_FIELD);
+
+    return FALSE;
+  }
 
-  if (game_status != MAINMENU)
+  if (game_status != GAME_MODE_MAIN)
     InitAnimation();
 
   button_status = MB_RELEASED;
 
   request_gadget_id = -1;
 
-  while(result < 0)
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+
+#if 0
+  SetMouseCursor(CURSOR_DEFAULT);
+#endif
+
+  while (result < 0)
   {
-    if (XPending(display))
+    if (PendingEvent())
     {
-      XEvent event;
+      Event event;
 
-      XNextEvent(display, &event);
+      NextEvent(&event);
 
       switch(event.type)
       {
-       case ButtonPress:
-       case ButtonRelease:
-       case MotionNotify:
+       case EVENT_BUTTONPRESS:
+       case EVENT_BUTTONRELEASE:
+       case EVENT_MOTIONNOTIFY:
        {
-
-#if 0
-         int choice;
-#endif
-
-         if (event.type == MotionNotify)
+         if (event.type == EVENT_MOTIONNOTIFY)
          {
-           Window root, child;
-           int root_x, root_y;
-           int win_x, win_y;
-           unsigned int mask;
-
-           if (!XQueryPointer(display, window, &root, &child,
-                              &root_x, &root_y, &win_x, &win_y, &mask))
-             continue;
+           if (!PointerInWindow(window))
+             continue; /* window and pointer are on different screens */
 
            if (!button_status)
              continue;
 
            motion_status = TRUE;
-           mx = ((XMotionEvent *) &event)->x;
-           my = ((XMotionEvent *) &event)->y;
+           mx = ((MotionEvent *) &event)->x;
+           my = ((MotionEvent *) &event)->y;
          }
          else
          {
            motion_status = FALSE;
-           mx = ((XButtonEvent *) &event)->x;
-           my = ((XButtonEvent *) &event)->y;
-           if (event.type==ButtonPress)
-             button_status = ((XButtonEvent *) &event)->button;
+           mx = ((ButtonEvent *) &event)->x;
+           my = ((ButtonEvent *) &event)->y;
+           if (event.type == EVENT_BUTTONPRESS)
+             button_status = ((ButtonEvent *) &event)->button;
            else
              button_status = MB_RELEASED;
          }
 
-
-
-#if 0
-         if (req_state & REQ_ASK)
-           choice = CheckYesNoButtons(mx,my,button_status);
-         else if (req_state & REQ_CONFIRM)
-           choice = CheckConfirmButton(mx,my,button_status);
-         else
-           choice = CheckPlayerButtons(mx,my,button_status);
-
-         switch(choice)
-         {
-           case BUTTON_OK:
-             result = TRUE;
-             break;
-           case BUTTON_NO:
-             result = FALSE;
-             break;
-           case BUTTON_CONFIRM:
-             result = TRUE | FALSE;
-             break;
-
-           case BUTTON_PLAYER_1:
-             result = 1;
-             break;
-           case BUTTON_PLAYER_2:
-             result = 2;
-             break;
-           case BUTTON_PLAYER_3:
-             result = 3;
-             break;
-           case BUTTON_PLAYER_4:
-             result = 4;
-             break;
-
-           default:
-             break;
-         }
-#else
-
          /* this sets 'request_gadget_id' */
          HandleGadgets(mx, my, button_status);
 
@@ -2054,20 +2215,18 @@ boolean Request(char *text, unsigned int req_state)
            default:
              break;
          }
-#endif
 
          break;
        }
 
-       case KeyPress:
-         switch(XLookupKeysym((XKeyEvent *)&event,
-                              ((XKeyEvent *)&event)->state))
+       case EVENT_KEYPRESS:
+         switch(GetEventKey((KeyEvent *)&event, TRUE))
          {
-           case XK_Return:
+           case KSYM_Return:
              result = 1;
              break;
 
-           case XK_Escape:
+           case KSYM_Escape:
              result = 0;
              break;
 
@@ -2078,8 +2237,8 @@ boolean Request(char *text, unsigned int req_state)
            result = 0;
          break;
 
-       case KeyRelease:
-         key_joystick_mapping = 0;
+       case EVENT_KEYRELEASE:
+         ClearPlayerAction();
          break;
 
        default:
@@ -2103,7 +2262,7 @@ boolean Request(char *text, unsigned int req_state)
     Delay(10);
   }
 
-  if (game_status != MAINMENU)
+  if (game_status != GAME_MODE_MAIN)
     StopAnimation();
 
   UnmapToolButtons();
@@ -2114,24 +2273,26 @@ boolean Request(char *text, unsigned int req_state)
 
     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
     {
-      XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
-               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
-               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+      BlitBitmap(bitmap_db_door, bitmap_db_door,
+                DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
+                DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
       OpenDoor(DOOR_OPEN_1);
     }
   }
 
   RemapAllGadgets();
 
-#ifndef MSDOS
+  SetDrawBackgroundMask(REDRAW_FIELD);
+
+#if defined(PLATFORM_UNIX)
   /* continue network game after request */
   if (options.network &&
-      game_status == PLAYING &&
+      game_status == GAME_MODE_PLAYING &&
       req_state & REQUEST_WAIT_FOR)
     SendToServer_ContinuePlaying();
 #endif
 
-  return(result);
+  return result;
 }
 
 unsigned int OpenDoor(unsigned int door_state)
@@ -2140,9 +2301,9 @@ unsigned int OpenDoor(unsigned int door_state)
 
   if (door_state & DOOR_COPY_BACK)
   {
-    XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
-             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
-             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+    BlitBitmap(bitmap_db_door, bitmap_db_door,
+              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
+              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
     door_state &= ~DOOR_COPY_BACK;
   }
 
@@ -2155,10 +2316,10 @@ unsigned int CloseDoor(unsigned int door_state)
 {
   unsigned int new_door_state;
 
-  XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
-           DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
-  XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
-           VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
+  BlitBitmap(backbuffer, bitmap_db_door,
+            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+  BlitBitmap(backbuffer, bitmap_db_door,
+            VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
 
   new_door_state = MoveDoor(door_state);
 
@@ -2167,20 +2328,35 @@ unsigned int CloseDoor(unsigned int door_state)
 
 unsigned int GetDoorState()
 {
-  return(MoveDoor(DOOR_GET_STATE));
+  return MoveDoor(DOOR_GET_STATE);
+}
+
+unsigned int SetDoorState(unsigned int door_state)
+{
+  return MoveDoor(door_state | DOOR_SET_STATE);
 }
 
 unsigned int MoveDoor(unsigned int door_state)
 {
   static int door1 = DOOR_OPEN_1;
   static int door2 = DOOR_CLOSE_2;
-  static unsigned long door_delay = 0;
-  int x, start, stepsize = 2;
-  unsigned long door_delay_value = stepsize * 5;
+  unsigned long door_delay = 0;
+  unsigned long door_delay_value;
+  int stepsize = 1;
 
   if (door_state == DOOR_GET_STATE)
     return(door1 | door2);
 
+  if (door_state & DOOR_SET_STATE)
+  {
+    if (door_state & DOOR_ACTION_1)
+      door1 = door_state & DOOR_ACTION_1;
+    if (door_state & DOOR_ACTION_2)
+      door2 = door_state & DOOR_ACTION_2;
+
+    return(door1 | door2);
+  }
+
   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
     door_state &= ~DOOR_OPEN_1;
   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
@@ -2190,138 +2366,254 @@ unsigned int MoveDoor(unsigned int door_state)
   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
     door_state &= ~DOOR_CLOSE_2;
 
+  door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
+                     door_2.step_delay);
+
   if (setup.quick_doors)
   {
-    stepsize = 20;
+    stepsize = 20;             /* must be choosen to always draw last frame */
     door_delay_value = 0;
-    StopSound(SND_OEFFNEN);
+
+    StopSound(SND_DOOR_OPENING);
+    StopSound(SND_DOOR_CLOSING);
+  }
+
+  if (global.autoplay_leveldir)
+  {
+    door_state |= DOOR_NO_DELAY;
+    door_state &= ~DOOR_CLOSE_ALL;
   }
 
   if (door_state & DOOR_ACTION)
   {
-    if (!(door_state & DOOR_NO_DELAY))
-      PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
+    boolean door_1_done = !(door_state & DOOR_ACTION_1);
+    boolean door_2_done = !(door_state & DOOR_ACTION_2);
+    int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
+    int end = (door_state & DOOR_ACTION_1 &&
+              door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
+    int x;
 
-    start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
+    if (!(door_state & DOOR_NO_DELAY))
+    {
+      /* opening door sound has priority over simultaneously closing door */
+      if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
+       PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
+      else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
+       PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
+    }
 
-    for(x=start; x<=DXSIZE; x+=stepsize)
+    for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
     {
-      WaitUntilDelayReached(&door_delay, door_delay_value);
+      Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+      GC gc = bitmap->stored_clip_gc;
 
       if (door_state & DOOR_ACTION_1)
       {
-       int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
-       int j = (DXSIZE - i) / 3;
-
-       XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
-                 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
-                 DXSIZE,DYSIZE - i/2, DX, DY);
-
-       XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
-
-       XSetClipOrigin(display, clip_gc[PIX_DOOR],
-                      DX - i, (DY + j) - DOOR_GFX_PAGEY1);
-       XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
-                 DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
-                 DY + 140 + j);
-       XSetClipOrigin(display, clip_gc[PIX_DOOR],
-                      DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
-
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
-                 DX, DY + 77 - j);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
-                 DX, DY + 203 - j);
-       XSetClipOrigin(display, clip_gc[PIX_DOOR],
-                      DX - i, (DY + j) - DOOR_GFX_PAGEY1);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
-                 DX + DXSIZE - i, DY + 77 + j);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
-                 DX + DXSIZE - i, DY + 203 + j);
+       int a = MIN(x * door_1.step_offset, end);
+       int i = (door_state & DOOR_OPEN_1 ? end - a : a);
+
+       if (x <= a)
+       {
+         BlitBitmap(bitmap_db_door, drawto,
+                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
+                    DXSIZE,DYSIZE - i / 2, DX, DY);
+
+         ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
+       }
+
+       if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
+       {
+         int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
+         int dst1_x = DX + DXSIZE - i, dst1_y = DY;
+         int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
+         int dst2_x = DX,              dst2_y = DY;
+         int width = i, height = DYSIZE;
+
+         SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
+         BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
+                          dst1_x, dst1_y);
+
+         SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
+         BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
+                          dst2_x, dst2_y);
+       }
+       else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
+       {
+         int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
+         int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
+         int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
+         int dst2_x = DX,              dst2_y = DY;
+         int width = DXSIZE, height = i;
+
+         SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
+         BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
+                          dst1_x, dst1_y);
+
+         SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
+         BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
+                          dst2_x, dst2_y);
+       }
+       else if (x <= DXSIZE)   /* ANIM_DEFAULT */
+       {
+         int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
+
+         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
+                          DX + DXSIZE - i, DY + j);
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
+                          DX + DXSIZE - i, DY + 140 + j);
+         SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
+                       DY - (DOOR_GFX_PAGEY1 + j));
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
+                          DX, DY);
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
+                          DX, DY + 140 - j);
+
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
+                          DX, DY + 77 - j);
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
+                          DX, DY + 203 - j);
+         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
+                          DX + DXSIZE - i, DY + 77 + j);
+         BlitBitmapMasked(bitmap, drawto,
+                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
+                          DX + DXSIZE - i, DY + 203 + j);
+       }
 
        redraw_mask |= REDRAW_DOOR_1;
+       door_1_done = (a == end);
       }
 
       if (door_state & DOOR_ACTION_2)
       {
-       int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
-       int j = (VXSIZE - i) / 3;
-
-       XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
-                 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
-                 VXSIZE, VYSIZE - i/2, VX, VY);
-
-       XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
-
-       XSetClipOrigin(display, clip_gc[PIX_DOOR],
-                      VX - i, (VY + j) - DOOR_GFX_PAGEY2);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
-       XSetClipOrigin(display, clip_gc[PIX_DOOR],
-                      VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
-       XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
-                 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
-
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
-                 VX, VY + VYSIZE / 2 - j);
-       XSetClipOrigin(display, clip_gc[PIX_DOOR],
-                      VX - i, (VY + j) - DOOR_GFX_PAGEY2);
-       XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
-                 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
-                 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
-
-       redraw_mask |= REDRAW_DOOR_2;
-      }
+       int a = MIN(x * door_2.step_offset, VXSIZE);
+       int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
 
+       if (x <= VYSIZE)
+       {
+         BlitBitmap(bitmap_db_door, drawto,
+                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
+                    VXSIZE, VYSIZE - i / 2, VX, VY);
 
+         ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
+       }
 
-#if 1
-      BackToFront();
-#else
-      XCopyArea(display, drawto, window, gc, DX, DY, DXSIZE, DYSIZE, DX, DY);
-#endif
+       if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
+       {
+         int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
+         int dst1_x = VX + VXSIZE - i, dst1_y = VY;
+         int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
+         int dst2_x = VX,              dst2_y = VY;
+         int width = i, height = VYSIZE;
+
+         SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
+         BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
+                          dst1_x, dst1_y);
+
+         SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
+         BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
+                          dst2_x, dst2_y);
+       }
+       else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
+       {
+         int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
+         int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
+         int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
+         int dst2_x = VX,              dst2_y = VY;
+         int width = VXSIZE, height = i;
+
+         SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
+         BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
+                          dst1_x, dst1_y);
+
+         SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
+         BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
+                          dst2_x, dst2_y);
+       }
+       else if (x <= VXSIZE)   /* ANIM_DEFAULT */
+       {
+         int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
+
+         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
+         BlitBitmapMasked(bitmap, drawto,
+                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
+                          VX + VXSIZE - i, VY + j);
+         SetClipOrigin(bitmap, gc,
+                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
+         BlitBitmapMasked(bitmap, drawto,
+                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
+                          VX, VY);
+
+         BlitBitmapMasked(bitmap, drawto,
+                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
+                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
+         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
+         BlitBitmapMasked(bitmap, drawto,
+                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
+                          i, VYSIZE / 2 - j,
+                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
+       }
 
+       redraw_mask |= REDRAW_DOOR_2;
+       door_2_done = (a == VXSIZE);
+      }
 
+      BackToFront();
 
-      if (game_status == MAINMENU)
+      if (game_status == GAME_MODE_MAIN)
        DoAnimation();
+
+      if (!(door_state & DOOR_NO_DELAY))
+       WaitUntilDelayReached(&door_delay, door_delay_value);
     }
   }
 
   if (setup.quick_doors)
-    StopSound(SND_OEFFNEN);
+  {
+    StopSound(SND_DOOR_OPENING);
+    StopSound(SND_DOOR_CLOSING);
+  }
 
   if (door_state & DOOR_ACTION_1)
     door1 = door_state & DOOR_ACTION_1;
   if (door_state & DOOR_ACTION_2)
     door2 = door_state & DOOR_ACTION_2;
 
-  return(door1 | door2);
+  return (door1 | door2);
 }
 
-int ReadPixel(Drawable d, int x, int y)
+void DrawSpecialEditorDoor()
 {
-  XImage *pixel_image;
-  unsigned long pixel_value;
-
-  pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
-  pixel_value = XGetPixel(pixel_image, 0, 0);
+  /* draw bigger toolbox window */
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+            DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
+            EX - 4, EY - 12);
+  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
+            EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
+            EX - 4, EY - 4);
+
+  redraw_mask |= REDRAW_ALL;
+}
 
-  XDestroyImage(pixel_image);
+void UndrawSpecialEditorDoor()
+{
+  /* draw normal tape recorder window */
+  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
+            EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
+            EX - 4, EY - 12);
 
-  return pixel_value;
+  redraw_mask |= REDRAW_ALL;
 }
 
+
 /* ---------- new tool button stuff ---------------------------------------- */
 
 /* graphic position values for tool buttons */
@@ -2427,11 +2719,11 @@ void CreateToolButtons()
 {
   int i;
 
-  for (i=0; i<NUM_TOOL_BUTTONS; i++)
+  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
   {
-    Pixmap gd_pixmap = pix[PIX_DOOR];
-    Pixmap deco_pixmap = 0;
-    int deco_x, deco_y, deco_xpos, deco_ypos;
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+    Bitmap *deco_bitmap = None;
+    int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
     struct GadgetInfo *gi;
     unsigned long event_mask;
     int gd_xoffset, gd_yoffset;
@@ -2448,8 +2740,10 @@ void CreateToolButtons()
 
     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
     {
-      getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
-                          &deco_pixmap, &deco_x, &deco_y);
+      int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
+
+      getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
+                          &deco_bitmap, &deco_x, &deco_y);
       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
     }
@@ -2462,9 +2756,9 @@ void CreateToolButtons()
                      GDI_HEIGHT, toolbutton_info[i].height,
                      GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
-                     GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
-                     GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
-                     GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
+                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
+                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
+                     GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
                      GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
                      GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
                      GDI_DECORATION_SHIFTING, 1, 1,
@@ -2479,268 +2773,97 @@ void CreateToolButtons()
   }
 }
 
+void FreeToolButtons()
+{
+  int i;
+
+  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
+    FreeGadget(tool_gadget[i]);
+}
+
 static void UnmapToolButtons()
 {
   int i;
 
-  for (i=0; i<NUM_TOOL_BUTTONS; i++)
+  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
     UnmapGadget(tool_gadget[i]);
 }
 
 static void HandleToolButtons(struct GadgetInfo *gi)
 {
   request_gadget_id = gi->custom_id;
+}
 
+int get_next_element(int element)
+{
+  switch(element)
+  {
+    case EL_QUICKSAND_FILLING:         return EL_QUICKSAND_FULL;
+    case EL_QUICKSAND_EMPTYING:                return EL_QUICKSAND_EMPTY;
+    case EL_MAGIC_WALL_FILLING:                return EL_MAGIC_WALL_FULL;
+    case EL_MAGIC_WALL_EMPTYING:       return EL_MAGIC_WALL_ACTIVE;
+    case EL_BD_MAGIC_WALL_FILLING:     return EL_BD_MAGIC_WALL_FULL;
+    case EL_BD_MAGIC_WALL_EMPTYING:    return EL_BD_MAGIC_WALL_ACTIVE;
+    case EL_AMOEBA_DROPPING:           return EL_AMOEBA_WET;
 
-#if 0
-  int id = gi->custom_id;
+    default:                           return element;
+  }
+}
 
-  if (game_status != PLAYING)
-    return;
+int el_act_dir2img(int element, int action, int direction)
+{
+  element = GFX_ELEMENT(element);
+  direction = MV_DIR_BIT(direction);
 
-  switch (id)
-  {
-    case GAME_CTRL_ID_STOP:
-      if (AllPlayersGone)
-      {
-       CloseDoor(DOOR_CLOSE_1);
-       game_status = MAINMENU;
-       DrawMainMenu();
-       break;
-      }
+  return element_info[element].direction_graphic[action][direction];
+}
 
-      if (Request("Do you really want to quit the game ?",
-                 REQ_ASK | REQ_STAY_CLOSED))
-      { 
-#ifndef MSDOS
-       if (options.network)
-         SendToServer_StopPlaying();
-       else
-#endif
-       {
-         game_status = MAINMENU;
-         DrawMainMenu();
-       }
-      }
-      else
-       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
-      break;
+static int el_act_dir2crm(int element, int action, int direction)
+{
+  element = GFX_ELEMENT(element);
+  direction = MV_DIR_BIT(direction);
 
-    case GAME_CTRL_ID_PAUSE:
-      if (options.network)
-      {
-#ifndef MSDOS
-       if (tape.pausing)
-         SendToServer_ContinuePlaying();
-       else
-         SendToServer_PausePlaying();
-#endif
-      }
-      else
-       TapeTogglePause();
-      break;
+  return element_info[element].direction_crumbled[action][direction];
+}
 
-    case GAME_CTRL_ID_PLAY:
-      if (tape.pausing)
-      {
-#ifndef MSDOS
-       if (options.network)
-         SendToServer_ContinuePlaying();
-       else
-#endif
-       {
-         tape.pausing = FALSE;
-         DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
-       }
-      }
-      break;
+int el_act2img(int element, int action)
+{
+  element = GFX_ELEMENT(element);
 
-    case SOUND_CTRL_ID_MUSIC:
-      if (setup.sound_music)
-      { 
-       setup.sound_music = FALSE;
-       FadeSound(background_loop[level_nr % num_bg_loops]);
-      }
-      else if (sound_loops_allowed)
-      { 
-       setup.sound = setup.sound_music = TRUE;
-       PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
-      }
-      break;
+  return element_info[element].graphic[action];
+}
 
-    case SOUND_CTRL_ID_LOOPS:
-      if (setup.sound_loops)
-       setup.sound_loops = FALSE;
-      else if (sound_loops_allowed)
-       setup.sound = setup.sound_loops = TRUE;
-      break;
+int el_act2crm(int element, int action)
+{
+  element = GFX_ELEMENT(element);
 
-    case SOUND_CTRL_ID_SIMPLE:
-      if (setup.sound_simple)
-       setup.sound_simple = FALSE;
-      else if (sound_status==SOUND_AVAILABLE)
-       setup.sound = setup.sound_simple = TRUE;
-      break;
+  return element_info[element].crumbled[action];
+}
 
-    default:
-      break;
-  }
-#endif
+int el_dir2img(int element, int direction)
+{
+  element = GFX_ELEMENT(element);
 
+  return el_act_dir2img(element, ACTION_DEFAULT, direction);
+}
 
+int el2img(int element)
+{
+  element = GFX_ELEMENT(element);
 
+  return element_info[element].graphic[ACTION_DEFAULT];
 }
 
-int el2gfx(int element)
+int el2edimg(int element)
 {
-  switch(element)
-  {
-    case EL_LEERRAUM:          return -1;
-    case EL_ERDREICH:          return GFX_ERDREICH;
-    case EL_MAUERWERK:         return GFX_MAUERWERK;
-    case EL_FELSBODEN:         return GFX_FELSBODEN;
-    case EL_FELSBROCKEN:       return GFX_FELSBROCKEN;
-    case EL_SCHLUESSEL:                return GFX_SCHLUESSEL;
-    case EL_EDELSTEIN:         return GFX_EDELSTEIN;
-    case EL_AUSGANG_ZU:                return GFX_AUSGANG_ZU;
-    case EL_AUSGANG_ACT:       return GFX_AUSGANG_ACT;
-    case EL_AUSGANG_AUF:       return GFX_AUSGANG_AUF;
-    case EL_SPIELFIGUR:                return GFX_SPIELFIGUR;
-    case EL_SPIELER1:          return GFX_SPIELER1;
-    case EL_SPIELER2:          return GFX_SPIELER2;
-    case EL_SPIELER3:          return GFX_SPIELER3;
-    case EL_SPIELER4:          return GFX_SPIELER4;
-    case EL_KAEFER:            return GFX_KAEFER;
-    case EL_KAEFER_R:          return GFX_KAEFER_R;
-    case EL_KAEFER_O:          return GFX_KAEFER_O;
-    case EL_KAEFER_L:          return GFX_KAEFER_L;
-    case EL_KAEFER_U:          return GFX_KAEFER_U;
-    case EL_FLIEGER:           return GFX_FLIEGER;
-    case EL_FLIEGER_R:         return GFX_FLIEGER_R;
-    case EL_FLIEGER_O:         return GFX_FLIEGER_O;
-    case EL_FLIEGER_L:         return GFX_FLIEGER_L;
-    case EL_FLIEGER_U:         return GFX_FLIEGER_U;
-    case EL_BUTTERFLY:         return GFX_BUTTERFLY;
-    case EL_BUTTERFLY_R:       return GFX_BUTTERFLY_R;
-    case EL_BUTTERFLY_O:       return GFX_BUTTERFLY_O;
-    case EL_BUTTERFLY_L:       return GFX_BUTTERFLY_L;
-    case EL_BUTTERFLY_U:       return GFX_BUTTERFLY_U;
-    case EL_FIREFLY:           return GFX_FIREFLY;
-    case EL_FIREFLY_R:         return GFX_FIREFLY_R;
-    case EL_FIREFLY_O:         return GFX_FIREFLY_O;
-    case EL_FIREFLY_L:         return GFX_FIREFLY_L;
-    case EL_FIREFLY_U:         return GFX_FIREFLY_U;
-    case EL_MAMPFER:           return GFX_MAMPFER;
-    case EL_ROBOT:             return GFX_ROBOT;
-    case EL_BETON:             return GFX_BETON;
-    case EL_DIAMANT:           return GFX_DIAMANT;
-    case EL_MORAST_LEER:       return GFX_MORAST_LEER;
-    case EL_MORAST_VOLL:       return GFX_MORAST_VOLL;
-    case EL_TROPFEN:           return GFX_TROPFEN;
-    case EL_BOMBE:             return GFX_BOMBE;
-    case EL_SIEB_INAKTIV:      return GFX_SIEB_INAKTIV;
-    case EL_SIEB_LEER:         return GFX_SIEB_LEER;
-    case EL_SIEB_VOLL:         return GFX_SIEB_VOLL;
-    case EL_SIEB_TOT:          return GFX_SIEB_TOT;
-    case EL_SALZSAEURE:                return GFX_SALZSAEURE;
-    case EL_AMOEBE_TOT:                return GFX_AMOEBE_TOT;
-    case EL_AMOEBE_NASS:       return GFX_AMOEBE_NASS;
-    case EL_AMOEBE_NORM:       return GFX_AMOEBE_NORM;
-    case EL_AMOEBE_VOLL:       return GFX_AMOEBE_VOLL;
-    case EL_AMOEBE_BD:         return GFX_AMOEBE_BD;
-    case EL_AMOEBA2DIAM:       return GFX_AMOEBA2DIAM;
-    case EL_KOKOSNUSS:         return GFX_KOKOSNUSS;
-    case EL_LIFE:              return GFX_LIFE;
-    case EL_LIFE_ASYNC:                return GFX_LIFE_ASYNC;
-    case EL_DYNAMIT:           return GFX_DYNAMIT;
-    case EL_BADEWANNE:         return GFX_BADEWANNE;
-    case EL_BADEWANNE1:                return GFX_BADEWANNE1;
-    case EL_BADEWANNE2:                return GFX_BADEWANNE2;
-    case EL_BADEWANNE3:                return GFX_BADEWANNE3;
-    case EL_BADEWANNE4:                return GFX_BADEWANNE4;
-    case EL_BADEWANNE5:                return GFX_BADEWANNE5;
-    case EL_ABLENK_AUS:                return GFX_ABLENK_AUS;
-    case EL_ABLENK_EIN:                return GFX_ABLENK_EIN;
-    case EL_SCHLUESSEL1:       return GFX_SCHLUESSEL1;
-    case EL_SCHLUESSEL2:       return GFX_SCHLUESSEL2;
-    case EL_SCHLUESSEL3:       return GFX_SCHLUESSEL3;
-    case EL_SCHLUESSEL4:       return GFX_SCHLUESSEL4;
-    case EL_PFORTE1:           return GFX_PFORTE1;
-    case EL_PFORTE2:           return GFX_PFORTE2;
-    case EL_PFORTE3:           return GFX_PFORTE3;
-    case EL_PFORTE4:           return GFX_PFORTE4;
-    case EL_PFORTE1X:          return GFX_PFORTE1X;
-    case EL_PFORTE2X:          return GFX_PFORTE2X;
-    case EL_PFORTE3X:          return GFX_PFORTE3X;
-    case EL_PFORTE4X:          return GFX_PFORTE4X;
-    case EL_DYNAMIT_AUS:       return GFX_DYNAMIT_AUS;
-    case EL_PACMAN:            return GFX_PACMAN;
-    case EL_PACMAN_R:          return GFX_PACMAN_R;
-    case EL_PACMAN_O:          return GFX_PACMAN_O;
-    case EL_PACMAN_L:          return GFX_PACMAN_L;
-    case EL_PACMAN_U:          return GFX_PACMAN_U;
-    case EL_UNSICHTBAR:                return GFX_UNSICHTBAR;
-    case EL_ERZ_EDEL:          return GFX_ERZ_EDEL;
-    case EL_ERZ_DIAM:          return GFX_ERZ_DIAM;
-    case EL_BIRNE_AUS:         return GFX_BIRNE_AUS;
-    case EL_BIRNE_EIN:         return GFX_BIRNE_EIN;
-    case EL_ZEIT_VOLL:         return GFX_ZEIT_VOLL;
-    case EL_ZEIT_LEER:         return GFX_ZEIT_LEER;
-    case EL_MAUER_LEBT:                return GFX_MAUER_LEBT;
-    case EL_MAUER_X:           return GFX_MAUER_X;
-    case EL_MAUER_Y:           return GFX_MAUER_Y;
-    case EL_MAUER_XY:          return GFX_MAUER_XY;
-    case EL_EDELSTEIN_BD:      return GFX_EDELSTEIN_BD;
-    case EL_EDELSTEIN_GELB:    return GFX_EDELSTEIN_GELB;
-    case EL_EDELSTEIN_ROT:     return GFX_EDELSTEIN_ROT;
-    case EL_EDELSTEIN_LILA:    return GFX_EDELSTEIN_LILA;
-    case EL_ERZ_EDEL_BD:       return GFX_ERZ_EDEL_BD;
-    case EL_ERZ_EDEL_GELB:     return GFX_ERZ_EDEL_GELB;
-    case EL_ERZ_EDEL_ROT:      return GFX_ERZ_EDEL_ROT;
-    case EL_ERZ_EDEL_LILA:     return GFX_ERZ_EDEL_LILA;
-    case EL_MAMPFER2:          return GFX_MAMPFER2;
-    case EL_SIEB2_INAKTIV:     return GFX_SIEB2_INAKTIV;
-    case EL_SIEB2_LEER:                return GFX_SIEB2_LEER;
-    case EL_SIEB2_VOLL:                return GFX_SIEB2_VOLL;
-    case EL_SIEB2_TOT:         return GFX_SIEB2_TOT;
-    case EL_DYNABOMB:          return GFX_DYNABOMB;
-    case EL_DYNABOMB_NR:       return GFX_DYNABOMB_NR;
-    case EL_DYNABOMB_SZ:       return GFX_DYNABOMB_SZ;
-    case EL_DYNABOMB_XL:       return GFX_DYNABOMB_XL;
-    case EL_SOKOBAN_OBJEKT:    return GFX_SOKOBAN_OBJEKT;
-    case EL_SOKOBAN_FELD_LEER: return GFX_SOKOBAN_FELD_LEER;
-    case EL_SOKOBAN_FELD_VOLL: return GFX_SOKOBAN_FELD_VOLL;
-    case EL_MAULWURF:          return GFX_MAULWURF;
-    case EL_PINGUIN:           return GFX_PINGUIN;
-    case EL_SCHWEIN:           return GFX_SCHWEIN;
-    case EL_DRACHE:            return GFX_DRACHE;
-    case EL_SONDE:             return GFX_SONDE;
-    case EL_PFEIL_L:           return GFX_PFEIL_L;
-    case EL_PFEIL_R:           return GFX_PFEIL_R;
-    case EL_PFEIL_O:           return GFX_PFEIL_O;
-    case EL_PFEIL_U:           return GFX_PFEIL_U;
-    case EL_SPEED_PILL:                return GFX_SPEED_PILL;
-    case EL_SP_TERMINAL_ACTIVE:        return GFX_SP_TERMINAL;
-    case EL_SP_BUG_ACTIVE:     return GFX_SP_BUG_ACTIVE;
-    case EL_INVISIBLE_STEEL:   return GFX_INVISIBLE_STEEL;
-    case EL_BLACK_ORB:         return GFX_BLACK_ORB;
-
-    default:
-    {
-      if (IS_CHAR(element))
-       return GFX_CHAR_START + (element - EL_CHAR_START);
-      else if (element >= EL_SP_START && element <= EL_SP_END)
-      {
-       int nr_element = element - EL_SP_START;
-       int gfx_per_line = 8;
-       int nr_graphic =
-         (nr_element / gfx_per_line) * MORE_PER_LINE +
-         (nr_element % gfx_per_line);
+  element = GFX_ELEMENT(element);
 
-       return GFX_START_ROCKSMORE + nr_graphic;
-      }
-      else
-       return -1;
-    }
-  }
+  return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
+}
+
+int el2preimg(int element)
+{
+  element = GFX_ELEMENT(element);
+
+  return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
 }