diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/mmo.h | 14 | ||||
-rw-r--r-- | src/map/clif.c | 15 | ||||
-rw-r--r-- | src/map/homunculus.c | 5 | ||||
-rw-r--r-- | src/map/instance.c | 12 | ||||
-rw-r--r-- | src/map/map.c | 35 | ||||
-rw-r--r-- | src/map/map.h | 22 | ||||
-rw-r--r-- | src/map/pc.c | 5 | ||||
-rw-r--r-- | src/map/quest.c | 291 | ||||
-rw-r--r-- | src/map/quest.h | 14 | ||||
-rw-r--r-- | src/map/script.c | 208 |
10 files changed, 527 insertions, 94 deletions
diff --git a/src/common/mmo.h b/src/common/mmo.h index fa8f3048d..1b9562e9d 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -1271,6 +1271,20 @@ enum hz_char_ask_name_answer { CHAR_ASK_NAME_ANS_OFFLINE = 3, // login-server offline }; +/** + * Quest Info Types + */ +enum questinfo_type { + QINFO_JOB, + QINFO_SEX, + QINFO_BASE_LEVEL, + QINFO_JOB_LEVEL, + QINFO_ITEM, + QINFO_HOMUN_LEVEL, + QINFO_HOMUN_TYPE, + QINFO_QUEST +}; + /* packet size constant for itemlist */ #if MAX_INVENTORY > MAX_STORAGE && MAX_INVENTORY > MAX_CART #define MAX_ITEMLIST MAX_INVENTORY diff --git a/src/map/clif.c b/src/map/clif.c index 904bfdd68..2a2d87ccc 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -10066,16 +10066,11 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) #if PACKETVER >= 20090218 { int i; - for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { - struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; - if( quest->check(sd, qi->quest_id, HAVEQUEST) == -1 ) {// Check if quest is not started - if( qi->hasJob ) { // Check if quest is job-specific, check is user is said job class. - if (sd->status.class == qi->job) - clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); - } else { - clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); - } - } + 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); + + if (quest->questinfo_validate(sd, qi)) + clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); } } #endif diff --git a/src/map/homunculus.c b/src/map/homunculus.c index a6e7bb71c..6df272243 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -37,6 +37,7 @@ #include "map/party.h" #include "map/pc.h" #include "map/pet.h" +#include "map/quest.h" #include "map/script.h" #include "map/skill.h" #include "map/status.h" @@ -406,6 +407,7 @@ static bool homunculus_levelup(struct homun_data *hd) growth_int/10.0, growth_dex/10.0, growth_luk/10.0); clif_disp_onlyself(hd->master, output); } + quest->questinfo_refresh(hd->master); return true; } @@ -419,6 +421,7 @@ static int homunculus_change_class(struct homun_data *hd, short class_) hd->homunculus.class_ = class_; status->set_viewdata(&hd->bl, class_); homun->calc_skilltree(hd, 1); + quest->questinfo_refresh(hd->master); return 1; } @@ -471,7 +474,7 @@ static bool homunculus_evolve(struct homun_data *hd) if (!(battle_config.hom_setting&0x2)) skill->unit_move(&sd->hd->bl,timer->gettick(),1); // apply land skills immediately - + quest->questinfo_refresh(sd); return true; } diff --git a/src/map/instance.c b/src/map/instance.c index 2c40449ad..8bd45ba50 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -30,6 +30,7 @@ #include "map/npc.h" #include "map/party.h" #include "map/pc.h" +#include "map/quest.h" #include "common/HPM.h" #include "common/cbasetypes.h" #include "common/db.h" @@ -295,10 +296,10 @@ static int instance_add_map(const char *name, int instance_id, bool usebasename, } //Mimic questinfo - if( map->list[m].qi_count ) { - map->list[im].qi_count = map->list[m].qi_count; - CREATE( map->list[im].qi_data, struct questinfo, map->list[im].qi_count ); - memcpy( map->list[im].qi_data, map->list[m].qi_data, map->list[im].qi_count * sizeof(struct questinfo) ); + VECTOR_INIT(map->list[im].qi_data); + VECTOR_ENSURE(map->list[im].qi_data, VECTOR_LENGTH(map->list[m].qi_data), 1); + for (i = 0; i < VECTOR_LENGTH(map->list[m].qi_data); i++) { + VECTOR_PUSH(map->list[im].qi_data, VECTOR_INDEX(map->list[m].qi_data, i)); } map->list[im].m = im; @@ -517,8 +518,7 @@ static void instance_del_map(int16 m) aFree(map->list[m].zone_mf); } - if( map->list[m].qi_data ) - aFree(map->list[m].qi_data); + quest->questinfo_vector_clear(m); // Remove from instance for( i = 0; i < instance->list[map->list[m].instance_id].num_map; i++ ) { diff --git a/src/map/map.c b/src/map/map.c index 8ea059700..0124a3035 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3681,8 +3681,7 @@ static void do_final_maps(void) if( map->list[i].channel ) channel->delete(map->list[i].channel); - if( map->list[i].qi_data ) - aFree(map->list[i].qi_data); + quest->questinfo_vector_clear(i); HPM->data_store_destroy(&map->list[i].hdata); } @@ -3752,11 +3751,7 @@ static void map_flags_init(void) map->list[i].short_damage_rate = 100; map->list[i].long_damage_rate = 100; - if( map->list[i].qi_data ) - aFree(map->list[i].qi_data); - - map->list[i].qi_data = NULL; - map->list[i].qi_count = 0; + VECTOR_INIT(map->list[i].qi_data); } } @@ -5972,34 +5967,24 @@ static int map_get_new_bonus_id(void) static void map_add_questinfo(int m, struct questinfo *qi) { - unsigned short i; - nullpo_retv(qi); Assert_retv(m >= 0 && m < map->count); - /* duplicate, override */ - for(i = 0; i < map->list[m].qi_count; i++) { - if( map->list[m].qi_data[i].nd == qi->nd ) - break; - } - - if( i == map->list[m].qi_count ) - RECREATE(map->list[m].qi_data, struct questinfo, ++map->list[m].qi_count); - memcpy(&map->list[m].qi_data[i], qi, sizeof(struct questinfo)); + VECTOR_ENSURE(map->list[m].qi_data, 1, 1); + VECTOR_PUSH(map->list[m].qi_data, *qi); } static bool map_remove_questinfo(int m, struct npc_data *nd) { unsigned short i; + nullpo_retr(false, nd); Assert_retr(false, m >= 0 && m < map->count); - for(i = 0; i < map->list[m].qi_count; i++) { - struct questinfo *qi = &map->list[m].qi_data[i]; - if( qi->nd == nd ) { - memset(&map->list[m].qi_data[i], 0, sizeof(struct questinfo)); - if( i != --map->list[m].qi_count ) { - memmove(&map->list[m].qi_data[i],&map->list[m].qi_data[i+1],sizeof(struct questinfo)*(map->list[m].qi_count-i)); - } + + for (i = 0; i < VECTOR_LENGTH(map->list[m].qi_data); i++) { + struct questinfo *qi_data = &VECTOR_INDEX(map->list[m].qi_data, i); + if (qi_data->nd == nd) { + VECTOR_ERASE(map->list[m].qi_data, i); return true; } } diff --git a/src/map/map.h b/src/map/map.h index d6779ca91..04525b4d5 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -773,14 +773,31 @@ struct map_drop_list { int drop_per; }; +struct questinfo_qreq { + int id; + int state; +}; struct questinfo { struct npc_data *nd; unsigned short icon; unsigned char color; - int quest_id; bool hasJob; unsigned short job;/* perhaps a mapid mask would be most flexible? */ + bool sex_enabled; + int sex; + struct { + int min; + int max; + } base_level; + struct { + int min; + int max; + } job_level; + VECTOR_DECL(struct item) items; + struct s_homunculus homunculus; + int homunculus_type; + VECTOR_DECL(struct questinfo_qreq) quest_requirement; }; @@ -922,8 +939,7 @@ struct map_data { } cell_buf; /* ShowEvent Data Cache */ - struct questinfo *qi_data; - unsigned short qi_count; + VECTOR_DECL(struct questinfo) qi_data; /* speeds up clif_updatestatus processing by causing hpmeter to run only when someone with the permission can view it */ unsigned short hpmeter_visible; diff --git a/src/map/pc.c b/src/map/pc.c index d9e41fde2..f2cff8ab3 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4783,6 +4783,7 @@ static int pc_additem(struct map_session_data *sd, struct item *item_data, int a pc->inventory_rental_add(sd, seconds); } } + quest->questinfo_refresh(sd); return 0; } @@ -4820,6 +4821,7 @@ static int pc_delitem(struct map_session_data *sd, int n, int amount, int type, clif->delitem(sd,n,amount,reason); if(!(type&2)) clif->updatestatus(sd,SP_WEIGHT); + quest->questinfo_refresh(sd); return 0; } @@ -6881,6 +6883,7 @@ static int pc_checkbaselevelup(struct map_session_data *sd) party->send_levelup(sd); pc->baselevelchanged(sd); + quest->questinfo_refresh(sd); return 1; } @@ -6943,6 +6946,7 @@ static int pc_checkjoblevelup(struct map_session_data *sd) clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. npc->script_event(sd, NPCE_JOBLVUP); + quest->questinfo_refresh(sd); return 1; } @@ -9036,6 +9040,7 @@ static int pc_jobchange(struct map_session_data *sd, int class, int upper) break; } } + quest->questinfo_refresh(sd); return 0; } diff --git a/src/map/quest.c b/src/map/quest.c index 614c79cb6..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" @@ -154,6 +155,7 @@ static int quest_add(struct map_session_data *sd, int quest_id, unsigned int tim #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); @@ -211,10 +213,10 @@ static 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; } @@ -254,6 +256,7 @@ static 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); @@ -381,6 +384,7 @@ static int quest_update_status(struct map_session_data *sd, int quest_id, enum q } clif->quest_delete(sd, quest_id); + quest->questinfo_refresh(sd); if( map->save_settings&64 ) chrif->save(sd,0); @@ -638,6 +642,278 @@ static 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. * @@ -699,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; } diff --git a/src/map/quest.h b/src/map/quest.h index d33d84885..305a48df1 100644 --- a/src/map/quest.h +++ b/src/map/quest.h @@ -28,6 +28,7 @@ struct block_list; struct config_setting_t; struct map_session_data; +struct questinfo; #define MAX_QUEST_DB (60355+1) // Highest quest ID + 1 @@ -79,6 +80,19 @@ struct quest_interface { void (*clear) (void); int (*read_db) (void); struct quest_db *(*read_db_sub) (struct config_setting_t *cs, int n, const char *source); + + int (*questinfo_validate_icon) (int icon); + void (*questinfo_refresh) (struct map_session_data *sd); + bool (*questinfo_validate) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_job) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_sex) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_baselevel) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_joblevel) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_items) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_homunculus_level) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_homunculus_type) (struct map_session_data *sd, struct questinfo *qi); + bool (*questinfo_validate_quests) (struct map_session_data *sd, struct questinfo *qi); + void (*questinfo_vector_clear) (int m); }; #ifdef HERCULES_CORE diff --git a/src/map/script.c b/src/map/script.c index 260a9848c..9a5d33604 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -20913,63 +20913,177 @@ static BUILDIN(readbook) static BUILDIN(questinfo) { struct npc_data *nd = map->id2nd(st->oid); - int quest_id, icon; - struct questinfo qi; + struct questinfo qi = { 0 }; + int icon = script_getnum(st, 2); - if( nd == NULL || nd->bl.m == -1 ) + if (nd == NULL) return true; - quest_id = script_getnum(st, 2); - icon = script_getnum(st, 3); - -#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 + if (nd->bl.m == -1) { + ShowWarning("buildin_questinfo: questinfo cannot be set for an npc with no valid map.\n"); + return false; + } - qi.quest_id = quest_id; - qi.icon = (unsigned char)icon; qi.nd = nd; - - if (script_hasdata(st, 4)) { - int color = script_getnum(st, 4); + qi.icon = quest->questinfo_validate_icon(icon); + if (script_hasdata(st, 3)) { + int color = script_getnum(st, 3); if (color < 0 || color > 3) { - ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color); + ShowWarning("buildin_questinfo: invalid color '%d', defaulting to 0.\n", color); script->reportfunc(st); color = 0; } qi.color = (unsigned char)color; } - qi.hasJob = false; + map->add_questinfo(nd->bl.m, &qi); + return true; +} - if (script_hasdata(st, 5)) { - int job = script_getnum(st, 5); +static BUILDIN(setquestinfo) +{ + struct npc_data *nd = map->id2nd(st->oid); + struct questinfo *qi = NULL; + uint32 type = script_getnum(st, 2); - if (!pc->db_checkid(job)) { - ShowError("buildin_questinfo: Nonexistant Job Class.\n"); - } else { - qi.hasJob = true; - qi.job = (unsigned short)job; + if (nd == NULL) + return true; + + if (nd->bl.m == -1) { + ShowWarning("buildin_setquestinfo: questinfo cannot be set for an npc with no valid map.\n"); + return false; + } + + qi = &VECTOR_LAST(map->list[nd->bl.m].qi_data); + if (qi == NULL) { + ShowWarning("buildin_setquestinfo: no valide questinfo data has been found for this npc.\n"); + return false; + } + if (qi->nd != nd) { + ShowWarning("buildin_setquestinfo: invalid usage, setquestinfo must be used only after questinfo.\n"); + return false; + } + switch (type) { + case QINFO_JOB: + { + int jobid = script_getnum(st, 3); + if (!pc->db_checkid(jobid)) { + ShowWarning("buildin_setquestinfo: invalid job id given (%d).\n", jobid); + return false; } + qi->hasJob = true; + qi->job = jobid; + break; } + case QINFO_SEX: + { + int sex = script_getnum(st, 3); + if (sex != SEX_MALE && sex != SEX_FEMALE) { + ShowWarning("buildin_setquestinfo: unsupported sex has been given (%d).\n", sex); + return false; + } + qi->sex_enabled = true; + qi->sex = sex; + break; + } + case QINFO_BASE_LEVEL: + { + int min = script_getnum(st, 3); + int max = script_getnum(st, 4); + if (min > max) { + ShowWarning("buildin_setquestinfo: minimal level (%d) is bigger than the maximal level (%d).\n", min, max); + return false; + } + qi->base_level.min = min; + qi->base_level.max = max; + break; + } + case QINFO_JOB_LEVEL: + { + int min = script_getnum(st, 3); + int max = script_getnum(st, 4); + if (min > max) { + ShowWarning("buildin_setquestinfo: minimal level (%d) is bigger than the maximal level (%d).\n", min, max); + return false; + } + qi->job_level.min = min; + qi->job_level.max = max; + break; + } + case QINFO_ITEM: + { + struct item item = { 0 }; + + item.nameid = script_getnum(st, 3); + item.amount = script_getnum(st, 4); + + if (itemdb->exists(item.nameid) == NULL) { + ShowWarning("buildin_setquestinfo: non existing item (%d) have been given.\n", item.nameid); + return false; + } + if (item.amount <= 0 || item.amount > MAX_AMOUNT) { + ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than 0 and smaller than %d.\n", item.amount, MAX_AMOUNT + 1); + return false; + } + if (VECTOR_LENGTH(qi->items) == 0) + VECTOR_INIT(qi->items); + VECTOR_ENSURE(qi->items, 1, 1); + VECTOR_PUSH(qi->items, item); + break; + } + case QINFO_HOMUN_LEVEL: + { + int min = script_getnum(st, 3); + if (min > battle_config.hom_max_level && min > battle_config.hom_S_max_level) { + ShowWarning("buildin_setquestinfo: minimum homunculus level given (%d) is bigger than the max possible level.\n", min); + return false; + } + qi->homunculus.level = min; + break; + } + case QINFO_HOMUN_TYPE: + { + int hom_type = script_getnum(st, 3); + if (hom_type < HT_REG || hom_type > HT_S) { + ShowWarning("buildin_setquestinfo: invalid homunculus type (%d).\n", hom_type); + return false; + } + qi->homunculus_type = hom_type; + break; + } + case QINFO_QUEST: + { + struct questinfo_qreq quest_req = { 0 }; + struct quest_db *quest_data = NULL; + + quest_req.id = script_getnum(st, 3); + quest_req.state = script_getnum(st, 4); - map->add_questinfo(nd->bl.m,&qi); + quest_data = quest->db(quest_req.id); + if (quest_data == &quest->dummy) { + ShowWarning("buildin_setquestinfo: invalid quest given (%d).\n", quest_req.id); + return false; + } + if (quest_req.state < Q_INACTIVE || quest_req.state > Q_COMPLETE) { + ShowWarning("buildin_setquestinfo: invalid quest state given (%d).\n", quest_req.state); + return false; + } + if (VECTOR_LENGTH(qi->quest_requirement) == 0) + VECTOR_INIT(qi->quest_requirement); + VECTOR_ENSURE(qi->quest_requirement, 1, 1); + VECTOR_PUSH(qi->quest_requirement, quest_req); + break; + } + default: + ShowWarning("buildin_setquestinfo: invalid type given (%u).\n", type); + return false; + } return true; } static BUILDIN(setquest) { - unsigned short i; int quest_id; unsigned int time_limit; struct map_session_data *sd = script->rid2sd(st); @@ -20981,19 +21095,6 @@ static BUILDIN(setquest) time_limit = script_hasdata(st, 3) ? script_getnum(st, 3) : 0; quest->add(sd, quest_id, time_limit); - - // If questinfo is set, remove quest bubble once quest is set. - for (i = 0; i < map->list[sd->bl.m].qi_count; i++) { - struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; - if (qi->quest_id == quest_id) { -#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 - } - } - return true; } @@ -25095,7 +25196,8 @@ static void script_parse_builtin(void) BUILDIN_DEF(checkbound, "i???????"), //Quest Log System [Inkfish] - BUILDIN_DEF(questinfo, "ii??"), + BUILDIN_DEF(questinfo, "i?"), + BUILDIN_DEF(setquestinfo, "i??"), BUILDIN_DEF(setquest, "i?"), BUILDIN_DEF(erasequest, "i?"), BUILDIN_DEF(completequest, "i?"), @@ -25556,6 +25658,16 @@ static void script_hardcoded_constants(void) script->set_constant("P_AIRSHIP_ITEM_NOT_ENOUGH", P_AIRSHIP_ITEM_NOT_ENOUGH, false, false); script->set_constant("P_AIRSHIP_ITEM_INVALID", P_AIRSHIP_ITEM_INVALID, false, false); + script->constdb_comment("questinfo types"); + script->set_constant("QINFO_JOB", QINFO_JOB, false, false); + script->set_constant("QINFO_SEX", QINFO_SEX, false, false); + script->set_constant("QINFO_BASE_LEVEL", QINFO_BASE_LEVEL, false, false); + script->set_constant("QINFO_JOB_LEVEL", QINFO_JOB_LEVEL, false, false); + script->set_constant("QINFO_ITEM", QINFO_ITEM, false, false); + script->set_constant("QINFO_HOMUN_LEVEL", QINFO_HOMUN_LEVEL, false, false); + script->set_constant("QINFO_HOMUN_TYPE", QINFO_HOMUN_TYPE, false, false); + script->set_constant("QINFO_QUEST", QINFO_QUEST, false, false); + script->constdb_comment("Renewal"); #ifdef RENEWAL script->set_constant("RENEWAL", 1, false, false); |