Skip to content

Commit

Permalink
Fixed quest information icons not displaying properly on NPC. (bugrep…
Browse files Browse the repository at this point in the history
…ort:8156, bugreport:8157) (Hercules 1ab0017)
  • Loading branch information
aleos89 committed Mar 31, 2014
1 parent 0239b61 commit 5e02af2
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 23 deletions.
10 changes: 10 additions & 0 deletions db/const.txt
Expand Up @@ -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
Expand Down
81 changes: 67 additions & 14 deletions doc/script_commands.txt
Expand Up @@ -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>;
Expand Down Expand Up @@ -7689,23 +7735,30 @@ Return the state of the quest:

---------------------------------------

*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 players.
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 values 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

---------------------------------------

Expand Down
19 changes: 18 additions & 1 deletion src/map/clif.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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
}


Expand Down
48 changes: 48 additions & 0 deletions src/map/map.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 16 additions & 0 deletions src/map/map.h
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
{
Expand Down
3 changes: 3 additions & 0 deletions src/map/npc.c
Expand Up @@ -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);
Expand Down

0 comments on commit 5e02af2

Please sign in to comment.