added setup option to use extended list for game speed selection
[rocksndiamonds.git] / src / screens.c
index 758b3f67f1036cf977ecb6310784b9e365f3fa13..7fccb2e9b59bea10a90bf5667d62f0993459f47b 100644 (file)
@@ -280,6 +280,8 @@ static TreeInfo *scroll_delay_current = NULL;
 static TreeInfo *snapshot_modes = NULL;
 static TreeInfo *snapshot_mode_current = NULL;
 
+static TreeInfo *game_speeds_normal = NULL;
+static TreeInfo *game_speeds_extended = NULL;
 static TreeInfo *game_speeds = NULL;
 static TreeInfo *game_speed_current = NULL;
 
@@ -310,11 +312,7 @@ static TreeInfo *grid_size_current[2][2] = { { NULL, NULL }, { NULL, NULL } };
 static TreeInfo *level_number = NULL;
 static TreeInfo *level_number_current = NULL;
 
-static struct
-{
-  int value;
-  char *text;
-} window_sizes_list[] =
+static struct ValueTextInfo window_sizes_list[] =
 {
   {    50,     "50 %"                          },
   {    80,     "80 %"                          },
@@ -332,11 +330,7 @@ static struct
   {    -1,     NULL                            },
 };
 
-static struct
-{
-  char *value;
-  char *text;
-} scaling_types_list[] =
+static struct StringValueTextInfo scaling_types_list[] =
 {
   {    SCALING_QUALITY_NEAREST, "Off"          },
   {    SCALING_QUALITY_LINEAR,  "Linear"       },
@@ -345,11 +339,7 @@ static struct
   {    NULL,                    NULL           },
 };
 
-static struct
-{
-  char *value;
-  char *text;
-} rendering_modes_list[] =
+static struct StringValueTextInfo rendering_modes_list[] =
 {
   {    STR_SPECIAL_RENDERING_OFF,      "Off (May show artifacts, fast)" },
   {    STR_SPECIAL_RENDERING_BITMAP,   "Bitmap/Texture mode (slower)"   },
@@ -362,11 +352,7 @@ static struct
   {    NULL,                            NULL                            },
 };
 
-static struct
-{
-  char *value;
-  char *text;
-} vsync_modes_list[] =
+static struct StringValueTextInfo vsync_modes_list[] =
 {
   {    STR_VSYNC_MODE_OFF,             "Off"           },
   {    STR_VSYNC_MODE_NORMAL,          "Normal"        },
@@ -375,42 +361,40 @@ static struct
   {    NULL,                            NULL           },
 };
 
-static struct
-{
-  int value;
-  char *text;
-} game_speeds_list[] =
+static struct ValueTextInfo game_speeds_list_normal[] =
 {
-#if 1
   {    30,     "Very Slow"                     },
   {    25,     "Slow"                          },
   {    20,     "Normal"                        },
   {    15,     "Fast"                          },
   {    10,     "Very Fast"                     },
-#else
-  {    1000,   "1/1s (Extremely Slow)"         },
-  {    500,    "1/2s"                          },
-  {    200,    "1/5s"                          },
-  {    100,    "1/10s"                         },
-  {    50,     "1/20s"                         },
-  {    29,     "1/35s (Original Supaplex)"     },
-  {    25,     "1/40s"                         },
-  {    20,     "1/50s (Normal Speed)"          },
-  {    14,     "1/70s (Maximum Supaplex)"      },
-  {    10,     "1/100s"                        },
-  {    5,      "1/200s"                        },
-  {    2,      "1/500s"                        },
-  {    1,      "1/1000s (Extremely Fast)"      },
-#endif
 
   {    -1,     NULL                            },
 };
 
-static struct
-{
-  int value;
-  char *text;
-} scroll_delays_list[] =
+static struct ValueTextInfo game_speeds_list_extended[] =
+{
+  {    1000,   "1 fps (Extremely Slow)"        },
+  {    500,    "2 fps"                         },
+  {    200,    "5 fps"                         },
+  {    100,    "10 fps"                        },
+  {    50,     "20 fps"                        },
+  {    29,     "35 fps (Original Supaplex)"    },
+  {    25,     "40 fps"                        },
+  {    20,     "50 fps (=== Normal Speed ===)" },
+  {    16,     "60 fps (60 Hz VSync Speed)"    },
+  {    14,     "70 fps (Maximum Supaplex)"     },
+  {    10,     "100 fps"                       },
+  {    5,      "200 fps"                       },
+  {    2,      "500 fps"                       },
+  {    1,      "1000 fps (Extremely Fast)"     },
+
+  {    -1,     NULL                            },
+};
+
+static struct ValueTextInfo *game_speeds_list;
+
+static struct ValueTextInfo scroll_delays_list[] =
 {
   {    0,      "0 Tiles (No Scroll Delay)"     },
   {    1,      "1 Tile"                        },
@@ -425,11 +409,7 @@ static struct
   {    -1,     NULL                            },
 };
 
-static struct
-{
-  char *value;
-  char *text;
-} snapshot_modes_list[] =
+static struct StringValueTextInfo snapshot_modes_list[] =
 {
   {    STR_SNAPSHOT_MODE_OFF,                  "Off"           },
   {    STR_SNAPSHOT_MODE_EVERY_STEP,           "Every Step"    },
@@ -439,11 +419,7 @@ static struct
   {    NULL,                                   NULL            },
 };
 
-static struct
-{
-  int value;
-  char *text;
-} volumes_list[] =
+static struct ValueTextInfo volumes_list[] =
 {
   {    0,      "0 %"                           },
   {    1,      "1 %"                           },
@@ -463,11 +439,7 @@ static struct
   {    -1,     NULL                            },
 };
 
-static struct
-{
-  char *value;
-  char *text;
-} touch_controls_list[] =
+static struct StringValueTextInfo touch_controls_list[] =
 {
   {    TOUCH_CONTROL_OFF,              "Off"                   },
   {    TOUCH_CONTROL_VIRTUAL_BUTTONS,  "Virtual Buttons"       },
@@ -477,11 +449,7 @@ static struct
   {    NULL,                           NULL                    },
 };
 
-static struct
-{
-  int value;
-  char *text;
-} distances_list[] =
+static struct ValueTextInfo distances_list[] =
 {
   {    1,      "1 %"                           },
   {    2,      "2 %"                           },
@@ -496,11 +464,7 @@ static struct
   {    -1,     NULL                            },
 };
 
-static struct
-{
-  int value;
-  char *text;
-} transparencies_list[] =
+static struct ValueTextInfo transparencies_list[] =
 {
   {    0,      "0 % (Opaque)"                  },
   {    10,     "10 %"                          },
@@ -517,11 +481,7 @@ static struct
   {    -1,     NULL                            },
 };
 
-static struct
-{
-  int value;
-  char *text;
-} grid_sizes_list[] =
+static struct ValueTextInfo grid_sizes_list[] =
 {
   {    3,      "3"                             },
   {    4,      "4"                             },
@@ -4751,8 +4711,19 @@ static void execSetupMain(void)
   DrawSetupScreen();
 }
 
-static void execSetupGame_setGameSpeeds(void)
+static void execSetupGame_setGameSpeeds(boolean update_value)
 {
+  if (setup.game_speed_extended)
+  {
+    game_speeds_list = game_speeds_list_extended;
+    game_speeds      = game_speeds_extended;
+  }
+  else
+  {
+    game_speeds_list = game_speeds_list_normal;
+    game_speeds      = game_speeds_normal;
+  }
+
   if (game_speeds == NULL)
   {
     int i;
@@ -4781,6 +4752,11 @@ static void execSetupGame_setGameSpeeds(void)
     /* sort game speed values to start with slowest game speed */
     sortTreeInfo(&game_speeds);
 
+    update_value = TRUE;
+  }
+
+  if (update_value)
+  {
     /* set current game speed to configured game speed value */
     game_speed_current =
       getTreeInfoFromIdentifier(game_speeds, i_to_a(setup.game_frame_delay));
@@ -4793,6 +4769,11 @@ static void execSetupGame_setGameSpeeds(void)
     /* if that also fails, set current game speed to first available speed */
     if (game_speed_current == NULL)
       game_speed_current = game_speeds;
+
+    if (setup.game_speed_extended)
+      game_speeds_extended = game_speeds;
+    else
+      game_speeds_normal = game_speeds;
   }
 
   setup.game_frame_delay = atoi(game_speed_current->identifier);
@@ -4918,9 +4899,45 @@ static void execSetupGame_setNetworkServerText(void)
   network_server_text = network_server_hostname;
 }
 
+static void CheckGameSpeedForVsync(boolean force_vsync_game_speed)
+{
+  if (strEqual(setup.vsync_mode, STR_VSYNC_MODE_OFF) ||
+      setup.game_frame_delay <= MAX_VSYNC_FRAME_DELAY)
+    return;
+
+  if (force_vsync_game_speed)
+  {
+    char message[100];
+    char *game_speed_text = "Fast";
+    int game_speed_value = 15;
+
+    if (setup.game_speed_extended)
+    {
+      game_speed_text = "60 fps";
+      game_speed_value = 16;
+    }
+
+    sprintf(message, "Game speed was set to \"%s\" for VSync to work!",
+           game_speed_text);
+
+    /* set game speed to existing list value that is fast enough for vsync */
+    setup.game_frame_delay = game_speed_value;
+
+    execSetupGame_setGameSpeeds(TRUE);
+
+    Request(message, REQ_CONFIRM);
+  }
+  else
+  {
+    Request("Warning! Game speed too low for VSync to work!", REQ_CONFIRM);
+  }
+}
+
 static void execSetupGame(void)
 {
-  execSetupGame_setGameSpeeds();
+  boolean check_vsync_game_speed = (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED);
+
+  execSetupGame_setGameSpeeds(FALSE);
   execSetupGame_setScrollDelays();
   execSetupGame_setSnapshotModes();
 
@@ -4929,6 +4946,10 @@ static void execSetupGame(void)
   setup_mode = SETUP_MODE_GAME;
 
   DrawSetupScreen();
+
+  // check if game speed is high enough for 60 Hz vsync to work
+  if (check_vsync_game_speed)
+    CheckGameSpeedForVsync(FALSE);
 }
 
 static void execSetupChooseGameSpeed(void)
@@ -5197,6 +5218,8 @@ static void execSetupGraphics_setVsyncModes(void)
 
 static void execSetupGraphics(void)
 {
+  boolean check_vsync_game_speed = (setup_mode == SETUP_MODE_CHOOSE_VSYNC);
+
   // update "setup.window_scaling_percent" from list selection
   // (in this case, window scaling was changed on setup screen)
   if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
@@ -5214,6 +5237,10 @@ static void execSetupGraphics(void)
 
   DrawSetupScreen();
 
+  // check if game speed is high enough for 60 Hz vsync to work
+  if (check_vsync_game_speed)
+    CheckGameSpeedForVsync(TRUE);
+
 #if defined(TARGET_SDL2)
   // window scaling may have changed at this point
   ToggleFullscreenOrChangeWindowScalingIfNeeded();
@@ -5985,6 +6012,30 @@ static void ToggleNetworkModeIfNeeded(void)
   DrawSetupScreen();
 }
 
+static void ToggleGameSpeedsListIfNeeded(void)
+{
+  boolean using_game_speeds_extended = (game_speeds == game_speeds_extended);
+
+  if (setup.game_speed_extended == using_game_speeds_extended)
+    return;
+
+  /* try to match similar values when changing game speeds list */
+  if (setup.game_speed_extended)
+    setup.game_frame_delay = (setup.game_frame_delay == 15 ? 16 :
+                             setup.game_frame_delay == 30 ? 29 :
+                             setup.game_frame_delay);
+  else
+    setup.game_frame_delay = (setup.game_frame_delay == 14 ? 15 :
+                             setup.game_frame_delay == 16 ? 15 :
+                             setup.game_frame_delay >= 29 ? 30 :
+                             setup.game_frame_delay <= 10 ? 10 :
+                             setup.game_frame_delay);
+
+  execSetupGame_setGameSpeeds(TRUE);
+
+  DrawSetupScreen();
+}
+
 static struct
 {
   void *value;
@@ -6100,6 +6151,7 @@ static struct TokenInfo setup_info_game[] =
   { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record Tapes:"    },
   { TYPE_ENTER_LIST,   execSetupChooseGameSpeed, "Game Speed:"         },
   { TYPE_STRING,       &game_speed_text,       ""                      },
+  { TYPE_SWITCH,       &setup.game_speed_extended, "Game Speed Extended List:" },
 #if 1
   { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
   { TYPE_STRING,       &scroll_delay_text,     ""                      },
@@ -6663,6 +6715,10 @@ static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx)
   // network mode may have changed at this point
   if (si->value == &setup.network_mode)
     ToggleNetworkModeIfNeeded();
+
+  // game speed list may have changed at this point
+  if (si->value == &setup.game_speed_extended)
+    ToggleGameSpeedsListIfNeeded();
 }
 
 static struct TokenInfo *getSetupInfoFinal(struct TokenInfo *setup_info_orig)