// 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/socket.h" #include "common/strlib.h" #include "map/itemdb.h" #include "map/script.h" #include "map/quest.h" #include "plugins/HPMHooking.h" #include "emap/quest.h" /** * Reads and parses an entry from the quest_db. * * @param cs The config setting containing the entry. * @param n The sequential index of the current config setting. * @param source The source configuration file. * @return The parsed quest entry. * @retval NULL in case of errors. */ struct quest_db *equest_read_db_sub_pre(struct config_setting_t **csPtr, int *nPtr, const char **sourcePtr) { struct quest_db *entry = NULL; struct config_setting_t *t = NULL; int i32 = 0, quest_id; const char *str = NULL; const int n = *nPtr; struct config_setting_t *cs = *csPtr; const char *source = *sourcePtr; /* * Id: Quest ID [int] * Name: Quest Name [string] * TimeLimit: Time Limit (seconds) [int, optional] * Targets: ( [array, optional] * { * MobId: Mob ID [int] * Count: [int] * }, * ... (can repeated up to MAX_QUEST_OBJECTIVES times) * ) * Drops: ( * { * ItemId: Item ID to drop [int] * Rate: Drop rate [int] * MobId: Mob ID to match [int, optional] * }, * ... (can be repeated) * ) */ if (!libconfig->setting_lookup_int(cs, "Id", &quest_id)) { ShowWarning("quest_read_db: Missing id in \"%s\", entry #%d, skipping.\n", source, n); hookStop(); return NULL; } if (quest_id < 0 || quest_id >= MAX_QUEST_DB) { ShowWarning("quest_read_db: Invalid quest ID '%d' in \"%s\", entry #%d (min: 0, max: %d), skipping.\n", quest_id, source, n, MAX_QUEST_DB); hookStop(); return NULL; } if (!libconfig->setting_lookup_string(cs, "Name", &str) || !*str) { ShowWarning("quest_read_db_sub: Missing Name in quest %d of \"%s\", skipping.\n", quest_id, source); hookStop(); return NULL; } script->set_constant2(str, quest_id, false, false); CREATE(entry, struct quest_db, 1); entry->id = quest_id; //safestrncpy(entry->name, str, sizeof(entry->name)); if (libconfig->setting_lookup_int(cs, "TimeLimit", &i32)) // This is an unsigned value, do not check for >= 0 entry->time = (unsigned int)i32; if ((t=libconfig->setting_get_member(cs, "Targets")) && config_setting_is_list(t)) { /* int i, len = libconfig->setting_length(t); for (i = 0; i < len && entry->objectives_count < MAX_QUEST_OBJECTIVES; i++) { // Note: We ensure that objectives_count < MAX_QUEST_OBJECTIVES because // quest_log (as well as the client) expect this maximum size. struct config_setting_t *tt = libconfig->setting_get_elem(t, i); int mob_id = 0, count = 0; if (!tt) break; if (!config_setting_is_group(tt)) continue; if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id) || mob_id <= 0) continue; if (!libconfig->setting_lookup_int(tt, "Count", &count) || count <= 0) continue; RECREATE(entry->objectives, struct quest_objective, ++entry->objectives_count); entry->objectives[entry->objectives_count-1].mob = mob_id; entry->objectives[entry->objectives_count-1].count = count; } */ entry->objectives_count = 1; RECREATE(entry->objectives, struct quest_objective, 1); entry->objectives[0].mob = 1; entry->objectives[0].count = 0; } if ((t=libconfig->setting_get_member(cs, "Drops")) && config_setting_is_list(t)) { int i, len = libconfig->setting_length(t); for (i = 0; i < len; i++) { struct config_setting_t *tt = libconfig->setting_get_elem(t, i); int mob_id = 0, nameid = 0, rate = 0; if (!tt) break; if (!config_setting_is_group(tt)) continue; if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id)) mob_id = 0; // Zero = any monster if (mob_id < 0) continue; if (!libconfig->setting_lookup_int(tt, "ItemId", &nameid) || !itemdb->exists(nameid)) continue; if (!libconfig->setting_lookup_int(tt, "Rate", &rate) || rate <= 0) continue; RECREATE(entry->dropitem, struct quest_dropitem, ++entry->dropitem_count); entry->dropitem[entry->dropitem_count-1].mob_id = mob_id; entry->dropitem[entry->dropitem_count-1].nameid = nameid; entry->dropitem[entry->dropitem_count-1].rate = rate; } } hookStop(); return entry; }