diff options
-rw-r--r-- | db/const.txt | 10 | ||||
-rw-r--r-- | doc/script_commands.txt | 85 | ||||
-rw-r--r-- | src/map/clif.c | 18 | ||||
-rw-r--r-- | src/map/instance.c | 10 | ||||
-rw-r--r-- | src/map/map.c | 47 | ||||
-rw-r--r-- | src/map/map.h | 17 | ||||
-rw-r--r-- | src/map/npc.c | 3 | ||||
-rw-r--r-- | src/map/script.c | 104 |
8 files changed, 265 insertions, 29 deletions
diff --git a/db/const.txt b/db/const.txt index 6ecae2177..29a6994cb 100644 --- a/db/const.txt +++ b/db/const.txt @@ -3220,6 +3220,16 @@ HAVEQUEST 0 PLAYTIME 1 HUNTING 2 +QTYPE_NONE 0x270f +QTYPE_QUEST 0x00 +QTYPE_QUEST2 0x01 +QTYPE_JOB 0x02 +QTYPE_JOB2 0x03 +QTYPE_EVENT 0x04 +QTYPE_EVENT2 0x05 +QTYPE_WARG 0x06 +QTYPE_WARG2 0x08 + FW_DONTCARE 0 FW_THIN 100 FW_EXTRALIGHT 200 diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 9969ff1a8..bd0b032f1 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -7886,10 +7886,56 @@ that fails, the command returns an empty string instead. ========================= --------------------------------------- +*questinfo <Quest ID>, <Icon> {, <Map Mark Color>{, <Job Class>}}; + +This is esentially a combination of checkquest and showevent. Use this only +in an OnInit label. For the Quest ID, specify the quest ID that you want +checked if it has been started yet. + +For Icon, use one of the following: + +No Icon : QTYPE_NONE +! Quest Icon : QTYPE_QUEST +? Quest Icon : QTYPE_QUEST2 +! Job Icon : QTYPE_JOB +? Job Icon : QTYPE_JOB2 +! Event Icon : QTYPE_EVENT +? Event Icon : QTYPE_EVENT2 +Warg : QTYPE_WARG +Warg Face : QTYPE_WARG2 (Only for packetver >= 20120410) + +Map Mark Color, when used, creates a mark in the user's mini map on the position of the NPC, +the available color values are: + +0 - No Marker +1 - Yellow Marker +2 - Green Marker +3 - Purple Marker + +When a user shows up on a map, each NPC is checked for questinfo that has been set. +If questinfo is present, it will check if the quest has been started, if it has not, the bubble will appear. + +Optionally, you can also specify a Job Class if the quest bubble should only appear for a certain class. + +Example +izlude,100,100,4 script Test 844,{ + mes "[Test]"; + mes "Hello World."; + close; + + OnInit: + questinfo 1001, QTYPE_QUEST, 0, Job_Novice; + end; +} + +--------------------------------------- + *setquest <ID>; Place quest of <ID> in the users quest log, the state of which is "active". +If *questinfo is set, and the same ID is specified here, the icon will be cleared when the quest is set. + --------------------------------------- *completequest <ID>; @@ -7937,27 +7983,30 @@ If parameter "HUNTING" is supplied: --------------------------------------- -*showevent <state>, <color>; +*showevent <icon>{,<mark color>} + +Show an emotion on top of a NPC, and optionally, +a colored mark in the mini-map like "viewpoint". +This is used to indicate that a NPC has a quest or an event to +a certain player. -Show a colored mark in the mini-map like "viewpoint" and an emotion on top -of a NPC. This is used to indicate that a NPC has a quest or an event to -certain player/s. +Available Icons: -state can be: - 0 = disable ( Used to disable and remove the mark and the emotion from - the NPC. ) - 1 = exclamation emotion ( Used to show an important quest event to - certain player. ) - 2 = interrogation emotion ( Used to show an non-important quest event - to certain player. ) -Other value may cause client crashes. +Remove Icon : QTYPE_NONE +! Quest Icon : QTYPE_QUEST +? Quest Icon : QTYPE_QUEST2 +! Job Icon : QTYPE_JOB +? Job Icon : QTYPE_JOB2 +! Event Icon : QTYPE_EVENT +? Event Icon : QTYPE_EVENT2 +Warg : QTYPE_WARG +Warg Face : QTYPE_WARG2 (Only for packetver >= 20120410) -color can be: - 0 = yellow "Quest" - 1 = orange "Job" - 2 = green "Event" - 3 = an MVP flag -Other values show a transparent mark in the mini-map. +Mark Color: +0 - No Mark +1 - Yellow Mark +2 - Green Mark +3 - Purple Mark ---------------------------------------- diff --git a/src/map/clif.c b/src/map/clif.c index 94fc6f7a7..decdfc2ce 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9316,6 +9316,8 @@ void clif_hercules_chsys_mjoin(struct map_session_data *sd) { /// Notification from the client, that it has finished map loading and is about to display player's character (CZ_NOTIFY_ACTORINIT). /// 007d void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { + int i; + if(sd->bl.prev != NULL) return; @@ -9624,10 +9626,24 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { skill->usave_trigger(sd); } -// Trigger skill effects if you appear standing on them + // Trigger skill effects if you appear standing on them if(!battle_config.pc_invincible_time) skill->unit_move(&sd->bl,timer->gettick(),1); + // NPC Quest / Event Icon Check [Kisuka] +#if PACKETVER >= 20090218 + 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->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); + } + } + } +#endif } diff --git a/src/map/instance.c b/src/map/instance.c index 045be5431..83b538ffc 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -242,6 +242,13 @@ int instance_add_map(const char *name, int instance_id, bool usebasename, const } } + //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) ); + } + map->list[im].m = im; map->list[im].instance_id = instance_id; map->list[im].instance_src_map = m; @@ -443,6 +450,9 @@ void instance_del_map(int16 m) { aFree(map->list[m].zone_mf); } + if( map->list[m].qi_data ) + aFree(map->list[m].qi_data); + // Remove from instance for( i = 0; i < instance->list[map->list[m].instance_id].num_map; i++ ) { if( instance->list[map->list[m].instance_id].map[i] == m ) { diff --git a/src/map/map.c b/src/map/map.c index 133c63a1c..81bd732df 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3112,6 +3112,10 @@ void do_final_maps(void) { if( map->list[i].channel ) clif->chsys_delete(map->list[i].channel); + + if( map->list[i].qi_data ) + aFree(map->list[i].qi_data); + } map->zone_db_clear(); @@ -3177,6 +3181,12 @@ void map_flags_init(void) { map->list[i].misc_damage_rate = 100; 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; } } @@ -4968,6 +4978,38 @@ int map_get_new_bonus_id (void) { return map->bonus_id++; } +void map_add_questinfo(int m, struct questinfo *qi) { + unsigned short i; + + /* 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)); +} + +bool map_remove_questinfo(int m, struct npc_data *nd) { + unsigned short i; + + 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)); + } + return true; + } + } + + return false; +} + /** * @see DBApply */ @@ -5834,7 +5876,10 @@ void map_defaults(void) { map->delblcell = map_delblcell; map->get_new_bonus_id = map_get_new_bonus_id; - + + map->add_questinfo = map_add_questinfo; + map->remove_questinfo = map_remove_questinfo; + /** * mapit interface **/ diff --git a/src/map/map.h b/src/map/map.h index 408d03c76..6e4878dfd 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -557,6 +557,17 @@ struct map_drop_list { int drop_per; }; + +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? */ +}; + + struct map_data { char name[MAP_NAME_LENGTH]; uint16 index; // The map index used by the mapindex* functions. @@ -691,6 +702,10 @@ struct map_data { int (*getcellp)(struct map_data* m,int16 x,int16 y,cell_chk cellchk); void (*setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag); char *cellPos; + + /* ShowEvent Data Cache */ + struct questinfo *qi_data; + unsigned short qi_count; }; /// Stores information about a remote map (for multi-mapserver setups). @@ -1030,6 +1045,8 @@ struct map_interface { void (*addblcell) (struct block_list *bl); void (*delblcell) (struct block_list *bl); int (*get_new_bonus_id) (void); + void (*add_questinfo) (int m, struct questinfo *qi); + bool (*remove_questinfo) (int m, struct npc_data *nd); }; struct map_interface *map; diff --git a/src/map/npc.c b/src/map/npc.c index 2b6d807cb..e4416c19f 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1790,6 +1790,9 @@ int npc_unload(struct npc_data* nd, bool single) { aFree(nd->path);/* remove now that no other instances exist */ } } + + if( single && nd->bl.m != -1 ) + map->remove_questinfo(nd->bl.m,nd); if( (nd->subtype == SHOP || nd->subtype == CASHSHOP) && nd->src_id == 0) //src check for duplicate shops [Orcao] aFree(nd->u.shop.shop_item); diff --git a/src/map/script.c b/src/map/script.c index 826c5ae34..efc3e0264 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -15456,12 +15456,82 @@ BUILDIN(readbook) Questlog script commands *******************/ +BUILDIN(questinfo) +{ + struct npc_data *nd = map->id2nd(st->oid); + int quest, icon, job, color = 0; + struct questinfo qi; + + if( nd == NULL || nd->bl.m == -1 ) + return true; + + quest = script_getnum(st, 2); + icon = script_getnum(st, 3); + + #if 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 + + qi.quest_id = quest; + qi.icon = (unsigned char)icon; + qi.nd = nd; + + if( script_hasdata(st, 4) ) { + color = script_getnum(st, 4); + if( color < 0 || color > 3 ) { + ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color); + script->reportfunc(st); + color = 0; + } + qi.color = (unsigned char)color; + } + + qi.hasJob = false; + + if(script_hasdata(st, 5)) { + job = script_getnum(st, 5); + + if (!pcdb_checkid(job)) + ShowError("buildin_questinfo: Nonexistant Job Class.\n"); + else { + qi.hasJob = true; + qi.job = (unsigned short)job; + } + } + + map->add_questinfo(nd->bl.m,&qi); + + return true; +} + BUILDIN(setquest) { struct map_session_data *sd = script->rid2sd(st); - nullpo_retr(false,sd); + unsigned short i; + if (!sd) + return false; + quest->add(sd, script_getnum(st, 2)); + + // 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 == script_getnum(st, 2) ) { +#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; } @@ -15510,17 +15580,32 @@ BUILDIN(checkquest) BUILDIN(showevent) { TBL_PC *sd = script->rid2sd(st); struct npc_data *nd = map->id2nd(st->oid); - int state, color; + int icon, color = 0; if( sd == NULL || nd == NULL ) return true; - state = script_getnum(st, 2); - color = script_getnum(st, 3); - - if( color < 0 || color > 3 ) - color = 0; // set default color + + icon = script_getnum(st, 2); + if( script_hasdata(st, 3) ) { + color = script_getnum(st, 3); + if( color < 0 || color > 3 ) { + ShowWarning("buildin_showevent: invalid color '%d', changing to 0\n",color); + script->reportfunc(st); + color = 0; + } + } + + #if 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 - clif->quest_show_event(sd, &nd->bl, state, color); + clif->quest_show_event(sd, &nd->bl, icon, color); return true; } @@ -18026,12 +18111,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(useatcmd, "s"), //Quest Log System [Inkfish] + BUILDIN_DEF(questinfo, "ii??"), BUILDIN_DEF(setquest, "i"), BUILDIN_DEF(erasequest, "i"), BUILDIN_DEF(completequest, "i"), BUILDIN_DEF(checkquest, "i?"), BUILDIN_DEF(changequest, "ii"), - BUILDIN_DEF(showevent, "ii"), + BUILDIN_DEF(showevent, "i?"), /** * hQueue [Ind/Hercules] |