jblanked 1 год назад
Родитель
Сommit
27d847f46e
10 измененных файлов с 196 добавлено и 54 удалено
  1. 1 7
      callback/callback.c
  2. 0 1
      flip_world.h
  3. 28 38
      game/game.c
  4. 3 1
      game/game.h
  5. 138 0
      game/level.c
  6. 19 0
      game/level.h
  7. 2 2
      game/world.c
  8. 1 1
      game/world.h
  9. 2 2
      jsmn/jsmn.c
  10. 2 2
      jsmn/jsmn.h

+ 1 - 7
callback/callback.c

@@ -780,16 +780,10 @@ static char *flip_world_parse_worlds(DataLoaderModel *model)
         FURI_LOG_E(TAG, "Failed to load world data");
         FURI_LOG_E(TAG, "Failed to load world data");
         return "Failed to load world data";
         return "Failed to load world data";
     }
     }
-    char *data = (char *)furi_string_get_cstr(world_data);
-    if (!data)
-    {
-        FURI_LOG_E(TAG, "Failed to get world data");
-        return "Failed to get world data";
-    }
     // we used 10 since we passed 10 in the request
     // we used 10 since we passed 10 in the request
     for (int i = 0; i < 10; i++)
     for (int i = 0; i < 10; i++)
     {
     {
-        char *json = get_json_array_value("worlds", i, data, 1024);
+        char *json = get_json_array_value("worlds", i, furi_string_get_cstr(world_data), 1024);
         if (!json)
         if (!json)
         {
         {
             FURI_LOG_E(TAG, "Failed to get worlds. Data likely empty");
             FURI_LOG_E(TAG, "Failed to get worlds. Data likely empty");

+ 0 - 1
flip_world.h

@@ -76,4 +76,3 @@ typedef struct
 
 
 extern char *game_fps_choices[];
 extern char *game_fps_choices[];
 extern char *game_fps; // The game FPS
 extern char *game_fps; // The game FPS
-// TODO - Add Download world function and download world pack button

+ 28 - 38
game/game.c

@@ -4,7 +4,7 @@
 
 
 // Forward declaration of player_desc, because it's used in player_spawn function.
 // Forward declaration of player_desc, because it's used in player_spawn function.
 
 
-static void player_spawn(Level *level, GameManager *manager)
+void player_spawn(Level *level, GameManager *manager)
 {
 {
     Entity *player = level_add_entity(level, &player_desc);
     Entity *player = level_add_entity(level, &player_desc);
 
 
@@ -64,6 +64,14 @@ static void player_update(Entity *self, GameManager *manager, void *context)
         player->is_looking_left = false;
         player->is_looking_left = false;
     }
     }
 
 
+    // switch levels if holding OK
+    if (input.held & GameKeyOk)
+    {
+        game_manager_next_level_set(manager, game_manager_current_level_get(manager) == level_tree ? level_example : level_tree);
+        furi_delay_ms(1000);
+        return;
+    }
+
     // Clamp the player's position to stay within world bounds
     // Clamp the player's position to stay within world bounds
     pos.x = CLAMP(pos.x, WORLD_WIDTH - 5, 5);
     pos.x = CLAMP(pos.x, WORLD_WIDTH - 5, 5);
     pos.y = CLAMP(pos.y, WORLD_HEIGHT - 5, 5);
     pos.y = CLAMP(pos.y, WORLD_HEIGHT - 5, 5);
@@ -116,40 +124,6 @@ const EntityDescription player_desc = {
     .context_size = sizeof(PlayerContext), // size of entity context, will be automatically allocated and freed
     .context_size = sizeof(PlayerContext), // size of entity context, will be automatically allocated and freed
 };
 };
 
 
-/****** Level ******/
-
-static void level_alloc(Level *level, GameManager *manager, void *context)
-{
-    UNUSED(manager);
-    UNUSED(context);
-
-    // Add player entity to the level
-    player_spawn(level, manager);
-
-    // check if tree world exists
-    if (!world_exists("tree_world"))
-    {
-        FURI_LOG_E("Game", "Tree world does not exist");
-        easy_flipper_dialog("[WORLD ERROR]", "No world data installed.\n\n\nSettings -> Game ->\nInstall Official World Pack");
-        draw_example_world(level);
-        return;
-    }
-
-    if (!draw_json_world_furi(level, load_furi_world("tree_world")))
-    {
-        FURI_LOG_E("Game", "Tree World exists but failed to draw.");
-        draw_example_world(level);
-    }
-}
-
-static const LevelBehaviour level = {
-    .alloc = level_alloc, // called once, when level allocated
-    .free = NULL,         // called once, when level freed
-    .start = NULL,        // called when level is changed to this level
-    .stop = NULL,         // called when level is changed from this level
-    .context_size = 0,    // size of level context, will be automatically allocated and freed
-};
-
 /****** Game ******/
 /****** Game ******/
 
 
 /*
 /*
@@ -163,8 +137,24 @@ static void game_start(GameManager *game_manager, void *ctx)
     GameContext *game_context = ctx;
     GameContext *game_context = ctx;
     game_context->score = 0;
     game_context->score = 0;
 
 
-    // Add level to the game
-    game_manager_add_level(game_manager, &level);
+    // load all levels
+    // if (level_load_all())
+    // {
+    //     // loop through all levels and add them to the game
+    //     for (int i = level_count; i > 0; i--)
+    //     {
+    //         levels[i] = game_manager_add_level(game_manager, level_behaviors[i]);
+    //     }
+    // }
+    // else
+    // {
+    //     FURI_LOG_E("Game", "Failed to load levels");
+    //     easy_flipper_dialog("[LEVEL ERROR]", "No level data installed.\n\n\nSettings -> Game ->\nInstall Official Level Pack");
+    //     game_manager_add_level(game_manager, &example_level);
+    // }
+
+    level_tree = game_manager_add_level(game_manager, &tree_level);
+    level_example = game_manager_add_level(game_manager, &example_level);
 }
 }
 
 
 /*
 /*
@@ -207,7 +197,7 @@ float game_fps_int()
     Your game configuration, do not rename this variable, but you can change its content here.
     Your game configuration, do not rename this variable, but you can change its content here.
 */
 */
 const Game game = {
 const Game game = {
-    .target_fps = 240,                   // target fps, game will try to keep this value
+    .target_fps = 30,                    // target fps, game will try to keep this value
     .show_fps = false,                   // show fps counter on the screen
     .show_fps = false,                   // show fps counter on the screen
     .always_backlight = true,            // keep display backlight always on
     .always_backlight = true,            // keep display backlight always on
     .start = game_start,                 // will be called once, when game starts
     .start = game_start,                 // will be called once, when game starts

+ 3 - 1
game/game.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 #include "engine/engine.h"
 #include "engine/engine.h"
 #include <game/world.h>
 #include <game/world.h>
+#include <game/level.h>
 #include "flip_world.h"
 #include "flip_world.h"
 #include "flip_storage/storage.h"
 #include "flip_storage/storage.h"
 
 
@@ -23,4 +24,5 @@ typedef struct
     bool is_looking_left; // player is looking left
     bool is_looking_left; // player is looking left
 } PlayerContext;
 } PlayerContext;
 
 
-extern const EntityDescription player_desc;
+extern const EntityDescription player_desc;
+void player_spawn(Level *level, GameManager *manager);

+ 138 - 0
game/level.c

@@ -0,0 +1,138 @@
+#include <game/level.h>
+
+/****** Level ******/
+
+static void level_start(Level *level, GameManager *manager, void *context)
+{
+    UNUSED(manager);
+    LevelContext *level_context = context;
+    // check if the world exists
+    if (!world_exists(level_context->id))
+    {
+        FURI_LOG_E("Game", "World does not exist");
+        easy_flipper_dialog("[WORLD ERROR]", "No world data installed.\n\n\nSettings -> Game ->\nInstall Official World Pack");
+        draw_example_world(level);
+        return;
+    }
+    // draw the world
+    if (!draw_json_world_furi(level, load_furi_world(level_context->id)))
+    {
+        FURI_LOG_E("Game", "World exists but failed to draw.");
+        draw_example_world(level);
+    }
+}
+
+static void level_alloc_tree_world(Level *level, GameManager *manager, void *context)
+{
+    UNUSED(level);
+    LevelContext *level_context = context;
+    snprintf(level_context->id, sizeof(level_context->id), "tree_world");
+    level_context->index = 0;
+    // Add player entity to the level
+    player_spawn(level, manager);
+}
+static void level_alloc_example_world(Level *level, GameManager *manager, void *context)
+{
+    UNUSED(level);
+    LevelContext *level_context = context;
+    snprintf(level_context->id, sizeof(level_context->id), "example_world");
+    level_context->index = 1;
+    // Add player entity to the level
+    player_spawn(level, manager);
+}
+
+Level *level_tree;
+Level *level_example;
+
+const LevelBehaviour tree_level = {
+    .alloc = level_alloc_tree_world,      // called once, when level allocated
+    .free = NULL,                         // called once, when level freed
+    .start = level_start,                 // called when level is changed to this level
+    .stop = NULL,                         // called when level is changed from this level
+    .context_size = sizeof(LevelContext), // size of level context, will be automatically allocated and freed
+};
+const LevelBehaviour example_level = {
+    .alloc = level_alloc_example_world,   // called once, when level allocated
+    .free = NULL,                         // called once, when level freed
+    .start = level_start,                 // called when level is changed to this level
+    .stop = NULL,                         // called when level is changed from this level
+    .context_size = sizeof(LevelContext), // size of level context, will be automatically allocated and freed
+};
+
+void level_alloc_world(Level *level, GameManager *manager, void *context)
+{
+    UNUSED(level);
+    LevelContext *level_context = context;
+    snprintf(level_context->id, sizeof(level_context->id), "%s", level_contexts[level_context->index].id);
+    level_context->index = level_contexts[level_context->index].index;
+    // Add player entity to the level
+    player_spawn(level, manager);
+}
+
+bool level_load_all()
+{
+    char file_path[128];
+    snprintf(
+        file_path,
+        sizeof(file_path),
+        STORAGE_EXT_PATH_PREFIX "/apps_data/flip_world/worlds.json");
+
+    FuriString *world_data = flipper_http_load_from_file(file_path);
+    if (!world_data)
+    {
+        FURI_LOG_E(TAG, "Failed to load world data");
+        return false;
+    }
+
+    const char *json_data = furi_string_get_cstr(world_data);
+    if (!json_data)
+    {
+        FURI_LOG_E(TAG, "Failed to get world data");
+        furi_string_free(world_data);
+        return false;
+    }
+
+    const LevelBehaviour new_behavior = {
+        .alloc = level_alloc_world,
+        .free = NULL,
+        .start = level_start,
+        .stop = NULL,
+        .context_size = sizeof(LevelContext),
+    };
+
+    for (int i = 0; i < 10; i++)
+    {
+        char *json = get_json_array_value("worlds", i, json_data, 1024);
+        if (!json)
+        {
+            FURI_LOG_E(TAG, "Failed to get worlds. Data likely empty");
+            break;
+        }
+
+        char *world_id = get_json_value("name", json, 1024);
+        if (!world_id)
+        {
+            FURI_LOG_E(TAG, "Failed to get world id");
+            furi_string_free(world_data);
+            free(json);
+            return false;
+        }
+
+        snprintf(level_contexts[i].id, sizeof(level_contexts[i].id), "%s", "example_world");
+        // safely copy the i value to the index
+        level_contexts[i].index = i;
+        level_behaviors[i] = &new_behavior;
+        level_count++;
+        free(json);
+        free(world_id);
+    }
+
+    furi_string_free(world_data);
+    return true;
+}
+
+// array of LevelBehaviour structures
+const LevelBehaviour *level_behaviors[10] = {0};
+LevelContext level_contexts[] = {0};
+Level *levels[] = {0};
+int level_count = 0;

+ 19 - 0
game/level.h

@@ -0,0 +1,19 @@
+#pragma once
+#include "game.h"
+
+typedef struct
+{
+    char id[64];
+    int index;
+} LevelContext;
+
+extern Level *level_tree;
+extern Level *level_example;
+extern const LevelBehaviour tree_level;
+extern const LevelBehaviour example_level;
+extern const LevelBehaviour *level_behaviors[10];
+extern LevelContext level_contexts[];
+extern Level *levels[];
+extern int level_count;
+
+bool level_load_all();

+ 2 - 2
game/world.c

@@ -7,7 +7,7 @@ void draw_bounds(Canvas *canvas)
     canvas_draw_frame(canvas, -camera_x, -camera_y, WORLD_WIDTH, WORLD_HEIGHT);
     canvas_draw_frame(canvas, -camera_x, -camera_y, WORLD_WIDTH, WORLD_HEIGHT);
 }
 }
 
 
-bool draw_json_world(Level *level, char *json_data)
+bool draw_json_world(Level *level, const char *json_data)
 {
 {
     for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
     for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
     {
     {
@@ -57,7 +57,7 @@ bool draw_json_world_furi(Level *level, FuriString *json_data)
 {
 {
     for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
     for (int i = 0; i < MAX_WORLD_OBJECTS; i++)
     {
     {
-        char *data = get_json_array_value("json_data", i, (char *)furi_string_get_cstr(json_data), MAX_WORLD_TOKENS);
+        char *data = get_json_array_value("json_data", i, furi_string_get_cstr(json_data), MAX_WORLD_TOKENS);
         if (data == NULL)
         if (data == NULL)
         {
         {
             break;
             break;

+ 1 - 1
game/world.h

@@ -16,5 +16,5 @@
 void draw_bounds(Canvas *canvas);
 void draw_bounds(Canvas *canvas);
 void draw_example_world(Level *level);
 void draw_example_world(Level *level);
 void draw_tree_world(Level *level);
 void draw_tree_world(Level *level);
-bool draw_json_world(Level *level, char *json_data);
+bool draw_json_world(Level *level, const char *json_data);
 bool draw_json_world_furi(Level *level, FuriString *json_data);
 bool draw_json_world_furi(Level *level, FuriString *json_data);

+ 2 - 2
jsmn/jsmn.c

@@ -448,7 +448,7 @@ int jsoneq(const char *json, jsmntok_t *tok, const char *s)
 }
 }
 
 
 // Return the value of the key in the JSON data
 // Return the value of the key in the JSON data
-char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
+char *get_json_value(char *key, const char *json_data, uint32_t max_tokens)
 {
 {
     // Parse the JSON feed
     // Parse the JSON feed
     if (json_data != NULL)
     if (json_data != NULL)
@@ -562,7 +562,7 @@ static int skip_token(const jsmntok_t *tokens, int start, int total)
 }
 }
 
 
 // Revised get_json_array_value
 // Revised get_json_array_value
-char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens)
+char *get_json_array_value(char *key, uint32_t index, const char *json_data, uint32_t max_tokens)
 {
 {
     // Always extract the full array each time from the original json_data
     // Always extract the full array each time from the original json_data
     char *array_str = get_json_value(key, json_data, max_tokens);
     char *array_str = get_json_value(key, json_data, max_tokens);

+ 2 - 2
jsmn/jsmn.h

@@ -122,10 +122,10 @@ char *jsmn(const char *key, const char *value);
 int jsoneq(const char *json, jsmntok_t *tok, const char *s);
 int jsoneq(const char *json, jsmntok_t *tok, const char *s);
 
 
 // Return the value of the key in the JSON data
 // Return the value of the key in the JSON data
-char *get_json_value(char *key, char *json_data, uint32_t max_tokens);
+char *get_json_value(char *key, const char *json_data, uint32_t max_tokens);
 
 
 // Revised get_json_array_value function
 // Revised get_json_array_value function
-char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens);
+char *get_json_array_value(char *key, uint32_t index, const char *json_data, uint32_t max_tokens);
 
 
 // Revised get_json_array_values function with correct token skipping
 // Revised get_json_array_values function with correct token skipping
 char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values);
 char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values);