moved code for HTTP request handling to separate functions
[rocksndiamonds.git] / src / screens.c
index 5aa80c9c88cd55cf196463f259b874465664be78..55aa0c22f855bd6abad91e51fcfd88a8353108d5 100644 (file)
@@ -282,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;
@@ -1957,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)
 {
@@ -2106,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
@@ -2121,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
        {
@@ -4023,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
 // ============================================================================
@@ -4160,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)
@@ -5117,6 +5267,7 @@ static void drawHallOfFameList(int level_nr, int first_entry)
   {
     int entry = first_entry + i;
     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);
@@ -5127,8 +5278,9 @@ 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++)
@@ -5153,6 +5305,14 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
   {
     level_nr = mx;
 
+    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);
@@ -5196,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();
@@ -5435,6 +5606,9 @@ static void execSetupGame(void)
 
   execSetupGame_setNetworkServerText();
 
+  if (!setup.provide_uploading_tapes)
+    setHideSetupEntry(execOfferUploadTapes);
+
   setup_mode = SETUP_MODE_GAME;
 
   DrawSetupScreen();
@@ -6520,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;
@@ -6737,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:"           },
@@ -6759,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"                  },
 
@@ -7338,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();
@@ -8896,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
 }
 
 
@@ -9690,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();
+}