Fixed quest information icons not displaying properly on NPC. (bugreport:8156, bugreport:8157) (Hercules 1ab0017)

This commit is contained in:
aleos89 2014-03-31 08:16:44 -04:00
parent 0239b612f4
commit 5e02af25af
7 changed files with 257 additions and 24 deletions

View File

@ -4515,6 +4515,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

View File

@ -7633,10 +7633,56 @@ if (instance_check_party(getcharid(1),2,2,149)) {
=========================
---------------------------------------
*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>;
@ -7689,23 +7735,30 @@ Return the state of the quest:
---------------------------------------
*showevent <state>, <color>;
*showevent <icon>{,<mark color>}
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 players.
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.
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 values may cause client crashes.
Available Icons:
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.
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)
Mark Color:
0 - No Mark
1 - Yellow Mark
2 - Green Mark
3 - Purple Mark
---------------------------------------

View File

@ -9450,6 +9450,8 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd)
/// 007d
void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
{
int i;
if(sd->bl.prev != NULL)
return;
@ -9775,9 +9777,24 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
clif_changed_dir(&sd->bl, SELF);
}
// 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,gettick(),1);
// NPC Quest / Event Icon Check [Kisuka]
#if PACKETVER >= 20090218
for(i = 0; i < map[sd->bl.m].qi_count; i++) {
struct questinfo *qi = &map[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
}

View File

@ -2260,6 +2260,13 @@ int map_addinstancemap(const char *name, int id)
snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%.3d%s", id, iname);
map[dst_m].name[MAP_NAME_LENGTH-1] = '\0';
// Mimic questinfo
if( map[src_m].qi_count ) {
map[dst_m].qi_count = map[src_m].qi_count;
CREATE( map[dst_m].qi_data, struct questinfo, map[dst_m].qi_count );
memcpy( map[dst_m].qi_data, map[src_m].qi_data, map[dst_m].qi_count * sizeof(struct questinfo) );
}
map[dst_m].m = dst_m;
map[dst_m].instance_id = id;
map[dst_m].users = 0;
@ -2356,6 +2363,9 @@ int map_delinstancemap(int m)
map_removemapdb(&map[m]);
memset(&map[m], 0x00, sizeof(map[0]));
if( map[m].qi_data )
aFree(map[m].qi_data);
// Make delete timers invalid to avoid errors
map[m].mob_delete_timer = INVALID_TIMER;
@ -3102,6 +3112,12 @@ void map_flags_init(void)
// adjustments
if( battle_config.pk_mode )
map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
if( map[i].qi_data )
aFree(map[i].qi_data);
map[i].qi_data = NULL;
map[i].qi_count = 0;
}
}
@ -3678,6 +3694,37 @@ int log_sql_init(void)
return 0;
}
void map_add_questinfo(int m, struct questinfo *qi) {
unsigned short i;
/* duplicate, override */
for(i = 0; i < map[m].qi_count; i++) {
if( map[m].qi_data[i].nd == qi->nd )
break;
}
if( i == map[m].qi_count )
RECREATE(map[m].qi_data, struct questinfo, ++map[m].qi_count);
memcpy(&map[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[m].qi_count; i++) {
struct questinfo *qi = &map[m].qi_data[i];
if( qi->nd == nd ) {
memset(&map[m].qi_data[i], 0, sizeof(struct questinfo));
if( i != --map[m].qi_count )
memmove(&map[m].qi_data[i],&map[m].qi_data[i+1],sizeof(struct questinfo)*(map[m].qi_count-i));
return true;
}
}
return false;
}
/**
* @see DBApply
*/
@ -3813,6 +3860,7 @@ void do_final(void)
if(map[i].cell) aFree(map[i].cell);
if(map[i].block) aFree(map[i].block);
if(map[i].block_mob) aFree(map[i].block_mob);
if(map[i].qi_data) aFree(map[i].qi_data);
if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random]
if(map[i].mob_delete_timer != INVALID_TIMER)
delete_timer(map[i].mob_delete_timer, map_removemobs_timer);

View File

@ -580,6 +580,15 @@ struct s_skill_damage {
#define MAX_MAP_SKILL_MODIFIER 5
#endif
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.
@ -688,6 +697,10 @@ struct map_data {
/* rAthena Local Chat */
struct Channel *channel;
/* ShowEvent Data Cache */
struct questinfo *qi_data;
unsigned short qi_count;
/* speeds up clif_updatestatus processing by causing hpmeter to run only when someone with the permission can view it */
unsigned short hpmeter_visible;
@ -806,6 +819,9 @@ struct mob_data * map_id2boss(int id);
// reload config file looking only for npcs
void map_reloadnpc(bool clear);
void map_add_questinfo(int m, struct questinfo *qi);
bool map_remove_questinfo(int m, struct npc_data *nd);
/// Bitfield of flags for the iterator.
enum e_mapitflags
{

View File

@ -1945,6 +1945,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->subtype == ITEMSHOP || nd->subtype == POINTSHOP) && nd->src_id == 0) //src check for duplicate shops [Orcao]
aFree(nd->u.shop.shop_item);

View File

@ -16545,12 +16545,82 @@ BUILDIN_FUNC(readbook)
Questlog script commands
*******************/
BUILDIN_FUNC(questinfo)
{
TBL_NPC* nd = map_id2nd(st->oid);
int quest_id, icon, job, color = 0;
struct questinfo qi;
if( nd == NULL || nd->bl.m == -1 )
return true;
quest_id = 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_id;
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_FUNC(setquest)
{
struct map_session_data *sd = script_rid2sd(st);
nullpo_ret(sd);
int i, quest_id;
quest_add(sd, script_getnum(st, 2));
nullpo_ret(sd);
quest_id = script_getnum(st, 2);
quest_add(sd, quest_id);
// If questinfo is set, remove quest bubble once quest is set.
for(i = 0; i < map[sd->bl.m].qi_count; i++) {
struct questinfo *qi = &map[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 SCRIPT_CMD_SUCCESS;
}
@ -16613,17 +16683,32 @@ BUILDIN_FUNC(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 0;
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;
}
}
clif_quest_show_event(sd, &nd->bl, state, color);
#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, icon, color);
return SCRIPT_CMD_SUCCESS;
}
@ -19150,13 +19235,14 @@ struct script_function buildin_func[] = {
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(isbegin_quest,"i"),
BUILDIN_DEF(changequest, "ii"),
BUILDIN_DEF(showevent, "ii"),
BUILDIN_DEF(showevent, "i?"),
//Bound items [Xantara] & [Akinari]
BUILDIN_DEF2(getitem,"getitembound","vii?"),