+ HandleMainMenu_SelectLevel(0, 0, new_level_nr);
+ }
+ else if (game_status == GAME_MODE_LEVELS)
+ {
+ // store level set if chosen from "last played level set" menu
+ StoreLastPlayedLevels(leveldir_current);
+ }
+ else if (game_status == GAME_MODE_NAMES)
+ {
+ if (mx >= sx1_edit_name && mx <= sx2_edit_name)
+ {
+ SetGameStatus(GAME_MODE_PSEUDO_TYPENAMES);
+
+ DrawTypeName();
+
+ return;
+ }
+
+ // change active user to selected user
+ user.nr = entry_pos;
+
+ // save number of new active user
+ SaveUserSetup();
+
+ // load setup of new active user
+ LoadSetup();
+
+ // load last level set of new active user
+ LoadLevelSetup_LastSeries();
+ LoadLevelSetup_SeriesInfo();
+
+ // update list of last played level sets
+ UpdateLastPlayedLevels_TreeInfo();
+
+ TapeErase();
+
+ ToggleFullscreenIfNeeded();
+ ChangeWindowScalingIfNeeded();
+
+ ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_GRAPHICS);
+ ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_SOUNDS);
+ ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_MUSIC);
+ }
+ else if (game_status == GAME_MODE_SCORES)
+ {
+ if (scores.continue_playing && scores.continue_on_return)
+ {
+ StartPlayingFromHallOfFame();
+
+ return;
+ }
+ else if (!scores.continue_on_return)
+ {
+ SetGameStatus(GAME_MODE_SCOREINFO);
+
+ DrawScoreInfo(node_cursor->pos);
+
+ return;
+ }
+ }
+
+ SetGameStatus(GAME_MODE_MAIN);
+
+ DrawMainMenu();
+ }
+ }
+ }
+ }
+
+ if (game_status == GAME_MODE_SCORES)
+ PlayMenuSoundIfLoop();
+}
+
+void DrawChoosePlayerName(void)
+{
+ int i;
+
+ if (player_name != NULL)
+ {
+ freeTreeInfo(player_name);
+
+ player_name = NULL;
+ }
+
+ for (i = 0; i < MAX_PLAYER_NAMES; i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_PLAYER_NAME);
+ char identifier[32], name[MAX_PLAYER_NAME_LEN + 1];
+ int value = i;
+
+ ti->node_top = &player_name;
+ ti->sort_priority = 10000 + value;
+ ti->color = getPlayerNameColor(global.user_names[i]);
+
+ snprintf(identifier, sizeof(identifier), "%d", value);
+ snprintf(name, sizeof(name), "%s", global.user_names[i]);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+
+ pushTreeInfo(&player_name, ti);
+ }
+
+ // sort player entries by player number
+ sortTreeInfo(&player_name);
+
+ // set current player entry to selected player entry
+ player_name_current =
+ getTreeInfoFromIdentifier(player_name, i_to_a(user.nr));
+
+ // if that fails, set current player name to first available name
+ if (player_name_current == NULL)
+ player_name_current = player_name;
+
+ // set text size for main name input (also used on name selection screen)
+ InitializeMainControls();
+
+ DrawChooseTree(&player_name_current);
+}
+
+void HandleChoosePlayerName(int mx, int my, int dx, int dy, int button)
+{
+ HandleChooseTree(mx, my, dx, dy, button, &player_name_current);
+}
+
+void DrawChooseLevelSet(void)
+{
+ DrawChooseTree(&leveldir_current);
+}
+
+void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button)
+{
+ HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
+}
+
+void DrawChooseLevelNr(void)
+{
+ int i;
+
+ if (level_number != NULL)
+ {
+ freeTreeInfo(level_number);
+
+ level_number = NULL;
+ }
+
+ for (i = leveldir_current->first_level; i <= leveldir_current->last_level;i++)
+ {
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_LEVEL_NR);
+ char identifier[32], name[64];
+ int value = i;
+
+ // temporarily load level info to get level name
+ LoadLevelInfoOnly(i);
+
+ ti->node_top = &level_number;
+ ti->sort_priority = 10000 + value;
+ ti->color = (level.no_level_file ? FC_BLUE :
+ LevelStats_getSolved(i) ? FC_GREEN :
+ LevelStats_getPlayed(i) ? FC_YELLOW : FC_RED);
+
+ snprintf(identifier, sizeof(identifier), "%d", value);
+ snprintf(name, sizeof(name), "%03d: %s", value,
+ (level.no_level_file ? "(no file)" : level.name));
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+
+ pushTreeInfo(&level_number, ti);
+ }
+
+ // sort level number values to start with lowest level number
+ sortTreeInfo(&level_number);
+
+ // set current level number to current level number
+ level_number_current =
+ getTreeInfoFromIdentifier(level_number, i_to_a(level_nr));
+
+ // if that also fails, set current level number to first available level
+ if (level_number_current == NULL)
+ level_number_current = level_number;
+
+ DrawChooseTree(&level_number_current);
+}
+
+void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
+{
+ HandleChooseTree(mx, my, dx, dy, button, &level_number_current);
+}
+
+static void DrawHallOfFame_setScoreEntries(void)
+{
+ int max_empty_entries = 10; // at least show "top ten" list, if empty
+ int max_visible_entries = NUM_MENU_ENTRIES_ON_SCREEN - 1; // w/o back link
+ int min_score_entries = MIN(max_empty_entries, max_visible_entries);
+ int score_pos = (scores.last_added >= 0 ? scores.last_added : 0);
+ int i;
+
+ if (score_entries != NULL)
+ {
+ freeTreeInfo(score_entries);
+
+ score_entries = NULL;
+ }
+
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+ {
+ // do not add empty score entries if off-screen
+ if (scores.entry[i].score == 0 &&
+ scores.entry[i].time == 0 &&
+ i >= min_score_entries)
+ break;
+
+ TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_SCORE_ENTRY);
+ char identifier[32], name[64];
+ int value = i;
+
+ ti->node_top = &score_entries;
+ ti->sort_priority = 10000 + value;
+ ti->color = FC_YELLOW;
+ ti->pos = i;
+
+ snprintf(identifier, sizeof(identifier), "%d", value);
+ snprintf(name, sizeof(name), "%03d.", value + 1);
+
+ setString(&ti->identifier, identifier);
+ setString(&ti->name, name);
+ setString(&ti->name_sorting, name);
+
+ pushTreeInfo(&score_entries, ti);
+ }
+
+ // sort score entries to start with highest score entry
+ sortTreeInfo(&score_entries);
+
+ // add top tree node to create back link to main menu
+ score_entries = addTopTreeInfoNode(score_entries);
+
+ // set current score entry to last added or highest score entry
+ score_entry_current =
+ getTreeInfoFromIdentifier(score_entries, i_to_a(score_pos));
+
+ // if that fails, set current score entry to first valid score entry
+ if (score_entry_current == NULL)
+ score_entry_current = getFirstValidTreeInfoEntry(score_entries);
+
+ if (score_entries != NULL && scores.continue_playing)
+ setString(&score_entries->node_group->name, BACKLINK_TEXT_NEXT);
+
+ // ("score_entries" and "score_entry_current" may be NULL here)
+}
+
+void DrawHallOfFame(int nr)
+{
+ scores.last_level_nr = nr;
+
+ // (this is needed when called from GameEnd() after winning a game)
+ KeyboardAutoRepeatOn();
+
+ // (this is needed when called from GameEnd() after winning a game)
+ SetDrawDeactivationMask(REDRAW_NONE);
+ SetDrawBackgroundMask(REDRAW_FIELD);
+
+ LoadLocalAndServerScore(scores.last_level_nr, TRUE);
+
+ DrawHallOfFame_setScoreEntries();
+
+ if (scores.last_added >= 0)
+ SetAnimStatus(GAME_MODE_PSEUDO_SCORESNEW);
+
+ FadeSetEnterScreen();
+
+ DrawChooseTree(&score_entry_current);
+}
+
+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));