fixed drawing of crumbled borders for 64x64 sized game graphics
[rocksndiamonds.git] / src / tools.c
index d7c3968842a6575759d2c90aa185997735932716..68a81be9036294e7c17d4d62d7e08fd6d2f0a908 100644 (file)
@@ -17,7 +17,7 @@
 #include "init.h"
 #include "game.h"
 #include "events.h"
-#include "cartoons.h"
+#include "anim.h"
 #include "network.h"
 #include "tape.h"
 #include "screens.h"
@@ -234,7 +234,7 @@ void DumpTile(int x, int y)
 
 void SetDrawtoField(int mode)
 {
-  if (mode == DRAW_FIELDBUFFER)
+  if (mode == DRAW_TO_FIELDBUFFER)
   {
     FX = 2 * TILEX_VAR;
     FY = 2 * TILEY_VAR;
@@ -245,7 +245,7 @@ void SetDrawtoField(int mode)
 
     drawto_field = fieldbuffer;
   }
-  else /* DRAW_BACKBUFFER */
+  else /* DRAW_TO_BACKBUFFER */
   {
     FX = SX;
     FY = SY;
@@ -294,7 +294,7 @@ static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
   if (x == -1 && y == -1)
     return;
 
-  if (draw_target == DRAW_BORDER_TO_SCREEN)
+  if (draw_target == DRAW_TO_SCREEN)
     BlitToScreenMasked(src_bitmap, x, y, width, height, x, y);
   else
     BlitBitmapMasked(src_bitmap, dst_bitmap, x, y, width, height, x, y);
@@ -312,7 +312,7 @@ static void DrawMaskedBorderExt_FIELD(int draw_target)
 static void DrawMaskedBorderExt_DOOR_1(int draw_target)
 {
   // when drawing to backbuffer, never draw border over open doors
-  if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
+  if (draw_target == DRAW_TO_BACKBUFFER &&
       (GetDoorState() & DOOR_OPEN_1))
     return;
 
@@ -325,7 +325,7 @@ static void DrawMaskedBorderExt_DOOR_1(int draw_target)
 static void DrawMaskedBorderExt_DOOR_2(int draw_target)
 {
   // when drawing to backbuffer, never draw border over open doors
-  if (draw_target == DRAW_BORDER_TO_BACKBUFFER &&
+  if (draw_target == DRAW_TO_BACKBUFFER &&
       (GetDoorState() & DOOR_OPEN_2))
     return;
 
@@ -371,18 +371,18 @@ static void DrawMaskedBorderExt(int redraw_mask, int draw_target)
 
 void DrawMaskedBorder_FIELD()
 {
-  DrawMaskedBorderExt_FIELD(DRAW_BORDER_TO_BACKBUFFER);
+  DrawMaskedBorderExt_FIELD(DRAW_TO_BACKBUFFER);
 }
 
 void DrawMaskedBorder(int redraw_mask)
 {
-  DrawMaskedBorderExt(redraw_mask, DRAW_BORDER_TO_BACKBUFFER);
+  DrawMaskedBorderExt(redraw_mask, DRAW_TO_BACKBUFFER);
 }
 
 void DrawMaskedBorderToTarget(int draw_target)
 {
-  if (draw_target == DRAW_BORDER_TO_BACKBUFFER ||
-      draw_target == DRAW_BORDER_TO_SCREEN)
+  if (draw_target == DRAW_TO_BACKBUFFER ||
+      draw_target == DRAW_TO_SCREEN)
   {
     DrawMaskedBorderExt(REDRAW_ALL, draw_target);
   }
@@ -390,12 +390,12 @@ void DrawMaskedBorderToTarget(int draw_target)
   {
     int last_border_status = global.border_status;
 
-    if (draw_target == DRAW_BORDER_TO_FADE_SOURCE)
+    if (draw_target == DRAW_TO_FADE_SOURCE)
     {
       global.border_status = gfx.fade_border_source_status;
       gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_source;
     }
-    else if (draw_target == DRAW_BORDER_TO_FADE_TARGET)
+    else if (draw_target == DRAW_TO_FADE_TARGET)
     {
       global.border_status = gfx.fade_border_target_status;
       gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
@@ -528,6 +528,22 @@ static void PrintFrameTimeDebugging()
 }
 #endif
 
+static int unifiedRedrawMask(int mask)
+{
+  if (mask & REDRAW_ALL)
+    return REDRAW_ALL;
+
+  if (mask & REDRAW_FIELD && mask & REDRAW_DOORS)
+    return REDRAW_ALL;
+
+  return mask;
+}
+
+static boolean equalRedrawMasks(int mask_1, int mask_2)
+{
+  return unifiedRedrawMask(mask_1) == unifiedRedrawMask(mask_2);
+}
+
 void BackToFront()
 {
   static int last_redraw_mask = REDRAW_NONE;
@@ -550,6 +566,10 @@ void BackToFront()
   if (redraw_mask & REDRAW_FPS)
     DrawFramesPerSecond();
 
+  // remove playfield redraw before potentially merging with doors redraw
+  if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
+    redraw_mask &= ~REDRAW_FIELD;
+
   // redraw complete window if both playfield and (some) doors need redraw
   if (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS)
     redraw_mask = REDRAW_ALL;
@@ -570,14 +590,37 @@ void BackToFront()
   }
   else if (redraw_mask & REDRAW_DOORS)
   {
+    // merge door areas to prevent calling screen redraw more than once
+    int x1 = WIN_XSIZE;
+    int y1 = WIN_YSIZE;
+    int x2 = 0;
+    int y2 = 0;
+
     if (redraw_mask & REDRAW_DOOR_1)
-      BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
+    {
+      x1 = MIN(x1, DX);
+      y1 = MIN(y1, DY);
+      x2 = MAX(x2, DX + DXSIZE);
+      y2 = MAX(y2, DY + DYSIZE);
+    }
 
     if (redraw_mask & REDRAW_DOOR_2)
-      BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
+    {
+      x1 = MIN(x1, VX);
+      y1 = MIN(y1, VY);
+      x2 = MAX(x2, VX + VXSIZE);
+      y2 = MAX(y2, VY + VYSIZE);
+    }
 
     if (redraw_mask & REDRAW_DOOR_3)
-      BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
+    {
+      x1 = MIN(x1, EX);
+      y1 = MIN(y1, EY);
+      x2 = MAX(x2, EX + EXSIZE);
+      y2 = MAX(y2, EY + EYSIZE);
+    }
+
+    BlitBitmap(backbuffer, window, x1, y1, x2 - x1, y2 - y1, x1, y1);
   }
 
   redraw_mask = REDRAW_NONE;
@@ -598,26 +641,11 @@ void BackToFront_WithFrameDelay(unsigned int frame_delay_value)
   SetVideoFrameDelay(frame_delay_value_old);
 }
 
-static void FadeCrossSaveBackbuffer()
-{
-  BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-}
-
-static void FadeCrossRestoreBackbuffer()
-{
-  int redraw_mask_last = redraw_mask;
-
-  BlitBitmap(bitmap_db_cross, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-
-  // do not change redraw mask when restoring backbuffer after cross-fading
-  redraw_mask = redraw_mask_last;
-}
+static int fade_type_skip = FADE_TYPE_NONE;
 
 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
 {
-  static int fade_type_skip = FADE_TYPE_NONE;
   void (*draw_border_function)(void) = NULL;
-  Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
   int x, y, width, height;
   int fade_delay, post_delay;
 
@@ -632,18 +660,8 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type)
       return;
     }
 
-#if 1
-    FadeCrossSaveBackbuffer();
-#endif
-
     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
-    {
-#if 0
-      FadeCrossSaveBackbuffer();
-#endif
-
       return;
-    }
   }
 
   redraw_mask |= fade_mask;
@@ -706,17 +724,23 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type)
     return;
   }
 
-  FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
+  FadeRectangle(x, y, width, height, fade_mode, fade_delay, post_delay,
                draw_border_function);
 
-  if (fade_type == FADE_TYPE_FADE_OUT)
-    FadeCrossRestoreBackbuffer();
-
   redraw_mask &= ~fade_mask;
 }
 
 static void SetScreenStates_BeforeFadingIn()
 {
+  // temporarily set screen mode for animations to screen after fading in
+  global.anim_status = global.anim_status_next;
+
+  // store backbuffer with all animations that will be started after fading in
+  if (fade_type_skip != FADE_MODE_SKIP_FADE_IN)
+    PrepareFadeBitmap(DRAW_TO_FADE_TARGET);
+
+  // set screen mode for animations back to fading
+  global.anim_status = GAME_MODE_PSEUDO_FADING;
 }
 
 static void SetScreenStates_AfterFadingIn()
@@ -725,10 +749,6 @@ static void SetScreenStates_AfterFadingIn()
   gfx.fade_border_source_status = global.border_status;
 
   global.anim_status = global.anim_status_next;
-
-  // force update of global animation status in case of rapid screen changes
-  redraw_mask = REDRAW_ALL;
-  BackToFront();
 }
 
 static void SetScreenStates_BeforeFadingOut()
@@ -736,7 +756,12 @@ static void SetScreenStates_BeforeFadingOut()
   // store new target screen (to use correct masked border for fading)
   gfx.fade_border_target_status = game_status;
 
+  // set screen mode for animations to fading
   global.anim_status = GAME_MODE_PSEUDO_FADING;
+
+  // store backbuffer with all animations that will be stopped for fading out
+  if (fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
+    PrepareFadeBitmap(DRAW_TO_FADE_SOURCE);
 }
 
 static void SetScreenStates_AfterFadingOut()
@@ -763,10 +788,18 @@ void FadeIn(int fade_mask)
   FADE_SYSIZE = FULL_SYSIZE;
 
   SetScreenStates_AfterFadingIn();
+
+  // force update of global animation status in case of rapid screen changes
+  redraw_mask = REDRAW_ALL;
+  BackToFront();
 }
 
 void FadeOut(int fade_mask)
 {
+  // update screen if areas covered by "fade_mask" and "redraw_mask" differ
+  if (!equalRedrawMasks(fade_mask, redraw_mask))
+    BackToFront();
+
   SetScreenStates_BeforeFadingOut();
 
 #if 0
@@ -1041,7 +1074,7 @@ static void RedrawGlobalBorderIfNeeded()
 
   // copy current draw buffer to later copy back areas that have not changed
   if (game_status_last != GAME_MODE_TITLE)
-    BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+    BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
   if (CheckIfGlobalBorderRedrawIsNeeded())
   {
@@ -1054,20 +1087,20 @@ static void RedrawGlobalBorderIfNeeded()
     if (real_sx_last != -1 && real_sy_last != -1 &&
        REAL_SX != -1 && REAL_SY != -1 &&
        full_sxsize_last == FULL_SXSIZE && full_sysize_last == FULL_SYSIZE)
-      BlitBitmap(bitmap_db_store, backbuffer,
+      BlitBitmap(bitmap_db_store_1, backbuffer,
                 real_sx_last, real_sy_last, FULL_SXSIZE, FULL_SYSIZE,
                 REAL_SX, REAL_SY);
 
     if (dx_last != -1 && dy_last != -1 &&
        DX != -1 && DY != -1 &&
        dxsize_last == DXSIZE && dysize_last == DYSIZE)
-      BlitBitmap(bitmap_db_store, backbuffer,
+      BlitBitmap(bitmap_db_store_1, backbuffer,
                 dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
 
     if (vx_last != -1 && vy_last != -1 &&
        VX != -1 && VY != -1 &&
        vxsize_last == VXSIZE && vysize_last == VYSIZE)
-      BlitBitmap(bitmap_db_store, backbuffer,
+      BlitBitmap(bitmap_db_store_1, backbuffer,
                 vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
 
     redraw_mask = REDRAW_ALL;
@@ -1103,11 +1136,11 @@ void ClearField()
   if (game_status == GAME_MODE_PLAYING)
   {
     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
-    SetDrawtoField(DRAW_FIELDBUFFER);
+    SetDrawtoField(DRAW_TO_FIELDBUFFER);
   }
   else
   {
-    SetDrawtoField(DRAW_BACKBUFFER);
+    SetDrawtoField(DRAW_TO_BACKBUFFER);
   }
 }
 
@@ -1186,52 +1219,64 @@ int getGraphicAnimationFrame(int graphic, int sync_frame)
                           sync_frame);
 }
 
-void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
-                             Bitmap **bitmap, int *x, int *y,
-                             boolean get_backside)
+void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
 {
   struct GraphicInfo *g = &graphic_info[graphic];
-  Bitmap *src_bitmap = g->bitmap;
-  int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
-  int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
   int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
 
-  // if no in-game graphics defined, always use standard graphic size
-  if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
-    tilesize = TILESIZE;
-
   if (tilesize == gfx.standard_tile_size)
-    src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
+    *bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
   else if (tilesize == game.tile_size)
-    src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
+    *bitmap = g->bitmaps[IMG_BITMAP_GAME];
   else
-    src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
+    *bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
+}
+
+void getGraphicSourceXY(int graphic, int frame, int *x, int *y,
+                       boolean get_backside)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+  int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
+  int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
 
   if (g->offset_y == 0)                /* frames are ordered horizontally */
   {
     int max_width = g->anim_frames_per_line * g->width;
     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
 
-    src_x = pos % max_width;
-    src_y = src_y % g->height + pos / max_width * g->height;
+    *x = pos % max_width;
+    *y = src_y % g->height + pos / max_width * g->height;
   }
   else if (g->offset_x == 0)   /* frames are ordered vertically */
   {
     int max_height = g->anim_frames_per_line * g->height;
     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
 
-    src_x = src_x % g->width + pos / max_height * g->width;
-    src_y = pos % max_height;
+    *x = src_x % g->width + pos / max_height * g->width;
+    *y = pos % max_height;
   }
   else                         /* frames are ordered diagonally */
   {
-    src_x = src_x + frame * g->offset_x;
-    src_y = src_y + frame * g->offset_y;
+    *x = src_x + frame * g->offset_x;
+    *y = src_y + frame * g->offset_y;
   }
+}
 
-  *bitmap = src_bitmap;
-  *x = src_x * tilesize / g->tile_size;
-  *y = src_y * tilesize / g->tile_size;
+void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
+                             Bitmap **bitmap, int *x, int *y,
+                             boolean get_backside)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+
+  // if no in-game graphics defined, always use standard graphic size
+  if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
+    tilesize = TILESIZE;
+
+  getGraphicSourceBitmap(graphic, tilesize, bitmap);
+  getGraphicSourceXY(graphic, frame, x, y, get_backside);
+
+  *x = *x * tilesize / g->tile_size;
+  *y = *y * tilesize / g->tile_size;
 }
 
 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
@@ -1261,40 +1306,8 @@ void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
 inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
                                       int *x, int *y, boolean get_backside)
 {
-  struct GraphicInfo *g = &graphic_info[graphic];
-  int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
-  int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
-
-  if (TILESIZE_VAR != TILESIZE)
-    return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
-                                   get_backside);
-
-  *bitmap = g->bitmap;
-
-  if (g->offset_y == 0)                /* frames are ordered horizontally */
-  {
-    int max_width = g->anim_frames_per_line * g->width;
-    int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
-
-    *x = pos % max_width;
-    *y = src_y % g->height + pos / max_width * g->height;
-  }
-  else if (g->offset_x == 0)   /* frames are ordered vertically */
-  {
-    int max_height = g->anim_frames_per_line * g->height;
-    int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
-
-    *x = src_x % g->width + pos / max_height * g->width;
-    *y = pos % max_height;
-  }
-  else                         /* frames are ordered diagonally */
-  {
-    *x = src_x + frame * g->offset_x;
-    *y = src_y + frame * g->offset_y;
-  }
-
-  *x = *x * TILESIZE_VAR / g->tile_size;
-  *y = *y * TILESIZE_VAR / g->tile_size;
+  getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
+                          get_backside);
 }
 
 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
@@ -1747,6 +1760,9 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
   int width, height, cx, cy;
   int sx = SCREENX(x), sy = SCREENY(y);
   int crumbled_border_size = graphic_info[graphic].border_size;
+  int crumbled_tile_size = graphic_info[graphic].tile_size;
+  int crumbled_border_size_var =
+    crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
   int i;
 
   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
@@ -1774,8 +1790,8 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
 
   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
 
-  width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
-  height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
+  width  = crumbled_border_size_var;
+  height = crumbled_border_size_var;
   cx = (dx > 0 ? TILESIZE_VAR - width  : 0);
   cy = (dy > 0 ? TILESIZE_VAR - height : 0);
 
@@ -1791,7 +1807,9 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
   int width, height, bx, by, cx, cy;
   int sx = SCREENX(x), sy = SCREENY(y);
   int crumbled_border_size = graphic_info[graphic].border_size;
-  int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
+  int crumbled_tile_size = graphic_info[graphic].tile_size;
+  int crumbled_border_size_var =
+    crumbled_border_size * TILESIZE_VAR / crumbled_tile_size;
   int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
   int i;
 
@@ -1810,7 +1828,7 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
 
   /* (remaining middle border part must be at least as big as corner part) */
   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
-      crumbled_border_size >= TILESIZE / 3)
+      crumbled_border_size_var >= TILESIZE_VAR / 3)
     return;
 
   /* correct corners of crumbled border, if needed */
@@ -2300,11 +2318,11 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
     int sy = SY + (SYSIZE - ysize * font_height) / 2;
     int xx, yy;
 
-    SetDrawtoField(DRAW_FIELDBUFFER);
+    SetDrawtoField(DRAW_TO_FIELDBUFFER);
 
     BlitScreenToBitmap(backbuffer);
 
-    SetDrawtoField(DRAW_BACKBUFFER);
+    SetDrawtoField(DRAW_TO_BACKBUFFER);
 
     for (yy = 0; yy < ysize; yy++)
       for (xx = 0; xx < xsize; xx++)
@@ -2361,7 +2379,7 @@ void ShowEnvelope(int envelope_nr)
 
   game.envelope_active = FALSE;
 
-  SetDrawtoField(DRAW_FIELDBUFFER);
+  SetDrawtoField(DRAW_TO_FIELDBUFFER);
 
   redraw_mask |= REDRAW_FIELD;
   BackToFront();
@@ -2515,7 +2533,7 @@ void DrawEnvelopeRequest(char *text)
     RedrawGadget(tool_gadget[i]);
 
   // store readily prepared envelope request for later use when animating
-  BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+  BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
   if (text_door_style)
     free(text_door_style);
@@ -2576,7 +2594,7 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
     setRequestPosition(&src_x, &src_y, FALSE);
     setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
 
-    BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+    BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
     for (yy = 0; yy < 2; yy++)
     {
@@ -2590,10 +2608,10 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
        int yy_size = (yy ? tile_size : ysize_size_top);
 
        if (draw_masked)
-         BlitBitmapMasked(bitmap_db_cross, backbuffer,
+         BlitBitmapMasked(bitmap_db_store_2, backbuffer,
                           src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
        else
-         BlitBitmap(bitmap_db_cross, backbuffer,
+         BlitBitmap(bitmap_db_store_2, backbuffer,
                     src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
       }
     }
@@ -2620,13 +2638,13 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
   if (game_status == GAME_MODE_PLAYING)
     BlitScreenToBitmap(backbuffer);
 
-  SetDrawtoField(DRAW_BACKBUFFER);
+  SetDrawtoField(DRAW_TO_BACKBUFFER);
 
   // SetDrawBackgroundMask(REDRAW_NONE);
 
   if (action == ACTION_OPENING)
   {
-    BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+    BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
     if (req_state & REQ_ASK)
     {
@@ -2673,7 +2691,7 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
   game.envelope_active = FALSE;
 
   if (action == ACTION_CLOSING)
-    BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+    BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
   // SetDrawBackgroundMask(last_draw_background_mask);
 
@@ -2684,7 +2702,7 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
   if (action == ACTION_CLOSING &&
       game_status == GAME_MODE_PLAYING &&
       level.game_engine_type == GAME_ENGINE_TYPE_RND)
-    SetDrawtoField(DRAW_FIELDBUFFER);
+    SetDrawtoField(DRAW_TO_FIELDBUFFER);
 }
 
 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
@@ -3569,16 +3587,16 @@ static int RequestHandleEvents(unsigned int req_state)
   {
     if (level_solved)
     {
-      SetDrawtoField(DRAW_FIELDBUFFER);
+      SetDrawtoField(DRAW_TO_FIELDBUFFER);
 
       HandleGameActions();
 
-      SetDrawtoField(DRAW_BACKBUFFER);
+      SetDrawtoField(DRAW_TO_BACKBUFFER);
 
       if (global.use_envelope_request)
       {
        /* copy current state of request area to middle of playfield area */
-       BlitBitmap(bitmap_db_cross, drawto, sx, sy, width, height, sx, sy);
+       BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
       }
     }
 
@@ -3652,7 +3670,10 @@ static int RequestHandleEvents(unsigned int req_state)
          }
 
          case EVENT_KEYPRESS:
-           switch (GetEventKey((KeyEvent *)&event, TRUE))
+         {
+           Key key = GetEventKey((KeyEvent *)&event, TRUE);
+
+           switch (key)
            {
              case KSYM_space:
                if (req_state & REQ_CONFIRM)
@@ -3674,12 +3695,15 @@ static int RequestHandleEvents(unsigned int req_state)
                break;
 
              default:
+               HandleKeysDebug(key);
                break;
            }
 
            if (req_state & REQ_PLAYER)
              result = 0;
+
            break;
+         }
 
          case EVENT_KEYRELEASE:
            ClearPlayerAction();
@@ -3706,7 +3730,7 @@ static int RequestHandleEvents(unsigned int req_state)
       if (global.use_envelope_request)
       {
        /* copy back current state of pressed buttons inside request area */
-       BlitBitmap(drawto, bitmap_db_cross, sx, sy, width, height, sx, sy);
+       BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
       }
     }
 
@@ -4441,7 +4465,8 @@ unsigned int MoveDoor(unsigned int door_state)
          int sync_frame = kk_door * door_delay_value;
          int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
 
-         getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
+         getFixedGraphicSource(dpc->graphic, frame, &bitmap,
+                               &g_src_x, &g_src_y);
        }
 
        // draw door panel
@@ -7245,6 +7270,7 @@ inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
                     &g_em->crumbled_src_x, &g_em->crumbled_src_y);
 
     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
+    g_em->crumbled_tile_size = graphic_info[crumbled].tile_size;
 
     g_em->has_crumbled_graphics = TRUE;
   }
@@ -7254,6 +7280,7 @@ inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
     g_em->crumbled_src_x = 0;
     g_em->crumbled_src_y = 0;
     g_em->crumbled_border_size = 0;
+    g_em->crumbled_tile_size = 0;
 
     g_em->has_crumbled_graphics = FALSE;
   }
@@ -8013,42 +8040,38 @@ void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
                                boolean any_player_snapping,
                                boolean any_player_dropping)
 {
-  static boolean player_was_waiting = TRUE;
-
   if (frame == 0 && !any_player_dropping)
   {
-    if (!player_was_waiting)
+    if (!local_player->was_waiting)
     {
-      if (!SaveEngineSnapshotToList())
+      if (!CheckSaveEngineSnapshotToList())
        return;
 
-      player_was_waiting = TRUE;
+      local_player->was_waiting = TRUE;
     }
   }
   else if (any_player_moving || any_player_snapping || any_player_dropping)
   {
-    player_was_waiting = FALSE;
+    local_player->was_waiting = FALSE;
   }
 }
 
 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
                                boolean murphy_is_dropping)
 {
-  static boolean player_was_waiting = TRUE;
-
   if (murphy_is_waiting)
   {
-    if (!player_was_waiting)
+    if (!local_player->was_waiting)
     {
-      if (!SaveEngineSnapshotToList())
+      if (!CheckSaveEngineSnapshotToList())
        return;
 
-      player_was_waiting = TRUE;
+      local_player->was_waiting = TRUE;
     }
   }
   else
   {
-    player_was_waiting = FALSE;
+    local_player->was_waiting = FALSE;
   }
 }
 
@@ -8339,7 +8362,7 @@ void ChangeViewportPropertiesIfNeeded()
   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
   boolean init_gfx_buffers = FALSE;
   boolean init_video_buffer = FALSE;
-  boolean init_gadgets_and_toons = FALSE;
+  boolean init_gadgets_and_anims = FALSE;
   boolean init_em_graphics = FALSE;
 
   if (new_win_xsize != WIN_XSIZE ||
@@ -8350,7 +8373,7 @@ void ChangeViewportPropertiesIfNeeded()
 
     init_video_buffer = TRUE;
     init_gfx_buffers = TRUE;
-    init_gadgets_and_toons = TRUE;
+    init_gadgets_and_anims = TRUE;
 
     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
   }
@@ -8465,10 +8488,10 @@ void ChangeViewportPropertiesIfNeeded()
     TILESIZE_VAR = new_tilesize_var;
 
     init_gfx_buffers = TRUE;
-    init_gadgets_and_toons = TRUE;
+    init_gadgets_and_anims = TRUE;
 
     // printf("::: viewports: init_gfx_buffers\n");
-    // printf("::: viewports: init_gadgets_and_toons\n");
+    // printf("::: viewports: init_gadgets_and_anims\n");
   }
 
   if (init_gfx_buffers)
@@ -8495,12 +8518,11 @@ void ChangeViewportPropertiesIfNeeded()
     InitImageTextures();
   }
 
-  if (init_gadgets_and_toons)
+  if (init_gadgets_and_anims)
   {
-    // printf("::: init_gadgets_and_toons\n");
+    // printf("::: init_gadgets_and_anims\n");
 
     InitGadgets();
-    InitToons();
     InitGlobalAnimations();
   }