diff options
Diffstat (limited to 'src/map/quest.c')
-rw-r--r-- | src/map/quest.c | 336 |
1 files changed, 316 insertions, 20 deletions
diff --git a/src/map/quest.c b/src/map/quest.c index 071cab961..ab0b06974 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -25,6 +25,7 @@ #include "map/battle.h" #include "map/chrif.h" #include "map/clif.h" +#include "map/homunculus.h" #include "map/intif.h" #include "map/itemdb.h" #include "map/log.h" @@ -52,8 +53,8 @@ #include <string.h> #include <time.h> -struct quest_interface quest_s; -struct quest_db *db_data[MAX_QUEST_DB]; ///< Quest database +static struct quest_interface quest_s; +static struct quest_db *db_data[MAX_QUEST_DB]; ///< Quest database struct quest_interface *quest; @@ -63,7 +64,8 @@ struct quest_interface *quest; * @param quest_id ID to lookup * @return Quest entry (equals to &quest->dummy if the ID is invalid) */ -struct quest_db *quest_db(int quest_id) { +static struct quest_db *quest_db(int quest_id) +{ if (quest_id < 0 || quest_id >= MAX_QUEST_DB || quest->db_data[quest_id] == NULL) return &quest->dummy; return quest->db_data[quest_id]; @@ -75,7 +77,7 @@ struct quest_db *quest_db(int quest_id) { * @param sd Player's data * @return 0 in case of success, nonzero otherwise (i.e. the player has no quests) */ -int quest_pc_login(struct map_session_data *sd) +static int quest_pc_login(struct map_session_data *sd) { #if PACKETVER < 20141022 int i; @@ -108,7 +110,7 @@ int quest_pc_login(struct map_session_data *sd) * @param time_limit Custom time, in UNIX epoch, for this quest * @return 0 in case of success, nonzero otherwise */ -int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit) +static int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit) { int n; struct quest_db *qi = quest->db(quest_id); @@ -153,6 +155,7 @@ int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit #else clif->quest_update_objective(sd, &sd->quest_log[n]); #endif + quest->questinfo_refresh(sd); if ((map->save_settings & 64) != 0) chrif->save(sd, 0); @@ -168,7 +171,7 @@ int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit * @param qid2 New quest to add * @return 0 in case of success, nonzero otherwise */ -int quest_change(struct map_session_data *sd, int qid1, int qid2) +static int quest_change(struct map_session_data *sd, int qid1, int qid2) { int i; struct quest_db *qi = quest->db(qid2); @@ -210,10 +213,10 @@ int quest_change(struct map_session_data *sd, int qid1, int qid2) #else clif->quest_update_objective(sd, &sd->quest_log[i]); #endif + quest->questinfo_refresh(sd); if( map->save_settings&64 ) chrif->save(sd,0); - return 0; } @@ -224,7 +227,7 @@ int quest_change(struct map_session_data *sd, int qid1, int qid2) * @param quest_id ID of the quest to remove * @return 0 in case of success, nonzero otherwise */ -int quest_delete(struct map_session_data *sd, int quest_id) +static int quest_delete(struct map_session_data *sd, int quest_id) { int i; @@ -253,6 +256,7 @@ int quest_delete(struct map_session_data *sd, int quest_id) sd->save_quest = true; clif->quest_delete(sd, quest_id); + quest->questinfo_refresh(sd); if( map->save_settings&64 ) chrif->save(sd,0); @@ -268,7 +272,7 @@ int quest_delete(struct map_session_data *sd, int quest_id) * int Party ID * int Mob ID */ -int quest_update_objective_sub(struct block_list *bl, va_list ap) +static int quest_update_objective_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd = NULL; int party_id = va_arg(ap, int); @@ -295,7 +299,7 @@ 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(struct map_session_data *sd, int mob_id) +static void quest_update_objective(struct map_session_data *sd, int mob_id) { int i,j; @@ -351,7 +355,7 @@ void quest_update_objective(struct map_session_data *sd, int mob_id) * @param qs New quest state * @return 0 in case of success, nonzero otherwise */ -int quest_update_status(struct map_session_data *sd, int quest_id, enum quest_state qs) +static int quest_update_status(struct map_session_data *sd, int quest_id, enum quest_state qs) { int i; @@ -380,6 +384,7 @@ int quest_update_status(struct map_session_data *sd, int quest_id, enum quest_st } clif->quest_delete(sd, quest_id); + quest->questinfo_refresh(sd); if( map->save_settings&64 ) chrif->save(sd,0); @@ -402,7 +407,7 @@ int quest_update_status(struct map_session_data *sd, int quest_id, enum quest_st * 1 if the quest's timeout has expired * 0 otherwise */ -int quest_check(struct map_session_data *sd, int quest_id, enum quest_check_type type) +static int quest_check(struct map_session_data *sd, int quest_id, enum quest_check_type type) { int i; @@ -444,7 +449,7 @@ int quest_check(struct map_session_data *sd, int quest_id, enum quest_check_type * @return The parsed quest entry. * @retval NULL in case of errors. */ -struct quest_db *quest_read_db_sub(struct config_setting_t *cs, int n, const char *source) +static struct quest_db *quest_read_db_sub(struct config_setting_t *cs, int n, const char *source) { struct quest_db *entry = NULL; struct config_setting_t *t = NULL; @@ -544,7 +549,7 @@ struct quest_db *quest_read_db_sub(struct config_setting_t *cs, int n, const cha * * @return Number of loaded quests, or -1 if the file couldn't be read. */ -int quest_read_db(void) +static int quest_read_db(void) { char filepath[256]; struct config_t quest_db_conf; @@ -591,7 +596,8 @@ int quest_read_db(void) * @see map->foreachpc * @param ap Ignored */ -int quest_reload_check_sub(struct map_session_data *sd, va_list ap) { +static int quest_reload_check_sub(struct map_session_data *sd, va_list ap) +{ int i, j; nullpo_ret(sd); @@ -620,7 +626,8 @@ int quest_reload_check_sub(struct map_session_data *sd, va_list ap) { /** * Clears the quest database for shutdown or reload. */ -void quest_clear_db(void) { +static void quest_clear_db(void) +{ int i; for (i = 0; i < MAX_QUEST_DB; i++) { @@ -635,12 +642,285 @@ void quest_clear_db(void) { } } +/* +* Limit the questinfo icon id to avoid client problems +*/ +static int quest_questinfo_validate_icon(int icon) +{ +#if PACKETVER >= 20170315 + if (icon < 0 || (icon > 10 && icon != 9999)) + icon = 9999; +#elif PACKETVER >= 20120410 + if (icon < 0 || (icon > 8 && icon != 9999) || icon == 7) + icon = 9999; // Default to nothing if icon id is invalid. +#else + if (icon < 0 || icon > 7) + icon = 0; + else + icon = icon + 1; +#endif + return icon; +} + +/** + * Refresh the questinfo bubbles on the player map. + * + * @param sd session data. + * @param qi questinfo data. + * + */ +static void quest_questinfo_refresh(struct map_session_data *sd) +{ + int i; + + nullpo_retv(sd); + + for (i = 0; i < VECTOR_LENGTH(map->list[sd->bl.m].qi_data); i++) { + struct questinfo *qi = &VECTOR_INDEX(map->list[sd->bl.m].qi_data, i); + // Remove the bubbles if one of the conditions is no longer valid. + if (quest->questinfo_validate(sd, qi) == false) { +#if PACKETVER >= 20120410 + clif->quest_show_event(sd, &qi->nd->bl, 9999, 0); +#else + clif->quest_show_event(sd, &qi->nd->bl, 0, 0); +#endif + } else { + clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); + } + } +} + +/** + * Validate all possible conditions required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if conditions are correct. + * @retval false if one condition or more are in-correct. + */ +static bool quest_questinfo_validate(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + if (qi->hasJob && quest->questinfo_validate_job(sd, qi) == false) + return false; + if (qi->sex_enabled && quest->questinfo_validate_sex(sd, qi) == false) + return false; + if ((qi->base_level.min != 0 || qi->base_level.max != 0) && quest->questinfo_validate_baselevel(sd, qi) == false) + return false; + if ((qi->job_level.min != 0 || qi->job_level.max != 0) && quest->questinfo_validate_joblevel(sd, qi) == false) + return false; + if (VECTOR_LENGTH(qi->items) > 0 && quest->questinfo_validate_items(sd, qi) == false) + return false; + if (qi->homunculus.level != 0 && quest->questinfo_validate_homunculus_level(sd, qi) == false) + return false; + if (qi->homunculus.class_ != 0 && quest->questinfo_validate_homunculus_type(sd, qi) == false) + return false; + if (VECTOR_LENGTH(qi->quest_requirement) > 0 && quest->questinfo_validate_quests(sd, qi) == false) + return false; + return true; +} + +/** + * Validate job required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player job is matching the required. + * @retval false if player job is NOT matching the required. + */ +static bool quest_questinfo_validate_job(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + if (sd->status.class == qi->job) + return true; + return false; +} + +/** + * Validate sex required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player sex is matching the required. + * @retval false if player sex is NOT matching the required. + */ +static bool quest_questinfo_validate_sex(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + if (sd->status.sex == qi->sex) + return true; + return false; +} + +/** + * Validate base level required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player base level is included in the required level range. + * @retval false if player base level is NOT included in the required level range. + */ +static bool quest_questinfo_validate_baselevel(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + if (sd->status.base_level >= qi->base_level.min && sd->status.base_level <= qi->base_level.max) + return true; + return false; +} + +/** + * Validate job level required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player job level is included in the required level range. + * @retval false if player job level is NOT included in the required level range. + */ +static bool quest_questinfo_validate_joblevel(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + if (sd->status.job_level >= qi->job_level.min && sd->status.job_level <= qi->job_level.max) + return true; + return false; +} + +/** + * Validate items list required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player have all the items required. + * @retval false if player is missing one or more of the items required. + */ +static bool quest_questinfo_validate_items(struct map_session_data *sd, struct questinfo *qi) +{ + int i, idx; + + nullpo_retr(false, sd); + nullpo_retr(false, qi); + + + for (i = 0; i < VECTOR_LENGTH(qi->items); i++) { + struct item *item = &VECTOR_INDEX(qi->items, i); + idx = pc->search_inventory(sd, item->nameid); + if (idx == INDEX_NOT_FOUND) + return false; + if (sd->status.inventory[idx].amount < item->amount) + return false; + } + + return true; +} + +/** + * Validate minimal homunculus level required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if homunculus level >= the required value. + * @retval false if homunculus level smaller than the required value. + */ +static bool quest_questinfo_validate_homunculus_level(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + + if (sd->hd == NULL) + return false; + if (!homun_alive(sd->hd)) + return false; + if (sd->hd->homunculus.level < qi->homunculus.level) + return false; + return true; +} + +/** + * Validate homunculus type required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player's homunculus is matching the required. + * @retval false if player's homunculus is NOT matching the required. + */ +static bool quest_questinfo_validate_homunculus_type(struct map_session_data *sd, struct questinfo *qi) +{ + nullpo_retr(false, sd); + nullpo_retr(false, qi); + + if (sd->hd == NULL) + return false; + if (!homun_alive(sd->hd)) + return false; + if (homun->class2type(sd->hd->homunculus.class_) != qi->homunculus_type) + return false; + return true; +} + +/** + * Validate quest list required for the questinfo + * + * @param sd session data. + * @param qi questinfo data. + * + * @retval true if player have all the quests required. + * @retval false if player is missing one or more of the quests required. + */ +static bool quest_questinfo_validate_quests(struct map_session_data *sd, struct questinfo *qi) +{ + int i; + + nullpo_retr(false, sd); + nullpo_retr(false, qi); + + for (i = 0; i < VECTOR_LENGTH(qi->quest_requirement); i++) { + struct questinfo_qreq *quest_requirement = &VECTOR_INDEX(qi->quest_requirement, i); + if (quest->check(sd, quest_requirement->id, HAVEQUEST) != quest_requirement->state) + return false; + } + + return true; +} + +/** + * Clears the questinfo data vector + * + * @param m mapindex. + * + */ +static void quest_questinfo_vector_clear(int m) +{ + int i; + + Assert_retv(m >= 0 && m < map->count); + + for (i = 0; i < VECTOR_LENGTH(map->list[m].qi_data); i++) { + struct questinfo *qi_data = &VECTOR_INDEX(map->list[m].qi_data, i); + VECTOR_CLEAR(qi_data->items); + VECTOR_CLEAR(qi_data->quest_requirement); + } + VECTOR_CLEAR(map->list[m].qi_data); +} + /** * Initializes the quest interface. * * @param minimal Run in minimal mode (skips most of the loading) */ -void do_init_quest(bool minimal) { +static void do_init_quest(bool minimal) +{ if (minimal) return; @@ -650,14 +930,16 @@ void do_init_quest(bool minimal) { /** * Finalizes the quest interface before shutdown. */ -void do_final_quest(void) { +static void do_final_quest(void) +{ quest->clear(); } /** * Reloads the quest database. */ -void do_reload_quest(void) { +static void do_reload_quest(void) +{ quest->clear(); quest->read_db(); @@ -669,7 +951,8 @@ void do_reload_quest(void) { /** * Initializes default values for the quest interface. */ -void quest_defaults(void) { +void quest_defaults(void) +{ quest = &quest_s; quest->db_data = db_data; @@ -692,4 +975,17 @@ void quest_defaults(void) { quest->clear = quest_clear_db; quest->read_db = quest_read_db; quest->read_db_sub = quest_read_db_sub; + + quest->questinfo_validate_icon = quest_questinfo_validate_icon; + quest->questinfo_refresh = quest_questinfo_refresh; + quest->questinfo_validate = quest_questinfo_validate; + quest->questinfo_validate_job = quest_questinfo_validate_job; + quest->questinfo_validate_sex = quest_questinfo_validate_sex; + quest->questinfo_validate_baselevel = quest_questinfo_validate_baselevel; + quest->questinfo_validate_joblevel = quest_questinfo_validate_joblevel; + quest->questinfo_validate_items = quest_questinfo_validate_items; + quest->questinfo_validate_homunculus_level = quest_questinfo_validate_homunculus_level; + quest->questinfo_validate_homunculus_type = quest_questinfo_validate_homunculus_type; + quest->questinfo_validate_quests = quest_questinfo_validate_quests; + quest->questinfo_vector_clear = quest_questinfo_vector_clear; } |