summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshennetsind <shennetsind@users.noreply.github.com>2013-10-25 21:11:05 -0700
committershennetsind <shennetsind@users.noreply.github.com>2013-10-25 21:11:05 -0700
commit1ab0017183e910271f4590beee37530fa3ce8ba0 (patch)
tree03ef8eb76a73d498e69e8c7e1160a1015a4c9653
parent5f6f1d66834b8328496c1678f0ce4f90a001b3fb (diff)
parentf7158456d9f6338b38b16f321c9a229fc6547bc0 (diff)
downloadhercules-1ab0017183e910271f4590beee37530fa3ce8ba0.tar.gz
hercules-1ab0017183e910271f4590beee37530fa3ce8ba0.tar.bz2
hercules-1ab0017183e910271f4590beee37530fa3ce8ba0.tar.xz
hercules-1ab0017183e910271f4590beee37530fa3ce8ba0.zip
Merge pull request #202 from kisuka/master
Quest Bubbles (Actually Works Finally)
-rw-r--r--db/const.txt10
-rw-r--r--doc/script_commands.txt85
-rw-r--r--src/map/clif.c18
-rw-r--r--src/map/instance.c10
-rw-r--r--src/map/map.c47
-rw-r--r--src/map/map.h17
-rw-r--r--src/map/npc.c3
-rw-r--r--src/map/script.c104
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]