From d2b8de52e56914d8135c5209fb3e2a7339065b94 Mon Sep 17 00:00:00 2001 From: Haru Date: Mon, 19 Jan 2015 13:37:45 +0100 Subject: Converted quest_db to libconfig - This allows for more fields to be easily added to the file (coming soon). - Special thanks to Dastgir. Signed-off-by: Haru --- src/map/quest.c | 139 +++++++++++++++++++++++++++++++++++--------------------- src/map/quest.h | 2 + 2 files changed, 88 insertions(+), 53 deletions(-) (limited to 'src/map') 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; -- cgit v1.2.3-70-g09d2 From 9fc2159be0bd53f4d787d4a1009250c4e8994a34 Mon Sep 17 00:00:00 2001 From: Haru Date: Mon, 19 Jan 2015 13:40:48 +0100 Subject: Added additional item drops support to the quest db - Special thanks to Dastgir, Michieru Signed-off-by: Haru --- db/quest_db.conf | 8 +++++ src/map/quest.c | 77 ++++++++++++++++++++++++++++++++++++++++++----- src/map/quest.h | 8 +++++ tools/questdbconverter.pl | 8 +++++ 4 files changed, 93 insertions(+), 8 deletions(-) (limited to 'src/map') diff --git a/db/quest_db.conf b/db/quest_db.conf index ca0442ebc..20d2195bd 100644 --- a/db/quest_db.conf +++ b/db/quest_db.conf @@ -15,6 +15,14 @@ quest_db: ( }, ... (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) + ) }, ******************************************************************************/ { diff --git a/src/map/quest.c b/src/map/quest.c index a1974ab84..1c8986f3c 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -29,6 +29,7 @@ #include "../common/conf.h" #include "../common/malloc.h" #include "../common/nullpo.h" +#include "../common/random.h" #include "../common/showmsg.h" #include "../common/socket.h" #include "../common/strlib.h" @@ -245,7 +246,7 @@ int quest_update_objective_sub(struct block_list *bl, va_list ap) { /** - * Updates the quest objectives for a character after killing a monster. + * Updates the quest objectives for a character after killing a monster, including the handling of quest-granted drops. * * @param sd Character's data * @param mob_id Monster ID @@ -253,21 +254,44 @@ int quest_update_objective_sub(struct block_list *bl, va_list ap) { void quest_update_objective(TBL_PC *sd, int mob_id) { int i,j; - for( i = 0; i < sd->avail_quests; i++ ) { + for (i = 0; i < sd->avail_quests; i++) { struct quest_db *qi = NULL; - if( sd->quest_log[i].state != Q_ACTIVE ) // Skip inactive quests + if (sd->quest_log[i].state != Q_ACTIVE) // Skip inactive quests continue; qi = quest->db(sd->quest_log[i].quest_id); - for( j = 0; j < qi->num_objectives; j++ ) { - if( qi->mob[j] == mob_id && sd->quest_log[i].count[j] < qi->count[j] ) { + for (j = 0; j < qi->num_objectives; j++) { + if (qi->mob[j] == mob_id && sd->quest_log[i].count[j] < qi->count[j]) { sd->quest_log[i].count[j]++; sd->save_quest = true; clif->quest_update_objective(sd, &sd->quest_log[i]); } } + + // process quest-granted extra drop bonuses + for (j = 0; j < qi->dropitem_count; j++) { + struct quest_dropitem *dropitem = &qi->dropitem[j]; + struct item item; + struct item_data *data = NULL; + int temp; + if (dropitem->mob_id != 0 && dropitem->mob_id != mob_id) + continue; + // TODO: Should this be affected by server rates? + if (rnd()%10000 >= dropitem->rate) + continue; + if (!(data = itemdb->exists(dropitem->nameid))) + continue; + memset(&item,0,sizeof(item)); + item.nameid = dropitem->nameid; + item.identify = itemdb->isidentified2(data); + item.amount = 1; + if((temp = pc->additem(sd, &item, 1, LOG_TYPE_OTHER)) != 0) { // TODO: We might want a new log type here? + // Failed to obtain the item + clif->additem(sd, 0, 0, temp); + } + } } } @@ -387,6 +411,14 @@ struct quest_db *quest_read_db_sub(config_setting_t *cs, int n, const char *sour * }, * ... (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); @@ -428,6 +460,30 @@ struct quest_db *quest_read_db_sub(config_setting_t *cs, int n, const char *sour entry->num_objectives++; } } + + 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++) { + 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; + } + } return entry; } @@ -442,9 +498,10 @@ int quest_read_db(void) config_t quest_db_conf; config_setting_t *qdb = NULL, *q = NULL; int i = 0, count = 0; + const char *filename = "quest_db.conf"; - 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"))) { + sprintf(filepath, "%s/%s", map->db_path, filename); + if (libconfig->read_file(&quest_db_conf, filepath) || !(qdb = libconfig->setting_get_member(quest_db_conf.root, filename))) { ShowError("can't read %s\n", filepath); return -1; } @@ -456,13 +513,15 @@ int quest_read_db(void) if (quest->db_data[entry->id] != NULL) { ShowWarning("quest_read_db: Duplicate quest %d.\n", entry->id); + if (quest->db_data[entry->id]->dropitem) + aFree(quest->db_data[entry->id]->dropitem); aFree(quest->db_data[entry->id]); } quest->db_data[entry->id] = entry; count++; } - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, "quest_db.txt"); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename); return count; } @@ -508,6 +567,8 @@ void quest_clear_db(void) { for (i = 0; i < MAX_QUEST_DB; i++) { if (quest->db_data[i]) { + if (quest->db_data[i]->dropitem) + aFree(quest->db_data[i]->dropitem); aFree(quest->db_data[i]); quest->db_data[i] = NULL; } diff --git a/src/map/quest.h b/src/map/quest.h index ec01e295e..db9ffa142 100644 --- a/src/map/quest.h +++ b/src/map/quest.h @@ -12,12 +12,20 @@ #define MAX_QUEST_DB (60355+1) // Highest quest ID + 1 +struct quest_dropitem { + int mob_id; + int nameid; + int rate; +}; + struct quest_db { int id; unsigned int time; int mob[MAX_QUEST_OBJECTIVES]; int count[MAX_QUEST_OBJECTIVES]; int num_objectives; + int dropitem_count; + struct quest_dropitem *dropitem; //char name[NAME_LENGTH]; }; diff --git a/tools/questdbconverter.pl b/tools/questdbconverter.pl index 9c59d434d..00431fb79 100755 --- a/tools/questdbconverter.pl +++ b/tools/questdbconverter.pl @@ -76,6 +76,14 @@ quest_db: ( }, ... (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) + ) }, ******************************************************************************/ -- cgit v1.2.3-70-g09d2 From 49df787e2c2faa2621b5490c6e88c86a4b7a813f Mon Sep 17 00:00:00 2001 From: Haru Date: Wed, 21 Jan 2015 12:54:13 +0100 Subject: Reduced quest db memory usage by about 900kB Signed-off-by: Haru --- src/map/clif.c | 44 ++++++++++++++++++++++++-------------------- src/map/quest.c | 43 +++++++++++++++++++++++++------------------ src/map/quest.h | 11 +++++++---- 3 files changed, 56 insertions(+), 42 deletions(-) (limited to 'src/map') diff --git a/src/map/clif.c b/src/map/clif.c index 268066d1a..291b5cb46 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -15829,7 +15829,8 @@ void clif_parse_PartyTick(int fd, struct map_session_data* sd) /// Sends list of all quest states (ZC_ALL_QUEST_LIST). /// 02b1 .W .L { .L .B }*num -void clif_quest_send_list(struct map_session_data *sd) { +void clif_quest_send_list(struct map_session_data *sd) +{ int fd = sd->fd; int i; #if PACKETVER >= 20141022 @@ -15846,7 +15847,7 @@ void clif_quest_send_list(struct map_session_data *sd) { WFIFOW(fd, 2) = len; WFIFOL(fd, 4) = sd->avail_quests; - for( i = 0; i < sd->avail_quests; i++ ) { + for (i = 0; i < sd->avail_quests; i++) { #if PACKETVER >= 20141022 struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); #endif @@ -15855,7 +15856,7 @@ void clif_quest_send_list(struct map_session_data *sd) { #if PACKETVER >= 20141022 WFIFOL(fd, i*info_len+13) = sd->quest_log[i].time - qi->time; WFIFOL(fd, i*info_len+17) = sd->quest_log[i].time; - WFIFOW(fd, i*info_len+21) = qi->num_objectives; + WFIFOW(fd, i*info_len+21) = qi->objectives_count; #endif } @@ -15865,7 +15866,8 @@ void clif_quest_send_list(struct map_session_data *sd) { /// Sends list of all quest missions (ZC_ALL_QUEST_MISSION). /// 02b2 .W .L { .L .L .L .W { .L .W .24B }*3 }*num -void clif_quest_send_mission(struct map_session_data *sd) { +void clif_quest_send_mission(struct map_session_data *sd) +{ int fd = sd->fd; int i, j; int len = sd->avail_quests*104+8; @@ -15876,17 +15878,17 @@ void clif_quest_send_mission(struct map_session_data *sd) { WFIFOW(fd, 2) = len; WFIFOL(fd, 4) = sd->avail_quests; - for( i = 0; i < sd->avail_quests; i++ ) { + for (i = 0; i < sd->avail_quests; i++) { struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); WFIFOL(fd, i*104+8) = sd->quest_log[i].quest_id; WFIFOL(fd, i*104+12) = sd->quest_log[i].time - qi->time; WFIFOL(fd, i*104+16) = sd->quest_log[i].time; - WFIFOW(fd, i*104+20) = qi->num_objectives; + WFIFOW(fd, i*104+20) = qi->objectives_count; - for( j = 0 ; j < qi->num_objectives; j++ ) { - WFIFOL(fd, i*104+22+j*30) = qi->mob[j]; + for (j = 0 ; j < qi->objectives_count; j++) { + WFIFOL(fd, i*104+22+j*30) = qi->objectives[j].mob; WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].count[j]; - monster = mob->db(qi->mob[j]); + monster = mob->db(qi->objectives[j].mob); memcpy(WFIFOP(fd, i*104+28+j*30), monster->jname, NAME_LENGTH); } } @@ -15897,7 +15899,8 @@ void clif_quest_send_mission(struct map_session_data *sd) { /// Notification about a new quest (ZC_ADD_QUEST). /// 02b3 .L .B .L .L .W { .L .W .24B }*3 -void clif_quest_add(struct map_session_data *sd, struct quest *qd) { +void clif_quest_add(struct map_session_data *sd, struct quest *qd) +{ int fd = sd->fd; int i; struct quest_db *qi = quest->db(qd->quest_id); @@ -15908,13 +15911,13 @@ void clif_quest_add(struct map_session_data *sd, struct quest *qd) { WFIFOB(fd, 6) = qd->state; WFIFOB(fd, 7) = qd->time - qi->time; WFIFOL(fd, 11) = qd->time; - WFIFOW(fd, 15) = qi->num_objectives; + WFIFOW(fd, 15) = qi->objectives_count; - for( i = 0; i < qi->num_objectives; i++ ) { + for (i = 0; i < qi->objectives_count; i++) { struct mob_db *monster; - WFIFOL(fd, i*30+17) = qi->mob[i]; + WFIFOL(fd, i*30+17) = qi->objectives[i].mob; WFIFOW(fd, i*30+21) = qd->count[i]; - monster = mob->db(qi->mob[i]); + monster = mob->db(qi->objectives[i].count); memcpy(WFIFOP(fd, i*30+23), monster->jname, NAME_LENGTH); } @@ -15936,21 +15939,22 @@ void clif_quest_delete(struct map_session_data *sd, int quest_id) { /// Notification of an update to the hunting mission counter (ZC_UPDATE_MISSION_HUNT). /// 02b5 .W .W { .L .L .W .W }*3 -void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd) { +void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd) +{ int fd = sd->fd; int i; struct quest_db *qi = quest->db(qd->quest_id); - int len = qi->num_objectives*12+6; + int len = qi->objectives_count*12+6; WFIFOHEAD(fd, len); WFIFOW(fd, 0) = 0x2b5; WFIFOW(fd, 2) = len; - WFIFOW(fd, 4) = qi->num_objectives; + WFIFOW(fd, 4) = qi->objectives_count; - for( i = 0; i < qi->num_objectives; i++ ) { + for (i = 0; i < qi->objectives_count; i++) { WFIFOL(fd, i*12+6) = qd->quest_id; - WFIFOL(fd, i*12+10) = qi->mob[i]; - WFIFOW(fd, i*12+14) = qi->count[i]; + WFIFOL(fd, i*12+10) = qi->objectives[i].mob; + WFIFOW(fd, i*12+14) = qi->objectives[i].count; WFIFOW(fd, i*12+16) = qd->count[i]; } diff --git a/src/map/quest.c b/src/map/quest.c index 1c8986f3c..93ec1b04c 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -251,7 +251,8 @@ int quest_update_objective_sub(struct block_list *bl, va_list ap) { * @param sd Character's data * @param mob_id Monster ID */ -void quest_update_objective(TBL_PC *sd, int mob_id) { +void quest_update_objective(TBL_PC *sd, int mob_id) +{ int i,j; for (i = 0; i < sd->avail_quests; i++) { @@ -262,8 +263,8 @@ void quest_update_objective(TBL_PC *sd, int mob_id) { qi = quest->db(sd->quest_log[i].quest_id); - for (j = 0; j < qi->num_objectives; j++) { - if (qi->mob[j] == mob_id && sd->quest_log[i].count[j] < qi->count[j]) { + for (j = 0; j < qi->objectives_count; j++) { + if (qi->objectives[j].mob == mob_id && sd->quest_log[i].count[j] < qi->objectives[j].count) { sd->quest_log[i].count[j]++; sd->save_quest = true; clif->quest_update_objective(sd, &sd->quest_log[i]); @@ -354,14 +355,15 @@ int quest_update_status(TBL_PC *sd, int quest_id, enum quest_state qs) { * 1 if the quest's timeout has expired * 0 otherwise */ -int quest_check(TBL_PC *sd, int quest_id, enum quest_check_type type) { +int quest_check(TBL_PC *sd, int quest_id, enum quest_check_type type) +{ int i; ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); - if( i == sd->num_quests ) + if (i == sd->num_quests) return -1; - switch( type ) { + switch (type) { case HAVEQUEST: return sd->quest_log[i].state; case PLAYTIME: @@ -370,10 +372,10 @@ int quest_check(TBL_PC *sd, int quest_id, enum quest_check_type type) { if( sd->quest_log[i].state == Q_INACTIVE || sd->quest_log[i].state == Q_ACTIVE ) { int j; struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); - ARR_FIND(0, MAX_QUEST_OBJECTIVES, j, sd->quest_log[i].count[j] < qi->count[j]); - if( j == MAX_QUEST_OBJECTIVES ) + ARR_FIND(0, qi->objectives_count, j, sd->quest_log[i].count[j] < qi->objectives[j].count); + if (j == qi->objectives_count) return 2; - if( sd->quest_log[i].time < (unsigned int)time(NULL) ) + if (sd->quest_log[i].time < (unsigned int)time(NULL)) return 1; } return 0; @@ -443,21 +445,22 @@ struct quest_db *quest_read_db_sub(config_setting_t *cs, int n, const char *sour 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++) { + 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. 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", &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 { - entry->mob[entry->num_objectives] = 0; + if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id) || mob_id <= 0) continue; - } - entry->num_objectives++; + 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; } } @@ -515,6 +518,8 @@ int quest_read_db(void) ShowWarning("quest_read_db: Duplicate quest %d.\n", entry->id); if (quest->db_data[entry->id]->dropitem) aFree(quest->db_data[entry->id]->dropitem); + if (quest->db_data[entry->id]->objectives) + aFree(quest->db_data[entry->id]->objectives); aFree(quest->db_data[entry->id]); } quest->db_data[entry->id] = entry; @@ -567,6 +572,8 @@ void quest_clear_db(void) { for (i = 0; i < MAX_QUEST_DB; i++) { if (quest->db_data[i]) { + if (quest->db_data[i]->objectives) + aFree(quest->db_data[i]->objectives); if (quest->db_data[i]->dropitem) aFree(quest->db_data[i]->dropitem); aFree(quest->db_data[i]); diff --git a/src/map/quest.h b/src/map/quest.h index db9ffa142..36ac69a53 100644 --- a/src/map/quest.h +++ b/src/map/quest.h @@ -8,7 +8,6 @@ #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 @@ -18,12 +17,16 @@ struct quest_dropitem { int rate; }; +struct quest_objective { + int mob; + int count; +}; + struct quest_db { int id; unsigned int time; - int mob[MAX_QUEST_OBJECTIVES]; - int count[MAX_QUEST_OBJECTIVES]; - int num_objectives; + int objectives_count; + struct quest_objective *objectives; int dropitem_count; struct quest_dropitem *dropitem; //char name[NAME_LENGTH]; -- cgit v1.2.3-70-g09d2