Просмотр исходного кода

start pvp

I think Im going this route:
1. Load lobby list
2. Load Player stats
3. Player selects an available lobby
4. Player joins + websocket connection starts
5. Update player positions/states via websocket on position change
6. End websocket connection when player leaves

Tomorrow I'll work on the server side and create a view for #3 in the app
jblanked 9 месяцев назад
Родитель
Сommit
b830c3bc51
4 измененных файлов с 92 добавлено и 7 удалено
  1. 49 5
      callback/callback.c
  2. 3 2
      game/game.c
  3. 39 0
      game/world.c
  4. 1 0
      game/world.h

+ 49 - 5
callback/callback.c

@@ -1224,14 +1224,58 @@ static void run(FlipWorldApp *app)
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipWorldViewMessage);
         view_dispatcher_switch_to_view(app->view_dispatcher, FlipWorldViewMessage);
 
 
         // Make the request
         // Make the request
-        if (!flipper_http_process_response_async(fhttp, fetch_world_list_i, parse_world_list_i) || !flipper_http_process_response_async(fhttp, fetch_player_stats_i, set_player_context))
+        if (game_mode_index != 1) // not GAME_MODE_PVP
         {
         {
-            FURI_LOG_E(HTTP_TAG, "Failed to make request");
-            flipper_http_free(fhttp);
+            if (!flipper_http_process_response_async(fhttp, fetch_world_list_i, parse_world_list_i) || !flipper_http_process_response_async(fhttp, fetch_player_stats_i, set_player_context))
+            {
+                FURI_LOG_E(HTTP_TAG, "Failed to make request");
+                flipper_http_free(fhttp);
+            }
+            else
+            {
+                flipper_http_free(fhttp);
+            }
         }
         }
         else
         else
         {
         {
-            flipper_http_free(fhttp);
+            // load pvp info (this returns the lobbies available)
+            bool fetch_pvp_lobbies()
+            {
+                // ensure flip_world directory exists
+                char directory_path[128];
+                snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world");
+                Storage *storage = furi_record_open(RECORD_STORAGE);
+                storage_common_mkdir(storage, directory_path);
+                snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/pvp");
+                storage_common_mkdir(storage, directory_path);
+                furi_record_close(RECORD_STORAGE);
+                snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/pvp/pvp_lobbies.json");
+                fhttp->save_received_data = true;
+                return flipper_http_request(fhttp, GET, "https://www.jblanked.com/flipper/api/world/pvp/lobbies/", "{\"Content-Type\":\"application/json\"}", NULL);
+            }
+
+            bool parse_pvp_lobbies()
+            {
+                // as long as the request is not an issue, we are good
+                // the game will handle the rest
+                return fhttp->state != ISSUE;
+            }
+
+            // load pvp lobbies and player stats
+            if (!flipper_http_process_response_async(fhttp, fetch_pvp_lobbies, parse_pvp_lobbies) || !flipper_http_process_response_async(fhttp, fetch_player_stats_i, set_player_context))
+            {
+                // unlike the pve/story, receiving data is necessary
+                // so send the user back to the main menu if it fails
+                FURI_LOG_E(HTTP_TAG, "Failed to make request");
+                easy_flipper_dialog("Error", "Failed to make request. Press BACK to return.");
+                view_dispatcher_switch_to_view(app->view_dispatcher,
+                                               FlipWorldViewSubmenu);
+                flipper_http_free(fhttp);
+            }
+            else
+            {
+                flipper_http_free(fhttp);
+            }
         }
         }
 
 
         if (!alloc_submenu_settings(app))
         if (!alloc_submenu_settings(app))
@@ -1272,7 +1316,7 @@ void callback_submenu_choices(void *context, uint32_t index)
         break;
         break;
     case FlipWorldSubmenuIndexPvP:
     case FlipWorldSubmenuIndexPvP:
         game_mode_index = 1; // GAME_MODE_PVP
         game_mode_index = 1; // GAME_MODE_PVP
-        easy_flipper_dialog("Unavailable", "\nPvP mode is not ready yet.\nPress BACK to return.");
+        run(app);
         break;
         break;
     case FlipWorldSubmenuIndexPvE:
     case FlipWorldSubmenuIndexPvE:
         game_mode_index = 0; // GAME_MODE_PVE
         game_mode_index = 0; // GAME_MODE_PVE

+ 3 - 2
game/game.c

@@ -61,8 +61,9 @@ static void game_start(GameManager *game_manager, void *ctx)
     }
     }
     else if (game_context->game_mode == GAME_MODE_PVP)
     else if (game_context->game_mode == GAME_MODE_PVP)
     {
     {
-        // show pvp menu
-        easy_flipper_dialog("Unavailable", "\nPvP mode is not ready yet.\nPress BACK to return.");
+        // show pvp
+        game_context->levels[0] = game_manager_add_level(game_manager, pvp_world());
+        game_context->level_count = 1;
     }
     }
 
 
     // imu
     // imu

+ 39 - 0
game/world.c

@@ -124,6 +124,45 @@ const LevelBehaviour *training_world()
     return &_training_world;
     return &_training_world;
 }
 }
 
 
+static void draw_pvp_world(Level *level, GameManager *manager, void *context)
+{
+    UNUSED(context);
+    if (!manager || !level)
+    {
+        FURI_LOG_E("Game", "Manager or level is NULL");
+        return;
+    }
+    GameContext *game_context = game_manager_game_context_get(manager);
+    level_clear(level);
+    FuriString *json_data_str = furi_string_alloc();
+    furi_string_cat_str(json_data_str, "{\"name\":\"pvp_world\",\"author\":\"ChatGPT\",\"json_data\":[{\"icon\":\"rock_medium\",\"x\":100,\"y\":100,\"amount\":10,\"horizontal\":true},{\"icon\":\"rock_medium\",\"x\":400,\"y\":300,\"amount\":6,\"horizontal\":true},{\"icon\":\"rock_small\",\"x\":600,\"y\":200,\"amount\":8,\"horizontal\":true},{\"icon\":\"fence\",\"x\":50,\"y\":50,\"amount\":10,\"horizontal\":true},{\"icon\":\"fence\",\"x\":250,\"y\":150,\"amount\":12,\"horizontal\":true},{\"icon\":\"fence\",\"x\":550,\"y\":350,\"amount\":12,\"horizontal\":true},{\"icon\":\"rock_large\",\"x\":400,\"y\":70,\"amount\":12,\"horizontal\":true},{\"icon\":\"rock_large\",\"x\":200,\"y\":200,\"amount\":6,\"horizontal\":false},{\"icon\":\"tree\",\"x\":5,\"y\":5,\"amount\":45,\"horizontal\":true},{\"icon\":\"tree\",\"x\":5,\"y\":5,\"amount\":20,\"horizontal\":false},{\"icon\":\"tree\",\"x\":22,\"y\":22,\"amount\":44,\"horizontal\":true},{\"icon\":\"tree\",\"x\":22,\"y\":22,\"amount\":20,\"horizontal\":false},{\"icon\":\"tree\",\"x\":5,\"y\":347,\"amount\":45,\"horizontal\":true},{\"icon\":\"tree\",\"x\":5,\"y\":364,\"amount\":45,\"horizontal\":true},{\"icon\":\"tree\",\"x\":735,\"y\":37,\"amount\":18,\"horizontal\":false},{\"icon\":\"tree\",\"x\":752,\"y\":37,\"amount\":18,\"horizontal\":false}]}");
+    if (!separate_world_data("pvp_world", json_data_str))
+    {
+        FURI_LOG_E("Game", "Failed to separate world data");
+    }
+    furi_string_free(json_data_str);
+    set_world(level, manager, "pvp_world");
+    game_context->icon_offset = 0;
+    if (!game_context->imu_present)
+    {
+        game_context->icon_offset += ((game_context->icon_count / 10) / 15);
+    }
+    player_spawn(level, manager);
+}
+
+static const LevelBehaviour _pvp_world = {
+    .alloc = NULL,
+    .free = NULL,
+    .start = draw_pvp_world,
+    .stop = NULL,
+    .context_size = 0,
+};
+
+const LevelBehaviour *pvp_world()
+{
+    return &_pvp_world;
+}
+
 FuriString *fetch_world(const char *name)
 FuriString *fetch_world(const char *name)
 {
 {
     if (!name)
     if (!name)

+ 1 - 0
game/world.h

@@ -11,5 +11,6 @@
 // Maximum number of world objects
 // Maximum number of world objects
 #define MAX_WORLD_OBJECTS 25 // any more than that and we may run out of heap when switching worlds
 #define MAX_WORLD_OBJECTS 25 // any more than that and we may run out of heap when switching worlds
 const LevelBehaviour *training_world();
 const LevelBehaviour *training_world();
+const LevelBehaviour *pvp_world();
 bool draw_json_world_furi(GameManager *manager, Level *level, const FuriString *json_data);
 bool draw_json_world_furi(GameManager *manager, Level *level, const FuriString *json_data);
 FuriString *fetch_world(const char *name);
 FuriString *fetch_world(const char *name);