2021-12-10 22:42:07 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ncurses.h>
|
|
|
|
|
|
|
|
#include <json-glib/json-glib.h>
|
|
|
|
|
|
|
|
#include <l3tde/util/string.h>
|
|
|
|
#include <l3tde/overworld.h>
|
|
|
|
#include <l3tde/map/terrain.h>
|
2021-12-12 21:48:56 +01:00
|
|
|
#include <l3tde/map.h>
|
2021-12-10 22:42:07 +01:00
|
|
|
|
|
|
|
#define TERRAINS_PATH "/terrains.json"
|
2021-12-12 21:48:56 +01:00
|
|
|
#define MAPS_PATH "/maps/"
|
2021-12-10 22:42:07 +01:00
|
|
|
#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);
|
2021-12-12 21:48:56 +01:00
|
|
|
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);
|
2021-12-10 22:42:07 +01:00
|
|
|
|
|
|
|
L3TDEOverworldPtr
|
|
|
|
l3tde_overworld_create () {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-12-12 21:48:56 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2021-12-10 22:42:07 +01:00
|
|
|
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;
|
|
|
|
}
|