added setting engine snapshot mode to setup screen and file
[rocksndiamonds.git] / src / screens.c
index 0bd9af8403d35c5a2de0cbdc3fb445a98d603b0b..6757061efb78766868ebd0b08f354ca4073d4aca 100644 (file)
 /* sub-screens on the setup screen (specific) */
 #define SETUP_MODE_CHOOSE_GAME_SPEED   16
 #define SETUP_MODE_CHOOSE_SCROLL_DELAY 17
-#define SETUP_MODE_CHOOSE_SCREEN_MODE  18
-#define SETUP_MODE_CHOOSE_WINDOW_SIZE  19
-#define SETUP_MODE_CHOOSE_SCALING_TYPE 20
-#define SETUP_MODE_CHOOSE_GRAPHICS     21
-#define SETUP_MODE_CHOOSE_SOUNDS       22
-#define SETUP_MODE_CHOOSE_MUSIC                23
-#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE        24
-#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 25
-#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 26
-#define SETUP_MODE_CHOOSE_TOUCH_CONTROL        27
-#define SETUP_MODE_CHOOSE_MOVE_DISTANCE        28
-#define SETUP_MODE_CHOOSE_DROP_DISTANCE        29
-
-#define MAX_SETUP_MODES                        30
+#define SETUP_MODE_CHOOSE_SNAPSHOT_MODE        18
+#define SETUP_MODE_CHOOSE_SCREEN_MODE  19
+#define SETUP_MODE_CHOOSE_WINDOW_SIZE  20
+#define SETUP_MODE_CHOOSE_SCALING_TYPE 21
+#define SETUP_MODE_CHOOSE_GRAPHICS     22
+#define SETUP_MODE_CHOOSE_SOUNDS       23
+#define SETUP_MODE_CHOOSE_MUSIC                24
+#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE        25
+#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 26
+#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 27
+#define SETUP_MODE_CHOOSE_TOUCH_CONTROL        28
+#define SETUP_MODE_CHOOSE_MOVE_DISTANCE        29
+#define SETUP_MODE_CHOOSE_DROP_DISTANCE        30
+
+#define MAX_SETUP_MODES                        31
 
 /* for input setup functions */
 #define SETUPINPUT_SCREEN_POS_START    0
@@ -201,6 +202,9 @@ static TreeInfo *scaling_type_current = NULL;
 static TreeInfo *scroll_delays = NULL;
 static TreeInfo *scroll_delay_current = NULL;
 
+static TreeInfo *snapshot_modes = NULL;
+static TreeInfo *snapshot_mode_current = NULL;
+
 static TreeInfo *game_speeds = NULL;
 static TreeInfo *game_speed_current = NULL;
 
@@ -310,6 +314,19 @@ static struct
   {    -1,     NULL                            },
 };
 
+static struct
+{
+  char *value;
+  char *text;
+} snapshot_modes_list[] =
+{
+  {    STR_SNAPSHOT_MODE_OFF,          "Off"           },
+  {    STR_SNAPSHOT_MODE_EVERY_STEP,   "Every Step"    },
+  {    STR_SNAPSHOT_MODE_EVERY_MOVE,   "Every Move"    },
+
+  {    NULL,                           NULL            },
+};
+
 static struct
 {
   int value;
@@ -317,6 +334,9 @@ static struct
 } volumes_list[] =
 {
   {    0,      "0 %"                           },
+  {    1,      "1 %"                           },
+  {    2,      "2 %"                           },
+  {    5,      "5 %"                           },
   {    10,     "10 %"                          },
   {    20,     "20 %"                          },
   {    30,     "30 %"                          },
@@ -961,10 +981,8 @@ static void InitializeMainControls()
 
     if (pos_button != NULL)            /* (x/y may be -1/-1 here) */
     {
-      if (pos_button->width == 0)
-       pos_button->width = button_width;
-      if (pos_button->height == 0)
-       pos_button->height = button_height;
+      pos_button->width  = button_width;
+      pos_button->height = button_height;
     }
 
     if (pos_text != NULL)              /* (x/y may be -1/-1 here) */
@@ -972,18 +990,19 @@ static void InitializeMainControls()
       /* calculate size for non-clickable text -- needed for text alignment */
       boolean calculate_text_size = (pos_button == NULL && text != NULL);
 
+      if (pos_text->width == -1 || calculate_text_size)
+       pos_text->width = text_width;
+      if (pos_text->height == -1 || calculate_text_size)
+       pos_text->height = text_height;
+
       if (visibleMenuPos(pos_button))
       {
        if (pos_text->x == -1)
          pos_text->x = pos_button->x + pos_button->width;
        if (pos_text->y == -1)
-         pos_text->y = pos_button->y;
+         pos_text->y =
+           pos_button->y + (pos_button->height - pos_text->height) / 2;
       }
-
-      if (pos_text->width == -1 || calculate_text_size)
-       pos_text->width = text_width;
-      if (pos_text->height == -1 || calculate_text_size)
-       pos_text->height = text_height;
     }
 
     if (pos_input != NULL)             /* (x/y may be -1/-1 here) */
@@ -1004,8 +1023,24 @@ static void InitializeMainControls()
   }
 }
 
+static void DrawPressedGraphicThruMask(int dst_x, int dst_y,
+                                      int graphic, boolean pressed)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int xoffset = (pressed ? g->pressed_xoffset : 0);
+  int yoffset = (pressed ? g->pressed_yoffset : 0);
+
+  getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+
+  BlitBitmapMasked(src_bitmap, drawto, src_x + xoffset, src_y + yoffset,
+                  g->width, g->height, dst_x, dst_y);
+}
+
 static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
-                                      boolean active_input)
+                                      boolean active_input,
+                                      boolean pressed_button)
 {
   int i;
 
@@ -1042,7 +1077,7 @@ static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
        int y = mSY + pos->y;
 
        DrawBackgroundForGraphic(x, y, pos->width, pos->height, button_graphic);
-       DrawFixedGraphicThruMaskExt(drawto, x, y, button_graphic, 0);
+       DrawPressedGraphicThruMask(x, y, button_graphic, pressed_button);
       }
 
       if (visibleTextPos(pos_text) && text != NULL)
@@ -1074,15 +1109,17 @@ static void DrawCursorAndText_Main_Ext(int nr, boolean active_text,
   }
 }
 
-static void DrawCursorAndText_Main(int nr, boolean active_text)
+static void DrawCursorAndText_Main(int nr, boolean active_text,
+                                  boolean pressed_button)
 {
-  DrawCursorAndText_Main_Ext(nr, active_text, FALSE);
+  DrawCursorAndText_Main_Ext(nr, active_text, FALSE, pressed_button);
 }
 
 #if 0
-static void DrawCursorAndText_Main_Input(int nr, boolean active_text)
+static void DrawCursorAndText_Main_Input(int nr, boolean active_text,
+                                        boolean pressed_button)
 {
-  DrawCursorAndText_Main_Ext(nr, active_text, TRUE);
+  DrawCursorAndText_Main_Ext(nr, active_text, TRUE, pressed_button);
 }
 #endif
 
@@ -1310,9 +1347,6 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   KeyboardAutoRepeatOn();
   ActivateJoystick();
 
-  SetDrawDeactivationMask(REDRAW_NONE);
-  SetDrawBackgroundMask(REDRAW_FIELD);
-
   audio.sound_deactivated = FALSE;
 
   GetPlayerConfig();
@@ -1374,16 +1408,20 @@ void DrawMainMenuExt(int fade_mask, boolean do_fading)
   LoadLevel(level_nr);
   LoadScore(level_nr);
 
+  // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
+  SetDrawDeactivationMask(REDRAW_NONE);
+  SetDrawBackgroundMask(REDRAW_FIELD);
+
   SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
 
   if (fade_mask == REDRAW_ALL)
-    RedrawBackground();
+    RedrawGlobalBorder();
 
   ClearField();
 
   InitializeMainControls();
 
-  DrawCursorAndText_Main(-1, FALSE);
+  DrawCursorAndText_Main(-1, FALSE, FALSE);
   DrawPreviewLevelInitial();
 
   HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
@@ -1619,9 +1657,11 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
 
     if (game_status == GAME_MODE_INFO)
     {
+      int fade_mask = (num_title_screens == 0 ? REDRAW_FIELD : REDRAW_ALL);
+
       info_mode = INFO_MODE_MAIN;
 
-      DrawInfoScreenExt(REDRAW_ALL, use_fading_main_menu);
+      DrawInfoScreenExt(fade_mask, use_fading_main_menu);
     }
     else       /* default: return to main menu */
     {
@@ -1688,12 +1728,14 @@ void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr)
 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 {
   static int choice = MAIN_CONTROL_GAME;
+  static boolean button_pressed_last = FALSE;
+  boolean button_pressed = FALSE;
   int pos = choice;
   int i;
 
   if (button == MB_MENU_INITIALIZE)
   {
-    DrawCursorAndText_Main(choice, TRUE);
+    DrawCursorAndText_Main(choice, TRUE, FALSE);
 
     return;
   }
@@ -1713,6 +1755,16 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        break;
       }
     }
+
+    // handle pressed/unpressed state for active/inactive menu buttons
+    // (if pos != -1, "i" contains index position corresponding to "pos")
+    if (button &&
+       pos >= MAIN_CONTROL_NAME && pos <= MAIN_CONTROL_QUIT &&
+       insideMenuPosRect(main_controls[i].pos_button, mx - mSX, my - mSY))
+      button_pressed = TRUE;
+
+    if (button_pressed != button_pressed_last)
+      DrawCursorAndText_Main(choice, TRUE, button_pressed);
   }
   else if (dx || dy)   /* keyboard input */
   {
@@ -1751,8 +1803,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       {
        PlaySound(SND_MENU_ITEM_ACTIVATING);
 
-       DrawCursorAndText_Main(choice, FALSE);
-       DrawCursorAndText_Main(pos, TRUE);
+       DrawCursorAndText_Main(choice, FALSE, FALSE);
+       DrawCursorAndText_Main(pos, TRUE, button_pressed);
 
        choice = pos;
       }
@@ -1839,6 +1891,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       }
     }
   }
+
+  button_pressed_last = button_pressed;
 }
 
 
@@ -1951,7 +2005,7 @@ static void DrawInfoScreen_Main(int fade_mask, boolean do_fading)
 
   if (fade_mask == REDRAW_ALL)
   {
-    RedrawBackground();
+    RedrawGlobalBorder();
 
     OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
   }
@@ -2090,7 +2144,7 @@ void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
   int ystart2 = mSY - SY + 150;
   int ybottom = mSY - SY + SYSIZE - 20;
 
-  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO);
 
   FadeOut(REDRAW_FIELD);
 
@@ -3017,6 +3071,41 @@ void DrawInfoScreen_LevelSet()
 {
   struct TitleMessageInfo *tmi = &readme;
   char *filename = getLevelSetInfoFilename();
+  char *title = "Level Set Information:";
+  int ystart1 = mSY - SY + 100;
+  int ybottom = mSY - SY + SYSIZE - 20;
+
+  if (filename == NULL)
+  {
+    DrawInfoScreen_NotAvailable(title, "No information for this level set.");
+
+    return;
+  }
+
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
+
+  FadeOut(REDRAW_FIELD);
+
+  ClearField();
+  DrawHeadline();
+
+  DrawTextSCentered(ystart1, FONT_TEXT_1, title);
+
+  /* if x position set to "-1", automatically determine by playfield width */
+  if (tmi->x == -1)
+    tmi->x = SXSIZE / 2;
+
+  /* if y position set to "-1", use static default value */
+  if (tmi->y == -1)
+    tmi->y = 150;
+
+  /* if width set to "-1", automatically determine by playfield width */
+  if (tmi->width == -1)
+    tmi->width = SXSIZE - 2 * TILEX;
+
+  /* if height set to "-1", automatically determine by playfield height */
+  if (tmi->height == -1)
+    tmi->height = SYSIZE - 20 - tmi->y - 10;
 
   /* if chars set to "-1", automatically determine by text and font width */
   if (tmi->chars == -1)
@@ -3030,25 +3119,12 @@ void DrawInfoScreen_LevelSet()
   else
     tmi->height = tmi->lines * getFontHeight(tmi->font);
 
-  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
-
-  FadeOut(REDRAW_FIELD);
-
-  ClearField();
-  DrawHeadline();
-
-  DrawTextCentered(mSY + 100, FONT_TEXT_1, "Level Set Information:");
-
-  if (filename != NULL)
-    DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
-                filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
-                tmi->autowrap, tmi->centered, tmi->parse_comments);
-  else
-    DrawTextCentered(mSY + ALIGNED_TEXT_YPOS(tmi), FONT_TEXT_2,
-                    "No information for this level set.");
+  DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
+              filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
+              tmi->autowrap, tmi->centered, tmi->parse_comments);
 
-  DrawTextCentered(mSY + SYSIZE - 20, FONT_TEXT_4,
-                  "Press any key or button for info menu");
+  DrawTextSCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for info menu");
 
   FadeIn(REDRAW_FIELD);
 }
@@ -3229,6 +3305,17 @@ void HandleTypeName(int newxpos, Key key)
 
 static void DrawChooseTree(TreeInfo **ti_ptr)
 {
+  int fade_mask = (DrawingAreaChanged() ? REDRAW_ALL : REDRAW_FIELD);
+
+  if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY))
+  {
+    game_status = GAME_MODE_MAIN;
+
+    DrawMainMenuExt(REDRAW_FIELD, FALSE);
+
+    return;
+  }
+
   UnmapAllGadgets();
 
   FreeScreenGadgets();
@@ -3236,14 +3323,14 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
 
   CloseDoor(DOOR_CLOSE_2);
 
-  FadeOut(REDRAW_FIELD);
+  FadeOut(fade_mask);
 
   ClearField();
 
   HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
   MapScreenTreeGadgets(*ti_ptr);
 
-  FadeIn(REDRAW_FIELD);
+  FadeIn(fade_mask);
 
   InitAnimation();
 }
@@ -3272,8 +3359,8 @@ static void clearMenuListArea()
   int scrollbar_xpos = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
 
   /* correct scrollbar position if placed outside menu (playfield) area */
-  if (scrollbar_xpos > SC_SCROLLBAR_XPOS)
-    scrollbar_xpos = SC_SCROLLBAR_XPOS;
+  if (scrollbar_xpos > SX + SC_SCROLLBAR_XPOS)
+    scrollbar_xpos = SX + SC_SCROLLBAR_XPOS;
 
   /* clear menu list area, but not title or scrollbar */
   DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
@@ -3434,7 +3521,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     else if (game_status == GAME_MODE_SETUP)
     {
       if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
-         setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
+         setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
+         setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
        execSetupGame();
       else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
               setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
@@ -3526,7 +3614,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
                                  ti->cl_first, ti);
       }
 
-
       return;
     }
 
@@ -3632,7 +3719,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
        if (game_status == GAME_MODE_SETUP)
        {
          if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED ||
-             setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
+             setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
+             setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
            execSetupGame();
          else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE ||
                   setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
@@ -3745,6 +3833,8 @@ void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
 
 void DrawHallOfFame(int highlight_position)
 {
+  int fade_mask = (DrawingAreaChanged() ? REDRAW_ALL : REDRAW_FIELD);
+
   UnmapAllGadgets();
   FadeSoundsAndMusic();
 
@@ -3763,7 +3853,7 @@ void DrawHallOfFame(int highlight_position)
 
   FadeSetEnterScreen();
 
-  FadeOut(REDRAW_FIELD);
+  FadeOut(fade_mask);
 
   InitAnimation();
 
@@ -3772,7 +3862,7 @@ void DrawHallOfFame(int highlight_position)
 
   HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
 
-  FadeIn(REDRAW_FIELD);
+  FadeIn(fade_mask);
 }
 
 static void drawHallOfFameList(int first_entry, int highlight_position)
@@ -3893,6 +3983,7 @@ static char *screen_mode_text;
 static char *window_size_text;
 static char *scaling_type_text;
 static char *scroll_delay_text;
+static char *snapshot_mode_text;
 static char *game_speed_text;
 static char *graphics_set_name;
 static char *sounds_set_name;
@@ -4011,10 +4102,61 @@ static void execSetupGame_setScrollDelays()
   scroll_delay_text = scroll_delay_current->name;
 }
 
+static void execSetupGame_setSnapshotModes()
+{
+  if (snapshot_modes == NULL)
+  {
+    int i;
+
+    for (i = 0; snapshot_modes_list[i].value != NULL; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      char *value = snapshot_modes_list[i].value;
+      char *text = snapshot_modes_list[i].text;
+
+      ti->node_top = &snapshot_modes;
+      ti->sort_priority = i;
+
+      sprintf(identifier, "%s", value);
+      sprintf(name, "%s", text);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, "Snapshot Mode");
+
+      pushTreeInfo(&snapshot_modes, ti);
+    }
+
+    /* sort snapshot mode values to start with lowest snapshot mode value */
+    sortTreeInfo(&snapshot_modes);
+
+    /* set current snapshot mode value to configured snapshot mode value */
+    snapshot_mode_current =
+      getTreeInfoFromIdentifier(snapshot_modes, setup.engine_snapshot_mode);
+
+    /* if that fails, set current snapshot mode to reliable default value */
+    if (snapshot_mode_current == NULL)
+      snapshot_mode_current =
+       getTreeInfoFromIdentifier(snapshot_modes, STR_SNAPSHOT_MODE_DEFAULT);
+
+    /* if that also fails, set current snapshot mode to first available value */
+    if (snapshot_mode_current == NULL)
+      snapshot_mode_current = snapshot_modes;
+  }
+
+  setup.engine_snapshot_mode = snapshot_mode_current->identifier;
+
+  /* needed for displaying snapshot mode text instead of identifier */
+  snapshot_mode_text = snapshot_mode_current->name;
+}
+
 static void execSetupGame()
 {
   execSetupGame_setGameSpeeds();
   execSetupGame_setScrollDelays();
+  execSetupGame_setSnapshotModes();
 
   setup_mode = SETUP_MODE_GAME;
 
@@ -4035,6 +4177,13 @@ static void execSetupChooseScrollDelay()
   DrawSetupScreen();
 }
 
+static void execSetupChooseSnapshotMode()
+{
+  setup_mode = SETUP_MODE_CHOOSE_SNAPSHOT_MODE;
+
+  DrawSetupScreen();
+}
+
 static void execSetupEditor()
 {
   setup_mode = SETUP_MODE_EDITOR;
@@ -4321,6 +4470,7 @@ static void execSetupSound()
 {
   if (volumes_simple == NULL)
   {
+    boolean current_volume_simple_found = FALSE;
     int i;
 
     for (i = 0; volumes_list[i].value != -1; i++)
@@ -4342,6 +4492,31 @@ static void execSetupSound()
       setString(&ti->infotext, "Sound Volume");
 
       pushTreeInfo(&volumes_simple, ti);
+
+      if (value == setup.volume_simple)
+        current_volume_simple_found = TRUE;
+    }
+
+    if (!current_volume_simple_found)
+    {
+      // add entry for non-preset volume value
+
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = setup.volume_simple;
+
+      ti->node_top = &volumes_simple;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%d %% (Current)", value);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, "Sound Volume");
+
+      pushTreeInfo(&volumes_simple, ti);
     }
 
     /* sort volume values to start with lowest volume value */
@@ -4363,6 +4538,7 @@ static void execSetupSound()
 
   if (volumes_loops == NULL)
   {
+    boolean current_volume_loops_found = FALSE;
     int i;
 
     for (i = 0; volumes_list[i].value != -1; i++)
@@ -4384,6 +4560,31 @@ static void execSetupSound()
       setString(&ti->infotext, "Loops Volume");
 
       pushTreeInfo(&volumes_loops, ti);
+
+      if (value == setup.volume_loops)
+        current_volume_loops_found = TRUE;
+    }
+
+    if (!current_volume_loops_found)
+    {
+      // add entry for non-preset volume value
+
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = setup.volume_loops;
+
+      ti->node_top = &volumes_loops;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%d %% (Current)", value);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, "Loops Volume");
+
+      pushTreeInfo(&volumes_loops, ti);
     }
 
     /* sort volume values to start with lowest volume value */
@@ -4405,6 +4606,7 @@ static void execSetupSound()
 
   if (volumes_music == NULL)
   {
+    boolean current_volume_music_found = FALSE;
     int i;
 
     for (i = 0; volumes_list[i].value != -1; i++)
@@ -4426,6 +4628,31 @@ static void execSetupSound()
       setString(&ti->infotext, "Music Volume");
 
       pushTreeInfo(&volumes_music, ti);
+
+      if (value == setup.volume_music)
+        current_volume_music_found = TRUE;
+    }
+
+    if (!current_volume_music_found)
+    {
+      // add entry for non-preset volume value
+
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = setup.volume_music;
+
+      ti->node_top = &volumes_music;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%d %% (Current)", value);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, "Music Volume");
+
+      pushTreeInfo(&volumes_music, ti);
     }
 
     /* sort volume values to start with lowest volume value */
@@ -4770,6 +4997,8 @@ static struct TokenInfo setup_info_game[] =
   { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
   { TYPE_STRING,       &scroll_delay_text,     ""                      },
 #endif
+  { TYPE_ENTER_LIST, execSetupChooseSnapshotMode,"Game Engine Snapshot Mode:" },
+  { TYPE_STRING,       &snapshot_mode_text,    ""                      },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -5290,6 +5519,7 @@ static void drawSetupInfoList(struct TokenInfo *setup_info,
 
 static void DrawSetupScreen_Generic()
 {
+  int fade_mask = (DrawingAreaChanged() ? REDRAW_ALL : REDRAW_FIELD);
   boolean redraw_all = FALSE;
   char *title_string = NULL;
   int i;
@@ -5304,7 +5534,7 @@ static void DrawSetupScreen_Generic()
   if (redraw_mask & REDRAW_ALL)
     redraw_all = TRUE;
 
-  FadeOut(REDRAW_FIELD);
+  FadeOut(fade_mask);
 
   ClearField();
 
@@ -5391,9 +5621,9 @@ static void DrawSetupScreen_Generic()
   MapScreenGadgets(max_setup_info);
 
   if (redraw_all)
-    redraw_mask = REDRAW_ALL;
+    redraw_mask = fade_mask = REDRAW_ALL;
 
-  FadeIn(redraw_mask);
+  FadeIn(fade_mask);
 
   InitAnimation();
 }
@@ -6284,6 +6514,8 @@ void DrawSetupScreen()
     DrawChooseTree(&game_speed_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
     DrawChooseTree(&scroll_delay_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
+    DrawChooseTree(&snapshot_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
     DrawChooseTree(&screen_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
@@ -6335,6 +6567,8 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
     HandleChooseTree(mx, my, dx, dy, button, &game_speed_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY)
     HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
+    HandleChooseTree(mx, my, dx, dy, button, &snapshot_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCREEN_MODE)
     HandleChooseTree(mx, my, dx, dy, button, &screen_mode_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
@@ -6568,8 +6802,8 @@ static void CreateScreenScrollbuttons()
     height = SC_SCROLLBUTTON_YSIZE;
 
     /* correct scrollbar position if placed outside menu (playfield) area */
-    if (x > SC_SCROLL_UP_XPOS)
-      x = SC_SCROLL_UP_XPOS;
+    if (x > SX + SC_SCROLL_UP_XPOS)
+      x = SX + SC_SCROLL_UP_XPOS;
 
     if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
       y = mSY + (SC_SCROLL_VERTICAL_YPOS +
@@ -6637,8 +6871,8 @@ static void CreateScreenScrollbars()
     height = scrollbar_info[i].height;
 
     /* correct scrollbar position if placed outside menu (playfield) area */
-    if (x > SC_SCROLL_VERTICAL_XPOS)
-      x = SC_SCROLL_VERTICAL_XPOS;
+    if (x > SX + SC_SCROLL_VERTICAL_XPOS)
+      x = SX + SC_SCROLL_VERTICAL_XPOS;
 
     if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
       height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;