Skip to content

Commit

Permalink
start world switching
Browse files Browse the repository at this point in the history
  • Loading branch information
jblanked committed Dec 17, 2024
1 parent 10bec4b commit 27d847f
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 54 deletions.
8 changes: 1 addition & 7 deletions callback/callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,16 +780,10 @@ static char *flip_world_parse_worlds(DataLoaderModel *model)
FURI_LOG_E(TAG, "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
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)
{
FURI_LOG_E(TAG, "Failed to get worlds. Data likely empty");
Expand Down
1 change: 0 additions & 1 deletion flip_world.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,3 @@ typedef struct

extern char *game_fps_choices[];
extern char *game_fps; // The game FPS
// TODO - Add Download world function and download world pack button
66 changes: 28 additions & 38 deletions game/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// 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);

Expand Down Expand Up @@ -64,6 +64,14 @@ static void player_update(Entity *self, GameManager *manager, void *context)
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
pos.x = CLAMP(pos.x, WORLD_WIDTH - 5, 5);
pos.y = CLAMP(pos.y, WORLD_HEIGHT - 5, 5);
Expand Down Expand Up @@ -116,40 +124,6 @@ const EntityDescription player_desc = {
.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 ******/

/*
Expand All @@ -163,8 +137,24 @@ static void game_start(GameManager *game_manager, void *ctx)
GameContext *game_context = ctx;
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);
}

/*
Expand Down Expand Up @@ -207,7 +197,7 @@ float game_fps_int()
Your game configuration, do not rename this variable, but you can change its content here.
*/
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
.always_backlight = true, // keep display backlight always on
.start = game_start, // will be called once, when game starts
Expand Down
4 changes: 3 additions & 1 deletion game/game.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include "engine/engine.h"
#include <game/world.h>
#include <game/level.h>
#include "flip_world.h"
#include "flip_storage/storage.h"

Expand All @@ -23,4 +24,5 @@ typedef struct
bool is_looking_left; // player is looking left
} PlayerContext;

extern const EntityDescription player_desc;
extern const EntityDescription player_desc;
void player_spawn(Level *level, GameManager *manager);
138 changes: 138 additions & 0 deletions game/level.c
Original file line number Diff line number Diff line change
@@ -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 changes: 19 additions & 0 deletions game/level.h
Original file line number Diff line number Diff line change
@@ -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();
4 changes: 2 additions & 2 deletions game/world.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ void draw_bounds(Canvas *canvas)
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++)
{
Expand Down Expand Up @@ -57,7 +57,7 @@ bool draw_json_world_furi(Level *level, FuriString *json_data)
{
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)
{
break;
Expand Down
2 changes: 1 addition & 1 deletion game/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
void draw_bounds(Canvas *canvas);
void draw_example_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);
4 changes: 2 additions & 2 deletions jsmn/jsmn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
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
if (json_data != NULL)
Expand Down Expand Up @@ -562,7 +562,7 @@ static int skip_token(const jsmntok_t *tokens, int start, int total)
}

// 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
char *array_str = get_json_value(key, json_data, max_tokens);
Expand Down
4 changes: 2 additions & 2 deletions jsmn/jsmn.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ char *jsmn(const char *key, const char *value);
int jsoneq(const char *json, jsmntok_t *tok, const char *s);

// 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
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
char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values);
Expand Down

0 comments on commit 27d847f

Please sign in to comment.