#include #include #include #include #include #include #include #define TERRAINS_PATH "/terrains.json" #define MAPS_PATH "/maps/" #define MAPS_JSON "/maps.json" static short l3tde_overworld_string_to_color (const char *color); static char ** l3tde_overworld_get_maps (size_t *maps_len_out); static L3TDEMapTerrainPtr * l3tde_overworld_load_terrains (size_t *terrains_len_out); static L3TDEMapHeaderPtr l3tde_overworld_get_header_from_map_json ( JsonObject *map_object); static L3TDEMapNodePtr ** l3tde_overworld_get_nodes_from_map_json ( L3TDEOverworldPtr self, JsonObject *map_object, size_t *nodes_x_len_out, size_t *nodes_y_len_out); static L3TDEMapNodePtr * l3tde_overworld_iterate_nodes_x_axys ( L3TDEOverworldPtr self, JsonArray *nodes_x_axys); L3TDEOverworldPtr l3tde_overworld_create (void) { L3TDEOverworldPtr self = malloc (sizeof *self); char **map_files = NULL; size_t map_files_len = 0; size_t terrains_len = 0; L3TDEMapTerrainPtr *terrains = l3tde_overworld_load_terrains (&terrains_len); map_files = l3tde_overworld_get_maps (&map_files_len); self->terrains = terrains; self->terrains_len = terrains_len; self->map_files = map_files; self->map_files_len = map_files_len; return self; } L3TDEMapPtr l3tde_overworld_get_map (L3TDEOverworldPtr self, size_t map_number) { GError *error = NULL; JsonParser *parser = NULL; JsonNode *root = NULL; JsonObject *map_object = NULL; L3TDEMapHeaderPtr header = NULL; L3TDEMapPtr map = NULL; L3TDEMapNodePtr **nodes = NULL; char **map_files = self->map_files; char *current_map_str = map_files[map_number]; char *current_map_path = NULL; size_t current_map_path_len = 0; size_t nodes_len; size_t nodes_x_len; current_map_path_len = snprintf (NULL, 0, "%s%s%s", RESOURCES_PATH, MAPS_PATH, current_map_str) + 1; current_map_path = malloc (sizeof *current_map_path * current_map_path_len); snprintf (current_map_path, current_map_path_len, "%s%s%s", RESOURCES_PATH, MAPS_PATH, current_map_str); parser = json_parser_new (); json_parser_load_from_file (parser, current_map_path, &error); if (error) { g_error ("%s", error->message); } root = json_parser_get_root (parser); map_object = json_node_get_object (root); header = l3tde_overworld_get_header_from_map_json (map_object); nodes = l3tde_overworld_get_nodes_from_map_json (self, map_object, &nodes_x_len, &nodes_len); if (!nodes) { g_error ("Nodes is null."); return NULL; } map = l3tde_map_create (header, nodes, nodes_x_len, nodes_len, NULL, 0); return map; } static L3TDEMapNodePtr ** l3tde_overworld_get_nodes_from_map_json ( L3TDEOverworldPtr self, JsonObject *map_object, size_t *nodes_x_len_out, size_t *nodes_y_len_out) { JsonArray *nodes_array; L3TDEMapNodePtr **nodes = NULL; size_t nodes_array_y_len = 0; if (!nodes_x_len_out || !nodes_y_len_out) { g_error ("The output size of the array must be a not " "null pointer."); return NULL; } *nodes_x_len_out = json_object_get_int_member ( map_object, "nodes_x_len"); *nodes_y_len_out = json_object_get_int_member ( map_object, "nodes_y_len"); nodes_array = json_object_get_array_member (map_object, "nodes"); nodes_array_y_len = json_array_get_length (nodes_array); if (*nodes_y_len_out != nodes_array_y_len) { g_error ("The map has an incorrect node size in the " " y axys unable to load. %ld", nodes_array_y_len); return NULL; } for (unsigned int i = 0; i < nodes_array_y_len; i++) { JsonArray *nodes_x_array = json_array_get_array_element (nodes_array, i); unsigned int nodes_x_array_len = json_array_get_length (nodes_x_array); if (nodes_x_array_len != *nodes_x_len_out) { g_error ("The map has an incorrect node size in " " the x axys."); return NULL; } nodes = realloc (nodes, sizeof *nodes * (i+1)); nodes[i] = l3tde_overworld_iterate_nodes_x_axys ( self, nodes_x_array); if (!nodes[i]) { return NULL; } } return nodes; } static L3TDEMapNodePtr * l3tde_overworld_iterate_nodes_x_axys ( L3TDEOverworldPtr self, JsonArray *nodes_x_axys) { L3TDEMapNodePtr *nodes = NULL; unsigned int nodes_x_array_len = json_array_get_length (nodes_x_axys); for (unsigned int i = 0; i < nodes_x_array_len; i++) { JsonObject *node_object = json_array_get_object_element (nodes_x_axys, i); size_t terrain_number = json_object_get_int_member (node_object, "terrain"); size_t navigation = json_object_get_int_member ( node_object, "navigation"); if (!(terrain_number < self->terrains_len)) { g_error ("Unexpected terrain number."); return NULL; } L3TDEMapTerrainPtr terrain = self->terrains[terrain_number]; nodes = realloc (nodes, sizeof *nodes * (i+1)); nodes[i] = l3tde_map_node_create (terrain, (L3TDEMapNodeNavigation) navigation); } return nodes; } static L3TDEMapHeaderPtr l3tde_overworld_get_header_from_map_json ( JsonObject *map_object) { const char *name; const char *description; JsonObject *header_object = json_object_get_object_member (map_object, "header"); name = json_object_get_string_member (header_object, "name"); description = json_object_get_string_member (header_object, "description"); return l3tde_map_header_create (name, strlen (name), description, strlen (description)); } static char ** l3tde_overworld_get_maps (size_t *maps_len_out) { size_t array_maps_len = 0; GError *error = NULL; JsonParser *parser = NULL; JsonNode *root = NULL; JsonArray *array_maps = NULL; char **return_value = NULL; size_t maps_len; parser = json_parser_new (); json_parser_load_from_file (parser, RESOURCES_PATH MAPS_JSON, &error); if (error) { g_error ("Unable to read %s.", RESOURCES_PATH MAPS_JSON); g_clear_error (&error); goto cleanup_l3tde_overworld_get_maps; } root = json_parser_get_root (parser); if (!JSON_NODE_HOLDS_ARRAY (root)) { g_error (RESOURCES_PATH MAPS_JSON " doesn't hold an array."); goto cleanup_l3tde_overworld_get_maps; } array_maps = json_node_get_array (root); array_maps_len = json_array_get_length (array_maps); for (size_t i = 0; i < array_maps_len; i++) { const char *path = json_array_get_string_element ( array_maps, i); maps_len = i+1; return_value = realloc (return_value, sizeof *return_value * maps_len); return_value[i] = copy_string (path, strlen(path)); } cleanup_l3tde_overworld_get_maps: if (parser) { g_clear_object (&parser); } if (maps_len_out) { *maps_len_out = maps_len; } return return_value; } static L3TDEMapTerrainPtr * l3tde_overworld_load_terrains (size_t *terrains_len_out) { size_t terrains_len; GError *error = NULL; L3TDEMapTerrainPtr *terrains = NULL; JsonParser *parser = NULL; JsonNode *root = NULL; JsonArray *json_array_terrains = NULL; parser = json_parser_new (); json_parser_load_from_file (parser, RESOURCES_PATH TERRAINS_PATH, &error); if (error) { g_error ("Unable to read %s: %s\n", RESOURCES_PATH TERRAINS_PATH, error->message); g_clear_error (&error); goto cleanup_l3tde_overworld_load_terrains; } root = json_parser_get_root (parser); if (!JSON_NODE_HOLDS_ARRAY (root)) { g_error ("Terrains json doesn't hold an array as the " "root node."); } json_array_terrains = json_node_get_array (root); terrains_len = json_array_get_length (json_array_terrains); terrains = realloc (terrains, sizeof *terrains * terrains_len); for (size_t i = 0; i < terrains_len; i++) { JsonNode *node = json_array_get_element (json_array_terrains, i); if (!JSON_NODE_HOLDS_OBJECT (node)) { g_error ("Terrain %ld is not a hash.", i); goto cleanup_l3tde_overworld_load_terrains; } JsonObject *object = json_node_get_object (node); const char *name = json_object_get_string_member ( object, "name"); const char *symbol = json_object_get_string_member ( object, "symbol"); const char *foreground = json_object_get_string_member (object, "foreground"); const char *background = json_object_get_string_member (object, "background"); if (strlen (symbol) > 1 || strlen (symbol) < 1) { g_error ("Symbol for terrain %ld is not valid.", i); goto cleanup_l3tde_overworld_load_terrains; } char symbol_as_char = symbol[0]; terrains[i] = l3tde_map_terrain_create (name, strlen(name), symbol_as_char, l3tde_overworld_string_to_color (foreground), l3tde_overworld_string_to_color (background)); } cleanup_l3tde_overworld_load_terrains: if (parser) { g_clear_object (&parser); } if (terrains_len_out) { *terrains_len_out = terrains_len; } return terrains; } static short l3tde_overworld_string_to_color (const char *color) { if (!strcmp (color, "black")) { return COLOR_BLACK; } else if (!strcmp (color, "red")) { return COLOR_RED; } else if (!strcmp (color, "green")) { return COLOR_GREEN; } else if (!strcmp (color, "yellow")) { return COLOR_YELLOW; } else if (!strcmp (color, "blue")) { return COLOR_BLUE; } else if (!strcmp (color, "magenta")) { return COLOR_MAGENTA; } else if (!strcmp (color, "cyan")) { return COLOR_CYAN; } else if (!strcmp (color, "white")) { return COLOR_WHITE; } g_error ("This color is not known."); // Defaulting to black if error. return COLOR_BLACK; }