completing the implementation of JSON terrains (WIP).

seeing a crash when trying to allocate a resource for stone in test_json_terrains.
This commit is contained in:
Enno Rehling 2015-09-11 12:12:53 +02:00
parent 8860244f1c
commit 59e2c12605
3 changed files with 101 additions and 5 deletions

View File

@ -54,6 +54,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* libc includes */
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@ -179,9 +180,14 @@ static void rt_register(resource_type * rtype)
resource_type *rt_get_or_create(const char *name) {
resource_type *rtype = rt_find(name);
if (!rtype) {
rtype = (resource_type *)calloc(sizeof(resource_type), 1);
rtype->_name = _strdup(name);
rt_register(rtype);
rtype = calloc(1, sizeof(resource_type));
if (!rtype) {
perror("resource_type allocation failed");
}
else {
rtype->_name = _strdup(name);
rt_register(rtype);
}
}
return rtype;
}

View File

@ -185,6 +185,39 @@ static void json_construction(cJSON *json, construction **consp) {
*consp = cons;
}
static void json_terrain_production(cJSON *json, terrain_production *prod) {
assert(json->type == cJSON_Object);
cJSON *child;
for (child = json->child; child; child = child->next) {
switch (child->type) {
case cJSON_String:
if (strcmp(child->string, "base") == 0) {
prod->base = _strdup(child->valuestring);
}
else if (strcmp(child->string, "level") == 0) {
prod->startlevel = _strdup(child->valuestring);
}
else if (strcmp(child->string, "div") == 0) {
prod->divisor = _strdup(child->valuestring);
}
else {
log_error("terrain_production %s contains unknown attribute %s", json->string, child->string);
}
break;
case cJSON_Number:
if (strcmp(child->string, "chance") == 0) {
prod->chance = (float)child->valuedouble;
}
else {
log_error("terrain_production %s contains unknown attribute %s", json->string, child->string);
}
break;
default:
log_error("terrain_production %s contains unknown attribute %s", json->string, child->string);
}
}
}
static void json_terrain(cJSON *json, terrain_type *ter) {
cJSON *child;
if (json->type != cJSON_Object) {
@ -193,6 +226,26 @@ static void json_terrain(cJSON *json, terrain_type *ter) {
}
for (child = json->child; child; child = child->next) {
switch (child->type) {
case cJSON_Object:
if (strcmp(child->string, "production") == 0) {
cJSON *entry;
int n, size = cJSON_GetArraySize(child);
ter->production = (terrain_production *)calloc(size + 1, sizeof(const item_type *));
ter->production[size].type = 0;
for (n = 0, entry = child->child; entry; entry = entry->next, ++n) {
ter->production[n].type = rt_get_or_create(entry->string);
if (entry->type != cJSON_Object) {
log_error("terrain %s contains invalid production %s", json->string, entry->string);
}
else {
json_terrain_production(entry, ter->production + n);
}
}
}
else {
log_error("terrain %s contains unknown attribute %s", json->string, child->string);
}
break;
case cJSON_Array:
if (strcmp(child->string, "flags") == 0) {
const char * flags[] = {
@ -200,10 +253,29 @@ static void json_terrain(cJSON *json, terrain_type *ter) {
};
ter->flags = json_flags(child, flags);
}
else if (strcmp(child->string, "herbs") == 0) {
cJSON *entry;
int n, size = cJSON_GetArraySize(child);
ter->herbs = malloc(sizeof(const item_type *) * (size+1));
ter->herbs[size] = 0;
for (n = 0, entry = child->child; entry; entry = entry->next) {
ter->herbs[n++] = it_get_or_create(rt_get_or_create(entry->valuestring));
}
}
else {
log_error("terrain %s contains unknown attribute %s", json->string, child->string);
}
break;
case cJSON_Number:
if (strcmp(child->string, "size") == 0) {
ter->size = child->valueint;
}
else if (strcmp(child->string, "road") == 0) {
ter->max_road = (short)child->valueint;
}
else if (strcmp(child->string, "seed") == 0) {
ter->distribution = (short)child->valueint;
}
default:
log_error("terrain %s contains unknown attribute %s", json->string, child->string);
}

View File

@ -389,7 +389,13 @@ static void test_configs(CuTest * tc)
static void test_terrains(CuTest * tc)
{
const char * data = "{\"terrains\": { \"plain\" : { \"flags\" : [ \"land\", \"fly\", \"walk\" ] } }}";
const char * data = "{\"terrains\": { \"plain\" : { "
"\"herbs\": [ \"h0\", \"h1\" ], "
"\"production\": { \"stone\": { \"chance\": 0.1, \"base\": \"1d4\", \"div\": \"1d5\", \"level\": \"1d6\" }, \"iron\": {} }, "
"\"size\": 4000, "
"\"road\": 50, "
"\"seed\": 3, "
"\"flags\" : [ \"forbidden\", \"arctic\", \"cavalry\", \"sea\", \"forest\", \"land\", \"sail\", \"fly\", \"swim\", \"walk\" ] } }}";
const terrain_type *ter;
cJSON *json = cJSON_Parse(data);
@ -401,7 +407,19 @@ static void test_terrains(CuTest * tc)
json_config(json);
ter = get_terrain("plain");
CuAssertPtrNotNull(tc, ter);
CuAssertIntEquals(tc, ter->flags, LAND_REGION | FLY_INTO | WALK_INTO);
CuAssertIntEquals(tc, ARCTIC_REGION | LAND_REGION | SEA_REGION | FOREST_REGION | CAVALRY_REGION | FORBIDDEN_REGION | FLY_INTO | WALK_INTO | SWIM_INTO | SAIL_INTO, ter->flags);
CuAssertIntEquals(tc, 4000, ter->size);
CuAssertIntEquals(tc, 50, ter->max_road);
CuAssertIntEquals(tc, 3, ter->distribution);
CuAssertPtrNotNull(tc, ter->herbs);
CuAssertPtrEquals(tc, rt_get_or_create("h0"), ter->herbs[0]->rtype);
CuAssertPtrEquals(tc, rt_get_or_create("h1"), ter->herbs[1]->rtype);
CuAssertPtrEquals(tc, 0, (void *)ter->herbs[2]);
CuAssertPtrNotNull(tc, ter->name); // anything named "plain" uses plain_name()
CuAssertPtrNotNull(tc, ter->production);
CuAssertPtrEquals(tc, rt_get_or_create("stone"), (resource_type *)ter->production[0].type);
CuAssertPtrEquals(tc, rt_get_or_create("iron"), (resource_type *)ter->production[1].type);
CuAssertPtrEquals(tc, 0, (void *)ter->production[2].type);
test_cleanup();
}