rnd-20140127-1-src
[rocksndiamonds.git] / src / tools.c
index ba0ec81ca5ffe036047f565321ccb0f5793cfe47..6f67e1432953addc1ea27e143c3613ece3b14bb6 100644 (file)
@@ -323,13 +323,6 @@ void BlitScreenToBitmap(Bitmap *target_bitmap)
   fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
 #endif
 
-  /* !!! THIS WORKS !!! */
-
-  printf("::: (%d, %d) [(%d / %d, %d / %d)]\n",
-        scroll_x, scroll_y,
-        SBX_Left, SBX_Right,
-        SBY_Upper, SBY_Lower);
-
   ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
   ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
 
@@ -338,11 +331,11 @@ void BlitScreenToBitmap(Bitmap *target_bitmap)
     if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
       fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
     else
-      fx += (dx > 0 ? TILEX_VAR : 0);
+      fx += (dx_var > 0 ? TILEX_VAR : 0);
   }
   else
   {
-    fx += dx;
+    fx += dx_var;
   }
 
   if (EVEN(SCR_FIELDY))
@@ -350,13 +343,21 @@ void BlitScreenToBitmap(Bitmap *target_bitmap)
     if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
       fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
     else
-      fy += (dy > 0 ? TILEY_VAR : 0);
+      fy += (dy_var > 0 ? TILEY_VAR : 0);
   }
   else
   {
-    fy += dy;
+    fy += dy_var;
   }
 
+#if 0
+  printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
+        scroll_x, scroll_y,
+        SBX_Left, SBX_Right,
+        SBY_Upper, SBY_Lower,
+        fx, fy);
+#endif
+
   if (border.draw_masked[GAME_MODE_PLAYING])
   {
     if (buffer != backbuffer)
@@ -394,12 +395,45 @@ void BackToFront()
   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
     redraw_mask |= REDRAW_FIELD;
 
+#if 0
+  // never redraw single tiles, always redraw the whole field
+  // (redrawing single tiles up to a certain threshold was faster on old,
+  // now legacy graphics, but slows things down on modern graphics now)
+  // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
+  if (redraw_mask & REDRAW_TILES)
+    redraw_mask |= REDRAW_FIELD;
+#endif
+
+#if 0
+  /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+  /* (force full redraw) */
+  if (game_status == GAME_MODE_PLAYING)
+    redraw_mask |= REDRAW_FIELD;
+#endif
+
   if (redraw_mask & REDRAW_FIELD)
     redraw_mask &= ~REDRAW_TILES;
 
   if (redraw_mask == REDRAW_NONE)
     return;
 
+#if 0
+  printf("::: ");
+  if (redraw_mask & REDRAW_ALL)
+    printf("[REDRAW_ALL]");
+  if (redraw_mask & REDRAW_FIELD)
+    printf("[REDRAW_FIELD]");
+  if (redraw_mask & REDRAW_TILES)
+    printf("[REDRAW_TILES]");
+  if (redraw_mask & REDRAW_DOOR_1)
+    printf("[REDRAW_DOOR_1]");
+  if (redraw_mask & REDRAW_DOOR_2)
+    printf("[REDRAW_DOOR_2]");
+  if (redraw_mask & REDRAW_FROM_BACKBUFFER)
+    printf("[REDRAW_FROM_BACKBUFFER]");
+  printf(" [%d]\n", FrameCounter);
+#endif
+
   if (redraw_mask & REDRAW_TILES &&
       game_status == GAME_MODE_PLAYING &&
       border.draw_masked[GAME_MODE_PLAYING])
@@ -596,18 +630,22 @@ void BackToFront()
       int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
 
       int dx = 0, dy = 0;
+      int dx_var = dx * TILESIZE_VAR / TILESIZE;
+      int dy_var = dy * TILESIZE_VAR / TILESIZE;
       int ffx, ffy;
       int fx = FX, fy = FY;
 
-      ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx * TILESIZE_VAR / TILESIZE;
-      ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy * TILESIZE_VAR / TILESIZE;
+      int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
+      int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
+
+      ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
+      ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
 
       if (EVEN(SCR_FIELDX))
       {
        if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
        {
-         fx = fx + dx * TILESIZE_VAR / TILESIZE - MIN(ffx, TILEX_VAR / 2) +
-           TILEX_VAR;
+         fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
 
          if (fx % TILEX_VAR)
            sx -= TILEX_VAR / 2;
@@ -616,7 +654,7 @@ void BackToFront()
        }
        else
        {
-         fx = fx - (dx <= 0 ? TILEX_VAR : 0) + TILEX_VAR;
+         fx += (dx_var > 0 ? TILEX_VAR : 0);
        }
       }
 
@@ -624,8 +662,7 @@ void BackToFront()
       {
        if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
        {
-         fy = fy + dy * TILESIZE_VAR / TILESIZE - MIN(ffy, TILEY_VAR / 2) +
-           TILEY_VAR;
+         fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
 
          if (fy % TILEY_VAR)
            sy -= TILEY_VAR / 2;
@@ -634,12 +671,16 @@ void BackToFront()
        }
        else
        {
-         fy = fy - (dy <= 0 ? TILEY_VAR : 0) + TILEY_VAR;
+         fy += (dy_var > 0 ? TILEY_VAR : 0);
        }
       }
 
-      for (x = 0; x < SCR_FIELDX; x++)
-       for (y = 0 ; y < SCR_FIELDY; y++)
+#if 0
+      printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
+#endif
+
+      for (x = 0; x < scr_fieldx; x++)
+       for (y = 0 ; y < scr_fieldy; y++)
          if (redraw[redraw_x1 + x][redraw_y1 + y])
            BlitBitmap(buffer, window,
                       FX + x * TILEX_VAR, FY + y * TILEY_VAR,
@@ -1046,7 +1087,18 @@ void DrawBackground(int x, int y, int width, int height)
   ClearRectangleOnBackground(backbuffer, x, y, width, height);
 #endif
 
+#if 1
+  /* (this only works for the current arrangement of playfield and panels) */
+  if (x < gfx.dx)
+    redraw_mask |= REDRAW_FIELD;
+  else if (y < gfx.vy)
+    redraw_mask |= REDRAW_DOOR_1;
+  else
+    redraw_mask |= REDRAW_DOOR_2;
+#else
+  /* (this is just wrong (when drawing to one of the two door panel areas)) */
   redraw_mask |= REDRAW_FIELD;
+#endif
 }
 
 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
@@ -2413,12 +2465,12 @@ void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
     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)
+void DrawEnvelopeBackground(int graphic, int startx, int starty,
+                           int x, int y, int xsize, int ysize, int font_nr,
+                           int line_spacing)
 {
   int font_width  = getFontWidth(font_nr);
-  int font_height = getFontHeight(font_nr);
-  int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+  int font_height = getFontHeight(font_nr) + line_spacing;
   Bitmap *src_bitmap;
   int src_x, src_y;
   int dst_x = SX + startx + x * font_width;
@@ -2463,7 +2515,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
-  unsigned long anim_delay = 0;
+  unsigned int anim_delay = 0;
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
@@ -2489,12 +2541,18 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
 
     SetDrawtoField(DRAW_BUFFERED);
 
+#if 1
+    BlitScreenToBitmap(backbuffer);
+#else
     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+#endif
 
     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);
+    for (yy = 0; yy < ysize; yy++)
+      for (xx = 0; xx < xsize; xx++)
+       DrawEnvelopeBackground(graphic, sx,sy, xx,yy, xsize, ysize,
+                              font_nr, 0);
 
 #if 1
     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
@@ -2515,19 +2573,23 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
   }
 }
 
-void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
+void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
 {
-#if 1
+#if 0
   int envelope_nr = 0;
 #endif
+#if 1
+  int graphic = IMG_BACKGROUND_REQUEST;
+#else
   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
+#endif
   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
-  unsigned long anim_delay = 0;
+  unsigned int anim_delay = 0;
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
-  int anim_delay_value = (no_delay ? 0 : frame_delay_value);
+  int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
 #if 1
   int max_word_len = maxWordLengthInString(text);
   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
@@ -2536,11 +2598,13 @@ void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
 #endif
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
+  int line_spacing = 2 * 1;
 #if 1
 
 #if 1
   int max_xsize = DXSIZE / font_width;
-  int max_ysize = DYSIZE / font_height;
+  // int max_ysize = DYSIZE / font_height;
+  int max_ysize = DYSIZE / (font_height + line_spacing);
 #else
   int max_xsize = 7;   /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
   int max_ysize = 13;  /* tools.c: MAX_REQUEST_LINES == 13 */
@@ -2611,7 +2675,8 @@ void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
     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 sy = (SYSIZE - ysize * font_height) / 2;
+    int sy = (SYSIZE - ysize * (font_height + line_spacing)) / 2;
     int xx, yy;
 
 #if 1
@@ -2619,20 +2684,26 @@ void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
 #else
     SetDrawtoField(DRAW_BUFFERED);
 
+#if 1
+    BlitScreenToBitmap(backbuffer);
+#else
     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+#endif
 
     SetDrawtoField(DRAW_BACKBUFFER);
 #endif
 
-    for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
-      DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
+    for (yy = 0; yy < ysize; yy++)
+      for (xx = 0; xx < xsize; xx++)
+       DrawEnvelopeBackground(graphic, sx,sy, xx,yy, xsize, ysize,
+                              font_nr, line_spacing);
 
 #if 1
 
 #if 1
     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
                   text_copy, font_nr, max_xsize,
-                  xsize - 2, ysize - 2, 2, mask_mode,
+                  xsize - 2, ysize - 2, line_spacing, mask_mode,
                   FALSE, TRUE, FALSE);
 #else
     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
@@ -2650,6 +2721,7 @@ void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
 
     /* copy request gadgets to door backbuffer */
 #if 1
+    /*
     if ((ysize - 2) > 13)
       BlitBitmap(bitmap_db_door, drawto,
                 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
@@ -2658,6 +2730,15 @@ void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
                 (ysize - 2 - 13) * font_height,
                 SX + sx + font_width,
                 SY + sy + font_height * (1 + 13));
+    */
+    if ((ysize - 2) > 13)
+      BlitBitmap(bitmap_db_door, drawto,
+                DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
+                DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
+                (xsize - 2) * font_width,
+                (ysize - 2 - 13) * (font_height + line_spacing),
+                SX + sx + font_width,
+                SY + sy + (font_height + line_spacing) * (1 + 13));
 #else
     if ((ysize - 2) > 13)
       BlitBitmap(bitmap_db_door, drawto,
@@ -2735,17 +2816,23 @@ void ShowEnvelope(int envelope_nr)
   BackToFront();
 }
 
-void ShowEnvelopeDoor(char *text, int action)
+void ShowEnvelopeRequest(char *text, int action)
 {
 #if 1
   int last_game_status = game_status;  /* save current game status */
   // int last_draw_background_mask = gfx.draw_background_mask;
-  int envelope_nr = 0;
 #endif
+#if 1
+  int graphic = IMG_BACKGROUND_REQUEST;
+  int sound_opening = SND_REQUEST_OPENING;
+  int sound_closing = SND_REQUEST_CLOSING;
+#else
+  int envelope_nr = 0;
   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];
+#endif
 #if 0
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
@@ -2792,9 +2879,9 @@ void ShowEnvelopeDoor(char *text, int action)
     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
 
     if (anim_mode == ANIM_DEFAULT)
-      AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
+      AnimateEnvelopeRequest(text, ANIM_DEFAULT, ACTION_OPENING);
 
-    AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
+    AnimateEnvelopeRequest(text, main_anim_mode, ACTION_OPENING);
 
 #if 0
     if (tape.playing)
@@ -2808,10 +2895,10 @@ void ShowEnvelopeDoor(char *text, int action)
     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
 
     if (anim_mode != ANIM_NONE)
-      AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
+      AnimateEnvelopeRequest(text, main_anim_mode, ACTION_CLOSING);
 
     if (anim_mode == ANIM_DEFAULT)
-      AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
+      AnimateEnvelopeRequest(text, ANIM_DEFAULT, ACTION_CLOSING);
   }
 
   game.envelope_active = FALSE;
@@ -2897,7 +2984,7 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
   redraw_mask |= REDRAW_FIELD;
 }
 
-static void DrawPreviewLevelExt(int from_x, int from_y)
+static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
 {
   boolean show_level_border = (BorderElement != EL_EMPTY);
   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
@@ -3033,13 +3120,13 @@ static void DrawPreviewLevelLabelExt(int mode)
   redraw_mask |= REDRAW_MICROLEVEL;
 }
 
-void DrawPreviewLevel(boolean restart)
+static void DrawPreviewLevelExt(boolean restart)
 {
-  static unsigned long scroll_delay = 0;
-  static unsigned long label_delay = 0;
+  static unsigned int scroll_delay = 0;
+  static unsigned int label_delay = 0;
   static int from_x, from_y, scroll_direction;
   static int label_state, label_counter;
-  unsigned long scroll_delay_value = preview.step_delay;
+  unsigned int scroll_delay_value = preview.step_delay;
   boolean show_level_border = (BorderElement != EL_EMPTY);
   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
@@ -3070,7 +3157,7 @@ void DrawPreviewLevel(boolean restart)
     label_state = 1;
     label_counter = 0;
 
-    DrawPreviewLevelExt(from_x, from_y);
+    DrawPreviewLevelPlayfieldExt(from_x, from_y);
     DrawPreviewLevelLabelExt(label_state);
 
     /* initialize delay counters */
@@ -3172,7 +3259,7 @@ void DrawPreviewLevel(boolean restart)
        break;
     }
 
-    DrawPreviewLevelExt(from_x, from_y);
+    DrawPreviewLevelPlayfieldExt(from_x, from_y);
   }
 
   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
@@ -3219,6 +3306,16 @@ void DrawPreviewLevel(boolean restart)
   game_status = last_game_status;      /* restore current game status */
 }
 
+void DrawPreviewLevelInitial()
+{
+  DrawPreviewLevelExt(TRUE);
+}
+
+void DrawPreviewLevelAnimation()
+{
+  DrawPreviewLevelExt(FALSE);
+}
+
 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
                                    int graphic, int sync_frame, int mask_mode)
 {
@@ -3816,8 +3913,8 @@ boolean Request(char *text, unsigned int req_state)
   char *text_ptr;
   int i;
 
-#if 1
-  global.use_envelope_request = 0;
+#if 0
+  global.use_envelope_request = 1;
 #endif
 
 #if 1
@@ -3978,7 +4075,7 @@ boolean Request(char *text, unsigned int req_state)
 #if 1
   if (global.use_envelope_request)
   {
-    ShowEnvelopeDoor(text, ACTION_OPENING);
+    ShowEnvelopeRequest(text, ACTION_OPENING);
 
     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
     {
@@ -4120,6 +4217,9 @@ boolean Request(char *text, unsigned int req_state)
              break;
 
            case KSYM_Escape:
+#if defined(TARGET_SDL2)
+           case KSYM_Back:
+#endif
              result = 0;
              break;
 
@@ -4196,7 +4296,7 @@ boolean Request(char *text, unsigned int req_state)
 
 #if 1
   if (global.use_envelope_request)
-    ShowEnvelopeDoor(text, ACTION_CLOSING);
+    ShowEnvelopeRequest(text, ACTION_CLOSING);
 #endif
 
 #if 1
@@ -4293,8 +4393,8 @@ unsigned int MoveDoor(unsigned int door_state)
 {
   static int door1 = DOOR_OPEN_1;
   static int door2 = DOOR_CLOSE_2;
-  unsigned long door_delay = 0;
-  unsigned long door_delay_value;
+  unsigned int door_delay = 0;
+  unsigned int door_delay_value;
   int stepsize = 1;
 
   if (door_1.width < 0 || door_1.width > DXSIZE)
@@ -4604,6 +4704,102 @@ void UndrawSpecialEditorDoor()
 
 /* ---------- new tool button stuff ---------------------------------------- */
 
+#if 1
+
+static struct
+{
+  int graphic;
+  struct TextPosInfo *pos;
+  int gadget_id;
+  char *infotext;
+} toolbutton_info[NUM_TOOL_BUTTONS] =
+{
+  {
+    IMG_REQUEST_BUTTON_GFX_YES,                &request.button.yes,
+    TOOL_CTRL_ID_YES,                  "yes"
+  },
+  {
+    IMG_REQUEST_BUTTON_GFX_NO,         &request.button.no,
+    TOOL_CTRL_ID_NO,                   "no"
+  },
+  {
+    IMG_REQUEST_BUTTON_GFX_CONFIRM,    &request.button.confirm,
+    TOOL_CTRL_ID_CONFIRM,              "confirm"
+  },
+  {
+    IMG_REQUEST_BUTTON_GFX_PLAYER_1,   &request.button.player_1,
+    TOOL_CTRL_ID_PLAYER_1,             "player 1"
+  },
+  {
+    IMG_REQUEST_BUTTON_GFX_PLAYER_2,   &request.button.player_2,
+    TOOL_CTRL_ID_PLAYER_2,             "player 2"
+  },
+  {
+    IMG_REQUEST_BUTTON_GFX_PLAYER_3,   &request.button.player_3,
+    TOOL_CTRL_ID_PLAYER_3,             "player 3"
+  },
+  {
+    IMG_REQUEST_BUTTON_GFX_PLAYER_4,   &request.button.player_4,
+    TOOL_CTRL_ID_PLAYER_4,             "player 4"
+  }
+};
+
+void CreateToolButtons()
+{
+  int i;
+
+  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
+  {
+    struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
+    struct TextPosInfo *pos = toolbutton_info[i].pos;
+    struct GadgetInfo *gi;
+    Bitmap *deco_bitmap = None;
+    int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
+    unsigned int event_mask = GD_EVENT_RELEASED;
+    int gd_x   = gfx->src_x;
+    int gd_y   = gfx->src_y;
+    int gd_xp  = gfx->src_x + gfx->pressed_xoffset;
+    int gd_yp  = gfx->src_y + gfx->pressed_yoffset;
+    int id = i;
+
+    if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
+    {
+      int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
+
+      getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
+                           pos->size, &deco_bitmap, &deco_x, &deco_y);
+      deco_xpos = (gfx->width  - pos->size) / 2;
+      deco_ypos = (gfx->height - pos->size) / 2;
+    }
+
+    gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_INFO_TEXT, toolbutton_info[i].infotext,
+                     GDI_X, DX + pos->x,
+                     GDI_Y, DY + pos->y,
+                     GDI_WIDTH, gfx->width,
+                     GDI_HEIGHT, gfx->height,
+                     GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
+                     GDI_STATE, GD_BUTTON_UNPRESSED,
+                     GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
+                     GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
+                     GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
+                     GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
+                     GDI_DECORATION_SIZE, pos->size, pos->size,
+                     GDI_DECORATION_SHIFTING, 1, 1,
+                     GDI_DIRECT_DRAW, FALSE,
+                     GDI_EVENT_MASK, event_mask,
+                     GDI_CALLBACK_ACTION, HandleToolButtons,
+                     GDI_END);
+
+    if (gi == NULL)
+      Error(ERR_EXIT, "cannot create gadget");
+
+    tool_gadget[id] = gi;
+  }
+}
+
+#else
+
 /* graphic position values for tool buttons */
 #define TOOL_BUTTON_YES_XPOS           2
 #define TOOL_BUTTON_YES_YPOS           250
@@ -4713,7 +4909,7 @@ void CreateToolButtons()
     Bitmap *deco_bitmap = None;
     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
     struct GadgetInfo *gi;
-    unsigned long event_mask;
+    unsigned int event_mask;
     int gd_xoffset, gd_yoffset;
     int gd_x1, gd_x2, gd_y;
     int id = i;
@@ -4762,6 +4958,8 @@ void CreateToolButtons()
   }
 }
 
+#endif
+
 void FreeToolButtons()
 {
   int i;
@@ -7196,7 +7394,7 @@ int getGameFrameDelay_EM(int native_em_game_frame_delay)
   return game_frame_delay_value;
 }
 
-unsigned int InitRND(long seed)
+unsigned int InitRND(int seed)
 {
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     return InitEngineRandom_EM(seed);
@@ -8788,15 +8986,16 @@ void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
                            boolean any_player_moving,
                            boolean player_is_dropping)
 {
-  int i;
-
   if (tape.single_step && tape.recording && !tape.pausing)
   {
+#if 0
     boolean active_players = FALSE;
+    int i;
 
     for (i = 0; i < MAX_PLAYERS; i++)
       if (action[i] != JOY_NO_ACTION)
        active_players = TRUE;
+#endif
 
     // if (frame == 0)
     if (frame == 0 && !player_is_dropping)
@@ -8927,18 +9126,44 @@ void PlaySoundSelecting()
 #endif
 }
 
-void ToggleFullscreenIfNeeded()
+void ToggleFullscreenOrChangeWindowScalingIfNeeded()
 {
   boolean change_fullscreen = (setup.fullscreen !=
                               video.fullscreen_enabled);
   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
                                    !strEqual(setup.fullscreen_mode,
                                              video.fullscreen_mode_current));
+  boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
+                                          setup.window_scaling_percent !=
+                                          video.window_scaling_percent);
+
+  if (change_window_scaling_percent && video.fullscreen_enabled)
+    return;
+
+  if (!change_window_scaling_percent && !video.fullscreen_available)
+    return;
+
+#if defined(TARGET_SDL2)
+  if (change_window_scaling_percent)
+  {
+    SDLSetWindowScaling(setup.window_scaling_percent);
+
+    return;
+  }
+  else if (change_fullscreen)
+  {
+    SDLSetWindowFullscreen(setup.fullscreen);
+
+    /* set setup value according to successfully changed fullscreen mode */
+    setup.fullscreen = video.fullscreen_enabled;
 
-  if (!video.fullscreen_available)
     return;
+  }
+#endif
 
-  if (change_fullscreen || change_fullscreen_mode)
+  if (change_fullscreen ||
+      change_fullscreen_mode ||
+      change_window_scaling_percent)
   {
     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
 
@@ -8951,9 +9176,16 @@ void ToggleFullscreenIfNeeded()
       video.fullscreen_enabled = FALSE;                /* force new fullscreen mode */
     }
 
+    if (change_window_scaling_percent)
+    {
+      /* keep window mode, but change window scaling */
+      video.fullscreen_enabled = TRUE;         /* force new window scaling */
+    }
+
     /* toggle fullscreen */
     ChangeVideoModeIfNeeded(setup.fullscreen);
 
+    /* set setup value according to successfully changed fullscreen mode */
     setup.fullscreen = video.fullscreen_enabled;
 
     /* restore backbuffer content from temporary backbuffer backup bitmap */