added support for background image for loading screen
[rocksndiamonds.git] / src / screens.c
index bc1adac0ac4b76d1a308e8dd9f5f9299b66616f5..8b70372f58931af42d77a303e8f2a071502b6fed 100644 (file)
 #define SCREEN_CTRL_ID_NEXT_LEVEL      1
 #define SCREEN_CTRL_ID_PREV_LEVEL2     2
 #define SCREEN_CTRL_ID_NEXT_LEVEL2     3
-#define SCREEN_CTRL_ID_FIRST_LEVEL     4
-#define SCREEN_CTRL_ID_LAST_LEVEL      5
-#define SCREEN_CTRL_ID_LEVEL_NUMBER    6
-#define SCREEN_CTRL_ID_PREV_PLAYER     7
-#define SCREEN_CTRL_ID_NEXT_PLAYER     8
-#define SCREEN_CTRL_ID_INSERT_SOLUTION 9
-#define SCREEN_CTRL_ID_PLAY_SOLUTION   10
-#define SCREEN_CTRL_ID_SWITCH_ECS_AGA  11
-#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE 12
-#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE 13
-#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE2        14
-#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE2        15
-#define SCREEN_CTRL_ID_SCROLL_UP       16
-#define SCREEN_CTRL_ID_SCROLL_DOWN     17
-#define SCREEN_CTRL_ID_SCROLL_VERTICAL 18
-#define SCREEN_CTRL_ID_NETWORK_SERVER  19
-
-#define NUM_SCREEN_GADGETS             20
-
-#define NUM_SCREEN_MENUBUTTONS         16
+#define SCREEN_CTRL_ID_PREV_SCORE      4
+#define SCREEN_CTRL_ID_NEXT_SCORE      5
+#define SCREEN_CTRL_ID_FIRST_LEVEL     6
+#define SCREEN_CTRL_ID_LAST_LEVEL      7
+#define SCREEN_CTRL_ID_LEVEL_NUMBER    8
+#define SCREEN_CTRL_ID_PREV_PLAYER     9
+#define SCREEN_CTRL_ID_NEXT_PLAYER     10
+#define SCREEN_CTRL_ID_INSERT_SOLUTION 11
+#define SCREEN_CTRL_ID_PLAY_SOLUTION   12
+#define SCREEN_CTRL_ID_SWITCH_ECS_AGA  13
+#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE 14
+#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE 15
+#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE2        16
+#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE2        17
+
+#define NUM_SCREEN_MENUBUTTONS         18
+
+#define SCREEN_CTRL_ID_SCROLL_UP       18
+#define SCREEN_CTRL_ID_SCROLL_DOWN     19
+#define SCREEN_CTRL_ID_SCROLL_VERTICAL 20
+#define SCREEN_CTRL_ID_NETWORK_SERVER  21
+
+#define NUM_SCREEN_GADGETS             22
+
 #define NUM_SCREEN_SCROLLBUTTONS       2
 #define NUM_SCREEN_SCROLLBARS          1
 #define NUM_SCREEN_TEXTINPUT           1
 #define SCREEN_MASK_TOUCH              (1 << 3)
 #define SCREEN_MASK_TOUCH2             (1 << 4)
 #define SCREEN_MASK_SCORES             (1 << 5)
+#define SCREEN_MASK_SCORES_INFO                (1 << 6)
 
 // graphic position and size values for buttons and scrollbars
 #define SC_MENUBUTTON_XSIZE            TILEX
@@ -263,6 +268,7 @@ static void DrawChoosePlayerName(void);
 static void DrawChooseLevelSet(void);
 static void DrawChooseLevelNr(void);
 static void DrawScoreInfo(int);
+static void DrawScoreInfo_Content(int);
 static void DrawInfoScreen(void);
 static void DrawSetupScreen(void);
 static void DrawTypeName(void);
@@ -290,15 +296,15 @@ static void MapScreenTreeGadgets(TreeInfo *);
 static void UnmapScreenTreeGadgets(void);
 
 static void UpdateScreenMenuGadgets(int, boolean);
+static void AdjustScoreInfoButtons(int, int, int);
 
 static boolean OfferUploadTapes(void);
 static void execOfferUploadTapes(void);
 
 static void DrawHallOfFame_setScoreEntries(void);
 static void HandleHallOfFame_SelectLevel(int, int);
-static void HandleHallOfFame_SelectLevelOrScore(int, int);
-static char *getHallOfFameRankText(int);
-static char *getHallOfFameScoreText(int);
+static char *getHallOfFameRankText(int, int);
+static char *getHallOfFameScoreText(int, int);
 
 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 
@@ -1682,8 +1688,6 @@ void DrawMainMenu(void)
   // store valid level series information
   leveldir_last_valid = leveldir_current;
 
-  init_last = init;                    // switch to new busy animation
-
   // needed if last screen (level choice) changed graphics, sounds or music
   ReloadCustomArtwork(0);
 
@@ -4932,33 +4936,29 @@ static void drawChooseTreeText(TreeInfo *ti, int y, boolean active)
     int font_size_1 = getFontWidth(font_nr1);
     int font_size_3 = getFontWidth(font_nr3);
     int font_size_4 = getFontWidth(font_nr4);
-    int text_size_1 = 3 * font_size_1;
+    int text_size_1 = 4 * font_size_1;
     int text_size_4 = 5 * font_size_4;
     int border = amSX - SX + getFontDrawOffsetX(font_nr1);
     int dx1 = 0;
-    int dx2 = text_size_1;
-    int dx3 = dx2 + font_size_1;
+    int dx3 = text_size_1;
     int dx4 = screen_width - startdx - 2 * border - text_size_4;
     int num_dots = (dx4 - dx3) / font_size_3;
     int startx1 = startx + dx1;
-    int startx2 = startx + dx2;
     int startx3 = startx + dx3;
     int startx4 = startx + dx4;
     int pos = node->pos;
-    char *pos_text = getHallOfFameRankText(pos);
-    char *dot_text = ".";
+    char *pos_text = getHallOfFameRankText(pos, 3);
     int i;
 
     DrawText(startx1, starty, pos_text, font_nr1);
-    DrawText(startx2, starty, dot_text, font_nr1);
 
     for (i = 0; i < num_dots; i++)
-      DrawText(startx3 + i * font_size_3, starty, dot_text, font_nr3);
+      DrawText(startx3 + i * font_size_3, starty, ".", font_nr3);
 
     if (!strEqual(scores.entry[pos].name, EMPTY_PLAYER_NAME))
       DrawText(startx3, starty, scores.entry[pos].name, font_nr2);
 
-    DrawText(startx4, starty, getHallOfFameScoreText(pos), font_nr4);
+    DrawText(startx4, starty, getHallOfFameScoreText(pos, 5), font_nr4);
   }
   else
   {
@@ -5112,8 +5112,13 @@ static void drawChooseTreeScreen_Scores_NotAvailable(void)
 
 static TreeInfo *setHallOfFameActiveEntry(TreeInfo **ti_ptr)
 {
+  int score_pos = scores.last_added;
+
+  if (game_status_last_screen == GAME_MODE_SCOREINFO)
+    score_pos = scores.last_entry_nr;
+
   // set current tree entry to last added score entry
-  *ti_ptr = getTreeInfoFromIdentifier(score_entries, i_to_a(scores.last_added));
+  *ti_ptr = getTreeInfoFromIdentifier(score_entries, i_to_a(score_pos));
 
   // if that fails, set current tree entry to first entry (back link)
   if (*ti_ptr == NULL)
@@ -5784,11 +5789,15 @@ void DrawHallOfFame(int level_nr)
   DrawChooseTree(&score_entry_current);
 }
 
-static char *getHallOfFameRankText(int nr)
+static char *getHallOfFameRankText(int nr, int size)
 {
+  static char rank_text[10];
   boolean forced = (scores.force_last_added && nr == scores.last_added);
+  char *rank_text_raw = (forced ? "???" : int2str(nr + 1, size));
+
+  sprintf(rank_text, "%s%s", rank_text_raw, (size > 0 || !forced ? "." : ""));
 
-  return (forced ? "???" : int2str(nr + 1, 3));
+  return rank_text;
 }
 
 static char *getHallOfFameTimeText(int nr)
@@ -5803,14 +5812,14 @@ static char *getHallOfFameTimeText(int nr)
   return score_text;
 }
 
-static char *getHallOfFameScoreText(int nr)
+static char *getHallOfFameScoreText(int nr, int size)
 {
   if (!level.rate_time_over_score)
-    return int2str(scores.entry[nr].score, 5); // show normal score
+    return int2str(scores.entry[nr].score, size);      // show normal score
   else if (level.use_step_counter)
-    return int2str(scores.entry[nr].time, 5);  // show number of steps
+    return int2str(scores.entry[nr].time, size);       // show number of steps
   else
-    return getHallOfFameTimeText(nr);          // show playing time
+    return getHallOfFameTimeText(nr);                  // show playing time
 }
 
 static void HandleHallOfFame_SelectLevel(int step, int direction)
@@ -5832,20 +5841,30 @@ static void HandleHallOfFame_SelectLevel(int step, int direction)
 
     scores.last_level_nr = level_nr = new_level_nr;
 
+    LoadLevel(level_nr);
     LoadLocalAndServerScore(level_nr, TRUE);
 
     DrawHallOfFame_setScoreEntries();
 
-    // force remapping optional gadgets (especially scroll bar)
-    UnmapScreenTreeGadgets();
+    if (game_status == GAME_MODE_SCORES)
+    {
+      // force remapping optional gadgets (especially scroll bar)
+      UnmapScreenTreeGadgets();
 
-    // redraw complete high score screen, as sub-title has changed
-    ClearField();
+      // redraw complete high score screen, as sub-title has changed
+      ClearField();
 
-    // redraw level selection buttons (which have just been erased)
-    RedrawScreenMenuGadgets(SCREEN_MASK_SCORES);
+      // redraw level selection buttons (which have just been erased)
+      RedrawScreenMenuGadgets(SCREEN_MASK_SCORES);
 
-    HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, &score_entry_current);
+      HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, &score_entry_current);
+    }
+    else
+    {
+      scores.last_entry_nr = 0;
+
+      DrawScoreInfo_Content(scores.last_entry_nr);
+    }
 
     SaveLevelSetup_SeriesInfo();
   }
@@ -5859,7 +5878,7 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
 static void DrawScoreInfo_Content(int entry_nr)
 {
   struct ScoreEntry *entry = &scores.entry[entry_nr];
-  char *pos_text = getHallOfFameRankText(entry_nr);
+  char *pos_text = getHallOfFameRankText(entry_nr, 0);
   int font_title = MENU_INFO_FONT_TITLE;
   int font_head  = MENU_INFO_FONT_HEAD;
   int font_text  = MENU_INFO_FONT_TEXT;
@@ -5874,13 +5893,29 @@ static void DrawScoreInfo_Content(int entry_nr)
   int ystart  = mSY - SY + menu.top_spacing[GAME_MODE_SCOREINFO];
   int ybottom = mSY - SY + SYSIZE - menu.bottom_spacing[GAME_MODE_SCOREINFO];
   int xstart1 = mSX - SX + 2 * xstep;
-  int xstart2 = mSX - SX + 14 * xstep;
+  int xstart2 = mSX - SX + 13 * xstep;
+  int button_x = SX + xstart1;
+  int button_y1, button_y2;
+  int font_width = getFontWidth(font_text);
+  int font_height = getFontHeight(font_text);
+  int pad_left = xstart2;
+  int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT;
+  int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width;
+  int max_lines_per_text = 5;
+  int lines;
 
   ClearField();
 
   // redraw score selection buttons (which have just been erased)
   RedrawScreenMenuGadgets(SCREEN_MASK_SCORES);
 
+  if (score_entries == NULL)
+  {
+    drawChooseTreeScreen_Scores_NotAvailable();
+
+    return;
+  }
+
   drawChooseTreeHead(score_entries);
   drawChooseTreeInfo(score_entries);
 
@@ -5888,12 +5923,19 @@ static void DrawScoreInfo_Content(int entry_nr)
   ystart += ystep_title;
 
   DrawTextF(xstart1, ystart, font_head, "Level Set");
-  DrawTextF(xstart2, ystart, font_text, leveldir_current->name);
-  ystart += ystep_line;
+  lines = DrawTextBufferS(xstart2, ystart, leveldir_current->name, font_text,
+                         max_chars_per_line, -1, max_lines_per_text, 0, -1,
+                         TRUE, FALSE, FALSE);
+  ystart += ystep_line + (lines > 0 ? lines - 1 : 0) * font_height;
 
-  DrawTextF(xstart1, ystart, font_head, "Level Name");
-  DrawTextF(xstart2, ystart, font_text, level.name);
-  ystart += ystep_para;
+  DrawTextF(xstart1, ystart, font_head, "Level");
+  lines = DrawTextBufferS(xstart2, ystart, level.name, font_text,
+                         max_chars_per_line, -1, max_lines_per_text, 0, -1,
+                         TRUE, FALSE, FALSE);
+  ystart += ystep_para + (lines > 0 ? lines - 1 : 0) * font_height;
+
+  button_y1 = SY + ystart;
+  ystart += graphic_info[IMG_MENU_BUTTON_PREV_SCORE].height;
 
   DrawTextF(xstart1, ystart, font_head, "Rank");
   DrawTextF(xstart2, ystart, font_text, pos_text);
@@ -5903,22 +5945,6 @@ static void DrawScoreInfo_Content(int entry_nr)
   DrawTextF(xstart2, ystart, font_text, entry->name);
   ystart += ystep_line;
 
-  DrawTextF(xstart1, ystart, font_head, "Platform");
-  DrawTextF(xstart2, ystart, font_text, entry->platform);
-  ystart += ystep_line;
-
-  DrawTextF(xstart1, ystart, font_head, "Version");
-  DrawTextF(xstart2, ystart, font_text, entry->version);
-  ystart += ystep_line;
-
-  DrawTextF(xstart1, ystart, font_head, "Country");
-  DrawTextF(xstart2, ystart, font_text, entry->country_name);
-  ystart += ystep_line;
-
-  DrawTextF(xstart1, ystart, font_head, "Tape Date");
-  DrawTextF(xstart2, ystart, font_text, entry->tape_date);
-  ystart += ystep_line;
-
   if (level.use_step_counter)
   {
     DrawTextF(xstart1, ystart, font_head, "Steps");
@@ -5939,7 +5965,31 @@ static void DrawScoreInfo_Content(int entry_nr)
     ystart += ystep_line;
   }
 
+  ystart += ystep_line;
+
+  DrawTextF(xstart1, ystart, font_head, "Tape Date");
+  DrawTextF(xstart2, ystart, font_text, entry->tape_date);
+  ystart += ystep_line;
+
+  DrawTextF(xstart1, ystart, font_head, "Platform");
+  DrawTextF(xstart2, ystart, font_text, entry->platform);
+  ystart += ystep_line;
+
+  DrawTextF(xstart1, ystart, font_head, "Version");
+  DrawTextF(xstart2, ystart, font_text, entry->version);
+  ystart += ystep_line;
+
+  DrawTextF(xstart1, ystart, font_head, "Country");
+  lines = DrawTextBufferS(xstart2, ystart, entry->country_name, font_text,
+                         max_chars_per_line, -1, max_lines_per_text, 0, -1,
+                         TRUE, FALSE, FALSE);
+  ystart += ystep_line;
+
+  button_y2 = SY + ystart;
+
   DrawTextSCentered(ybottom, font_foot, "Press any key or button to go back");
+
+  AdjustScoreInfoButtons(button_x, button_y1, button_y2);
 }
 
 static void DrawScoreInfo(int entry_nr)
@@ -5952,11 +6002,11 @@ static void DrawScoreInfo(int entry_nr)
 
   FadeOut(REDRAW_FIELD);
 
-  // map gadgets for score info screen
-  MapScreenMenuGadgets(SCREEN_MASK_SCORES);
-
   DrawScoreInfo_Content(entry_nr);
 
+  // map gadgets for score info screen
+  MapScreenMenuGadgets(SCREEN_MASK_SCORES_INFO);
+
   FadeIn(REDRAW_FIELD);
 }
 
@@ -5986,6 +6036,18 @@ void HandleScoreInfo(int mx, int my, int dx, int dy, int button)
   boolean button_is_valid = (mx >= 0 && my >= 0);
   boolean button_screen_clicked = (button_action && button_is_valid);
 
+  if (server_scores.updated)
+  {
+    // reload scores, using updated server score cache file
+    LoadLocalAndServerScore(scores.last_level_nr, FALSE);
+
+    server_scores.updated = FALSE;
+
+    DrawHallOfFame_setScoreEntries();
+
+    DrawScoreInfo_Content(scores.last_entry_nr);
+  }
+
   if (button_screen_clicked)
   {
     PlaySound(SND_MENU_ITEM_SELECTING);
@@ -5994,18 +6056,14 @@ void HandleScoreInfo(int mx, int my, int dx, int dy, int button)
 
     DrawHallOfFame(level_nr);
   }
-  else if (dx || dy)
+  else if (dx)
   {
-    HandleScoreInfo_SelectScore(1, SIGN(dx ? dx : dy));
+    HandleHallOfFame_SelectLevel(1, SIGN(dx) * (ABS(dx) > 1 ? 10 : 1));
+  }
+  else if (dy)
+  {
+    HandleScoreInfo_SelectScore(1, SIGN(dy) * (ABS(dy) > 1 ? 10 : 1));
   }
-}
-
-static void HandleHallOfFame_SelectLevelOrScore(int step, int direction)
-{
-  if (game_status == GAME_MODE_SCORES)
-    HandleHallOfFame_SelectLevel(step, direction);
-  else
-    HandleScoreInfo_SelectScore(step, direction);
 }
 
 
@@ -9843,7 +9901,7 @@ static struct
     IMG_MENU_BUTTON_PREV_LEVEL2, IMG_MENU_BUTTON_PREV_LEVEL2_ACTIVE,
     &menu.scores.button.prev_level, NULL,
     SCREEN_CTRL_ID_PREV_LEVEL2,
-    SCREEN_MASK_SCORES,
+    SCREEN_MASK_SCORES | SCREEN_MASK_SCORES_INFO,
     GD_EVENT_PRESSED | GD_EVENT_REPEATED,
     FALSE, "previous level"
   },
@@ -9851,10 +9909,26 @@ static struct
     IMG_MENU_BUTTON_NEXT_LEVEL2, IMG_MENU_BUTTON_NEXT_LEVEL2_ACTIVE,
     &menu.scores.button.next_level, NULL,
     SCREEN_CTRL_ID_NEXT_LEVEL2,
-    SCREEN_MASK_SCORES,
+    SCREEN_MASK_SCORES | SCREEN_MASK_SCORES_INFO,
     GD_EVENT_PRESSED | GD_EVENT_REPEATED,
     FALSE, "next level"
   },
+  {
+    IMG_MENU_BUTTON_PREV_SCORE, IMG_MENU_BUTTON_PREV_SCORE_ACTIVE,
+    &menu.scores.button.prev_score, NULL,
+    SCREEN_CTRL_ID_PREV_SCORE,
+    SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_PRESSED | GD_EVENT_REPEATED,
+    FALSE, "previous score"
+  },
+  {
+    IMG_MENU_BUTTON_NEXT_SCORE, IMG_MENU_BUTTON_NEXT_SCORE_ACTIVE,
+    &menu.scores.button.next_score, NULL,
+    SCREEN_CTRL_ID_NEXT_SCORE,
+    SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_PRESSED | GD_EVENT_REPEATED,
+    FALSE, "next score"
+  },
   {
     IMG_MENU_BUTTON_FIRST_LEVEL, IMG_MENU_BUTTON_FIRST_LEVEL_ACTIVE,
     &menu.main.button.first_level, NULL,
@@ -10027,7 +10101,7 @@ static void CreateScreenMenubuttons(void)
     int screen_mask = menubutton_info[i].screen_mask;
     boolean is_touch_button = menubutton_info[i].is_touch_button;
     boolean is_check_button = menubutton_info[i].check_value != NULL;
-    boolean is_score_button = (screen_mask == SCREEN_MASK_SCORES);
+    boolean is_score_button = (screen_mask & SCREEN_MASK_SCORES_INFO);
     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
     int gfx_unpressed, gfx_pressed;
     int x, y, width, height;
@@ -10087,7 +10161,8 @@ static void CreateScreenMenubuttons(void)
             SX + (SXSIZE + title_width) / 2 + width / 2 : 0);
 
       if (pos->y == -1)
-       y = mSY + MENU_TITLE1_YPOS;
+       y = (id == SCREEN_CTRL_ID_PREV_LEVEL2 ||
+            id == SCREEN_CTRL_ID_NEXT_LEVEL2 ? mSY + MENU_TITLE1_YPOS : 0);
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
@@ -10411,6 +10486,20 @@ static void UnmapScreenTreeGadgets(void)
   UnmapScreenGadgets();
 }
 
+static void AdjustScoreInfoButtons(int x, int y1, int y2)
+{
+  struct GadgetInfo *gi_1 = screen_gadget[SCREEN_CTRL_ID_PREV_SCORE];
+  struct GadgetInfo *gi_2 = screen_gadget[SCREEN_CTRL_ID_NEXT_SCORE];
+  struct MenuPosInfo *pos_1 = menubutton_info[SCREEN_CTRL_ID_PREV_SCORE].pos;
+  struct MenuPosInfo *pos_2 = menubutton_info[SCREEN_CTRL_ID_NEXT_SCORE].pos;
+
+  if (pos_1->x == -1 && pos_1->y == -1)
+    ModifyGadget(gi_1, GDI_X, x, GDI_Y, y1, GDI_END);
+
+  if (pos_2->x == -1 && pos_2->y == -1)
+    ModifyGadget(gi_2, GDI_X, x, GDI_Y, y2, GDI_END);
+}
+
 static void HandleScreenGadgets(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
@@ -10430,11 +10519,19 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
       break;
 
     case SCREEN_CTRL_ID_PREV_LEVEL2:
-      HandleHallOfFame_SelectLevelOrScore(step, -1);
+      HandleHallOfFame_SelectLevel(step, -1);
       break;
 
     case SCREEN_CTRL_ID_NEXT_LEVEL2:
-      HandleHallOfFame_SelectLevelOrScore(step, +1);
+      HandleHallOfFame_SelectLevel(step, +1);
+      break;
+
+    case SCREEN_CTRL_ID_PREV_SCORE:
+      HandleScoreInfo_SelectScore(step, -1);
+      break;
+
+    case SCREEN_CTRL_ID_NEXT_SCORE:
+      HandleScoreInfo_SelectScore(step, +1);
       break;
 
     case SCREEN_CTRL_ID_FIRST_LEVEL: