149 lines
4.1 KiB
C
149 lines
4.1 KiB
C
#include "level.h"
|
|
#include "assets.h"
|
|
#include "debug.h"
|
|
#include "physics_world.h"
|
|
#include "tilemap.h"
|
|
#include <cjson/cJSON.h>
|
|
#include <stdio.h>
|
|
|
|
#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;
|
|
};
|
|
|
|
void _internal_level_destroy(Level* self) {
|
|
for(size_t map_index = 0; map_index < self->tilemaps_len; ++map_index) {
|
|
physics_world_remove_map(self->tilemaps[map_index]);
|
|
tilemap_destroy(self->tilemaps[map_index]);
|
|
}
|
|
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 = 0,
|
|
.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);
|
|
physics_world_add_map(*next_tilemap);
|
|
++next_tilemap;
|
|
} else if(strcmp(type->valuestring, "Entities")) {
|
|
// load entities
|
|
}
|
|
}
|
|
}
|
|
|
|
store_asset(Level_as_Asset(self));
|
|
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) {
|
|
LOG_ERROR("Failed to load level from '%s'.", filename);
|
|
free(filename);
|
|
return NULL;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
Tilemap* level_get_tilemap_layer(Level* self, size_t layer) {
|
|
ASSERT_RETURN(layer < self->tilemaps_len, NULL, "Layer index %zu out of range", layer);
|
|
return self->tilemaps[layer];
|
|
}
|
|
|
|
size_t level_get_tilemap_count(Level* self) {
|
|
return self->tilemaps_len;
|
|
}
|
|
|
|
asset_id level_get_asset_id(Level* self) {
|
|
LOG_INFO("(get) level asset id %zu", self->asset_id);
|
|
return self->asset_id;
|
|
}
|
|
|
|
void level_set_asset_id(Level* self, asset_id id) {
|
|
self->asset_id = id;
|
|
LOG_INFO("(set) level asset id %zu", self->asset_id);
|
|
}
|