From 235a8d18f8cbbb5aaf7563566ff68f15fc1054c1 Mon Sep 17 00:00:00 2001
From: Haru <haru@dotalux.com>
Date: Thu, 21 Apr 2016 21:20:29 +0200
Subject: Split supernovice angel call message detection to its own function

Signed-off-by: Haru <haru@dotalux.com>
---
 src/map/clif.c | 32 +-------------------------------
 src/map/pc.c   | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/map/pc.h   |  4 +++-
 3 files changed, 57 insertions(+), 32 deletions(-)

diff --git a/src/map/clif.c b/src/map/clif.c
index e1b4be8f4..64e652252 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -9743,37 +9743,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 		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;
-				}
-			}
-		}
-	}
+	pc->check_supernovice_call(sd, message);
 
 	pc->update_idle_time(sd, BCIDLE_CHAT);
 
diff --git a/src/map/pc.c b/src/map/pc.c
index 57b2fe19a..2edb09d85 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -11516,6 +11516,57 @@ int pc_have_magnifier(struct map_session_data *sd)
 	return n;
 }
 
+/**
+ * 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 +11922,8 @@ void pc_defaults(void) {
 	pc->db_checkid = pc_db_checkid;
 	pc->validate_levels = pc_validate_levels;
 
+	pc->check_supernovice_call = pc_check_supernovice_call;
+
 	/**
 	 * Autotrade persistency [Ind/Hercules <3]
 	 **/
diff --git a/src/map/pc.h b/src/map/pc.h
index b648b7113..05cb16a60 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -1089,8 +1089,10 @@ 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);
+
+	void (*check_supernovice_call) (struct map_session_data *sd, const char *message);
 };
 
 #ifdef HERCULES_CORE
-- 
cgit v1.2.3-70-g09d2


From ccfd0549ce64e84e41069ec8e040ce9806b963f2 Mon Sep 17 00:00:00 2001
From: Haru <haru@dotalux.com>
Date: Mon, 28 Mar 2016 13:11:40 +0200
Subject: Refactored the chat message packet processing functions

- Split the processing of public chat messages and whisper messages in
  two functions, to make them more straightforward.

Signed-off-by: Haru <haru@dotalux.com>
---
 src/map/clif.c           | 418 +++++++++++++++++++++++++++--------------------
 src/map/clif.h           |   3 +-
 src/map/packets_struct.h |  13 ++
 3 files changed, 253 insertions(+), 181 deletions(-)

diff --git a/src/map/clif.c b/src/map/clif.c
index 64e652252..abb08d498 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -8867,105 +8867,132 @@ 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;
-		}
+	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
+
 	return true;
 }
 
@@ -9712,23 +9739,32 @@ 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 char *name = NULL, *message = NULL;
-	char *fakename = NULL;
-	size_t namelen, messagelen;
+	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;
 
-	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)  )
@@ -9747,79 +9783,80 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
 
 	pc->update_idle_time(sd, BCIDLE_CHAT);
 
-	if( sd->gcbind ) {
-		channel->send(sd->gcbind,sd,message);
+	if (sd->gcbind != NULL) {
+		channel->send(sd->gcbind, sd, message);
 		return;
-	} else if ( sd->fontcolor && !sd->chatID ) {
-		char mout[200];
-		unsigned char mylen = 1;
+	}
+
+	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;
+	}
+
+	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)));
@@ -10092,19 +10129,26 @@ 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;
+	char target[NAME_LENGTH], message[CHAT_SIZE_MAX + 1];
+	const struct packet_whisper_message *packet = RP2PTR(fd);
 
-	// validate packet and retrieve name and message
-	if( !clif->process_message(sd, 1, &target, &namelen, &message, &messagelen) )
+	if (!clif->process_whisper_message(sd, packet, target, message, sizeof message))
 		return;
 
 	if ( atcommand->exec(fd, sd, message, true) )
@@ -10192,7 +10236,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;
 	}
 
@@ -10226,7 +10270,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)));
@@ -11922,19 +11966,23 @@ 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 struct packet_chat_message *packet = RP2PTR(fd);
+	char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1];
 
-	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) )
+	if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL)
 		return;
 
 	if( atcommand->exec(fd, sd, message, true)  )
@@ -11951,7 +11999,7 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd)
 
 	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)));
@@ -13030,19 +13078,23 @@ 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 struct packet_chat_message *packet = RP2PTR(fd);
+	char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1];
 
-	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) )
+	if (clif->process_chat_message(sd, packet, message, sizeof message) == NULL)
 		return;
 
 	if( atcommand->exec(fd, sd, message, true) )
@@ -13059,10 +13111,10 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd)
 
 	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)));
@@ -16144,18 +16196,23 @@ 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) )
@@ -16172,7 +16229,7 @@ void clif_parse_BattleChat(int fd, struct map_session_data* sd)
 
 	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).
@@ -19335,7 +19392,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
-- 
cgit v1.2.3-70-g09d2


From 7aa70331b7dcfb21533c3806a694819e70f936c2 Mon Sep 17 00:00:00 2001
From: Haru <haru@dotalux.com>
Date: Thu, 21 Apr 2016 23:03:43 +0200
Subject: Removed some code duplication in chat processing functions

Moved non-clif code that handles chat delay, atcommand detection, idle
timers to pc.c

Signed-off-by: Haru <haru@dotalux.com>
---
 src/map/clif.c | 77 ++++------------------------------------------------------
 src/map/pc.c   | 31 +++++++++++++++++++++++
 src/map/pc.h   |  1 +
 3 files changed, 37 insertions(+), 72 deletions(-)

diff --git a/src/map/clif.c b/src/map/clif.c
index abb08d498..2dea386be 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -8931,6 +8931,8 @@ const char *clif_process_chat_message(struct map_session_data *sd, const struct
 	safestrncpy(out_buf, packet->message, textlen+1); // [!] packet->message is not necessarily NUL terminated
 	message = out_buf + namelen + 3;
 
+	if (!pc->process_chat_message(sd, message))
+		return NULL;
 	return message;
 }
 
@@ -8993,6 +8995,9 @@ bool clif_process_whisper_message(struct map_session_data *sd, const struct pack
 	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;
 }
 
@@ -9767,22 +9772,8 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data *sd)
 	if (message == NULL)
 		return;
 
-	if( atcommand->exec(fd, sd, message, true)  )
-		return;
-
-	if( !pc->can_talk(sd) )
-		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->check_supernovice_call(sd, message);
 
-	pc->update_idle_time(sd, BCIDLE_CHAT);
-
 	if (sd->gcbind != NULL) {
 		channel->send(sd->gcbind, sd, message);
 		return;
@@ -10151,22 +10142,6 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd)
 	if (!clif->process_whisper_message(sd, packet, target, message, sizeof message))
 		return;
 
-	if ( atcommand->exec(fd, sd, message, true) )
-		return;
-
-	// Statuses that prevent the player from whispering
-	if( !pc->can_talk(sd) )
-		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);
 
@@ -11985,20 +11960,6 @@ void clif_parse_PartyMessage(int fd, struct map_session_data *sd)
 	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);
-
 	party->send_message(sd, message, (int)strlen(message));
 }
 
@@ -13097,20 +13058,6 @@ void clif_parse_GuildMessage(int fd, struct map_session_data *sd)
 	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);
-
 	if (sd->bg_id)
 		bg->send_message(sd, message, (int)strlen(message));
 	else
@@ -16215,20 +16162,6 @@ void clif_parse_BattleChat(int fd, struct map_session_data *sd)
 	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, message, (int)strlen(message));
 }
 
diff --git a/src/map/pc.c b/src/map/pc.c
index 2edb09d85..8fe9ddd6e 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -11516,6 +11516,36 @@ 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.
  *
@@ -11923,6 +11953,7 @@ void pc_defaults(void) {
 	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 05cb16a60..5d35fd1cc 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -1092,6 +1092,7 @@ END_ZEROED_BLOCK; /* End */
 
 	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);
 };
 
-- 
cgit v1.2.3-70-g09d2


From 654a8c90afe0671323b75bb2d718912a0abf6ac7 Mon Sep 17 00:00:00 2001
From: Haru <haru@dotalux.com>
Date: Thu, 21 Apr 2016 20:54:40 +0200
Subject: HPM Hooks Update

Signed-off-by: Haru <haru@dotalux.com>
---
 src/common/HPMDataCheck.h                          |   2 +
 .../HPMHooking/HPMHooking_map.HPMHooksCore.inc     |  20 +++-
 .../HPMHooking/HPMHooking_map.HookingPoints.inc    |   5 +-
 src/plugins/HPMHooking/HPMHooking_map.Hooks.inc    | 104 ++++++++++++++++++---
 4 files changed, 114 insertions(+), 17 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/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 ) {
-- 
cgit v1.2.3-70-g09d2