summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/map/quest.c139
-rw-r--r--src/map/quest.h2
2 files changed, 88 insertions, 53 deletions
diff --git a/src/map/quest.c b/src/map/quest.c
index e993ab69d..a1974ab84 100644
--- a/src/map/quest.c
+++ b/src/map/quest.c
@@ -26,6 +26,7 @@
#include "script.h"
#include "unit.h"
#include "../common/cbasetypes.h"
+#include "../common/conf.h"
#include "../common/malloc.h"
#include "../common/nullpo.h"
#include "../common/showmsg.h"
@@ -361,77 +362,108 @@ int quest_check(TBL_PC *sd, int quest_id, enum quest_check_type type) {
}
/**
- * Loads quests from the quest db.
+ * Reads and parses an entry from the quest_db.
*
- * @return Number of loaded quests, or -1 if the file couldn't be read.
+ * @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.
*/
-int quest_read_db(void) {
- // TODO[Haru] This duplicates some sv_readdb functionalities, and it would be
- // nice if it could be replaced by it. The reason why it wasn't is probably
- // because we need to accept commas (which is also used as delimiter) in the
- // last field (quest name), and sv_readdb isn't capable of doing so.
- FILE *fp;
- char line[1024];
- int i, count = 0;
- char *str[20], *p, *np;
- struct quest_db entry;
-
- sprintf(line, "%s/quest_db.txt", map->db_path);
- if ((fp=fopen(line,"r"))==NULL) {
- ShowError("can't read %s\n", line);
- return -1;
+struct quest_db *quest_read_db_sub(config_setting_t *cs, int n, const char *source)
+{
+ struct quest_db *entry = NULL;
+ config_setting_t *t = NULL;
+ int i32 = 0, quest_id;
+ const char *str = NULL;
+ /*
+ * 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)
+ * )
+ */
+ if (!libconfig->setting_lookup_int(cs, "Id", &quest_id)) {
+ ShowWarning("quest_read_db: Missing id in \"%s\", entry #%d, skipping.\n", source, n);
+ 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);
+ return NULL;
}
- while (fgets(line, sizeof(line), fp)) {
- if (line[0]=='/' && line[1]=='/')
- continue;
- memset(str,0,sizeof(str));
-
- for (i = 0, p = line; i < 8; i++) {
- if (( np = strchr(p,',') ) != NULL) {
- str[i] = p;
- *np = 0;
- p = np + 1;
- } else if (str[0] == 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);
+ return NULL;
+ }
+
+ 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->num_objectives < MAX_QUEST_OBJECTIVES; i++) {
+ config_setting_t *tt = libconfig->setting_get_elem(t, i);
+ if (!tt)
break;
+ if (!config_setting_is_group(tt))
+ continue;
+ if (libconfig->setting_lookup_int(tt, "MobId", &i32) && i32 > 0)
+ entry->mob[entry->num_objectives] = i32;
+ if (libconfig->setting_lookup_int(tt, "Count", &i32) && i32 > 0) {
+ entry->count[entry->num_objectives] = i32;
} else {
- ShowError("quest_read_db: insufficient columns in line %s\n", line);
+ entry->mob[entry->num_objectives] = 0;
continue;
}
+ entry->num_objectives++;
}
- if (str[0] == NULL)
- continue;
-
- memset(&entry, 0, sizeof(entry));
+ }
+ return entry;
+}
- entry.id = atoi(str[0]);
+/**
+ * Loads quests from the quest db.
+ *
+ * @return Number of loaded quests, or -1 if the file couldn't be read.
+ */
+int quest_read_db(void)
+{
+ char filepath[256];
+ config_t quest_db_conf;
+ config_setting_t *qdb = NULL, *q = NULL;
+ int i = 0, count = 0;
+
+ sprintf(filepath, "%s/quest_db.txt", map->db_path);
+ if (libconfig->read_file(&quest_db_conf, filepath) || !(qdb = libconfig->setting_get_member(quest_db_conf.root, "quest_db"))) {
+ ShowError("can't read %s\n", filepath);
+ return -1;
+ }
- if (entry.id < 0 || entry.id >= MAX_QUEST_DB) {
- ShowError("quest_read_db: Invalid quest ID '%d' in line '%s' (min: 0, max: %d.)\n", entry.id, line, MAX_QUEST_DB);
+ while ((q = libconfig->setting_get_elem(qdb, i++))) {
+ struct quest_db *entry = quest->read_db_sub(q, i-1, filepath);
+ if (!entry)
continue;
- }
-
- entry.time = atoi(str[1]);
- for (i = 0; i < MAX_QUEST_OBJECTIVES; i++) {
- entry.mob[i] = atoi(str[2*i+2]);
- entry.count[i] = atoi(str[2*i+3]);
-
- if (!entry.mob[i] || !entry.count[i])
- break;
+ if (quest->db_data[entry->id] != NULL) {
+ ShowWarning("quest_read_db: Duplicate quest %d.\n", entry->id);
+ aFree(quest->db_data[entry->id]);
}
+ quest->db_data[entry->id] = entry;
- entry.num_objectives = i;
-
- if (quest->db_data[entry.id] == NULL)
- quest->db_data[entry.id] = aMalloc(sizeof(struct quest_db));
-
- memcpy(quest->db_data[entry.id], &entry, sizeof(struct quest_db));
count++;
}
- fclose(fp);
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, "quest_db.txt");
- return 0;
+ return count;
}
/**
@@ -537,4 +569,5 @@ void quest_defaults(void) {
quest->check = quest_check;
quest->clear = quest_clear_db;
quest->read_db = quest_read_db;
+ quest->read_db_sub = quest_read_db_sub;
}
diff --git a/src/map/quest.h b/src/map/quest.h
index f988d0c61..ec01e295e 100644
--- a/src/map/quest.h
+++ b/src/map/quest.h
@@ -7,6 +7,7 @@
#include "map.h" // TBL_PC
#include "../common/cbasetypes.h"
+#include "../common/conf.h"
#include "../common/mmo.h" // MAX_QUEST_OBJECTIVES
#define MAX_QUEST_DB (60355+1) // Highest quest ID + 1
@@ -46,6 +47,7 @@ struct quest_interface {
int (*check) (TBL_PC *sd, int quest_id, enum quest_check_type type);
void (*clear) (void);
int (*read_db) (void);
+ struct quest_db *(*read_db_sub) (config_setting_t *cs, int n, const char *source);
};
struct quest_interface *quest;