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

set other player as an enemy and EnemyContext

jblanked 9 месяцев назад
Родитель
Сommit
5f8b6a2ff6
4 измененных файлов с 115 добавлено и 10 удалено
  1. 92 4
      callback/callback.c
  2. 20 4
      game/enemy.c
  3. 2 2
      game/player.c
  4. 1 0
      game/player.h

+ 92 - 4
callback/callback.c

@@ -1521,10 +1521,98 @@ static void callback_submenu_lobby_choices(void *context, uint32_t index)
 
         bool parse_lobby()
         {
-            // for now just return true and the game will handle the rest
-            // later we will parse the current player's attributes (which is not the current user)
-            // not sure how we're gonna handle two PlayerContexts O.o
-            return fhttp->state != ISSUE;
+            /*
+            expected output from fhttp->file_path
+           {"id":"new","player_count":1,"player_list":["JBlanked"],"player_stats":[{"username":"JBlanked","level":16,"xp":25511,"health":90,"strength":12,"max_health":100,"health_regen":1,"elapsed_health_regen":0,"attack_timer":0.1,"elapsed_attack_timer":0,"direction":"up","state":"moving","start_position_x":450,"start_position_y":300,"dx":5,"dy":0}],"data":{}}
+
+           expected out to save
+           {"enemy_data":[{"id":"cyclops","index":0,"start_position":{"x":350,"y":210},"end_position":{"x":350,"y":210},"move_timer":1,"speed":1,"attack_timer":0.1,"strength":12,"health":100"}]}
+           */
+            // we need to save the first player's stats as enemy_data for the pvp_world, so that the game renders the player as an Enemy using EnemyContext
+            // saved at STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/%s/%s_json_data.json
+            // 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/worlds");
+            storage_common_mkdir(storage, directory_path);
+            snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/pvp_world");
+            storage_common_mkdir(storage, directory_path);
+            furi_record_close(RECORD_STORAGE);
+
+            snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds/pvp_world/pvp_world_enemy_data.json");
+
+            FuriString *lobby = flipper_http_load_from_file(fhttp->file_path);
+            if (!lobby)
+            {
+                FURI_LOG_E(TAG, "Failed to load lobby details");
+                flipper_http_free(fhttp);
+                return false;
+            }
+
+            // parse the lobby details
+            FuriString *player_stats = get_json_array_value_furi("player_stats", 0, lobby);
+            if (!player_stats)
+            {
+                FURI_LOG_E(TAG, "Failed to get player stats");
+                furi_string_free(lobby);
+                flipper_http_free(fhttp);
+                return false;
+            }
+
+            // available keys from player_stats
+            FuriString *username = get_json_value_furi("username", player_stats);
+            FuriString *strength = get_json_value_furi("strength", player_stats);
+            FuriString *health = get_json_value_furi("health", player_stats);
+            FuriString *attack_timer = get_json_value_furi("attack_timer", player_stats);
+
+            if (!username || !strength || !health || !attack_timer)
+            {
+                FURI_LOG_E(TAG, "Failed to get player stats");
+                furi_string_free(player_stats);
+                furi_string_free(lobby);
+                flipper_http_free(fhttp);
+                return false;
+            }
+
+            // create enemy data
+            FuriString *enemy_data = furi_string_alloc();
+            furi_string_printf(enemy_data, "{\"enemy_data\":[{\"id\":\"sword\",\"is_user\":\"true\",\"index\":0,\"start_position\":{\"x\":350,\"y\":210},\"end_position\":{\"x\":350,\"y\":210},\"move_timer\":1,\"speed\":1,\"attack_timer\":%s,\"strength\":%s,\"health\":%s}]}",
+                               furi_string_get_cstr(attack_timer), furi_string_get_cstr(strength), furi_string_get_cstr(health));
+
+            File *file = storage_file_alloc(storage);
+            if (!storage_file_open(file, directory_path, FSAM_WRITE, FSOM_CREATE_ALWAYS))
+            {
+                FURI_LOG_E("Game", "Failed to open file for writing: %s", directory_path);
+                storage_file_free(file);
+                furi_record_close(RECORD_STORAGE);
+                furi_string_free(enemy_data);
+                furi_string_free(player_stats);
+                furi_string_free(lobby);
+                furi_string_free(username);
+                furi_string_free(strength);
+                furi_string_free(health);
+                furi_string_free(attack_timer);
+                return false;
+            }
+
+            size_t data_size = furi_string_size(enemy_data);
+            if (storage_file_write(file, furi_string_get_cstr(enemy_data), data_size) != data_size)
+            {
+                FURI_LOG_E("Game", "Failed to write enemy_data");
+            }
+            storage_file_close(file);
+
+            furi_string_free(enemy_data);
+            furi_string_free(player_stats);
+            furi_string_free(lobby);
+            furi_string_free(username);
+            furi_string_free(strength);
+            furi_string_free(health);
+            furi_string_free(attack_timer);
+
+            return true;
         }
 
         // well.. we need to wait for the response to be received

+ 20 - 4
game/enemy.c

@@ -15,7 +15,8 @@ static EntityContext *enemy_generic_alloc(
     float speed,
     float attack_timer,
     float strength,
-    float health)
+    float health,
+    bool is_user)
 {
     if (!enemy_context_generic)
     {
@@ -44,6 +45,8 @@ static EntityContext *enemy_generic_alloc(
     enemy_context_generic->state = ENTITY_MOVING_TO_END; // Start in IDLE state
     // Set radius based on size, for example, average of size.x and size.y divided by 2
     enemy_context_generic->radius = (size.x + size.y) / 4.0f;
+    //
+    enemy_context_generic->is_user = is_user;
     return enemy_context_generic;
 }
 
@@ -80,6 +83,7 @@ static void enemy_start(Entity *self, GameManager *manager, void *context)
     enemy_context->direction = enemy_context_generic->direction;
     enemy_context->state = enemy_context_generic->state;
     enemy_context->radius = enemy_context_generic->radius;
+    enemy_context->is_user = enemy_context_generic->is_user;
 
     // Set enemy's initial position based on start_position
     entity_pos_set(self, enemy_context->start_position);
@@ -565,7 +569,9 @@ const EntityDescription *enemy(
     float speed,
     float attack_timer,
     float strength,
-    float health)
+    float health,
+    bool is_user)
+
 {
     SpriteContext *sprite_context = get_sprite_context(id);
     if (!sprite_context)
@@ -585,7 +591,8 @@ const EntityDescription *enemy(
         speed,
         attack_timer,
         strength,
-        health);
+        health,
+        is_user);
     if (!enemy_context_generic)
     {
         FURI_LOG_E("Game", "Failed to allocate EntityContext");
@@ -651,6 +658,13 @@ void spawn_enemy(Level *level, GameManager *manager, FuriString *json)
         return;
     }
 
+    FuriString *is_user = get_json_value_furi("is_user", json);
+    bool is_user_value = false;
+    if (is_user)
+    {
+        is_user_value = strstr(furi_string_get_cstr(is_user), "true") != NULL;
+    }
+
     GameContext *game_context = game_manager_game_context_get(manager);
     if (game_context && game_context->enemy_count < MAX_ENEMIES && !game_context->enemies[game_context->enemy_count])
     {
@@ -664,7 +678,8 @@ void spawn_enemy(Level *level, GameManager *manager, FuriString *json)
                                                                                        atof_furi(speed),
                                                                                        atof_furi(attack_timer),
                                                                                        atof_furi(strength),
-                                                                                       atof_furi(health)));
+                                                                                       atof_furi(health),
+                                                                                       is_user_value));
         game_context->enemy_count++;
     }
 
@@ -681,4 +696,5 @@ void spawn_enemy(Level *level, GameManager *manager, FuriString *json)
     furi_string_free(attack_timer);
     furi_string_free(strength);
     furi_string_free(health);
+    furi_string_free(is_user);
 }

+ 2 - 2
game/player.c

@@ -228,8 +228,8 @@ static void player_update(Entity *self, GameManager *manager, void *context)
     if (game_context->game_mode == GAME_MODE_PVP && (player->old_position.x != pos.x || player->old_position.y != pos.y))
     {
         elapsed_ws_timer++;
-        // only send the websocket update every 100ms
-        if (elapsed_ws_timer >= (game_context->fps / 10))
+        // only send the websocket update every 200ms
+        if (elapsed_ws_timer >= (game_context->fps / 5))
         {
             if (game_context->fhttp)
             {

+ 1 - 0
game/player.h

@@ -29,6 +29,7 @@ typedef struct
     float strength;             // Damage the entity deals
     float health;               // Health of the entity
     char message[64];           // Message to display when interacting with the entity
+    bool is_user;               // Flag to indicate if the entity is a live player or not
 } EntityContext;
 
 typedef struct