rnd-20061019-1-src
[rocksndiamonds.git] / src / tools.c
index f7a3011e0e1b4a71882de655a283fa444bf46e41..41ed06d693d078aa0c8d52cdce9efa773474f012 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
 *----------------------------------------------------------*
-* (c) 1995-2002 Artsoft Entertainment                      *
+* (c) 1995-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
@@ -44,8 +44,6 @@ static int el_act2crm(int, int);
 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
 static int request_gadget_id = -1;
 
-static int preview_tilesize = TILEX / 4;
-
 static char *print_if_not_empty(int element)
 {
   static char *s = NULL;
@@ -140,8 +138,10 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
       level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     /* currently there is no partial redraw -- always redraw whole playfield */
-
     RedrawPlayfield_EM(TRUE);
+
+    /* blit playfield from scroll buffer to normal back buffer for fading in */
+    BlitScreenToBitmap_EM(backbuffer);
   }
   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
   {
@@ -183,9 +183,78 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
     }
   }
 
+  if (force_redraw)
+  {
+    x = gfx.sx;
+    y = gfx.sy;
+    width = gfx.sxsize;
+    height = gfx.sysize;
+  }
+
   BlitBitmap(drawto, window, x, y, width, height, x, y);
 }
 
+void DrawMaskedBorder_Rect(int x, int y, int width, int height)
+{
+  Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
+
+  SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
+  BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
+}
+
+void DrawMaskedBorder_FIELD()
+{
+  if (game_status >= GAME_MODE_TITLE &&
+      game_status <= GAME_MODE_PLAYING &&
+      border.draw_masked[game_status])
+    DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+}
+
+void DrawMaskedBorder_DOOR_1()
+{
+  if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
+      (game_status != GAME_MODE_EDITOR ||
+       border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
+    DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
+}
+
+void DrawMaskedBorder_DOOR_2()
+{
+  if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
+      game_status != GAME_MODE_EDITOR)
+    DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
+}
+
+void DrawMaskedBorder_DOOR_3()
+{
+  /* currently not available */
+}
+
+void DrawMaskedBorder_ALL()
+{
+  DrawMaskedBorder_FIELD();
+  DrawMaskedBorder_DOOR_1();
+  DrawMaskedBorder_DOOR_2();
+  DrawMaskedBorder_DOOR_3();
+}
+
+void DrawMaskedBorder(int redraw_mask)
+{
+  if (redraw_mask & REDRAW_ALL)
+    DrawMaskedBorder_ALL();
+  else
+  {
+    if (redraw_mask & REDRAW_FIELD)
+      DrawMaskedBorder_FIELD();
+    if (redraw_mask & REDRAW_DOOR_1)
+      DrawMaskedBorder_DOOR_1();
+    if (redraw_mask & REDRAW_DOOR_2)
+      DrawMaskedBorder_DOOR_2();
+    if (redraw_mask & REDRAW_DOOR_3)
+      DrawMaskedBorder_DOOR_3();
+  }
+}
+
 void BackToFront()
 {
   int x,y;
@@ -203,6 +272,11 @@ void BackToFront()
   if (redraw_mask == REDRAW_NONE)
     return;
 
+  if (redraw_mask & REDRAW_TILES &&
+      game_status == GAME_MODE_PLAYING &&
+      border.draw_masked[game_status])
+    redraw_mask |= REDRAW_FIELD;
+
   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
   {
     static boolean last_frame_skipped = FALSE;
@@ -240,8 +314,15 @@ void BackToFront()
 
   SyncDisplay();
 
+#if 1
+  DrawMaskedBorder(redraw_mask);
+#endif
+
   if (redraw_mask & REDRAW_ALL)
   {
+#if 0
+    DrawMaskedBorder(REDRAW_ALL);
+#endif
     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
     redraw_mask = REDRAW_NONE;
@@ -252,6 +333,9 @@ void BackToFront()
     if (game_status != GAME_MODE_PLAYING ||
        redraw_mask & REDRAW_FROM_BACKBUFFER)
     {
+#if 0
+      DrawMaskedBorder(REDRAW_FIELD);
+#endif
       BlitBitmap(backbuffer, window,
                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
     }
@@ -270,7 +354,21 @@ void BackToFront()
          ABS(ScreenMovPos) == ScrollStepSize ||
          redraw_tiles > REDRAWTILES_THRESHOLD)
       {
+#if 1
+       if (border.draw_masked[GFX_SPECIAL_ARG_MAIN])
+       {
+         BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
+
+         DrawMaskedBorder(REDRAW_FIELD);
+         BlitBitmap(backbuffer, window,
+                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                    REAL_SX, REAL_SY);
+       }
+       else
+         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+#else
        BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+#endif
 
 #if 0
 #ifdef DEBUG
@@ -294,13 +392,28 @@ void BackToFront()
   if (redraw_mask & REDRAW_DOORS)
   {
     if (redraw_mask & REDRAW_DOOR_1)
+    {
+#if 0
+      DrawMaskedBorder(REDRAW_DOOR_1);
+#endif
       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
+    }
 
     if (redraw_mask & REDRAW_DOOR_2)
+    {
+#if 0
+      DrawMaskedBorder(REDRAW_DOOR_2);
+#endif
       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
+    }
 
     if (redraw_mask & REDRAW_DOOR_3)
+    {
+#if 0
+      DrawMaskedBorder(REDRAW_DOOR_3);
+#endif
       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
+    }
 
     redraw_mask &= ~REDRAW_DOORS;
   }
@@ -416,48 +529,67 @@ void FadeToFront()
   BackToFront();
 }
 
-void FadeIn(int fade_delay)
+void FadeExt(int fade_mask, int fade_mode)
 {
-  if (fade_delay == 0)
+  void (*draw_border_function)(void) = NULL;
+  Bitmap *bitmap = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_db_cross : NULL);
+  int fade_delay = menu.fade_delay;
+  int post_delay = (fade_mode == FADE_MODE_FADE_OUT ? menu.post_delay : 0);
+  int x, y, width, height;
+
+  if (fade_mask & REDRAW_FIELD)
   {
-    BackToFront();
+    x = REAL_SX;
+    y = REAL_SY;
+    width  = FULL_SXSIZE;
+    height = FULL_SYSIZE;
 
-    return;
+    draw_border_function = DrawMaskedBorder_FIELD;
+  }
+  else         /* REDRAW_ALL */
+  {
+    x = 0;
+    y = 0;
+    width  = WIN_XSIZE;
+    height = WIN_YSIZE;
   }
 
-  FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
-
-  redraw_mask = REDRAW_NONE;
-}
+  redraw_mask |= fade_mask;
 
-void FadeOut(int fade_delay, int post_delay)
-{
-  if (fade_delay == 0)
+  if (!setup.fade_screens || fade_delay == 0)
   {
-    ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+    if (fade_mode == FADE_MODE_FADE_OUT)
+      ClearRectangle(backbuffer, x, y, width, height);
+
     BackToFront();
 
     return;
   }
 
-  FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
+  FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
+               draw_border_function);
 
-  redraw_mask = REDRAW_NONE;
+  redraw_mask &= ~fade_mask;
 }
 
-void FadeCross(int fade_delay)
+void FadeIn(int fade_mask)
 {
-  if (fade_delay == 0)
-  {
-    BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-    BackToFront();
+  FadeExt(fade_mask, FADE_MODE_FADE_IN);
+}
 
-    return;
-  }
+void FadeOut(int fade_mask)
+{
+  FadeExt(fade_mask, FADE_MODE_FADE_OUT);
+}
 
-  FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
+void FadeCross(int fade_mask)
+{
+  FadeExt(fade_mask, FADE_MODE_CROSSFADE);
+}
 
-  redraw_mask = REDRAW_NONE;
+void FadeCrossSaveBackbuffer()
+{
+  BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 }
 
 void SetMainBackgroundImageIfDefined(int graphic)
@@ -482,9 +614,21 @@ void SetDoorBackgroundImage(int graphic)
                          graphic_info[IMG_BACKGROUND].bitmap);
 }
 
+void SetPanelBackground()
+{
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
+             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
+
+  SetDoorBackgroundBitmap(bitmap_db_panel);
+}
+
 void DrawBackground(int dst_x, int dst_y, int width, int height)
 {
+#if 1
+  ClearRectangleOnBackground(drawto, dst_x, dst_y, width, height);
+#else
   ClearRectangleOnBackground(backbuffer, dst_x, dst_y, width, height);
+#endif
 
   redraw_mask |= REDRAW_FIELD;
 }
@@ -550,17 +694,6 @@ inline int getGraphicAnimationFrame(int graphic, int sync_frame)
   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
     sync_frame = FrameCounter;
 
-#if 0
-  if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
-      sync_frame == 0 &&
-      FrameCounter > 10)
-  {
-    int x = 1 / 0;
-
-    printf("::: FOO!\n");
-  }
-#endif
-
   return getAnimationFrame(graphic_info[graphic].anim_frames,
                           graphic_info[graphic].anim_delay,
                           graphic_info[graphic].anim_mode,
@@ -1040,34 +1173,20 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
       int sxx = sx + xy[i][0];
       int syy = sy + xy[i][1];
 
-#if 1
       if (!IN_LEV_FIELD(xx, yy) ||
          !IN_SCR_FIELD(sxx, syy) ||
          IS_MOVING(xx, yy))
        continue;
 
-#if 1
       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
        continue;
-#endif
 
       element = TILE_GFX_ELEMENT(xx, yy);
 
       if (!GFX_CRUMBLED(element))
        continue;
-#else
-      if (!IN_LEV_FIELD(xx, yy) ||
-         !IN_SCR_FIELD(sxx, syy) ||
-         !GFX_CRUMBLED(Feld[xx][yy]) ||
-         IS_MOVING(xx, yy))
-       continue;
-#endif
 
-#if 1
       graphic = el_act2crm(element, ACTION_DEFAULT);
-#else
-      graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
-#endif
       crumbled_border_size = graphic_info[graphic].border_size;
 
       getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
@@ -1482,19 +1601,6 @@ void ShowEnvelope(int envelope_nr)
   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 getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
                             int tilesize)
 {
@@ -1526,25 +1632,14 @@ void getPreviewGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y,
   *y = src_y;
 }
 
-void DrawMicroElement(int xpos, int ypos, int element)
-{
-  Bitmap *src_bitmap;
-  int src_x, src_y;
-  int graphic = el2preimg(element);
-
-  getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
-  BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
-            xpos, ypos);
-}
-
-void DrawPreviewElement(int xpos, int ypos, int element, int tilesize)
+void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
 {
   Bitmap *src_bitmap;
   int src_x, src_y;
   int graphic = el2preimg(element);
 
   getPreviewGraphicSource(graphic, &src_bitmap, &src_x, &src_y, tilesize);
-  BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, xpos, ypos);
+  BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
 }
 
 void DrawLevel()
@@ -1572,34 +1667,36 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
   redraw_mask |= REDRAW_FIELD;
 }
 
-static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
+static void DrawPreviewLevelExt(int from_x, int from_y)
 {
   boolean show_level_border = (BorderElement != EL_EMPTY);
-  int level_size_x = lev_fieldx + (show_level_border ? 2 : 0);
-  int level_size_y = lev_fieldy + (show_level_border ? 2 : 0);
-  int preview_size_x = MICROLEVEL_XSIZE / preview_tilesize;
-  int preview_size_y = MICROLEVEL_YSIZE / preview_tilesize;
-  int real_preview_size_x = MIN(level_size_x, preview_size_x);
-  int real_preview_size_y = MIN(level_size_y, preview_size_y);
+  int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
+  int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
+  int tile_size = preview.tile_size;
+  int preview_width  = preview.xsize * tile_size;
+  int preview_height = preview.ysize * tile_size;
+  int real_preview_xsize = MIN(level_xsize, preview.xsize);
+  int real_preview_ysize = MIN(level_ysize, preview.ysize);
+  int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
+  int dst_y = SY + preview.y;
   int x, y;
 
-  DrawBackground(xpos, ypos, MICROLEVEL_XSIZE, MICROLEVEL_YSIZE);
+  DrawBackground(dst_x, dst_y, preview_width, preview_height);
 
-  xpos += (MICROLEVEL_XSIZE - real_preview_size_x * preview_tilesize) / 2;
-  ypos += (MICROLEVEL_YSIZE - real_preview_size_y * preview_tilesize) / 2;
+  dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
+  dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
 
-  for (x = 0; x < real_preview_size_x; x++)
+  for (x = 0; x < real_preview_xsize; x++)
   {
-    for (y = 0; y < real_preview_size_y; y++)
+    for (y = 0; y < real_preview_ysize; y++)
     {
       int lx = from_x + x + (show_level_border ? -1 : 0);
       int ly = from_y + y + (show_level_border ? -1 : 0);
       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
                     getBorderElement(lx, ly));
 
-      DrawPreviewElement(xpos + x * preview_tilesize,
-                        ypos + y * preview_tilesize,
-                        element, preview_tilesize);
+      DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
+                        element, tile_size);
     }
   }
 
@@ -1615,8 +1712,24 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 #define MICROLABEL_IMPORTED_BY_HEAD    6
 #define MICROLABEL_IMPORTED_BY         7
 
-static void DrawMicroLevelLabelExt(int mode)
+static int getMaxTextLength(struct MenuPosInfo *pos, int font_nr)
 {
+  int max_text_width = SXSIZE;
+  int font_width = getFontWidth(font_nr);
+
+  if (pos->align == ALIGN_CENTER)
+    max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
+  else if (pos->align == ALIGN_RIGHT)
+    max_text_width = pos->x;
+  else
+    max_text_width = SXSIZE - pos->x;
+
+  return max_text_width / font_width;
+}
+
+static void DrawPreviewLevelLabelExt(int mode)
+{
+  struct MenuPosInfo *pos = &menu.main.text.level_info_2;
   char label_text[MAX_OUTPUT_LINESIZE + 1];
   int max_len_label_text;
   int font_nr = FONT_TEXT_2;
@@ -1627,7 +1740,11 @@ static void DrawMicroLevelLabelExt(int mode)
       mode == MICROLABEL_IMPORTED_BY_HEAD)
     font_nr = FONT_TEXT_3;
 
+#if 1
+  max_len_label_text = getMaxTextLength(pos, font_nr);
+#else
   max_len_label_text = SXSIZE / getFontWidth(font_nr);
+#endif
 
   for (i = 0; i < max_len_label_text; i++)
     label_text[i] = ' ';
@@ -1635,10 +1752,14 @@ static void DrawMicroLevelLabelExt(int mode)
 
   if (strlen(label_text) > 0)
   {
+#if 1
+    DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
+#else
     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
     int lypos = MICROLABEL2_YPOS;
 
     DrawText(lxpos, lypos, label_text, font_nr);
+#endif
   }
 
   strncpy(label_text,
@@ -1654,42 +1775,56 @@ static void DrawMicroLevelLabelExt(int mode)
 
   if (strlen(label_text) > 0)
   {
+#if 1
+    DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
+#else
     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
     int lypos = MICROLABEL2_YPOS;
 
     DrawText(lxpos, lypos, label_text, font_nr);
+#endif
   }
 
   redraw_mask |= REDRAW_MICROLEVEL;
 }
 
-void DrawMicroLevel(int xpos, int ypos, boolean restart)
+void DrawPreviewLevel(boolean restart)
 {
   static unsigned long scroll_delay = 0;
   static unsigned long label_delay = 0;
   static int from_x, from_y, scroll_direction;
   static int label_state, label_counter;
-  int delay_factor = preview_tilesize / MICRO_TILESIZE;
-  unsigned long scroll_delay_value = MICROLEVEL_SCROLL_DELAY * delay_factor;
+  unsigned long scroll_delay_value = preview.step_delay;
   boolean show_level_border = (BorderElement != EL_EMPTY);
-  int level_size_x = lev_fieldx + (show_level_border ? 2 : 0);
-  int level_size_y = lev_fieldy + (show_level_border ? 2 : 0);
-  int preview_size_x = MICROLEVEL_XSIZE / preview_tilesize;
-  int preview_size_y = MICROLEVEL_YSIZE / preview_tilesize;
-  int last_game_status = game_status;  /* save current game status */
+  int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
+  int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
+  int last_game_status = game_status;          /* save current game status */
 
   /* force PREVIEW font on preview level */
   game_status = GAME_MODE_PSEUDO_PREVIEW;
 
   if (restart)
   {
-    from_x = from_y = 0;
+    from_x = 0;
+    from_y = 0;
+
+    if (preview.anim_mode == ANIM_CENTERED)
+    {
+      if (level_xsize > preview.xsize)
+       from_x = (level_xsize - preview.xsize) / 2;
+      if (level_ysize > preview.ysize)
+       from_y = (level_ysize - preview.ysize) / 2;
+    }
+
+    from_x += preview.xoffset;
+    from_y += preview.yoffset;
+
     scroll_direction = MV_RIGHT;
     label_state = 1;
     label_counter = 0;
 
-    DrawMicroLevelExt(xpos, ypos, from_x, from_y);
-    DrawMicroLevelLabelExt(label_state);
+    DrawPreviewLevelExt(from_x, from_y);
+    DrawPreviewLevelLabelExt(label_state);
 
     /* initialize delay counters */
     DelayReached(&scroll_delay, 0);
@@ -1697,18 +1832,30 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
 
     if (leveldir_current->name)
     {
+      struct MenuPosInfo *pos = &menu.main.text.level_info_1;
       char label_text[MAX_OUTPUT_LINESIZE + 1];
       int font_nr = FONT_TEXT_1;
+#if 1
+      int max_len_label_text = getMaxTextLength(pos, font_nr);
+#else
       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
+#endif
+#if 0
+      int text_width;
       int lxpos, lypos;
+#endif
 
       strncpy(label_text, leveldir_current->name, max_len_label_text);
       label_text[max_len_label_text] = '\0';
 
+#if 1
+      DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
+#else
       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
       lypos = SY + MICROLABEL1_YPOS;
 
       DrawText(lxpos, lypos, label_text, font_nr);
+#endif
     }
 
     game_status = last_game_status;    /* restore current game status */
@@ -1716,36 +1863,51 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
     return;
   }
 
-  /* scroll micro level, if needed */
-  if ((level_size_x > preview_size_x || level_size_y > preview_size_y) &&
+  /* scroll preview level, if needed */
+  if (preview.anim_mode != ANIM_NONE &&
+      (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
       DelayReached(&scroll_delay, scroll_delay_value))
   {
     switch (scroll_direction)
     {
       case MV_LEFT:
        if (from_x > 0)
-         from_x--;
+       {
+         from_x -= preview.step_offset;
+         from_x = (from_x < 0 ? 0 : from_x);
+       }
        else
          scroll_direction = MV_UP;
        break;
 
       case MV_RIGHT:
-       if (from_x < level_size_x - preview_size_x)
-         from_x++;
+       if (from_x < level_xsize - preview.xsize)
+       {
+         from_x += preview.step_offset;
+         from_x = (from_x > level_xsize - preview.xsize ?
+                   level_xsize - preview.xsize : from_x);
+       }
        else
          scroll_direction = MV_DOWN;
        break;
 
       case MV_UP:
        if (from_y > 0)
-         from_y--;
+       {
+         from_y -= preview.step_offset;
+         from_y = (from_y < 0 ? 0 : from_y);
+       }
        else
          scroll_direction = MV_RIGHT;
        break;
 
       case MV_DOWN:
-       if (from_y < level_size_y - preview_size_y)
-         from_y++;
+       if (from_y < level_ysize - preview.ysize)
+       {
+         from_y += preview.step_offset;
+         from_y = (from_y > level_ysize - preview.ysize ?
+                   level_ysize - preview.ysize : from_y);
+       }
        else
          scroll_direction = MV_LEFT;
        break;
@@ -1754,7 +1916,7 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
        break;
     }
 
-    DrawMicroLevelExt(xpos, ypos, from_x, from_y);
+    DrawPreviewLevelExt(from_x, from_y);
   }
 
   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
@@ -1795,7 +1957,7 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
                     MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
 
-    DrawMicroLevelLabelExt(label_state);
+    DrawPreviewLevelLabelExt(label_state);
   }
 
   game_status = last_game_status;      /* restore current game status */
@@ -1952,12 +2114,10 @@ void DrawPlayer(struct PlayerInfo *player)
   int last_player_frame = player->Frame;
   int frame = 0;
 
-#if 1
   /* GfxElement[][] is set to the element the player is digging or collecting;
      remove also for off-screen player if the player is not moving anymore */
   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
     GfxElement[jx][jy] = EL_UNDEFINED;
-#endif
 
   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
     return;
@@ -1983,10 +2143,8 @@ void DrawPlayer(struct PlayerInfo *player)
            player->is_dropping   ? ACTION_DROPPING        :
            player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
 
-#if 1
   if (player->is_waiting)
     move_dir = player->dir_waiting;
-#endif
 
   InitPlayerGfxAnimation(player, action, move_dir);
 
@@ -2062,8 +2220,15 @@ void DrawPlayer(struct PlayerInfo *player)
       GfxElement[jx][jy] = EL_UNDEFINED;
 
       /* make sure that pushed elements are drawn with correct frame rate */
+#if 1
+      graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
+
+      if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
+       GfxFrame[jx][jy] = player->StepFrame;
+#else
       if (player->is_pushing && player->is_moving)
        GfxFrame[jx][jy] = player->StepFrame;
+#endif
 
       DrawLevelField(jx, jy);
     }
@@ -2123,15 +2288,26 @@ void DrawPlayer(struct PlayerInfo *player)
     int px = SCREENX(jx), py = SCREENY(jy);
     int pxx = (TILEX - ABS(sxx)) * dx;
     int pyy = (TILEY - ABS(syy)) * dy;
+    int gfx_frame = GfxFrame[jx][jy];
 
     int graphic;
+    int sync_frame;
     int frame;
 
     if (!IS_MOVING(jx, jy))            /* push movement already finished */
+    {
       element = Feld[next_jx][next_jy];
+      gfx_frame = GfxFrame[next_jx][next_jy];
+    }
 
     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
+
+#if 1
+    sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
+    frame = getGraphicAnimationFrame(graphic, sync_frame);
+#else
     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
+#endif
 
     /* draw background element under pushed element (like the Sokoban field) */
     if (Back[next_jx][next_jy])
@@ -2220,6 +2396,10 @@ void WaitForEventToContinue()
 
   button_status = MB_RELEASED;
 
+#if 1
+  ClearEventQueue();
+#endif
+
   while (still_wait)
   {
     if (PendingEvent())
@@ -2319,6 +2499,10 @@ boolean Request(char *text, unsigned int req_state)
               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
   }
 
+#if 1
+  SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
+#endif
+
   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
 
   /* clear door drawing field */
@@ -2388,7 +2572,15 @@ boolean Request(char *text, unsigned int req_state)
 
   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
   {
-    SetDrawBackgroundMask(REDRAW_FIELD);
+    if (game_status == GAME_MODE_PLAYING)
+    {
+      SetPanelBackground();
+      SetDrawBackgroundMask(REDRAW_DOOR_1);
+    }
+    else
+    {
+      SetDrawBackgroundMask(REDRAW_FIELD);
+    }
 
     return FALSE;
   }
@@ -2513,8 +2705,13 @@ boolean Request(char *text, unsigned int req_state)
 
     DoAnimation();
 
+#if 1
+    if (!PendingEvent())       /* delay only if no pending events */
+      Delay(10);
+#else
     /* don't eat all CPU time */
     Delay(10);
+#endif
   }
 
   if (game_status != GAME_MODE_MAIN)
@@ -2533,7 +2730,15 @@ boolean Request(char *text, unsigned int req_state)
 
   RemapAllGadgets();
 
-  SetDrawBackgroundMask(REDRAW_FIELD);
+  if (game_status == GAME_MODE_PLAYING)
+  {
+    SetPanelBackground();
+    SetDrawBackgroundMask(REDRAW_DOOR_1);
+  }
+  else
+  {
+    SetDrawBackgroundMask(REDRAW_FIELD);
+  }
 
 #if defined(NETWORK_AVALIABLE)
   /* continue network game after request */
@@ -2672,17 +2877,8 @@ unsigned int MoveDoor(unsigned int door_state)
     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
     int door_skip = max_door_size - door_size;
-#if 1
     int end = door_size;
-#else
-    int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
-              DYSIZE : DXSIZE);
-#endif
-#if 1
     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
-#else
-    int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
-#endif
     int k;
 
     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
@@ -2794,15 +2990,9 @@ unsigned int MoveDoor(unsigned int door_state)
 
       if (door_state & DOOR_ACTION_2)
       {
-#if 1
        int a = MIN(x * door_2.step_offset, door_size);
        int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
        int i = p + door_skip;
-#else
-       int a = MIN(x * door_2.step_offset, door_size_2);
-       int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
-       int i = p + door_skip;
-#endif
 
        if (door_2.anim_mode & ANIM_STATIC_PANEL)
        {
@@ -3071,6 +3261,7 @@ void CreateToolButtons()
                      GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
                      GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
                      GDI_DECORATION_SHIFTING, 1, 1,
+                     GDI_DIRECT_DRAW, FALSE,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_ACTION, HandleToolButtons,
                      GDI_END);
@@ -5262,37 +5453,6 @@ int font2baseimg(int font_nr)
   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
 }
 
-#if 0
-void setCenteredPlayerNr_EM(int centered_player_nr)
-{
-  game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
-}
-
-int getCenteredPlayerNr_EM()
-{
-#if 0
-  if (game.centered_player_nr_next >= 0 &&
-      !native_em_level.ply[game.centered_player_nr_next]->alive)
-    game.centered_player_nr_next = game.centered_player_nr;
-#endif
-
-  if (game.centered_player_nr != game.centered_player_nr_next)
-    game.centered_player_nr = game.centered_player_nr_next;
-
-  return game.centered_player_nr;
-}
-
-void setSetCenteredPlayer_EM(boolean set_centered_player)
-{
-  game.set_centered_player = set_centered_player;
-}
-
-boolean getSetCenteredPlayer_EM()
-{
-  return game.set_centered_player;
-}
-#endif
-
 int getNumActivePlayers_EM()
 {
   int num_players = 0;
@@ -5308,7 +5468,6 @@ int getNumActivePlayers_EM()
   return num_players;
 }
 
-#if 1
 int getGameFrameDelay_EM(int native_em_game_frame_delay)
 {
   int game_frame_delay_value;
@@ -5323,14 +5482,13 @@ int getGameFrameDelay_EM(int native_em_game_frame_delay)
 
   return game_frame_delay_value;
 }
-#endif
 
 unsigned int InitRND(long seed)
 {
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
-    return InitEngineRND_EM(seed);
+    return InitEngineRandom_EM(seed);
   else
-    return InitEngineRND(seed);
+    return InitEngineRandom_RND(seed);
 }
 
 void InitGraphicInfo_EM(void)
@@ -5728,7 +5886,6 @@ void InitGraphicInfo_EM(void)
        g_em->height = TILEY - cy * step;
       }
 
-#if 1
       /* create unique graphic identifier to decide if tile must be redrawn */
       /* bit 31 - 16 (16 bit): EM style graphic
         bit 15 - 12 ( 4 bit): EM style frame
@@ -5736,29 +5893,12 @@ void InitGraphicInfo_EM(void)
         bit  5 -  0 ( 6 bit): graphic height */
       g_em->unique_identifier =
        (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
-#else
-      /* create unique graphic identifier to decide if tile must be redrawn */
-      /* bit 31 - 16 (16 bit): EM style element
-        bit 15 - 12 ( 4 bit): EM style frame
-        bit 11 -  6 ( 6 bit): graphic width
-        bit  5 -  0 ( 6 bit): graphic height */
-      g_em->unique_identifier =
-       (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
-#endif
-
-#if 0
-      if (effective_element == EL_ROCK)
-       printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
-              effective_action, j, graphic, frame, g_em->unique_identifier);
-#endif
 
 #if DEBUG_EM_GFX
 
-#if 1
       /* skip check for EMC elements not contained in original EMC artwork */
       if (element == EL_EMC_FAKE_ACID)
        continue;
-#endif
 
       if (g_em->bitmap != debug_bitmap ||
          g_em->src_x != debug_src_x ||
@@ -5832,13 +5972,8 @@ void InitGraphicInfo_EM(void)
       int action = object_mapping[i].action;
       int direction = object_mapping[i].direction;
       boolean is_backside = object_mapping[i].is_backside;
-#if 1
       int graphic_action  = el_act_dir2img(element, action, direction);
       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
-#else
-      int graphic_action  = element_info[element].graphic[action];
-      int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
-#endif
 
       if ((action == ACTION_SMASHED_BY_ROCK ||
           action == ACTION_SMASHED_BY_SPRING ||
@@ -5864,9 +5999,7 @@ void InitGraphicInfo_EM(void)
        g_em->dst_offset_y      = g_xx->dst_offset_y;
        g_em->width             = g_xx->width;
        g_em->height            = g_xx->height;
-#if 1
        g_em->unique_identifier = g_xx->unique_identifier;
-#endif
 
        if (!is_backside)
          g_em->preserve_background = TRUE;
@@ -5922,12 +6055,10 @@ void InitGraphicInfo_EM(void)
 
 #if DEBUG_EM_GFX
 
-#if 1
        /* skip check for EMC elements not contained in original EMC artwork */
        if (element == EL_PLAYER_3 ||
            element == EL_PLAYER_4)
          continue;
-#endif
 
        if (g_em->bitmap != debug_bitmap ||
            g_em->src_x != debug_src_x ||
@@ -6040,23 +6171,45 @@ void PlayMenuMusic()
 
 void ToggleFullscreenIfNeeded()
 {
+  boolean change_fullscreen = (setup.fullscreen !=
+                              video.fullscreen_enabled);
+  boolean change_fullscreen_mode = (video.fullscreen_enabled &&
+                                   !strEqual(setup.fullscreen_mode,
+                                             video.fullscreen_mode_current));
+
+  if (!video.fullscreen_available)
+    return;
+
+#if 1
+  if (change_fullscreen || change_fullscreen_mode)
+#else
   if (setup.fullscreen != video.fullscreen_enabled ||
       setup.fullscreen_mode != video.fullscreen_mode_current)
+#endif
   {
     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
 
     /* save backbuffer content which gets lost when toggling fullscreen mode */
     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
+#if 1
+    if (change_fullscreen_mode)
+#else
     if (setup.fullscreen && video.fullscreen_enabled)
+#endif
     {
-      /* keep fullscreen mode, but change screen mode */
+      /* keep fullscreen, but change fullscreen mode (screen resolution) */
+#if 1
+      /* (this is now set in sdl.c) */
+#else
       video.fullscreen_mode_current = setup.fullscreen_mode;
-      video.fullscreen_enabled = FALSE;
+#endif
+      video.fullscreen_enabled = FALSE;                /* force new fullscreen mode */
     }
 
     /* toggle fullscreen */
     ChangeVideoModeIfNeeded(setup.fullscreen);
+
     setup.fullscreen = video.fullscreen_enabled;
 
     /* restore backbuffer content from temporary backbuffer backup bitmap */
@@ -6064,6 +6217,11 @@ void ToggleFullscreenIfNeeded()
 
     FreeBitmap(tmp_backbuffer);
 
+#if 1
+    /* update visible window/screen */
+    BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+#else
     redraw_mask = REDRAW_ALL;
+#endif
   }
 }