diff --git a/src/kernel/item.c b/src/kernel/item.c index f801cf226..4aab13112 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -54,6 +54,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include +#include #include #include @@ -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; } diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index 7b2297146..1ea6e6ba3 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -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); } diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c index c317fc15a..ef7b7c0d1 100644 --- a/src/kernel/jsonconf.test.c +++ b/src/kernel/jsonconf.test.c @@ -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(); }