fixed a lot of bugs when using custom global borders with masked viewports
[rocksndiamonds.git] / src / tools.c
index 1cf7f74305e25fbbc1c382382cff971e76765711..be29c2000989a595b14eef85601b43d28dc07e82 100644 (file)
@@ -286,7 +286,7 @@ void RedrawPlayfield()
 
 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
 {
-  Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
+  Bitmap *bitmap = getGlobalBorderBitmapFromGameStatus();
 
   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
 }
@@ -687,6 +687,39 @@ void FadeSkipNextFadeOut()
   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
 }
 
+Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
+{
+  boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
+
+  return (graphic == IMG_UNDEFINED ? NULL :
+         graphic_info[graphic].bitmap != NULL || redefined ?
+         graphic_info[graphic].bitmap :
+         graphic_info[default_graphic].bitmap);
+}
+
+Bitmap *getBackgroundBitmap(int graphic)
+{
+  return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
+}
+
+Bitmap *getGlobalBorderBitmap(int graphic)
+{
+  return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
+}
+
+Bitmap *getGlobalBorderBitmapFromGameStatus()
+{
+  int graphic =
+    (game_status == GAME_MODE_MAIN ||
+     game_status == GAME_MODE_PSEUDO_TYPENAME  ? IMG_GLOBAL_BORDER_MAIN :
+     game_status == GAME_MODE_SCORES           ? IMG_GLOBAL_BORDER_SCORES :
+     game_status == GAME_MODE_EDITOR           ? IMG_GLOBAL_BORDER_EDITOR :
+     game_status == GAME_MODE_PLAYING          ? IMG_GLOBAL_BORDER_PLAYING :
+     IMG_GLOBAL_BORDER);
+
+  return getGlobalBorderBitmap(graphic);
+}
+
 void SetWindowBackgroundImageIfDefined(int graphic)
 {
   if (graphic_info[graphic].bitmap)
@@ -707,26 +740,17 @@ void SetDoorBackgroundImageIfDefined(int graphic)
 
 void SetWindowBackgroundImage(int graphic)
 {
-  SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
-                           graphic_info[graphic].bitmap ?
-                           graphic_info[graphic].bitmap :
-                           graphic_info[IMG_BACKGROUND].bitmap);
+  SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
 }
 
 void SetMainBackgroundImage(int graphic)
 {
-  SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
-                         graphic_info[graphic].bitmap ?
-                         graphic_info[graphic].bitmap :
-                         graphic_info[IMG_BACKGROUND].bitmap);
+  SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
 }
 
 void SetDoorBackgroundImage(int graphic)
 {
-  SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
-                         graphic_info[graphic].bitmap ?
-                         graphic_info[graphic].bitmap :
-                         graphic_info[IMG_BACKGROUND].bitmap);
+  SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
 }
 
 void SetPanelBackground()
@@ -786,23 +810,12 @@ static int vxsize_last = -1, vysize_last = -1;
 
 boolean CheckIfGlobalBorderHasChanged()
 {
-  int global_border_graphic;
-
   // if game status has not changed, global border has not changed either
   if (game_status == game_status_last)
     return FALSE;
 
-  global_border_graphic =
-    (game_status == GAME_MODE_MAIN ? IMG_GLOBAL_BORDER_MAIN :
-     game_status == GAME_MODE_SCORES ? IMG_GLOBAL_BORDER_SCORES :
-     game_status == GAME_MODE_EDITOR ? IMG_GLOBAL_BORDER_EDITOR :
-     game_status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
-     IMG_GLOBAL_BORDER);
-
-  global_border_bitmap =
-    (graphic_info[global_border_graphic].bitmap ?
-     graphic_info[global_border_graphic].bitmap :
-     graphic_info[IMG_GLOBAL_BORDER].bitmap);
+  // determine and store new global border bitmap for current game status
+  global_border_bitmap = getGlobalBorderBitmapFromGameStatus();
 
   return (global_border_bitmap_last != global_border_bitmap);
 }
@@ -835,6 +848,23 @@ boolean CheckIfGlobalBorderRedrawIsNeeded()
   return FALSE;
 }
 
+void RedrawGlobalBorderFromBitmap(Bitmap *bitmap)
+{
+  if (bitmap)
+    BlitBitmap(bitmap, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+  else
+    ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+}
+
+void RedrawGlobalBorder()
+{
+  Bitmap *bitmap = getGlobalBorderBitmapFromGameStatus();
+
+  RedrawGlobalBorderFromBitmap(bitmap);
+
+  redraw_mask = REDRAW_ALL;
+}
+
 static void RedrawGlobalBorderIfNeeded()
 {
   if (game_status == game_status_last)
@@ -846,12 +876,7 @@ static void RedrawGlobalBorderIfNeeded()
   if (CheckIfGlobalBorderRedrawIsNeeded())
   {
     // redraw global screen border (or clear, if defined to be empty)
-
-    if (global_border_bitmap)
-      BlitBitmap(global_border_bitmap, backbuffer,
-                0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-    else
-      ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+    RedrawGlobalBorderFromBitmap(global_border_bitmap);
 
     // copy previous playfield and door areas, if they are defined on both
     // previous and current screen and if they still have the same size
@@ -3378,7 +3403,6 @@ static int RequestHandleEvents(unsigned int req_state)
 {
   boolean level_solved = (game_status == GAME_MODE_PLAYING &&
                          local_player->LevelSolved_GameEnd);
-  int last_game_status = game_status;  /* save current game status */
   int width  = request.width;
   int height = request.height;
   int sx, sy;
@@ -3543,11 +3567,7 @@ static int RequestHandleEvents(unsigned int req_state)
        Delay(10);
     }
 
-    game_status = GAME_MODE_PSEUDO_DOOR;
-
     BackToFront();
-
-    game_status = last_game_status;    /* restore current game status */
   }
 
   return result;
@@ -4414,6 +4434,29 @@ unsigned int MoveDoor(unsigned int door_state)
   return (door1 | door2);
 }
 
+static boolean useSpecialEditorDoor()
+{
+  int graphic = IMG_GLOBAL_BORDER_EDITOR;
+  boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
+
+  // do not draw special editor door if editor border defined or redefined
+  if (graphic_info[graphic].bitmap != NULL || redefined)
+    return FALSE;
+
+  // do not draw special editor door if global border defined to be empty
+  if (graphic_info[IMG_GLOBAL_BORDER].bitmap == NULL)
+    return FALSE;
+
+  // do not draw special editor door if viewport definitions do not match
+  if (EX != VX ||
+      EY >= VY ||
+      EXSIZE != VXSIZE ||
+      EY + EYSIZE != VY + VYSIZE)
+    return FALSE;
+
+  return TRUE;
+}
+
 void DrawSpecialEditorDoor()
 {
   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
@@ -4425,6 +4468,9 @@ void DrawSpecialEditorDoor()
   int vy = VY - outer_border;
   int exsize = EXSIZE + 2 * outer_border;
 
+  if (!useSpecialEditorDoor())
+    return;
+
   /* draw bigger level editor toolbox window */
   BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
             top_border_width, top_border_height, ex, ey - top_border_height);
@@ -4446,6 +4492,9 @@ void UndrawSpecialEditorDoor()
   int exsize = EXSIZE + 2 * outer_border;
   int eysize = EYSIZE + 2 * outer_border;
 
+  if (!useSpecialEditorDoor())
+    return;
+
   /* draw normal tape recorder window */
   if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
   {