#include "level.h" #include "assets.h" #include "debug.h" #include "tilemap.h" #include #include #define LEVEL_EXT ".ldtkl" #define WORLD_EXT ".ldtk" #define LEVEL_DIR "assets/levels/" struct Level { asset_id asset_id; size_t level_iid; Transform transform; Tilemap** tilemaps; size_t tilemaps_len; Vector player_start; }; static void _deallocate_level(void* self_void) { Level* self = self_void; free(self); } static size_t _count_layers(cJSON* layers, size_t* entities, size_t* automap) { size_t ent_ = 0, auto_ = 0, tot_ = 0; cJSON* layer; cJSON_ArrayForEach(layer, layers) { cJSON* type = cJSON_GetObjectItem(layer, "__type"); if(type == NULL) { continue; } else if(strcmp(type->valuestring, "AutoLayer") == 0) { auto_++; } else if(strcmp(type->valuestring, "Entities") == 0) { ent_++; } tot_++; } if(entities != NULL) *entities = ent_; if(automap != NULL) *automap = auto_; return tot_; } Level* level_from_json(cJSON* json) { // allocate a new level struct Level* self = malloc(sizeof(Level)); ASSERT_RETURN(self != NULL, NULL, "Failed to allocate level object."); *self = (Level) { .asset_id = store_asset(self, &_deallocate_level), .transform = IdentityTransform }; // fetch the instance id cJSON* iid = cJSON_GetObjectItem(json, "iid"); if(iid != NULL && cJSON_IsNumber(iid)) self->level_iid = iid->valueint; // get the level's layers cJSON* layers = cJSON_GetObjectItem(json, "layerInstances"); // count the different kinds of layers size_t entity_layer_count; _count_layers(layers, &entity_layer_count, &self->tilemaps_len); // allocate tilemap array self->tilemaps = malloc(self->tilemaps_len * sizeof(Tilemap*)); Tilemap** next_tilemap = self->tilemaps; if(layers != NULL && cJSON_IsArray(layers)) { cJSON* layer; cJSON_ArrayForEach(layer, layers) { cJSON* type = cJSON_GetObjectItem(layer, "__type"); if(strcmp(type->valuestring, "AutoLayer") == 0) { // load a tilemap as an autolayer LOG_INFO("loading autolayer"); *next_tilemap = tilemap_from_autolayer(layer); ++next_tilemap; } else if(strcmp(type->valuestring, "Entities")) { // load entities } } } return self; } Level* level_load(const char* level_id) { // Convert the level ID to a filepath size_t filename_len = strlen(LEVEL_DIR) + strlen(level_id) + strlen(LEVEL_EXT) + 1; char* filename = malloc(filename_len); sprintf(filename, "%s%s%s", LEVEL_DIR, level_id, LEVEL_EXT); LOG_INFO("loading level %s at %s", level_id, filename); cJSON* level = load_json_from_file(filename); if(level == NULL) { free(filename); RETURN_ERROR(NULL, "Failed to load level from '%s'.", filename); } free(filename); return level_from_json(level); } void level_destroy(Level* self) { free_asset(self->asset_id); } void level_draw(Level* self) { Tilemap** end = self->tilemaps + self->tilemaps_len; for(Tilemap** map = self->tilemaps; map != end; ++map) { tilemap_draw(*map, self->transform); } }