/* vi: set ts=2: +-------------------+ | | Enno Rehling | Eressea PBEM host | Christian Schlittchen | (c) 1998 - 2004 | Katja Zedel | | Henning Peters +-------------------+ This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ #include #include #include "jsonconf.h" /* kernel includes */ #include "building.h" #include "direction.h" #include "keyword.h" #include "equipment.h" #include "item.h" #include "messages.h" #include "race.h" #include "region.h" #include "resources.h" #include "ship.h" #include "terrain.h" #include "skill.h" #include "spell.h" #include "spellbook.h" #include "calendar.h" /* util includes */ #include #include #include #include #include #include #include #include #include /* external libraries */ #include /* libc includes */ #include #include #include #include #include static int json_flags(cJSON *json, const char *flags[]) { cJSON *entry; int result = 0; assert(json->type==cJSON_Array); for (entry=json->child;entry;entry=entry->next) { if (entry->type == cJSON_String) { int i; for (i = 0; flags[i]; ++i) { if (strcmp(flags[i], entry->valuestring)==0) { result |= (1<child;child;child=child->next,++i) { mat[i].number = child->valueint; mat[i].rtype = rt_get_or_create(child->string); } *matp = mat; } static void json_maintenance_i(cJSON *json, maintenance *mt) { cJSON *child; for (child = json->child; child; child = child->next) { switch (child->type) { case cJSON_Number: if (strcmp(child->string, "amount") == 0) { mt->number = child->valueint; } else { log_error("maintenance contains unknown attribute %s", child->string); } break; case cJSON_String: if (strcmp(child->string, "type") == 0) { mt->rtype = rt_get_or_create(child->valuestring); } else { log_error("maintenance contains unknown attribute %s", child->string); } break; case cJSON_Array: if (strcmp(child->string, "flags") == 0) { const char * flags[] = { "variable", "required", 0 }; mt->flags = json_flags(child, flags); } else { log_error("maintenance contains unknown array %s", child->string); } break; default: log_error("maintenance contains unknown attribute %s", child->string); } } } static void json_maintenance(cJSON *json, maintenance **mtp) { cJSON *child; maintenance *mt; int i, size = 1; if (json->type == cJSON_Array) { size = cJSON_GetArraySize(json); } else if (json->type != cJSON_Object) { log_error("maintenance is not a json object or array (%d)", json->type); return; } *mtp = mt = (struct maintenance *) calloc(sizeof(struct maintenance), size + 1); if (json->type == cJSON_Array) { for (i = 0, child = json->child; child; child = child->next, ++i) { if (child->type == cJSON_Object) { json_maintenance_i(child, mt+i); } } } json_maintenance_i(json, mt); } static void json_construction(cJSON *json, construction **consp) { cJSON *child; if (json->type==cJSON_Array) { int size = 0; for (child=json->child;child;child=child->next) { construction *cons = 0; json_construction(child, &cons); if (cons) { cons->maxsize -= size; size += cons->maxsize + size; *consp = cons; consp = &cons->improvement; } } return; } if (json->type != cJSON_Object) { log_error("construction %s is not a json object: %d", json->string, json->type); return; } construction * cons = (construction *)calloc(sizeof(construction), 1); for (child=json->child;child;child=child->next) { switch(child->type) { case cJSON_Object: if (strcmp(child->string, "materials")==0) { json_requirements(child, &cons->materials); } break; case cJSON_Number: if (strcmp(child->string, "maxsize")==0) { cons->maxsize = child->valueint; } else if (strcmp(child->string, "reqsize")==0) { cons->reqsize = child->valueint; } else if (strcmp(child->string, "minskill")==0) { cons->minskill = child->valueint; } break; default: log_error("construction %s contains unknown attribute %s", json->string, child->string); } } *consp = cons; } static void json_terrain(cJSON *json, terrain_type *ter) { cJSON *child; if (json->type!=cJSON_Object) { log_error("terrain %s is not a json object: %d", json->string, json->type); return; } for (child=json->child;child;child=child->next) { switch(child->type) { case cJSON_Array: if (strcmp(child->string, "flags")==0) { const char * flags[] = { "land", "sea", "forest", "arctic", "cavalry", "forbidden", "sail", "fly", "swim", "walk", 0 }; ter->flags = json_flags(child, flags); } else { log_error("terrain %s contains unknown attribute %s", json->string, child->string); } break; default: log_error("terrain %s contains unknown attribute %s", json->string, child->string); } } } static void json_building(cJSON *json, building_type *bt) { cJSON *child; const char *flags[] = { "nodestroy", "nobuild", "unique", "decay", "dynamic", "magic", "oneperturn", "namechange", 0 }; if (json->type != cJSON_Object) { log_error("building %s is not a json object: %d", json->string, json->type); return; } for (child=json->child;child;child=child->next) { switch(child->type) { case cJSON_Array: if (strcmp(child->string, "construction") == 0) { json_construction(child, &bt->construction); } else if (strcmp(child->string, "maintenance") == 0) { json_maintenance(child, &bt->maintenance); } else if (strcmp(child->string, "flags") == 0) { json_flags(child, flags); } break; case cJSON_Object: if (strcmp(child->string, "construction")==0) { json_construction(child, &bt->construction); } else if (strcmp(child->string, "maintenance") == 0) { json_maintenance(child, &bt->maintenance); } break; case cJSON_String: if (strcmp(child->string, "name")==0) { bt->name = (const char *(*)(const struct building_type *, const struct building *, int))get_function(child->valuestring); break; } log_error("building %s contains unknown attribute %s", json->string, child->string); break; default: log_error("building %s contains unknown attribute %s", json->string, child->string); } } } static void json_item(cJSON *json, item_type *itype) { cJSON *child; const char *flags[] = { "herb", "cursed", "nodrop", "big", "animal", "vehicle", 0 }; if (json->type!=cJSON_Object) { log_error("ship %s is not a json object: %d", json->string, json->type); return; } for (child=json->child;child;child=child->next) { switch(child->type) { case cJSON_Number: if (strcmp(child->string, "weight")==0) { itype->weight = child->valueint; break; } if (strcmp(child->string, "capacity")==0) { itype->capacity = child->valueint; break; } log_error("item %s contains unknown attribute %s", json->string, child->string); break; case cJSON_Array: if (strcmp(child->string, "flags")==0) { itype->flags = json_flags(child, flags); break; } log_error("item %s contains unknown attribute %s", json->string, child->string); case cJSON_Object: default: log_error("item %s contains unknown attribute %s", json->string, child->string); } } } static void json_ship(cJSON *json, ship_type *st) { cJSON *child, *iter; if (json->type!=cJSON_Object) { log_error("ship %s is not a json object: %d", json->string, json->type); return; } for (child=json->child;child;child=child->next) { int i; switch(child->type) { case cJSON_Object: if (strcmp(child->string, "construction")==0) { json_construction(child, &st->construction); } else { log_error("ship %s contains unknown attribute %s", json->string, child->string); } break; case cJSON_Array: st->coasts = (terrain_type **) malloc(sizeof(terrain_type *) * (1+cJSON_GetArraySize(child))); for (i=0,iter=child->child;iter;iter=iter->next) { if (iter->type==cJSON_String) { terrain_type *ter = get_or_create_terrain(iter->valuestring); if (ter) { st->coasts[i++] = ter; } } } st->coasts[i] = 0; break; case cJSON_Number: if (strcmp(child->string, "range")==0) { st->range = child->valueint; } else { log_error("ship %s contains unknown attribute %s", json->string, child->string); } break; default: log_error("ship %s contains unknown attribute %s", json->string, child->string); } } } static void json_race(cJSON *json, race *rc) { cJSON *child; const char *flags[] = { "npc", "killpeasants", "scarepeasants", "nosteal", "moverandom", "cannotmove", "learn", "fly", "swim", "walk", "nolearn", "noteach", "horse", "desert", "illusionary", "absorbpeasants", "noheal", "noweapons", "shapeshift", "", "undead", "dragon", "coastal", "", "cansail", 0 }; const char *ecflags[] = { "", "giveitem", "giveperson", "giveunit", "getitem", 0 }; if (json->type != cJSON_Object) { log_error("race %s is not a json object: %d", json->string, json->type); return; } for (child=json->child;child;child=child->next) { switch(child->type) { case cJSON_String: if (strcmp(child->string, "damage")==0) { rc->def_damage = _strdup(child->valuestring); } break; case cJSON_Number: if (strcmp(child->string, "magres")==0) { rc->magres = (float)child->valuedouble; } else if (strcmp(child->string, "maxaura")==0) { rc->maxaura = (float)child->valuedouble; } else if (strcmp(child->string, "regaura")==0) { rc->regaura = (float)child->valuedouble; } else if (strcmp(child->string, "speed")==0) { rc->speed = (float)child->valuedouble; } else if (strcmp(child->string, "recruitcost")==0) { rc->recruitcost = child->valueint; } else if (strcmp(child->string, "maintenance")==0) { rc->maintenance = child->valueint; } else if (strcmp(child->string, "weight")==0) { rc->weight = child->valueint; } else if (strcmp(child->string, "capacity")==0) { rc->capacity = child->valueint; } else if (strcmp(child->string, "hp")==0) { rc->hitpoints = child->valueint; } else if (strcmp(child->string, "ac")==0) { rc->armor = child->valueint; } // TODO: studyspeed (orcs only) break; case cJSON_Array: if (strcmp(child->string, "flags")==0) { rc->flags = json_flags(child, flags); rc->ec_flags = json_flags(child, ecflags); } break; } } } static void json_terrains(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("terrains is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { json_terrain(child, get_or_create_terrain(child->string)); } } static void json_buildings(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("buildings is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { json_building(child, bt_get_or_create(child->string)); } } static void json_spells(cJSON *json) { cJSON *child; if (json->type != cJSON_Object) { log_error("spells is not a json object: %d", json->type); return; } for (child = json->child; child; child = child->next) { if (child->type == cJSON_Object) { spell *sp; cJSON * item = cJSON_GetObjectItem(child, "index"); sp = create_spell(child->string, item ? item->valueint : 0); for (item = child->child; item; item = item->next) { if (strcmp(item->string, "index") == 0) { continue; } else if (strcmp(item->string, "cast") == 0) { sp->cast = (spell_f)get_function(item->valuestring); } else if (strcmp(item->string, "fumble") == 0) { sp->fumble = (fumble_f)get_function(item->valuestring); } else if (strcmp(item->string, "syntax") == 0) { sp->syntax = _strdup(item->valuestring); } } } } } static void json_items(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("items is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { resource_type *rtype = rt_get_or_create(child->string); item_type *itype = rtype->itype; if (!itype) { rtype->itype = itype = it_get_or_create(rtype); } json_item(child, itype); } } static void json_ships(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("ships is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { json_ship(child, st_get_or_create(child->string)); } } static void json_locale(cJSON *json, struct locale *lang) { cJSON *child; if (json->type!=cJSON_Object) { log_error("strings is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { if (child->type==cJSON_String) { locale_setstring(lang, child->string, child->valuestring); } } } static void json_strings(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("strings is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { if (child->type==cJSON_Object) { struct locale *lang = get_or_create_locale(child->string); json_locale(child, lang); } else { log_error("strings for locale `%s` are not a json object: %d", child->string, child->type); } } } static void json_direction(cJSON *json, struct locale *lang) { cJSON *child; if (json->type!=cJSON_Object) { log_error("directions for locale `%s` not a json object: %d", locale_name(lang), json->type); return; } for (child=json->child;child;child=child->next) { direction_t dir = finddirection(child->string); if (dir!=NODIRECTION) { if (child->type==cJSON_String) { init_direction(lang, dir, child->valuestring); } else if (child->type==cJSON_Array) { cJSON *entry; for (entry=child->child;entry;entry=entry->next) { init_direction(lang, dir, entry->valuestring); } } else { log_error("invalid type %d for direction `%s`", child->type, child->string); } } } } static void json_directions(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("directions is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { struct locale * lang = get_or_create_locale(child->string); json_direction(child, lang); } } static void json_skill(cJSON *json, struct locale *lang) { cJSON *child; if (json->type!=cJSON_Object) { log_error("skill for locale `%s` not a json object: %d", locale_name(lang), json->type); return; } for (child=json->child;child;child=child->next) { skill_t sk = findskill(child->string); if (sk!=NOSKILL) { if (child->type==cJSON_String) { init_skill(lang, sk, child->valuestring); locale_setstring(lang, mkname("skill", skillnames[sk]), child->valuestring); } else if (child->type==cJSON_Array) { cJSON *entry; for (entry=child->child;entry;entry=entry->next) { init_skill(lang, sk, entry->valuestring); if (entry==child->child) { locale_setstring(lang, mkname("skill", skillnames[sk]), entry->valuestring); } } } else { log_error("invalid type %d for skill `%s`", child->type, child->string); } } else { log_error("unknown skill `%s` for locale `%s`", child->string, locale_name(lang)); } } } static void json_keyword(cJSON *json, struct locale *lang) { cJSON *child; if (json->type!=cJSON_Object) { log_error("keywords for locale `%s` not a json object: %d", locale_name(lang), json->type); return; } for (child=json->child;child;child=child->next) { keyword_t kwd = findkeyword(child->string); if (kwd!=NOKEYWORD) { if (child->type==cJSON_String) { init_keyword(lang, kwd, child->valuestring); locale_setstring(lang, mkname("keyword", keywords[kwd]), child->valuestring); } else if (child->type==cJSON_Array) { cJSON *entry; for (entry=child->child;entry;entry=entry->next) { init_keyword(lang, kwd, entry->valuestring); if (entry==child->child) { locale_setstring(lang, mkname("keyword", keywords[kwd]), entry->valuestring); } } } else { log_error("invalid type %d for keyword `%s`", child->type, child->string); } } else { log_error("unknown keyword `%s` for locale `%s`", child->string, locale_name(lang)); } } } static void json_skills(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("skills is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { struct locale * lang = get_or_create_locale(child->string); json_skill(child, lang); } } static void json_keywords(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("keywords is not a json object: %d", json->type); return; } for (child=json->child;child;child=child->next) { struct locale * lang = get_or_create_locale(child->string); json_keyword(child, lang); } } static void json_races(cJSON *json) { cJSON *child; if (json->type != cJSON_Object) { log_error("races is not a json object: %d", json->type); return; } for (child = json->child; child; child = child->next) { json_race(child, rc_get_or_create(child->string)); } } const char * json_relpath; static void json_include(cJSON *json) { cJSON *child; if (json->type != cJSON_Array) { log_error("config is not a json array: %d", json->type); return; } for (child = json->child; child; child = child->next) { FILE *F; if (json_relpath) { char name[MAX_PATH]; _snprintf(name, sizeof(name), "%s/%s", json_relpath, child->valuestring); F = fopen(name, "rt"); } else { F = fopen(child->valuestring, "rt"); } if (F) { cJSON *config; char *data; size_t sz; fseek(F, 0, SEEK_END); sz = ftell(F); rewind(F); data = malloc(sz); fread(data, 1, sz, F); fclose(F); config = cJSON_Parse(data); free(data); json_config(config); cJSON_Delete(config); } } } void json_config(cJSON *json) { cJSON *child; if (json->type!=cJSON_Object) { log_error("config is not a json object: %d", json->type); return; } reset_locales(); for (child=json->child;child;child=child->next) { if (strcmp(child->string, "races")==0) { json_races(child); } else if (strcmp(child->string, "items") == 0) { json_items(child); } else if (strcmp(child->string, "include") == 0) { json_include(child); } else if (strcmp(child->string, "ships") == 0) { json_ships(child); } else if (strcmp(child->string, "strings")==0) { json_strings(child); } else if (strcmp(child->string, "directions")==0) { json_directions(child); } else if (strcmp(child->string, "keywords")==0) { json_keywords(child); } else if (strcmp(child->string, "skills")==0) { json_skills(child); } else if (strcmp(child->string, "buildings") == 0) { json_buildings(child); } else if (strcmp(child->string, "spells") == 0) { json_spells(child); } else if (strcmp(child->string, "terrains") == 0) { json_terrains(child); } else { log_error("config contains unknown attribute %s", child->string); } } }