// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. // Copyright (c) 2014 - 2015 Evol developers #include "common/hercules.h" #include #include #include #include "common/conf.h" #include "common/HPMi.h" #include "common/memmgr.h" #include "common/mmo.h" #include "common/nullpo.h" #include "common/socket.h" #include "common/strlib.h" #include "map/itemdb.h" #include "map/npc.h" #include "map/pc.h" #include "map/quest.h" #include "ecommon/utils/strutil.h" #include "ecommon/struct/strutildata.h" #include "emap/craftconf.h" struct DBMap *craftconf_db = NULL; struct craft_db_entry *craft_create_db_entry(const int id __attribute__ ((unused))) { struct craft_db_entry *entry = aCalloc(sizeof(struct craft_db_entry), 1); if (!entry) return NULL; VECTOR_INIT(entry->inventories); VECTOR_INIT(entry->create_items); VECTOR_INIT(entry->delete_items); VECTOR_INIT(entry->required_items); VECTOR_INIT(entry->required_equips); VECTOR_INIT(entry->required_skills); VECTOR_INIT(entry->required_quests); entry->selected_inventory = NULL; // entry->return_code = 0; return entry; } static bool craft_lookup_const(const struct config_setting_t *it, const char *name, int *value) { if (libconfig->setting_lookup_int(it, name, value)) { return true; } else { const char *str = NULL; if (libconfig->setting_lookup_string(it, name, &str)) { if (*str && script->get_constant(str, value)) return true; } } return false; } static bool craft_get_const(const struct config_setting_t *it, int *value) { const char *str = libconfig->setting_get_string(it); if (str && *str && script->get_constant(str, value)) return true; *value = libconfig->setting_get_int(it); return true; } static int craft_get_item_id(struct craft_db_entry *entry, const char *const errorMessage, const char *const name, const char *const fieldName) { if (!strcmp(name, "Empty") || !entry || !errorMessage) return 0; struct item_data* id = itemdb->search_name(name); if (!id) { ShowWarning(errorMessage, entry->id, fieldName, name); return 0; } return id->nameid; } static void craft_read_source_inventory(struct craft_db_entry *entry, struct config_setting_t *tt) { int i32; int i = 0; if (!entry || !tt || !config_setting_is_group(tt)) return; struct config_setting_t *item; int invLen = VECTOR_LENGTH(entry->inventories); VECTOR_ENSURE(entry->inventories, 1, 1); VECTOR_INSERTZEROED(entry->inventories, invLen); struct craft_db_inventory *inventory = &VECTOR_INDEX(entry->inventories, invLen); while((item = libconfig->setting_get_elem(tt, i)) && i < craft_inventory_size) { int amount = 0; const char *name = config_setting_name(item); int itemId = craft_get_item_id(entry, "Wrong item name in craft %d in field %s in: %s\n", name, "SourceItems"); if (!itemId) { inventory->items[i].index = 0; inventory->items[i].amount = 0; i ++; continue; } if (craft_get_const(item, &i32) && i32 >= 0) amount = i32; if (amount < 1) { inventory->items[i].index = 0; inventory->items[i].amount = 0; ShowWarning("Wrong item amount in craft %d in field SourceItems in: %d\n", entry->id, amount); i ++; continue; } inventory->items[i].index = itemId; inventory->items[i].amount = amount; i ++; } } static void craft_read_create_items(struct craft_db_entry *entry, struct config_setting_t *tt) { int i32; int i = 0; if (!entry || !tt || !config_setting_is_group(tt)) return; struct config_setting_t *item; int invLen = VECTOR_LENGTH(entry->create_items); VECTOR_ENSURE(entry->create_items, 1, 1); VECTOR_INSERTZEROED(entry->create_items, invLen); struct craft_items_collection *collection = &VECTOR_INDEX(entry->create_items, invLen); VECTOR_INIT(*collection); int collecitonLen = VECTOR_LENGTH(*collection); while((item = libconfig->setting_get_elem(tt, i))) { int amount = 0; int cards[MAX_SLOTS]; const char *name = config_setting_name(item); int itemId = itemId = craft_get_item_id(entry, "Wrong item name in craft %d in field %s in: %s\n", name, "CreateItems"); int cardIdx = 0; for (int f = 0; f < MAX_SLOTS; f ++) cards[f] = 0; if (config_setting_is_group(item)) { struct config_setting_t *itemField; int fieldIndex = 0; while((itemField = libconfig->setting_get_elem(item, fieldIndex))) { const char *fieldName = config_setting_name(itemField); if (strcmp(fieldName, "Amount") == 0) { if (craft_get_const(itemField, &i32) && i32 >= 0) amount = i32; } else if (strcmp(fieldName, "Cards") == 0) { if (config_setting_is_aggregate(itemField)) { int sz = libconfig->setting_length(itemField); if (sz <= 0 || sz > MAX_SLOTS) ShowWarning("Wrong item cards amount in craft %d in field CreateItems.\n", entry->id); if (sz > MAX_SLOTS) sz = MAX_SLOTS; for (int f = 0; f < sz && cardIdx < sz; f ++) { const char *cardName = libconfig->setting_get_string_elem(itemField, f); if (cardName == NULL) { ShowWarning("Wrong item cards field format in craft %d in field CreateItems.\n", entry->id); continue; } const int cardId = craft_get_item_id(entry, "Wrong card name in craft %d in field %s in: %s\n", cardName, "CreateItems"); if (cardId == 0) continue; cards[cardIdx] = cardId; cardIdx ++; } } else { ShowWarning("Wrong item cards field format in craft %d in field CreateItems.\n", entry->id); } } else { ShowWarning("Wrong item field %s in craft %d in field CreateItems.\n", fieldName, entry->id); } fieldIndex ++; } } else if (craft_get_const(item, &i32) && i32 >= 0) { amount = i32; } if (!itemId) { i ++; continue; } if (amount < 1) { ShowWarning("Wrong item amount in craft %d in field CreateItems in: %d\n", entry->id, amount); i ++; continue; } VECTOR_ENSURE(*collection, 1, 1); VECTOR_INSERTZEROED(*collection, collecitonLen); struct item_pair2 *pair = &VECTOR_INDEX(*collection, collecitonLen); pair->index = itemId; pair->amount = amount; for (int f = 0; f < MAX_SLOTS; f ++) pair->cards[f] = cards[f]; collecitonLen ++; i ++; } } static void craft_read_items_collection(struct craft_db_entry *entry, struct craft_items_collection *vector, struct config_setting_t *t, const char *const fieldName, enum craft_field_type fieldType) { int i32; int i = 0; if (!entry || !t || !vector) return; struct config_setting_t *tt = libconfig->setting_get_member(t, fieldName); if (!tt || !config_setting_is_group(tt)) return; struct config_setting_t *item; int len = 0; while((item = libconfig->setting_get_elem(tt, i))) { int amount = 0; const char *name = config_setting_name(item); int itemId = 0; if (fieldType == CRAFT_ITEM) { itemId = craft_get_item_id(entry, "Wrong item name in craft %d in field %s in: %s\n", name, fieldName); if (!itemId) { i ++; continue; } } else if (fieldType == CRAFT_QUEST) { if (!script->get_constant(name, &itemId)) { ShowWarning("Wrong quest name in craft %d in field %s in: %s\n", entry->id, fieldName, name); i ++; continue; } if (!quest->db(itemId)) { ShowWarning("Wrong quest id in craft %d in field %s in: %s\n", entry->id, fieldName, name); i ++; continue; } } else if (fieldType == CRAFT_SKILL) { itemId = skill->name2id(name); if (!itemId) { ShowWarning("Wrong skill name in craft %d in field %s in: %s\n", entry->id, fieldName, name); i ++; continue; } } else if (fieldType == CRAFT_BOOL) { itemId = craft_get_item_id(entry, "Wrong item name in craft %d in field %s in: %s\n", name, fieldName); if (!itemId) { i ++; continue; } } if (fieldType == CRAFT_BOOL) { if (!libconfig->setting_get_bool(item)) { i ++; continue; } amount = 1; } else if (craft_get_const(item, &i32) && i32 >= 0) { amount = i32; } if (amount < 1) { if (fieldType == CRAFT_ITEM) { ShowWarning("Wrong item amount in craft %d in field %s in: %d\n", entry->id, fieldName, amount); } else if (fieldType == CRAFT_QUEST) { ShowWarning("Wrong quest level in craft %d in field %s in: %d\n", entry->id, fieldName, amount); } else if (fieldType == CRAFT_SKILL) { ShowWarning("Wrong skill level in craft %d in field %s in: %d\n", entry->id, fieldName, amount); } i ++; continue; } VECTOR_ENSURE(*vector, 1, 1); VECTOR_INSERTZEROED(*vector, len); struct item_pair2 *pair = &VECTOR_INDEX(*vector, len); len ++; pair->index = itemId; pair->amount = amount; //ShowInfo("%s: itemId=%d:%d\n", fieldName, itemId, amount); i ++; } } #define readField(name, var, def) \ if (craft_lookup_const(craftt, name, &i32) && i32 >= 0) \ { \ entry->var = i32; \ } \ else \ { \ entry->var = def; \ } static bool craft_read_db_sub(struct config_setting_t *craftt, int id __attribute__ ((unused)), const char *source) { int class_; int i32; const char *str = NULL; struct config_setting_t *t; if (!libconfig->setting_lookup_int(craftt, "Id", &class_)) { ShowWarning("craft_read_db_sub: Missing id in \"%s\", entry #%d, skipping.\n", source, class_); return false; } if (!libconfig->setting_lookup_string(craftt, "Name", &str) || !*str) { ShowWarning("craft_read_db_sub: Missing Name in craft %d of \"%s\", skipping.\n", class_, source); return false; } struct craft_db_entry *entry = craft_create_db_entry(class_); entry->id = class_; idb_put(craftconf_db, class_, entry); safestrncpy(entry->name, str, sizeof(entry->name)); script->set_constant2(entry->name, entry->id, false, false); //ShowInfo("Craft: id=%d, name=%s\n", class_, entry->name); readField("Priority", priority, 0); readField("Price", price, 0); readField("Lv", level, 0); readField("Flag", flag, -1); readField("ReturnCode", return_code, 0); if ((t = libconfig->setting_get_member(craftt, "SourceItems")) && config_setting_is_list(t)) { int i, len = libconfig->setting_length(t); for (i = 0; i < len; i++) { craft_read_source_inventory(entry, libconfig->setting_get_elem(t, i)); } } if ((t = libconfig->setting_get_member(craftt, "CreateItems")) && config_setting_is_list(t)) { int i, len = libconfig->setting_length(t); for (i = 0; i < len; i++) { craft_read_create_items(entry, libconfig->setting_get_elem(t, i)); } } craft_read_items_collection(entry, &entry->delete_items, craftt, "DeleteItems", CRAFT_ITEM); craft_read_items_collection(entry, &entry->required_items, craftt, "RequiredItems", CRAFT_ITEM); craft_read_items_collection(entry, &entry->required_skills, craftt, "RequiredSkills", CRAFT_ITEM); craft_read_items_collection(entry, &entry->required_quests, craftt, "RequiredQuests", CRAFT_QUEST); craft_read_items_collection(entry, &entry->required_equips, craftt, "RequiredEquips", CRAFT_BOOL); return true; } #undef readField static void load_craft_db(const char *filename) { struct config_t craft_db_conf; char filepath[300]; struct config_setting_t *cdb; struct config_setting_t *t; int i = 0; nullpo_retv(filename); sprintf(filepath, "%s/%s", map->db_path, filename); if (!libconfig->load_file(&craft_db_conf, filepath) || !(cdb = libconfig->setting_get_member(craft_db_conf.root, "craft_db"))) { ShowError("can't read %s\n", filepath); return; } while ((t = libconfig->setting_get_elem(cdb, i++))) { craft_read_db_sub(t, i - 1, filepath); } libconfig->destroy(&craft_db_conf); ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, filepath); } void do_init_craftconf(void) { craftconf_db = idb_alloc(DB_OPT_RELEASE_BOTH); load_craft_db("craft_db.conf"); } static void delete_craft_entry(struct craft_db_entry *entry) { if (!entry) return; VECTOR_CLEAR(entry->inventories); VECTOR_CLEAR(entry->delete_items); VECTOR_CLEAR(entry->required_items); VECTOR_CLEAR(entry->required_equips); VECTOR_CLEAR(entry->required_skills); VECTOR_CLEAR(entry->required_quests); const int len = VECTOR_LENGTH(entry->create_items); int f; for (f = 0; f < len; f ++) { struct craft_items_collection *collection = &VECTOR_INDEX( entry->create_items, f); VECTOR_CLEAR(*collection); } VECTOR_CLEAR(entry->create_items); } static int delete_craftconf_sub(union DBKey key __attribute__ ((unused)), struct DBData *data, va_list args __attribute__ ((unused))) { struct craft_db_entry *craft = DB->data2ptr(data); if (!craft) return 0; delete_craft_entry(craft); return 0; } void do_final_craftconf(void) { craftconf_db->destroy(craftconf_db, delete_craftconf_sub); }