summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/HPMDataCheck.h2
-rw-r--r--src/map/clif.c519
-rw-r--r--src/map/clif.h3
-rw-r--r--src/map/packets_struct.h13
-rw-r--r--src/map/pc.c84
-rw-r--r--src/map/pc.h5
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc20
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc5
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc104
9 files changed, 457 insertions, 298 deletions
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index e5f482686..86fcb671d 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -532,6 +532,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "packet_bgqueue_revoke_req", sizeof(struct packet_bgqueue_revoke_req), SERVER_TYPE_MAP },
{ "packet_bgqueue_update_info", sizeof(struct packet_bgqueue_update_info), SERVER_TYPE_MAP },
{ "packet_cart_additem_ack", sizeof(struct packet_cart_additem_ack), SERVER_TYPE_MAP },
+ { "packet_chat_message", sizeof(struct packet_chat_message), SERVER_TYPE_MAP },
{ "packet_damage", sizeof(struct packet_damage), SERVER_TYPE_MAP },
{ "packet_dropflooritem", sizeof(struct packet_dropflooritem), SERVER_TYPE_MAP },
{ "packet_equip_item", sizeof(struct packet_equip_item), SERVER_TYPE_MAP },
@@ -574,6 +575,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "packet_unequipitem_ack", sizeof(struct packet_unequipitem_ack), SERVER_TYPE_MAP },
{ "packet_unit_walking", sizeof(struct packet_unit_walking), SERVER_TYPE_MAP },
{ "packet_viewequip_ack", sizeof(struct packet_viewequip_ack), SERVER_TYPE_MAP },
+ { "packet_whisper_message", sizeof(struct packet_whisper_message), SERVER_TYPE_MAP },
{ "packet_wis_end", sizeof(struct packet_wis_end), SERVER_TYPE_MAP },
#else
#define MAP_PACKETS_STRUCT_H
diff --git a/src/map/clif.c b/src/map/clif.c
index e1b4be8f4..2dea386be 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -8867,105 +8867,137 @@ void clif_msgtable_skill(struct map_session_data* sd, uint16 skill_id, int msg_i
WFIFOSET(fd, packet_len(0x7e6));
}
-/// Validates one global/guild/party/whisper message packet and tries to recognize its components.
-/// Returns true if the packet was parsed successfully.
-/// Formats: 0 - <packet id>.w <packet len>.w (<name> : <message>).?B 00
-/// 1 - <packet id>.w <packet len>.w <name>.24B <message>.?B 00
-bool clif_process_message(struct map_session_data *sd, int format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_)
-{
- const char *text, *name, *message;
- unsigned int packetlen, textlen;
- size_t namelen, messagelen;
- int fd = sd->fd;
+/**
+ * Validates and processes a global/guild/party message packet.
+ *
+ * @param[in] sd The source character.
+ * @param[in] packet The packet data.
+ * @param[out] out_buf The output buffer (must be a valid buffer), that will
+ * be filled with "Name : Message".
+ * @param[in] out_buflen The size of out_buf (including the NUL terminator).
+ * @return a pointer to the "Message" part of out_buf.
+ * @retval NULL if the validation failed, the messages was a command or the
+ * character can't send chat messages. out_buf shan't be used.
+ */
+const char *clif_process_chat_message(struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int out_buflen)
+{
+ const char *srcname = NULL, *srcmessage = NULL, *message = NULL;
+ int textlen = 0, namelen = 0, messagelen = 0;
- nullpo_retr(false, sd);
- nullpo_retr(false, name_);
- nullpo_retr(false, namelen_);
- nullpo_retr(false, message_);
- nullpo_retr(false, messagelen_);
-
- *name_ = NULL;
- *namelen_ = 0;
- *message_ = NULL;
- *messagelen_ = 0;
-
- packetlen = RFIFOW(fd,2);
- // basic structure checks
- if (packetlen < 4 + 1) {
+ nullpo_ret(sd);
+ nullpo_ret(packet);
+ nullpo_ret(out_buf);
+
+ if (packet->packet_len < 4 + 1) {
// 4-byte header and at least an empty string is expected
- ShowWarning("clif_process_message: Received malformed packet from player '%s' (no message data)!\n", sd->status.name);
- return false;
+ ShowWarning("clif_process_chat_message: Received malformed packet from player '%s' (no message data)!\n", sd->status.name);
+ return NULL;
}
- text = RFIFOP(fd,4);
- textlen = packetlen - 4;
+#if PACKETVER >= 20151001
+ // Packet doesn't include a NUL terminator
+ textlen = packet->packet_len - 4;
+#else // PACKETVER < 20151001
+ // Packet includes a NUL terminator
+ textlen = packet->packet_len - 4 - 1;
+#endif // PACKETVER > 20151001
- // process <name> part of the packet
- if( format == 0 )
- {// name and message are separated by ' : '
- // validate name
- name = text;
- namelen = strnlen(sd->status.name, NAME_LENGTH-1); // name length (w/o zero byte)
+ // name and message are separated by ' : '
+ srcname = packet->message;
+ namelen = (int)strnlen(sd->status.name, NAME_LENGTH-1); // name length (w/o zero byte)
- if( strncmp(name, sd->status.name, namelen) || // the text must start with the speaker's name
- name[namelen] != ' ' || name[namelen+1] != ':' || name[namelen+2] != ' ' ) // followed by ' : '
- {
- //Hacked message, or infamous "client desynchronize" issue where they pick one char while loading another.
- ShowWarning("clif_process_message: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name);
- sockt->eof(fd); // Just kick them out to correct it.
- return false;
- }
+ if (strncmp(srcname, sd->status.name, namelen) != 0 // the text must start with the speaker's name
+ || srcname[namelen] != ' ' || srcname[namelen+1] != ':' || srcname[namelen+2] != ' ' // followed by ' : '
+ ) {
+ //Hacked message, or infamous "client desynchronize" issue where they pick one char while loading another.
+ ShowWarning("clif_process_chat_message: Player '%s' sent a message using an incorrect name! Forcing a relog...\n", sd->status.name);
+ sockt->eof(sd->fd); // Just kick them out to correct it.
+ return NULL;
+ }
+
+ srcmessage = packet->message + namelen + 3; // <name> " : " <message>
+ messagelen = textlen - namelen - 3;
- message = name + namelen + 3;
- messagelen = textlen - namelen - 3; // this should be the message length (w/ zero byte included)
+ if (messagelen >= CHAT_SIZE_MAX || textlen >= out_buflen) {
+ // messages mustn't be too long
+ // Normally you can only enter CHATBOX_SIZE-1 letters into the chat box, but Frost Joke / Dazzler's text can be longer.
+ // Also, the physical size of strings that use multibyte encoding can go multiple times over the chatbox capacity.
+ // Neither the official client nor server place any restriction on the length of the data in the packet,
+ // but we'll only allow reasonably long strings here. This also makes sure that they fit into the `chatlog` table.
+ ShowWarning("clif_process_chat_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHATBOX_SIZE-1, srcmessage);
+ return NULL;
}
- else
- {// name has fixed width
- if( textlen < NAME_LENGTH + 1 )
- {
- ShowWarning("clif_process_message: Received malformed packet from player '%s' (packet length is incorrect)!\n", sd->status.name);
- return false;
- }
- // validate name
- name = text;
- namelen = strnlen(name, NAME_LENGTH-1); // name length (w/o zero byte)
+ safestrncpy(out_buf, packet->message, textlen+1); // [!] packet->message is not necessarily NUL terminated
+ message = out_buf + namelen + 3;
- if (name[namelen] != '\0') {
- // only restriction is that the name must be zero-terminated
- ShowWarning("clif_process_message: Player '%s' sent an unterminated name!\n", sd->status.name);
- return false;
- }
+ if (!pc->process_chat_message(sd, message))
+ return NULL;
+ return message;
+}
- message = name + NAME_LENGTH;
- messagelen = textlen - NAME_LENGTH; // this should be the message length (w/ zero byte included)
- }
+/**
+ * Validates and processes a whisper message packet.
+ *
+ * @param[in] sd The source character.
+ * @param[in] packet The packet data.
+ * @param[out] out_name The parsed target name buffer (must be a valid
+ * buffer of size NAME_LENGTH).
+ * @param[out] out_message The output message buffer (must be a valid buffer).
+ * @param[in] out_messagelen The size of out_message.
+ * @retval true if the validation succeeded and the message is a chat message.
+ * @retval false if the validation failed, the messages was a command or the
+ * character can't send chat messages. out_name and out_message
+ * shan't be used.
+ */
+bool clif_process_whisper_message(struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int out_messagelen)
+{
+ int namelen = 0, messagelen = 0;
- if (messagelen != strnlen(message, messagelen)+1) {
- // the declared length must match real length
- ShowWarning("clif_process_message: Received malformed packet from player '%s' (length is incorrect)!\n", sd->status.name);
+ nullpo_retr(false, sd);
+ nullpo_retr(false, packet);
+ nullpo_retr(false, out_name);
+ nullpo_retr(false, out_message);
+
+ if (packet->packet_len < NAME_LENGTH + 4 + 1) {
+ // 4-byte header and at least an empty string is expected
+ ShowWarning("clif_process_whisper_message: Received malformed packet from player '%s' (packet length is incorrect)!\n", sd->status.name);
return false;
}
- // verify <message> part of the packet
- if (message[messagelen-1] != '\0') {
- // message must be zero-terminated
- ShowWarning("clif_process_message: Player '%s' sent an unterminated message string!\n", sd->status.name);
+
+ // validate name
+ namelen = (int)strnlen(packet->name, NAME_LENGTH-1); // name length (w/o zero byte)
+
+ if (packet->name[namelen] != '\0') {
+ // only restriction is that the name must be zero-terminated
+ ShowWarning("clif_process_whisper_message: Player '%s' sent an unterminated name!\n", sd->status.name);
return false;
}
- if (messagelen > CHAT_SIZE_MAX-1) {
+
+#if PACKETVER >= 20151001
+ // Packet doesn't include a NUL terminator
+ messagelen = packet->packet_len - NAME_LENGTH - 4;
+#else // PACKETVER < 20151001
+ // Packet includes a NUL terminator
+ messagelen = packet->packet_len - NAME_LENGTH - 4 - 1;
+#endif // PACKETVER > 20151001
+
+ if (messagelen >= CHAT_SIZE_MAX || messagelen >= out_messagelen) {
// messages mustn't be too long
// Normally you can only enter CHATBOX_SIZE-1 letters into the chat box, but Frost Joke / Dazzler's text can be longer.
// Also, the physical size of strings that use multibyte encoding can go multiple times over the chatbox capacity.
// Neither the official client nor server place any restriction on the length of the data in the packet,
// but we'll only allow reasonably long strings here. This also makes sure that they fit into the `chatlog` table.
- ShowWarning("clif_process_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX-1, message);
+ ShowWarning("clif_process_whisper_message: Player '%s' sent a message too long ('%.*s')!\n", sd->status.name, CHAT_SIZE_MAX-1, packet->message);
return false;
}
- *name_ = name;
- *namelen_ = namelen;
- *message_ = message;
- *messagelen_ = messagelen;
+ safestrncpy(out_name, packet->name, namelen+1); // [!] packet->name is not NUL terminated
+ safestrncpy(out_message, packet->message, messagelen+1); // [!] packet->message is not necessarily NUL terminated
+
+ if (!pc->process_chat_message(sd, out_message))
+ return false;
+
return true;
}
@@ -9712,144 +9744,110 @@ int clif_undisguise_timer(int tid, int64 tick, int id, intptr_t data) {
return 0;
}
-void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
-/// Validates and processes global messages
-/// 008c <packet len>.W <text>.?B (<name> : <message>) 00 (CZ_REQUEST_CHAT)
-/// There are various variants of this packet.
-void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
+/**
+ * Validates and processed global messages.
+ *
+ * There are various variants of this packet.
+ *
+ * @code
+ * 008c <packet len>.W <text>.?B (<name> : <message>) 00 (CZ_REQUEST_CHAT)
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ */
+void clif_parse_GlobalMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+void clif_parse_GlobalMessage(int fd, struct map_session_data *sd)
{
- const char *text = RFIFOP(fd,4);
- size_t textlen = RFIFOW(fd,2) - 4;
+ const struct packet_chat_message *packet = NULL;
+ char full_message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1];
+ const char *message = NULL;
+ bool is_fakename = false;
+ int outlen = 0;
- const char *name = NULL, *message = NULL;
- char *fakename = NULL;
- size_t namelen, messagelen;
-
- bool is_fake;
+ nullpo_retv(sd);
- // validate packet and retrieve name and message
- if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) )
+ packet = RP2PTR(fd);
+ message = clif->process_chat_message(sd, packet, full_message, sizeof full_message);
+ if (message == NULL)
return;
- if( atcommand->exec(fd, sd, message, true) )
- return;
+ pc->check_supernovice_call(sd, message);
- if( !pc->can_talk(sd) )
+ if (sd->gcbind != NULL) {
+ channel->send(sd->gcbind, sd, message);
return;
-
- if( battle_config.min_chat_delay ) { //[Skotlex]
- if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0)
- return;
- sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
}
- if( (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE ) {
- unsigned int next = pc->nextbaseexp(sd);
- if( next == 0 ) next = pc->thisbaseexp(sd);
- if( next ) { // 0%, 10%, 20%, ...
- int percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. );
- if( (battle_config.snovice_call_type || percent) && ( percent%100 ) == 0 ) {// 10.0%, 20.0%, ..., 90.0%
- switch (sd->state.snovice_call_flag) {
- case 0:
- if( strstr(message, msg_txt(1479)) ) // "Dear angel, can you hear my voice?"
- sd->state.snovice_call_flag = 1;
- break;
- case 1: {
- char buf[256];
- snprintf(buf, 256, msg_txt(1480), sd->status.name);
- if( strstr(message, buf) ) // "I am %s Super Novice~"
- sd->state.snovice_call_flag = 2;
- }
- break;
- case 2:
- if( strstr(message, msg_txt(1481)) ) // "Help me out~ Please~ T_T"
- sd->state.snovice_call_flag = 3;
- break;
- case 3:
- sc_start(NULL,&sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex]
- clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions
- sd->state.snovice_call_flag = 0;
- break;
- }
- }
- }
+ if (sd->fakename[0] != '\0') {
+ is_fakename = true;
+ outlen = (int)strlen(sd->fakename) + (int)strlen(message) + 3 + 1;
+ } else {
+ outlen = (int)strlen(full_message) + 1;
}
- pc->update_idle_time(sd, BCIDLE_CHAT);
-
- if( sd->gcbind ) {
- channel->send(sd->gcbind,sd,message);
- return;
- } else if ( sd->fontcolor && !sd->chatID ) {
- char mout[200];
- unsigned char mylen = 1;
+ if (sd->fontcolor != 0 && sd->chatID == 0) {
uint32 color = 0;
- if( sd->disguise == -1 ) {
+ if (sd->disguise == -1) {
sd->fontcolor_tid = timer->add(timer->gettick()+5000, clif->undisguise_timer, sd->bl.id, 0);
pc->disguise(sd,sd->status.class_);
- if( pc_isdead(sd) )
+ if (pc_isdead(sd))
clif->clearunit_single(-sd->bl.id, CLR_DEAD, sd->fd);
- if( unit->is_walking(&sd->bl) )
+ if (unit->is_walking(&sd->bl))
clif->move(&sd->ud);
- } else if ( sd->disguise == sd->status.class_ && sd->fontcolor_tid != INVALID_TIMER ) {
+ } else if (sd->disguise == sd->status.class_ && sd->fontcolor_tid != INVALID_TIMER) {
const struct TimerData *td;
- if( (td = timer->get(sd->fontcolor_tid)) ) {
+ if ((td = timer->get(sd->fontcolor_tid)) != NULL)
timer->settick(sd->fontcolor_tid, td->tick+5000);
- }
}
- mylen += snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message);
-
color = channel->config->colors[sd->fontcolor - 1];
- WFIFOHEAD(fd,mylen + 12);
+ WFIFOHEAD(fd, outlen + 12);
WFIFOW(fd,0) = 0x2C1;
- WFIFOW(fd,2) = mylen + 12;
+ WFIFOW(fd,2) = outlen + 12;
WFIFOL(fd,4) = sd->bl.id;
WFIFOL(fd,8) = RGB2BGR(color);
- safestrncpy(WFIFOP(fd,12), mout, mylen);
+ if (is_fakename)
+ safesnprintf(WFIFOP(fd, 12), outlen, "%s : %s", sd->fakename, message);
+ else
+ safestrncpy(WFIFOP(fd, 12), full_message, outlen);
clif->send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, AREA_WOS);
WFIFOL(fd,4) = -sd->bl.id;
- WFIFOSET(fd, mylen + 12);
+ WFIFOSET(fd, outlen + 12);
return;
}
- /**
- * Fake Name Design by FatalEror (bug report #9)
- **/
- if( ( is_fake = ( sd->fakename[0] ) ) ) {
- fakename = (char*) aMalloc(strlen(sd->fakename)+messagelen+3);
- strcpy(fakename, sd->fakename);
- strcat(fakename, " : ");
- strcat(fakename, message);
- textlen = strlen(fakename) + 1;
+ {
+ // send message to others
+ void *buf = aMalloc(8 + outlen);
+ WBUFW(buf, 0) = 0x8d;
+ WBUFW(buf, 2) = 8 + outlen;
+ WBUFL(buf, 4) = sd->bl.id;
+ if (is_fakename)
+ safesnprintf(WBUFP(buf, 8), outlen, "%s : %s", sd->fakename, message);
+ else
+ safestrncpy(WBUFP(buf, 8), full_message, outlen);
+ //FIXME: chat has range of 9 only
+ clif->send(buf, WBUFW(buf, 2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);
+ aFree(buf);
}
- // send message to others (using the send buffer for temp. storage)
- WFIFOHEAD(fd, 8 + textlen);
- WFIFOW(fd,0) = 0x8d;
- WFIFOW(fd,2) = 8 + textlen;
- WFIFOL(fd,4) = sd->bl.id;
- safestrncpy(WFIFOP(fd,8), is_fake ? fakename : text, textlen);
- //FIXME: chat has range of 9 only
- clif->send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);
// send back message to the speaker
- if( is_fake ) {
- WFIFOW(fd,0) = 0x8e;
- WFIFOW(fd,2) = textlen + 4;
- safestrncpy(WFIFOP(fd,4), fakename, textlen);
- aFree(fakename);
- } else {
- memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2));
- WFIFOW(fd,0) = 0x8e;
- }
+ WFIFOHEAD(fd, 4 + outlen);
+ WFIFOW(fd, 0) = 0x8e;
+ WFIFOW(fd, 2) = 4 + outlen;
+ if (is_fakename)
+ safesnprintf(WFIFOP(fd, 4), outlen, "%s : %s", sd->fakename, message);
+ else
+ safestrncpy(WFIFOP(fd, 4), full_message, outlen);
WFIFOSET(fd, WFIFOW(fd,2));
// Chat logging type 'O' / Global Chat
logs->chat(LOG_CHAT_GLOBAL, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, message);
// trigger listening npcs
- map->foreachinrange(npc_chat->sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl);
+ map->foreachinrange(npc_chat->sub, &sd->bl, AREA_SIZE, BL_NPC, full_message, strlen(full_message), &sd->bl);
}
void clif_parse_MapMove(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -10122,37 +10120,28 @@ void clif_parse_Restart(int fd, struct map_session_data *sd) {
}
}
-void clif_parse_WisMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
-/// Validates and processes whispered messages (CZ_WHISPER).
-/// 0096 <packet len>.W <nick>.24B <message>.?B
+/**
+ * Validates and processes whispered messages (CZ_WHISPER).
+ *
+ * @code
+ * 0096 <packet len>.W <nick>.24B <message>.?B
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ */
+void clif_parse_WisMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
void clif_parse_WisMessage(int fd, struct map_session_data* sd)
{
struct map_session_data* dstsd;
int i;
- const char *target, *message;
- size_t namelen, messagelen;
-
- // validate packet and retrieve name and message
- if( !clif->process_message(sd, 1, &target, &namelen, &message, &messagelen) )
- return;
-
- if ( atcommand->exec(fd, sd, message, true) )
- return;
+ char target[NAME_LENGTH], message[CHAT_SIZE_MAX + 1];
+ const struct packet_whisper_message *packet = RP2PTR(fd);
- // Statuses that prevent the player from whispering
- if( !pc->can_talk(sd) )
+ if (!clif->process_whisper_message(sd, packet, target, message, sizeof message))
return;
- if (battle_config.min_chat_delay) { //[Skotlex]
- if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) {
- return;
- }
- sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
- }
-
- pc->update_idle_time(sd, BCIDLE_CHAT);
-
// Chat logging type 'W' / Whisper
logs->chat(LOG_CHAT_WHISPER, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, target, message);
@@ -10222,7 +10211,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
// if there are 'Test' player on an other map-server and 'test' player on this map-server,
// and if we ask for 'Test', we must not contact 'test' player
// so, we send information to inter-server, which is the only one which decide (and copy correct name).
- intif->wis_message(sd, target, message, messagelen);
+ intif->wis_message(sd, target, message, strlen(message));
return;
}
@@ -10256,7 +10245,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
clif->wis_end(fd, 0); // 0: success to send wisper
// Normal message
- clif->wis_message(dstsd->fd, sd->status.name, message, messagelen);
+ clif->wis_message(dstsd->fd, sd->status.name, message, strlen(message));
}
void clif_parse_Broadcast(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -11952,36 +11941,26 @@ void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd)
#endif
}
-void clif_parse_PartyMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
-/// Validates and processes party messages (CZ_REQUEST_CHAT_PARTY).
-/// 0108 <packet len>.W <text>.?B (<name> : <message>) 00
-void clif_parse_PartyMessage(int fd, struct map_session_data* sd)
+/**
+ * Validates and processes party messages (CZ_REQUEST_CHAT_PARTY).
+ *
+ * @code
+ * 0108 <packet len>.W <text>.?B (<name> : <message>) 00
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ */
+void clif_parse_PartyMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+void clif_parse_PartyMessage(int fd, struct map_session_data *sd)
{
- const char *text = RFIFOP(fd,4);
- int textlen = RFIFOW(fd,2) - 4;
-
- const char *name, *message;
- size_t namelen, messagelen;
-
- // validate packet and retrieve name and message
- if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) )
- return;
+ const struct packet_chat_message *packet = RP2PTR(fd);
+ char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1];
- if( atcommand->exec(fd, sd, message, true) )
+ if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL)
return;
- if( !pc->can_talk(sd) )
- return;
-
- if (battle_config.min_chat_delay) {
- if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0)
- return;
- sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
- }
-
- pc->update_idle_time(sd, BCIDLE_CHAT);
-
- party->send_message(sd, text, textlen);
+ party->send_message(sd, message, (int)strlen(message));
}
void clif_parse_PartyChangeLeader(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
@@ -13060,39 +13039,29 @@ void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd) {
guild->expulsion(sd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOP(fd,14));
}
-void clif_parse_GuildMessage(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
-/// Validates and processes guild messages (CZ_GUILD_CHAT).
-/// 017e <packet len>.W <text>.?B (<name> : <message>) 00
-void clif_parse_GuildMessage(int fd, struct map_session_data* sd)
+/**
+ * Validates and processes guild messages (CZ_GUILD_CHAT).
+ *
+ * @code
+ * 017e <packet len>.W <text>.?B (<name> : <message>) 00
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ */
+void clif_parse_GuildMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+void clif_parse_GuildMessage(int fd, struct map_session_data *sd)
{
- const char *text = RFIFOP(fd,4);
- int textlen = RFIFOW(fd,2) - 4;
-
- const char *name, *message;
- size_t namelen, messagelen;
-
- // validate packet and retrieve name and message
- if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) )
- return;
+ const struct packet_chat_message *packet = RP2PTR(fd);
+ char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1];
- if( atcommand->exec(fd, sd, message, true) )
+ if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL)
return;
- if( !pc->can_talk(sd) )
- return;
-
- if (battle_config.min_chat_delay) {
- if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0)
- return;
- sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
- }
-
- pc->update_idle_time(sd, BCIDLE_CHAT);
-
- if( sd->bg_id )
- bg->send_message(sd, text, textlen);
+ if (sd->bg_id)
+ bg->send_message(sd, message, (int)strlen(message));
else
- guild->send_message(sd, text, textlen);
+ guild->send_message(sd, message, (int)strlen(message));
}
void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -16174,35 +16143,26 @@ void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name
aFree(buf);
}
-void clif_parse_BattleChat(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
-/// Validates and processes battlechat messages [pakpil] (CZ_BATTLEFIELD_CHAT).
-/// 0x2db <packet len>.W <text>.?B (<name> : <message>) 00
-void clif_parse_BattleChat(int fd, struct map_session_data* sd)
+/**
+ * Validates and processes battlechat messages [pakpil] (CZ_BATTLEFIELD_CHAT).
+ *
+ * @code
+ * 0x2db <packet len>.W <text>.?B (<name> : <message>) 00
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ */
+void clif_parse_BattleChat(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+void clif_parse_BattleChat(int fd, struct map_session_data *sd)
{
- const char *text = RFIFOP(fd,4);
- int textlen = RFIFOW(fd,2) - 4;
-
- const char *name, *message;
- size_t namelen, messagelen;
+ const struct packet_chat_message *packet = RP2PTR(fd);
+ char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1];
- if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) )
+ if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL)
return;
- if( atcommand->exec(fd, sd, message, true) )
- return;
-
- if( !pc->can_talk(sd) )
- return;
-
- if( battle_config.min_chat_delay ) {
- if( DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0 )
- return;
- sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
- }
-
- pc->update_idle_time(sd, BCIDLE_CHAT);
-
- bg->send_message(sd, text, textlen);
+ bg->send_message(sd, message, (int)strlen(message));
}
/// Notifies client of a battleground score change (ZC_BATTLEFIELD_NOTIFY_POINT).
@@ -19365,7 +19325,8 @@ void clif_defaults(void) {
clif->message = clif_displaymessage;
clif->messageln = clif_displaymessage2;
clif->messages = clif_displaymessage_sprintf;
- clif->process_message = clif_process_message;
+ clif->process_chat_message = clif_process_chat_message;
+ clif->process_whisper_message = clif_process_whisper_message;
clif->wisexin = clif_wisexin;
clif->wisall = clif_wisall;
clif->PMIgnoreList = clif_PMIgnoreList;
diff --git a/src/map/clif.h b/src/map/clif.h
index f930e4ca1..6d6c368f2 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -856,7 +856,8 @@ struct clif_interface {
void (*messageln) (const int fd, const char* mes);
/* message+s(printf) */
void (*messages) (const int fd, const char *mes, ...) __attribute__((format(printf, 2, 3)));
- bool (*process_message) (struct map_session_data *sd, int format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_);
+ const char *(*process_chat_message) (struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int out_buflen);
+ bool (*process_whisper_message) (struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int out_messagelen);
void (*wisexin) (struct map_session_data *sd,int type,int flag);
void (*wisall) (struct map_session_data *sd,int type,int flag);
void (*PMIgnoreList) (struct map_session_data* sd);
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index 25b20cddf..888d893b6 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -1215,6 +1215,19 @@ struct packet_quest_list_header {
//struct packet_quest_list_info list[]; // Variable-length
} __attribute__((packed));
+struct packet_chat_message {
+ uint16 packet_id;
+ int16 packet_len;
+ char message[];
+} __attribute__((packed));
+
+struct packet_whisper_message {
+ uint16 packet_id;
+ int16 packet_len;
+ char name[NAME_LENGTH];
+ char message[];
+} __attribute__((packed));
+
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#pragma pack(pop)
#endif // not NetBSD < 6 / Solaris
diff --git a/src/map/pc.c b/src/map/pc.c
index 57b2fe19a..8fe9ddd6e 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -11516,6 +11516,87 @@ int pc_have_magnifier(struct map_session_data *sd)
return n;
}
+/**
+ * Verifies a chat message, searching for atcommands, checking if the sender
+ * character can chat, and updating the idle timer.
+ *
+ * @param sd The sender character.
+ * @param message The message text.
+ * @return Whether the message is a valid chat message.
+ */
+bool pc_process_chat_message(struct map_session_data *sd, const char *message)
+{
+ if (atcommand->exec(sd->fd, sd, message, true)) {
+ return false;
+ }
+
+ if (!pc->can_talk(sd)) {
+ return false;
+ }
+
+ if (battle_config.min_chat_delay != 0) {
+ if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) {
+ return false;
+ }
+ sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay;
+ }
+
+ pc->update_idle_time(sd, BCIDLE_CHAT);
+
+ return true;
+}
+
+/**
+ * Checks a chat message, scanning for the Super Novice prayer sequence.
+ *
+ * If a match is found, the angel is invoked or the counter is incremented as
+ * appropriate.
+ *
+ * @param sd The sender character.
+ * @param message The message text.
+ */
+void pc_check_supernovice_call(struct map_session_data *sd, const char *message)
+{
+ unsigned int next = pc->nextbaseexp(sd);
+ int percent = 0;
+
+ if ((sd->class_&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE)
+ return;
+ if (next == 0)
+ next = pc->thisbaseexp(sd);
+ if (next == 0)
+ return;
+
+ // 0%, 10%, 20%, ...
+ percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. );
+ if ((battle_config.snovice_call_type != 0 || percent != 0) && (percent%100) == 0) {
+ // 10.0%, 20.0%, ..., 90.0%
+ switch (sd->state.snovice_call_flag) {
+ case 0:
+ if (strstr(message, msg_txt(1479))) // "Dear angel, can you hear my voice?"
+ sd->state.snovice_call_flag = 1;
+ break;
+ case 1:
+ {
+ char buf[256];
+ snprintf(buf, 256, msg_txt(1480), sd->status.name);
+ if (strstr(message, buf)) // "I am %s Super Novice~"
+ sd->state.snovice_call_flag = 2;
+ }
+ break;
+ case 2:
+ if (strstr(message, msg_txt(1481))) // "Help me out~ Please~ T_T"
+ sd->state.snovice_call_flag = 3;
+ break;
+ case 3:
+ sc_start(NULL, &sd->bl, status->skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex]
+ clif->skill_nodamage(&sd->bl, &sd->bl, MO_EXPLOSIONSPIRITS, 5, 1); // prayer always shows successful Lv5 cast and disregards noskill restrictions
+ sd->state.snovice_call_flag = 0;
+ break;
+ }
+ }
+}
+
void do_final_pc(void) {
db_destroy(pc->itemcd_db);
pc->at_db->destroy(pc->at_db,pc->autotrade_final);
@@ -11871,6 +11952,9 @@ void pc_defaults(void) {
pc->db_checkid = pc_db_checkid;
pc->validate_levels = pc_validate_levels;
+ pc->check_supernovice_call = pc_check_supernovice_call;
+ pc->process_chat_message = pc_process_chat_message;
+
/**
* Autotrade persistency [Ind/Hercules <3]
**/
diff --git a/src/map/pc.h b/src/map/pc.h
index b648b7113..5d35fd1cc 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -1089,8 +1089,11 @@ END_ZEROED_BLOCK; /* End */
int (*check_job_name) (const char *name);
void (*update_idle_time) (struct map_session_data* sd, enum e_battle_config_idletime type);
-
+
int (*have_magnifier) (struct map_session_data *sd);
+
+ bool (*process_chat_message) (struct map_session_data *sd, const char *message);
+ void (*check_supernovice_call) (struct map_session_data *sd, const char *message);
};
#ifdef HERCULES_CORE
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index a11e964c2..a1efd6f16 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -984,8 +984,10 @@ struct {
struct HPMHookPoint *HP_clif_message_post;
struct HPMHookPoint *HP_clif_messageln_pre;
struct HPMHookPoint *HP_clif_messageln_post;
- struct HPMHookPoint *HP_clif_process_message_pre;
- struct HPMHookPoint *HP_clif_process_message_post;
+ struct HPMHookPoint *HP_clif_process_chat_message_pre;
+ struct HPMHookPoint *HP_clif_process_chat_message_post;
+ struct HPMHookPoint *HP_clif_process_whisper_message_pre;
+ struct HPMHookPoint *HP_clif_process_whisper_message_post;
struct HPMHookPoint *HP_clif_wisexin_pre;
struct HPMHookPoint *HP_clif_wisexin_post;
struct HPMHookPoint *HP_clif_wisall_pre;
@@ -4338,6 +4340,10 @@ struct {
struct HPMHookPoint *HP_pc_db_checkid_post;
struct HPMHookPoint *HP_pc_validate_levels_pre;
struct HPMHookPoint *HP_pc_validate_levels_post;
+ struct HPMHookPoint *HP_pc_process_chat_message_pre;
+ struct HPMHookPoint *HP_pc_process_chat_message_post;
+ struct HPMHookPoint *HP_pc_check_supernovice_call_pre;
+ struct HPMHookPoint *HP_pc_check_supernovice_call_post;
struct HPMHookPoint *HP_pc_autotrade_load_pre;
struct HPMHookPoint *HP_pc_autotrade_load_post;
struct HPMHookPoint *HP_pc_autotrade_update_pre;
@@ -6867,8 +6873,10 @@ struct {
int HP_clif_message_post;
int HP_clif_messageln_pre;
int HP_clif_messageln_post;
- int HP_clif_process_message_pre;
- int HP_clif_process_message_post;
+ int HP_clif_process_chat_message_pre;
+ int HP_clif_process_chat_message_post;
+ int HP_clif_process_whisper_message_pre;
+ int HP_clif_process_whisper_message_post;
int HP_clif_wisexin_pre;
int HP_clif_wisexin_post;
int HP_clif_wisall_pre;
@@ -10221,6 +10229,10 @@ struct {
int HP_pc_db_checkid_post;
int HP_pc_validate_levels_pre;
int HP_pc_validate_levels_post;
+ int HP_pc_process_chat_message_pre;
+ int HP_pc_process_chat_message_post;
+ int HP_pc_check_supernovice_call_pre;
+ int HP_pc_check_supernovice_call_post;
int HP_pc_autotrade_load_pre;
int HP_pc_autotrade_load_post;
int HP_pc_autotrade_update_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index 8d9752849..2b29d14bb 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -512,7 +512,8 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(clif->msgtable_skill, HP_clif_msgtable_skill) },
{ HP_POP(clif->message, HP_clif_message) },
{ HP_POP(clif->messageln, HP_clif_messageln) },
- { HP_POP(clif->process_message, HP_clif_process_message) },
+ { HP_POP(clif->process_chat_message, HP_clif_process_chat_message) },
+ { HP_POP(clif->process_whisper_message, HP_clif_process_whisper_message) },
{ HP_POP(clif->wisexin, HP_clif_wisexin) },
{ HP_POP(clif->wisall, HP_clif_wisall) },
{ HP_POP(clif->PMIgnoreList, HP_clif_PMIgnoreList) },
@@ -2219,6 +2220,8 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(pc->expire_check, HP_pc_expire_check) },
{ HP_POP(pc->db_checkid, HP_pc_db_checkid) },
{ HP_POP(pc->validate_levels, HP_pc_validate_levels) },
+ { HP_POP(pc->process_chat_message, HP_pc_process_chat_message) },
+ { HP_POP(pc->check_supernovice_call, HP_pc_check_supernovice_call) },
{ HP_POP(pc->autotrade_load, HP_pc_autotrade_load) },
{ HP_POP(pc->autotrade_update, HP_pc_autotrade_update) },
{ HP_POP(pc->autotrade_start, HP_pc_autotrade_start) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index fa7b192c6..d867c9ed0 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -12820,15 +12820,42 @@ void HP_clif_messageln(const int fd, const char *mes) {
}
return;
}
-bool HP_clif_process_message(struct map_session_data *sd, int format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_) {
+const char* HP_clif_process_chat_message(struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int out_buflen) {
+ int hIndex = 0;
+ const char* retVal___ = NULL;
+ if( HPMHooks.count.HP_clif_process_chat_message_pre ) {
+ const char* (*preHookFunc) (struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int *out_buflen);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_process_chat_message_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_clif_process_chat_message_pre[hIndex].func;
+ retVal___ = preHookFunc(sd, packet, out_buf, &out_buflen);
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.clif.process_chat_message(sd, packet, out_buf, out_buflen);
+ }
+ if( HPMHooks.count.HP_clif_process_chat_message_post ) {
+ const char* (*postHookFunc) (const char* retVal___, struct map_session_data *sd, const struct packet_chat_message *packet, char *out_buf, int *out_buflen);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_process_chat_message_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_clif_process_chat_message_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, packet, out_buf, &out_buflen);
+ }
+ }
+ return retVal___;
+}
+bool HP_clif_process_whisper_message(struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int out_messagelen) {
int hIndex = 0;
bool retVal___ = false;
- if( HPMHooks.count.HP_clif_process_message_pre ) {
- bool (*preHookFunc) (struct map_session_data *sd, int *format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_);
+ if( HPMHooks.count.HP_clif_process_whisper_message_pre ) {
+ bool (*preHookFunc) (struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int *out_messagelen);
*HPMforce_return = false;
- for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_process_message_pre; hIndex++ ) {
- preHookFunc = HPMHooks.list.HP_clif_process_message_pre[hIndex].func;
- retVal___ = preHookFunc(sd, &format, name_, namelen_, message_, messagelen_);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_process_whisper_message_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_clif_process_whisper_message_pre[hIndex].func;
+ retVal___ = preHookFunc(sd, packet, out_name, out_message, &out_messagelen);
}
if( *HPMforce_return ) {
*HPMforce_return = false;
@@ -12836,13 +12863,13 @@ bool HP_clif_process_message(struct map_session_data *sd, int format, const char
}
}
{
- retVal___ = HPMHooks.source.clif.process_message(sd, format, name_, namelen_, message_, messagelen_);
+ retVal___ = HPMHooks.source.clif.process_whisper_message(sd, packet, out_name, out_message, out_messagelen);
}
- if( HPMHooks.count.HP_clif_process_message_post ) {
- bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int *format, const char **name_, size_t *namelen_, const char **message_, size_t *messagelen_);
- for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_process_message_post; hIndex++ ) {
- postHookFunc = HPMHooks.list.HP_clif_process_message_post[hIndex].func;
- retVal___ = postHookFunc(retVal___, sd, &format, name_, namelen_, message_, messagelen_);
+ if( HPMHooks.count.HP_clif_process_whisper_message_post ) {
+ bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, const struct packet_whisper_message *packet, char *out_name, char *out_message, int *out_messagelen);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_process_whisper_message_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_clif_process_whisper_message_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, packet, out_name, out_message, &out_messagelen);
}
}
return retVal___;
@@ -57836,6 +57863,59 @@ void HP_pc_validate_levels(void) {
}
return;
}
+bool HP_pc_process_chat_message(struct map_session_data *sd, const char *message) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if( HPMHooks.count.HP_pc_process_chat_message_pre ) {
+ bool (*preHookFunc) (struct map_session_data *sd, const char *message);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_process_chat_message_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_pc_process_chat_message_pre[hIndex].func;
+ retVal___ = preHookFunc(sd, message);
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.pc.process_chat_message(sd, message);
+ }
+ if( HPMHooks.count.HP_pc_process_chat_message_post ) {
+ bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, const char *message);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_process_chat_message_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_pc_process_chat_message_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, sd, message);
+ }
+ }
+ return retVal___;
+}
+void HP_pc_check_supernovice_call(struct map_session_data *sd, const char *message) {
+ int hIndex = 0;
+ if( HPMHooks.count.HP_pc_check_supernovice_call_pre ) {
+ void (*preHookFunc) (struct map_session_data *sd, const char *message);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_check_supernovice_call_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_pc_check_supernovice_call_pre[hIndex].func;
+ preHookFunc(sd, message);
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.pc.check_supernovice_call(sd, message);
+ }
+ if( HPMHooks.count.HP_pc_check_supernovice_call_post ) {
+ void (*postHookFunc) (struct map_session_data *sd, const char *message);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_pc_check_supernovice_call_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_pc_check_supernovice_call_post[hIndex].func;
+ postHookFunc(sd, message);
+ }
+ }
+ return;
+}
void HP_pc_autotrade_load(void) {
int hIndex = 0;
if( HPMHooks.count.HP_pc_autotrade_load_pre ) {