X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fscreens.c;h=55aa0c22f855bd6abad91e51fcfd88a8353108d5;hp=84b890f6e9bb6c0d05e2d519a36ba4ed89e91f15;hb=b937b0928312ad4a51f45c16a0792a09ba914659;hpb=1f6a3409735a6bacc8900cc48328dea4b0c08d9d diff --git a/src/screens.c b/src/screens.c index 84b890f6..55aa0c22 100644 --- a/src/screens.c +++ b/src/screens.c @@ -126,6 +126,7 @@ // other screen text constants #define STR_CHOOSE_TREE_EDIT "Edit" #define MENU_CHOOSE_TREE_FONT(x) (FONT_TEXT_1 + (x)) +#define MENU_CHOOSE_TREE_COLOR(ti, a) TREE_COLOR(ti, a) // for input setup functions #define SETUPINPUT_SCREEN_POS_START 0 @@ -281,6 +282,9 @@ static void MapScreenTreeGadgets(TreeInfo *); static void UpdateScreenMenuGadgets(int, boolean); +static boolean OfferUploadTapes(void); +static void execOfferUploadTapes(void); + static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS]; static int info_mode = INFO_MODE_MAIN; @@ -1629,12 +1633,15 @@ void DrawMainMenu(void) return; } - // leveldir_current may be invalid (level group, parent link) - if (!validLevelSeries(leveldir_current)) - leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid); + // leveldir_current may be invalid (level group, parent link, node copy) + leveldir_current = getValidLevelSeries(leveldir_current, leveldir_last_valid); if (leveldir_current != leveldir_last_valid) + { + UpdateLastPlayedLevels_TreeInfo(); + levelset_has_changed = TRUE; + } // store valid level series information leveldir_last_valid = leveldir_current; @@ -1734,6 +1741,8 @@ void DrawMainMenu(void) SetMouseCursor(CURSOR_DEFAULT); OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2); + + SyncEmscriptenFilesystem(); } static void gotoTopLevelDir(void) @@ -1951,6 +1960,16 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button) } } +static void HandleMainMenu_ToggleTeamMode(void) +{ + setup.team_mode = !setup.team_mode; + + InitializeMainControls(); + DrawCursorAndText_Main(MAIN_CONTROL_NAME, TRUE, FALSE); + + DrawPreviewPlayers(); +} + static void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr) { @@ -2100,9 +2119,16 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) } else if (dx != 0) { - if (choice != MAIN_CONTROL_INFO && - choice != MAIN_CONTROL_SETUP) + if (choice == MAIN_CONTROL_NAME) + { + // special case: cursor left or right pressed -- toggle team mode + HandleMainMenu_ToggleTeamMode(); + } + else if (choice != MAIN_CONTROL_INFO && + choice != MAIN_CONTROL_SETUP) + { HandleMainMenu_SelectLevel(1, dx, NO_DIRECT_LEVEL_SELECT); + } } } else @@ -2115,12 +2141,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) insideTextPosRect(main_controls[i].pos_text, mx - mSX, my - mSY)) { // special case: menu text "name/team" clicked -- toggle team mode - setup.team_mode = !setup.team_mode; - - InitializeMainControls(); - DrawCursorAndText_Main(choice, TRUE, FALSE); - - DrawPreviewPlayers(); + HandleMainMenu_ToggleTeamMode(); } else { @@ -2151,6 +2172,9 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); + // restore level set if chosen from "last played level set" menu + RestoreLastPlayedLevels(&leveldir_current); + if (setup.internal.choose_from_top_leveldir) gotoTopLevelDir(); @@ -2163,7 +2187,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) SetGameStatus(GAME_MODE_SCORES); - DrawHallOfFame(level_nr, -1); + DrawHallOfFame(level_nr); } else if (pos == MAIN_CONTROL_EDITOR) { @@ -2208,7 +2232,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); - if (Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED)) + if (!setup.ask_on_quit_program || + Request("Do you really want to quit?", REQ_ASK | REQ_STAY_CLOSED)) SetGameStatus(GAME_MODE_QUIT); } } @@ -4013,6 +4038,138 @@ void HandleInfoScreen(int mx, int my, int dx, int dy, int button) } +// ============================================================================ +// change name functions +// ============================================================================ + +struct ApiRenamePlayerThreadData +{ + char *player_name; + char *player_uuid; +}; + +static void *CreateThreadData_ApiRenamePlayer(void) +{ + struct ApiRenamePlayerThreadData *data = + checked_malloc(sizeof(struct ApiRenamePlayerThreadData)); + + data->player_name = getStringCopy(setup.player_name); + data->player_uuid = getStringCopy(setup.player_uuid); + + return data; +} + +static void FreeThreadData_ApiRenamePlayer(void *data_raw) +{ + struct ApiRenamePlayerThreadData *data = data_raw; + + checked_free(data->player_name); + checked_free(data->player_uuid); + checked_free(data); +} + +static boolean SetRequest_ApiRenamePlayer(struct HttpRequest *request, + void *data_raw) +{ + struct ApiRenamePlayerThreadData *data = data_raw; + char *player_name_raw = data->player_name; + char *player_uuid_raw = data->player_uuid; + + request->hostname = setup.api_server_hostname; + request->port = API_SERVER_PORT; + request->method = API_SERVER_METHOD; + request->uri = API_SERVER_URI_RENAME; + + char *player_name = getEscapedJSON(player_name_raw); + char *player_uuid = getEscapedJSON(player_uuid_raw); + + snprintf(request->body, MAX_HTTP_BODY_SIZE, + "{\n" + "%s" + " \"game_version\": \"%s\",\n" + " \"game_platform\": \"%s\",\n" + " \"name\": \"%s\",\n" + " \"uuid\": \"%s\"\n" + "}\n", + getPasswordJSON(setup.api_server_password), + getProgramRealVersionString(), + getProgramPlatformString(), + player_name, + player_uuid); + + checked_free(player_name); + checked_free(player_uuid); + + ConvertHttpRequestBodyToServerEncoding(request); + + return TRUE; +} + +static void HandleResponse_ApiRenamePlayer(struct HttpResponse *response, + void *data_raw) +{ + // nothing to do here +} + +static void ApiRenamePlayer_HttpRequestExt(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) +{ + if (!SetRequest_ApiRenamePlayer(request, data_raw)) + return; + + if (!DoHttpRequest(request, response)) + { + Error("HTTP request failed: %s", GetHttpError()); + + return; + } + + if (!HTTP_SUCCESS(response->status_code)) + { + Error("server failed to handle request: %d %s", + response->status_code, + response->status_text); + + return; + } + + HandleResponse_ApiRenamePlayer(response, data_raw); +} + +static void ApiRenamePlayer_HttpRequest(struct HttpRequest *request, + struct HttpResponse *response, + void *data_raw) +{ + ApiRenamePlayer_HttpRequestExt(request, response, data_raw); + + FreeThreadData_ApiRenamePlayer(data_raw); +} + +static int ApiRenamePlayerThread(void *data_raw) +{ + struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest)); + struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse)); + + ApiRenamePlayer_HttpRequest(request, response, data_raw); + + checked_free(request); + checked_free(response); + + return 0; +} + +static void ApiRenamePlayerAsThread(void) +{ + struct ApiRenamePlayerThreadData *data = + CreateThreadData_ApiRenamePlayer(); + + ExecuteAsThread(ApiRenamePlayerThread, + "ApiRenamePlayer", data, + "rename player on server"); +} + + // ============================================================================ // type name functions // ============================================================================ @@ -4150,6 +4307,9 @@ static void setTypeNameValues(char *name, struct TextPosInfo *pos, // save setup of edited user SaveSetup(); + // change name of edited user on score server + ApiRenamePlayerAsThread(); + if (game_status == GAME_MODE_PSEUDO_TYPENAMES || reset_setup) { if (reset_setup) @@ -4351,9 +4511,16 @@ static void DrawChooseTree(TreeInfo **ti_ptr) if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY)) { - SetGameStatus(GAME_MODE_MAIN); + if (game_status == GAME_MODE_SETUP) + { + execSetupArtwork(); + } + else // GAME_MODE_LEVELS + { + SetGameStatus(GAME_MODE_MAIN); - DrawMainMenu(); + DrawMainMenu(); + } return; } @@ -4387,13 +4554,38 @@ static void DrawChooseTree(TreeInfo **ti_ptr) FadeIn(fade_mask); } -static void drawChooseTreeList(int first_entry, int num_page_entries, - TreeInfo *ti) +static void drawChooseTreeText(int y, boolean active, TreeInfo *ti) { int num_entries = numTreeInfoInGroup(ti); boolean scrollbar_needed = (num_entries > NUM_MENU_ENTRIES_ON_SCREEN); int scrollbar_xpos = SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset; int screen_width = (scrollbar_needed ? scrollbar_xpos : SXSIZE); + int first_entry = ti->cl_first; + int entry_pos = first_entry + y; + TreeInfo *node_first = getTreeInfoFirstGroupEntry(ti); + TreeInfo *node = getTreeInfoFromPos(node_first, entry_pos); + int font_color = MENU_CHOOSE_TREE_COLOR(node, active); + int font_nr = MENU_CHOOSE_TREE_FONT(font_color); + int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; + int xpos = MENU_SCREEN_START_XPOS; + int ypos = MENU_SCREEN_START_YPOS + y; + int startx = amSX + xpos * 32; + int starty = amSY + ypos * 32; + int startx_text = startx + font_xoffset; + int endx_text = amSX + screen_width; + int max_text_size = endx_text - startx_text; + int max_buffer_len = max_text_size / getFontWidth(font_nr); + char buffer[max_buffer_len + 1]; + + strncpy(buffer, node->name, max_buffer_len); + buffer[max_buffer_len] = '\0'; + + DrawText(startx, starty, buffer, font_nr); +} + +static void drawChooseTreeList(int first_entry, int num_page_entries, + TreeInfo *ti) +{ int i; char *title_string = NULL; int yoffset_sets = MENU_TITLE1_YPOS; @@ -4415,22 +4607,7 @@ static void drawChooseTreeList(int first_entry, int num_page_entries, node_first = getTreeInfoFirstGroupEntry(ti); node = getTreeInfoFromPos(node_first, entry_pos); - int font_nr = MENU_CHOOSE_TREE_FONT(node->color); - int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset; - int xpos = MENU_SCREEN_START_XPOS; - int ypos = MENU_SCREEN_START_YPOS + i; - int startx = amSX + xpos * 32; - int starty = amSY + ypos * 32; - int startx_text = startx + font_xoffset; - int endx_text = amSX + screen_width; - int max_text_size = endx_text - startx_text; - int max_buffer_len = max_text_size / getFontWidth(font_nr); - char buffer[max_buffer_len + 1]; - - strncpy(buffer, node->name, max_buffer_len); - buffer[max_buffer_len] = '\0'; - - DrawText(startx, starty, buffer, font_nr); + drawChooseTreeText(i, FALSE, ti); if (node->parent_link) initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU); @@ -4481,6 +4658,12 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti) MarkTileDirty(x, 1); } +static void drawChooseTreeCursorAndText(int y, boolean active, TreeInfo *ti) +{ + drawChooseTreeCursor(y, active); + drawChooseTreeText(y, active, ti); +} + static void HandleChooseTree(int mx, int my, int dx, int dy, int button, TreeInfo **ti_ptr) { @@ -4528,7 +4711,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); - drawChooseTreeCursor(ti->cl_cursor, TRUE); + drawChooseTreeCursorAndText(ti->cl_cursor, TRUE, ti); return; } @@ -4638,7 +4821,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, { drawChooseTreeList(ti->cl_first, num_page_entries, ti); drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti); - drawChooseTreeCursor(ti->cl_cursor, TRUE); + drawChooseTreeCursorAndText(ti->cl_cursor, TRUE, ti); AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, ti->cl_first, ti); @@ -4702,8 +4885,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, { PlaySound(SND_MENU_ITEM_ACTIVATING); - drawChooseTreeCursor(ti->cl_cursor, FALSE); - drawChooseTreeCursor(y, TRUE); + drawChooseTreeCursorAndText(ti->cl_cursor, FALSE, ti); + drawChooseTreeCursorAndText(y, TRUE, ti); drawChooseTreeInfo(ti->cl_first + y, ti); ti->cl_cursor = y; @@ -4817,6 +5000,11 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, 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) @@ -4841,6 +5029,9 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, LoadLevelSetup_LastSeries(); LoadLevelSetup_SeriesInfo(); + // update list of last played level sets + UpdateLastPlayedLevels_TreeInfo(); + TapeErase(); ToggleFullscreenIfNeeded(); @@ -4988,7 +5179,7 @@ void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button) HandleChooseTree(mx, my, dx, dy, button, &level_number_current); } -void DrawHallOfFame(int level_nr, int highlight_position) +void DrawHallOfFame(int level_nr) { int fade_mask = REDRAW_FIELD; @@ -5005,9 +5196,9 @@ void DrawHallOfFame(int level_nr, int highlight_position) SetDrawDeactivationMask(REDRAW_NONE); SetDrawBackgroundMask(REDRAW_FIELD); - if (highlight_position < 0) - LoadScore(level_nr); - else + LoadLocalAndServerScore(level_nr, TRUE); + + if (scores.last_added >= 0) SetAnimStatus(GAME_MODE_PSEUDO_SCORESNEW); FadeSetEnterScreen(); @@ -5021,15 +5212,47 @@ void DrawHallOfFame(int level_nr, int highlight_position) OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW); - HandleHallOfFame(level_nr, highlight_position, 0, 0, MB_MENU_INITIALIZE); + HandleHallOfFame(level_nr, 0, 0, 0, MB_MENU_INITIALIZE); DrawMaskedBorder(fade_mask); FadeIn(fade_mask); } -static void drawHallOfFameList(int level_nr, int first_entry, - int highlight_position) +static int getHallOfFameFirstEntry(int first_entry, int step) +{ + if (step == 0) + first_entry = scores.last_added - (NUM_MENU_ENTRIES_ON_SCREEN + 1) / 2 + 1; + else + first_entry += step; + + if (first_entry < 0) + first_entry = 0; + else if (first_entry > MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN) + first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN); + + return first_entry; +} + +static char *getHallOfFameScoreText(int nr) +{ + if (!level.rate_time_over_score) + return int2str(scores.entry[nr].score, 5); // show normal score + + if (level.use_step_counter) + return int2str(scores.entry[nr].time, 5); // show number of steps + + static char score_text[10]; + int time_seconds = scores.entry[nr].time / FRAMES_PER_SECOND; + int mm = (time_seconds / 60) % 60; + int ss = (time_seconds % 60); + + sprintf(score_text, "%02d:%02d", mm, ss); // show playing time + + return score_text; +} + +static void drawHallOfFameList(int level_nr, int first_entry) { int i, j; @@ -5043,7 +5266,8 @@ static void drawHallOfFameList(int level_nr, int first_entry, for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++) { int entry = first_entry + i; - boolean active = (entry == highlight_position); + boolean active = (entry == scores.last_added); + boolean forced = (scores.force_last_added && active); int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1); int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2); int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3); @@ -5054,17 +5278,18 @@ static void drawHallOfFameList(int level_nr, int first_entry, int dx3 = SXSIZE - 2 * (mSX - SX + dxoff) - 5 * getFontWidth(font_nr4); int num_dots = (dx3 - dx2) / getFontWidth(font_nr3); int sy = mSY + 64 + i * 32; + char *pos_text = (forced ? "???" : int2str(entry + 1, 3)); - DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1); + DrawText(mSX, sy, pos_text, font_nr1); DrawText(mSX + dx1, sy, ".", font_nr1); for (j = 0; j < num_dots; j++) DrawText(mSX + dx2 + j * getFontWidth(font_nr3), sy, ".", font_nr3); - if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME)) - DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2); + if (!strEqual(scores.entry[entry].name, EMPTY_PLAYER_NAME)) + DrawText(mSX + dx2, sy, scores.entry[entry].name, font_nr2); - DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4); + DrawText(mSX + dx3, sy, getHallOfFameScoreText(entry), font_nr4); } redraw_mask |= REDRAW_FIELD; @@ -5074,22 +5299,23 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button) { static int level_nr = 0; static int first_entry = 0; - static int highlight_position = 0; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); if (button == MB_MENU_INITIALIZE) { level_nr = mx; - highlight_position = my; - first_entry = highlight_position - (NUM_MENU_ENTRIES_ON_SCREEN + 1) / 2 + 1; + if (server_scores.updated) + { + // reload scores, using updated server score cache file + LoadLocalAndServerScore(level_nr, FALSE); + + server_scores.updated = FALSE; + } - if (first_entry < 0) - first_entry = 0; - else if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES) - first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN); + first_entry = getHallOfFameFirstEntry(0, 0); - drawHallOfFameList(level_nr, first_entry, highlight_position); + drawHallOfFameList(level_nr, first_entry); return; } @@ -5099,25 +5325,15 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button) if (dy < 0) { - if (first_entry > 0) - { - first_entry -= step; - if (first_entry < 0) - first_entry = 0; + first_entry = getHallOfFameFirstEntry(first_entry, -step); - drawHallOfFameList(level_nr, first_entry, highlight_position); - } + drawHallOfFameList(level_nr, first_entry); } else if (dy > 0) { - if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES) - { - first_entry += step; - if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES) - first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN); + first_entry = getHallOfFameFirstEntry(first_entry, step); - drawHallOfFameList(level_nr, first_entry, highlight_position); - } + drawHallOfFameList(level_nr, first_entry); } else if (button == MB_MENU_LEAVE || button == MB_MENU_CHOICE) { @@ -5140,6 +5356,17 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button) DrawMainMenu(); } } + else if (server_scores.updated) + { + // reload scores, using updated server score cache file + LoadLocalAndServerScore(level_nr, FALSE); + + server_scores.updated = FALSE; + + first_entry = getHallOfFameFirstEntry(0, 0); + + drawHallOfFameList(level_nr, first_entry); + } if (game_status == GAME_MODE_SCORES) PlayMenuSoundIfLoop(); @@ -5379,6 +5606,9 @@ static void execSetupGame(void) execSetupGame_setNetworkServerText(); + if (!setup.provide_uploading_tapes) + setHideSetupEntry(execOfferUploadTapes); + setup_mode = SETUP_MODE_GAME; DrawSetupScreen(); @@ -6325,6 +6555,23 @@ static void execSetupTouch(void) static void execSetupArtwork(void) { + static ArtworkDirTree *gfx_last_valid = NULL; + static ArtworkDirTree *snd_last_valid = NULL; + static ArtworkDirTree *mus_last_valid = NULL; + + // current artwork directory may be invalid (level group, parent link) + if (!validLevelSeries(artwork.gfx_current)) + artwork.gfx_current = getFirstValidTreeInfoEntry(gfx_last_valid); + if (!validLevelSeries(artwork.snd_current)) + artwork.snd_current = getFirstValidTreeInfoEntry(snd_last_valid); + if (!validLevelSeries(artwork.mus_current)) + artwork.mus_current = getFirstValidTreeInfoEntry(mus_last_valid); + + // store valid artwork directory information + gfx_last_valid = artwork.gfx_current; + snd_last_valid = artwork.snd_current; + mus_last_valid = artwork.mus_current; + #if 0 Debug("screens:execSetupArtwork", "'%s', '%s', '%s'", artwork.gfx_current->subdir, @@ -6447,6 +6694,11 @@ static void execGadgetNetworkServer(void) ClickOnGadget(gi, MB_LEFTBUTTON); } +static void execOfferUploadTapes(void) +{ + OfferUploadTapes(); +} + static void ToggleNetworkModeIfNeeded(void) { int font_title = FONT_TITLE_1; @@ -6664,6 +6916,9 @@ static struct TokenInfo setup_info_game[] = { TYPE_PLAYER, &setup.network_player_nr,"Preferred Network Player:" }, { TYPE_TEXT_INPUT, execGadgetNetworkServer, "Network Server Hostname:" }, { TYPE_STRING, &network_server_text, "" }, + { TYPE_SWITCH, &setup.use_api_server, "Use Highscore Server:" }, + { TYPE_SWITCH, &setup.only_show_local_scores, "Only Show Local Scores:" }, + { TYPE_ENTER_LIST, execOfferUploadTapes, "Upload All Tapes to Server" }, { TYPE_SWITCH, &setup.multiple_users, "Multiple Users/Teams:" }, { TYPE_YES_NO, &setup.input_on_focus, "Only Move Focussed Player:" }, { TYPE_SWITCH, &setup.time_limit, "Time Limit:" }, @@ -6671,8 +6926,11 @@ static struct TokenInfo setup_info_game[] = { TYPE_SWITCH, &setup.skip_levels, "Skip Unsolved Levels:" }, { TYPE_SWITCH, &setup.increment_levels,"Increment Solved Levels:" }, { TYPE_SWITCH, &setup.auto_play_next_level,"Auto-play Next Level:" }, + { TYPE_SWITCH, &setup.count_score_after_game,"Count Score After Game:" }, { TYPE_SWITCH, &setup.show_scores_after_game,"Show Scores After Game:" }, { TYPE_YES_NO, &setup.ask_on_game_over, "Ask on Game Over:" }, + { TYPE_YES_NO, &setup.ask_on_quit_game, "Ask on Quit Game:" }, + { TYPE_YES_NO, &setup.ask_on_quit_program, "Ask on Quit Program:" }, { TYPE_SWITCH, &setup.autorecord, "Auto-Record Tapes:" }, { TYPE_ENTER_LIST, execSetupChooseGameSpeed, "Game Speed:" }, { TYPE_STRING, &game_speed_text, "" }, @@ -6683,7 +6941,8 @@ static struct TokenInfo setup_info_game[] = #endif { TYPE_ENTER_LIST, execSetupChooseSnapshotMode,"Game Engine Snapshot Mode:" }, { TYPE_STRING, &snapshot_mode_text, "" }, - { TYPE_SWITCH, &setup.show_snapshot_buttons,"Show Snapshot Buttons:" }, + { TYPE_SWITCH, &setup.show_load_save_buttons,"Show Load/Save Buttons:" }, + { TYPE_SWITCH, &setup.show_undo_redo_buttons,"Show Undo/Redo Buttons:" }, { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, @@ -7262,6 +7521,10 @@ static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx) if (si->value == &setup.network_mode) ToggleNetworkModeIfNeeded(); + // API server mode may have changed at this point + if (si->value == &setup.use_api_server) + runtime.use_api_server = setup.use_api_server; + // game speed list may have changed at this point if (si->value == &setup.game_speed_extended) ToggleGameSpeedsListIfNeeded(); @@ -8820,10 +9083,10 @@ void HandleGameActions(void) if (game_status != GAME_MODE_PLAYING) return; - GameActions(); // main game loop + GameActions(); // main game loop if (tape.auto_play && !tape.playing) - AutoPlayTapes(); // continue automatically playing next tape + AutoPlayTapesContinue(); // continue automatically playing next tape } @@ -9614,3 +9877,78 @@ void DrawScreenAfterAddingSet(char *tree_subdir_new, int tree_type) } } } + +static int UploadTapes(void) +{ + SetGameStatus(GAME_MODE_LOADING); + + FadeSetEnterScreen(); + FadeOut(REDRAW_ALL); + + ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE); + + FadeIn(REDRAW_ALL); + + DrawInitTextHead("Uploading tapes"); + + global.autoplay_mode = AUTOPLAY_MODE_UPLOAD; + global.autoplay_leveldir = "ALL"; + global.autoplay_all = TRUE; + + int num_tapes_uploaded = AutoPlayTapes(); + + global.autoplay_mode = AUTOPLAY_MODE_NONE; + global.autoplay_leveldir = NULL; + global.autoplay_all = FALSE; + + SetGameStatus(GAME_MODE_MAIN); + + DrawMainMenu(); + + return num_tapes_uploaded; +} + +static boolean OfferUploadTapes(void) +{ + if (!Request("Upload all your tapes to the high score server now?", REQ_ASK)) + return FALSE; + + int num_tapes_uploaded = UploadTapes(); + char message[100]; + + sprintf(message, "%d tapes uploaded!", num_tapes_uploaded); + + Request(message, REQ_CONFIRM); + + // after all tapes have been uploaded, remove entry from setup menu + setup.provide_uploading_tapes = FALSE; + + SaveSetup(); + + return (num_tapes_uploaded > 0); +} + +void CheckUploadTapes(void) +{ + if (!setup.ask_for_uploading_tapes) + return; + + if (directoryExists(getTapeDir(NULL))) + { + boolean tapes_uploaded = OfferUploadTapes(); + + if (!tapes_uploaded) + Request("You can upload your tapes from the setup menu later!", + REQ_CONFIRM); + } + else + { + // if tapes directory does not exist yet, never offer uploading all tapes + setup.provide_uploading_tapes = FALSE; + } + + // after asking for uploading all tapes once, do not ask again + setup.ask_for_uploading_tapes = FALSE; + + SaveSetup(); +}