Merge branch 'master' into global-anims
[rocksndiamonds.git] / src / tools.c
index 0370b1d3ca49c76e01e248b280fc1a1ec4aa6700..17a5cf5ad15e16cc0cf068af1a6949f89c55675a 100644 (file)
@@ -173,6 +173,9 @@ static int el_act2crm(int, int);
 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
 static int request_gadget_id = -1;
 
+static unsigned int sync_frame_delay = 0;
+static unsigned int sync_frame_delay_value = GAME_FRAME_DELAY;
+
 static char *print_if_not_empty(int element)
 {
   static char *s = NULL;
@@ -227,7 +230,7 @@ void DumpTile(int x, int y)
   printf("  CustomValue: %d\n", CustomValue[x][y]);
   printf("  GfxElement:  %d\n", GfxElement[x][y]);
   printf("  GfxAction:   %d\n", GfxAction[x][y]);
-  printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
+  printf("  GfxFrame:    %d [%d]\n", GfxFrame[x][y], FrameCounter);
   printf("\n");
 }
 
@@ -284,71 +287,99 @@ void RedrawPlayfield()
             gfx.sx, gfx.sy);
 }
 
-void DrawMaskedBorder_Rect(int x, int y, int width, int height)
+static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
+                                    boolean blit_to_screen)
 {
   Bitmap *bitmap = getGlobalBorderBitmapFromGameStatus();
 
-  BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
+  if (blit_to_screen)
+    BlitToScreenMasked(bitmap, x, y, width, height, x, y);
+  else
+    BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
 }
 
-void DrawMaskedBorder_FIELD()
+static void DrawMaskedBorderExt_FIELD(boolean blit_to_screen)
 {
   if (global.border_status >= GAME_MODE_TITLE &&
       global.border_status <= GAME_MODE_PLAYING &&
       border.draw_masked[global.border_status])
-    DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+    DrawMaskedBorderExt_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                            blit_to_screen);
 }
 
-void DrawMaskedBorder_DOOR_1()
+static void DrawMaskedBorderExt_DOOR_1(boolean blit_to_screen)
 {
+  // only draw border over closed doors when drawing to backbuffer
+  if (!blit_to_screen && (GetDoorState() & DOOR_OPEN_1))
+    return;
+
   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
       (global.border_status != GAME_MODE_EDITOR ||
        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
-    DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
+    DrawMaskedBorderExt_Rect(DX, DY, DXSIZE, DYSIZE, blit_to_screen);
 }
 
-void DrawMaskedBorder_DOOR_2()
+static void DrawMaskedBorderExt_DOOR_2(boolean blit_to_screen)
 {
+  // only draw border over closed doors when drawing to backbuffer
+  if (!blit_to_screen && (GetDoorState() & DOOR_OPEN_2))
+    return;
+
   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
       global.border_status != GAME_MODE_EDITOR)
-    DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
+    DrawMaskedBorderExt_Rect(VX, VY, VXSIZE, VYSIZE, blit_to_screen);
 }
 
-void DrawMaskedBorder_DOOR_3()
+static void DrawMaskedBorderExt_DOOR_3(boolean blit_to_screen)
 {
   /* currently not available */
 }
 
-void DrawMaskedBorder_ALL()
+static void DrawMaskedBorderExt_ALL(boolean blit_to_screen)
 {
-  DrawMaskedBorder_FIELD();
-  DrawMaskedBorder_DOOR_1();
-  DrawMaskedBorder_DOOR_2();
-  DrawMaskedBorder_DOOR_3();
+  DrawMaskedBorderExt_FIELD(blit_to_screen);
+  DrawMaskedBorderExt_DOOR_1(blit_to_screen);
+  DrawMaskedBorderExt_DOOR_2(blit_to_screen);
+  DrawMaskedBorderExt_DOOR_3(blit_to_screen);
 }
 
-void DrawMaskedBorder(int redraw_mask)
+static void DrawMaskedBorderExt(int redraw_mask, boolean blit_to_screen)
 {
   /* never draw masked screen borders on borderless screens */
-  if (effectiveGameStatus() == GAME_MODE_LOADING ||
-      effectiveGameStatus() == GAME_MODE_TITLE)
+  if (game_status == GAME_MODE_LOADING ||
+      game_status == GAME_MODE_TITLE)
     return;
 
   if (redraw_mask & REDRAW_ALL)
-    DrawMaskedBorder_ALL();
+    DrawMaskedBorderExt_ALL(blit_to_screen);
   else
   {
     if (redraw_mask & REDRAW_FIELD)
-      DrawMaskedBorder_FIELD();
+      DrawMaskedBorderExt_FIELD(blit_to_screen);
     if (redraw_mask & REDRAW_DOOR_1)
-      DrawMaskedBorder_DOOR_1();
+      DrawMaskedBorderExt_DOOR_1(blit_to_screen);
     if (redraw_mask & REDRAW_DOOR_2)
-      DrawMaskedBorder_DOOR_2();
+      DrawMaskedBorderExt_DOOR_2(blit_to_screen);
     if (redraw_mask & REDRAW_DOOR_3)
-      DrawMaskedBorder_DOOR_3();
+      DrawMaskedBorderExt_DOOR_3(blit_to_screen);
   }
 }
 
+void DrawMaskedBorder_FIELD()
+{
+  DrawMaskedBorderExt_FIELD(FALSE);
+}
+
+void DrawMaskedBorder(int redraw_mask)
+{
+  DrawMaskedBorderExt(redraw_mask, FALSE);
+}
+
+void DrawMaskedBorderToScreen(int redraw_mask)
+{
+  DrawMaskedBorderExt(redraw_mask, TRUE);
+}
+
 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
 {
   int fx = FX, fy = FY;
@@ -436,8 +467,12 @@ void BackToFront()
   if (redraw_mask == REDRAW_NONE)
     return;
 
+#if 1
+  // masked border now drawn immediately when blitting backbuffer to window
+#else
   // draw masked border to all viewports, if defined
   DrawMaskedBorder(redraw_mask);
+#endif
 
   // draw frames per second (only if debug mode is enabled)
   if (redraw_mask & REDRAW_FPS)
@@ -595,6 +630,10 @@ static void FadeExt(int fade_mask, int fade_mode, int fade_type)
 
 void FadeIn(int fade_mask)
 {
+#if 1
+  DrawMaskedBorder(REDRAW_ALL);
+#endif
+
   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
   else
@@ -608,6 +647,10 @@ void FadeIn(int fade_mask)
 
 void FadeOut(int fade_mask)
 {
+#if 0
+  DrawMaskedBorder(REDRAW_ALL);
+#endif
+
   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
   else
@@ -649,7 +692,7 @@ void FadeSetEnterScreen()
 
 void FadeSetNextScreen()
 {
-  fading = menu.next_screen;
+  fading = menu.next_screen[game_status];
 
   // (do not overwrite fade mode set by FadeSetEnterScreen)
   // FadeSetLeaveNext(fading, TRUE);   /* (keep same fade mode) */
@@ -826,6 +869,10 @@ boolean CheckIfGlobalBorderRedrawIsNeeded()
   if (game_status == game_status_last)
     return FALSE;
 
+  // redraw if last screen was title screen
+  if (game_status_last == GAME_MODE_TITLE)
+    return TRUE;
+
   // redraw if global screen border has changed
   if (CheckIfGlobalBorderHasChanged())
     return TRUE;
@@ -871,7 +918,8 @@ static void RedrawGlobalBorderIfNeeded()
     return;
 
   // copy current draw buffer to later copy back areas that have not changed
-  BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+  if (game_status_last != GAME_MODE_TITLE)
+    BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
   if (CheckIfGlobalBorderRedrawIsNeeded())
   {
@@ -1060,8 +1108,8 @@ void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
   }
 
   *bitmap = src_bitmap;
-  *x = src_x * tilesize / TILESIZE;
-  *y = src_y * tilesize / TILESIZE;
+  *x = src_x * tilesize / g->tile_size;
+  *y = src_y * tilesize / g->tile_size;
 }
 
 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
@@ -1122,6 +1170,9 @@ inline static void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
     *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;
 }
 
 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
@@ -1231,13 +1282,12 @@ void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
                                 int graphic, int frame)
 {
-  struct GraphicInfo *g = &graphic_info[graphic];
   Bitmap *src_bitmap;
   int src_x, src_y;
 
   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
 
-  BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
+  BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY,
                   dst_x, dst_y);
 }
 
@@ -1298,20 +1348,20 @@ inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
       width = -dx;
       dx = TILEX + dx;
     }
-    else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
+    else if (x == BX1 && dx < 0) /* object leaves playfield to the left */
     {
       width += dx;
       cx = -dx;
       dx = 0;
     }
-    else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
+    else if (x == BX2 && dx > 0) /* object leaves playfield to the right */
       width -= dx;
     else if (dx)               /* general horizontal movement */
       MarkTileDirty(x + SIGN(dx), y);
 
     if (y < BY1)               /* object enters playfield from the top */
     {
-      if (cut_mode==CUT_BELOW) /* object completely above top border */
+      if (cut_mode == CUT_BELOW) /* object completely above top border */
        return;
 
       y = BY1;
@@ -1325,7 +1375,7 @@ inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
       height = -dy;
       dy = TILEY + dy;
     }
-    else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
+    else if (y == BY1 && dy < 0) /* object leaves playfield to the top */
     {
       height += dy;
       cy = -dy;
@@ -2264,6 +2314,7 @@ static void setRequestPosition(int *x, int *y, boolean add_border_size)
 
 void DrawEnvelopeRequest(char *text)
 {
+  int last_game_status = game_status;  /* save current game status */
   char *text_final = text;
   char *text_door_style = NULL;
   int graphic = IMG_BACKGROUND_REQUEST;
@@ -2275,19 +2326,25 @@ void DrawEnvelopeRequest(char *text)
   int border_size = request.border_size;
   int line_spacing = request.line_spacing;
   int line_height = font_height + line_spacing;
-  int text_width = request.width - 2 * border_size;
-  int text_height = request.height - 2 * border_size;
-  int line_length = text_width / font_width;
-  int max_lines = text_height / line_height;
+  int max_text_width  = request.width  - 2 * border_size;
+  int max_text_height = request.height - 2 * border_size;
+  int line_length = max_text_width  / font_width;
+  int max_lines   = max_text_height / line_height;
+  int text_width = line_length * font_width;
   int width = request.width;
   int height = request.height;
-  int tile_size = request.step_offset;
+  int tile_size = MAX(request.step_offset, 1);
   int x_steps = width  / tile_size;
   int y_steps = height / tile_size;
+  int sx_offset = border_size;
+  int sy_offset = border_size;
   int sx, sy;
   int i, x, y;
 
-  if (request.wrap_single_words)
+  if (request.centered)
+    sx_offset = (request.width - text_width) / 2;
+
+  if (request.wrap_single_words && !request.autowrap)
   {
     char *src_text_ptr, *dst_text_ptr;
 
@@ -2324,10 +2381,15 @@ void DrawEnvelopeRequest(char *text)
                                  x, y, x_steps, y_steps,
                                  tile_size, tile_size);
 
-  DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
+  /* force DOOR font inside door area */
+  game_status = GAME_MODE_PSEUDO_DOOR;
+
+  DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
                 line_length, -1, max_lines, line_spacing, mask_mode,
                 request.autowrap, request.centered, FALSE);
 
+  game_status = last_game_status;      /* restore current game status */
+
   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
     RedrawGadget(tool_gadget[i]);
 
@@ -2350,7 +2412,7 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
   int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
   unsigned int anim_delay = 0;
 
-  int tile_size = request.step_offset;
+  int tile_size = MAX(request.step_offset, 1);
   int max_xsize = request.width  / tile_size;
   int max_ysize = request.height / tile_size;
   int max_xsize_inner = max_xsize - 2;
@@ -2372,13 +2434,6 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
     ystart = yend;
     end = 0;
   }
-  else
-  {
-    if (action == ACTION_OPENING)
-      PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
-    else if (action == ACTION_CLOSING)
-      PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
-  }
 
   for (i = start; i <= end; i++)
   {
@@ -2433,7 +2488,6 @@ void AnimateEnvelopeRequest(int anim_mode, int action)
 
 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
 {
-  int last_game_status = game_status;  /* save current game status */
   int graphic = IMG_BACKGROUND_REQUEST;
   int sound_opening = SND_REQUEST_OPENING;
   int sound_closing = SND_REQUEST_CLOSING;
@@ -2477,9 +2531,6 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
       InitAnimation();
   }
 
-  /* force DOOR font inside door area */
-  game_status = GAME_MODE_PSEUDO_DOOR;
-
   game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
 
   if (action == ACTION_OPENING)
@@ -2504,8 +2555,6 @@ void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
 
   game.envelope_active = FALSE;
 
-  game_status = last_game_status;      /* restore current game status */
-
   if (action == ACTION_CLOSING)
   {
     if (game_status != GAME_MODE_MAIN)
@@ -3390,8 +3439,7 @@ void WaitForEventToContinue()
 
     DoAnimation();
 
-    /* don't eat all CPU time */
-    Delay(10);
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 }
 
@@ -3562,12 +3610,11 @@ static int RequestHandleEvents(unsigned int req_state)
     else
     {
       DoAnimation();
-
-      if (!PendingEvent())     /* delay only if no pending events */
-       Delay(10);
     }
 
     BackToFront();
+
+    WaitUntilDelayReached(&sync_frame_delay, sync_frame_delay_value);
   }
 
   return result;
@@ -4431,6 +4478,10 @@ unsigned int MoveDoor(unsigned int door_state)
   if (door_state & DOOR_ACTION_2)
     door2 = door_state & DOOR_ACTION_2;
 
+  // draw masked border over door area
+  DrawMaskedBorder(REDRAW_DOOR_1);
+  DrawMaskedBorder(REDRAW_DOOR_2);
+
   return (door1 | door2);
 }
 
@@ -8132,10 +8183,13 @@ void ChangeViewportPropertiesIfNeeded()
   int gfx_game_mode = game_status;
   int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
                        game_status);
+  struct RectWithBorder *vp_window    = &viewport.window[gfx_game_mode];
   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
-  struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
-  struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
-  struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
+  struct RectWithBorder *vp_door_1    = &viewport.door_1[gfx_game_mode];
+  struct RectWithBorder *vp_door_2    = &viewport.door_2[gfx_game_mode2];
+  struct RectWithBorder *vp_door_3    = &viewport.door_2[GAME_MODE_EDITOR];
+  int new_win_xsize    = vp_window->width;
+  int new_win_ysize    = vp_window->height;
   int border_size      = vp_playfield->border_size;
   int new_sx           = vp_playfield->x + border_size;
   int new_sy           = vp_playfield->y + border_size;
@@ -8171,14 +8225,15 @@ void ChangeViewportPropertiesIfNeeded()
   boolean init_gadgets_and_toons = FALSE;
   boolean init_em_graphics = FALSE;
 
-  if (viewport.window.width  != WIN_XSIZE ||
-      viewport.window.height != WIN_YSIZE)
+  if (new_win_xsize != WIN_XSIZE ||
+      new_win_ysize != WIN_YSIZE)
   {
-    WIN_XSIZE = viewport.window.width;
-    WIN_YSIZE = viewport.window.height;
+    WIN_XSIZE = new_win_xsize;
+    WIN_YSIZE = new_win_ysize;
 
     init_video_buffer = TRUE;
     init_gfx_buffers = TRUE;
+    init_gadgets_and_toons = TRUE;
 
     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
   }
@@ -8320,6 +8375,7 @@ void ChangeViewportPropertiesIfNeeded()
     // printf("::: init_video_buffer\n");
 
     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+    InitImageTextures();
   }
 
   if (init_gadgets_and_toons)
@@ -8328,6 +8384,7 @@ void ChangeViewportPropertiesIfNeeded()
 
     InitGadgets();
     InitToons();
+    InitGlobalAnimations();
   }
 
   if (init_em_graphics)