Browse Source

> Implemented Channel System to replace @main. See tid:80999 for full details. (Hercules 7ec1e8f, 1e87c09)
* Adds @join and @channel commands to manipulate chat channels. (see doc/atcommands.txt)
* Speak in a #channel by sending a whisper to #channel or binding your global chat to the channel (@channel bindto <#channel_name>).
* Automatically join local map channels (#map) and guild ally channels (#ally), with mapflag 'nomapchannelautojoin' to disable the channel for a map (optional).
* Allow users to create private channels if 'allow_user_channel_creation' is true.
* Set default channels, text colors, and other settings in conf/channels.conf.
> Other changes:
* Improved overall guild processing/lookup by creating a cached guild state.
* Fixed a bug where equipping a garment would override costume garment.
* Removed clif_message and merged it with clif_disp_overhead, since both use the same packet.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17228 54d463be-8e91-2dee-dedb-b68131a5f0ec

euphyy 12 years ago
parent
commit
643861ba17

+ 1 - 0
conf/atcommand_athena.conf

@@ -56,6 +56,7 @@ aliases: {
 	guildstorage: ["gstorage"]
 	guildstorage: ["gstorage"]
 	accinfo: ["accountinfo"]
 	accinfo: ["accountinfo"]
 	itemreset: ["clearinventory"]
 	itemreset: ["clearinventory"]
+	channel: ["main"]
 }
 }
 
 
 /* Commands help file */
 /* Commands help file */

+ 44 - 0
conf/channels.conf

@@ -0,0 +1,44 @@
+/* Channel system configuration file */
+
+chsys: (
+{
+	/* Default channels (available to all players) */
+	default_channels: {
+		/* channel_name : channel_messages_color */
+	 	main: "Orange"
+		support: "Blue"
+		trade: "Red"
+		offtopic: "Cyan"
+		/* Add as many channels as you'd like. */
+	}
+
+	/* Colors available */
+	colors: {
+		Default: "0xffffff" /* Custom channels will use the first in the list unless a font is selected through @channel. */
+		Red: "0xff0000"
+		Blue: "0x83cfe9"
+		Orange: "0xe57c00"
+		Cyan: "0x00b89d"
+		Yellow: "0xffff90"
+		Green: "0x28bf00"
+		Normal: "0x00ff00"
+		/* Add as many channels as you'd like. */
+	}
+
+	/* Allow users to create their own (private) channels through @channels command? */
+	/* (must also allow players to use @channels in groups.conf) */
+	allow_user_channel_creation: true
+
+	/* "map_local_channel" is an instanced channel unique to each map. */
+	map_local_channel: true
+	map_local_channel_name: "map"
+	map_local_channel_color: "Yellow"
+	map_local_channel_autojoin: true /* Disable autojoin in specific maps through mapflag 'nomapchannelautojoin'. */
+
+	/* "ally_channel" is a channel shared by all your guild allies. */
+	ally_channel_enabled: true
+	ally_channel_name: "ally"
+	ally_channel_color: "Green"
+	ally_channel_autojoin: true
+}
+)

+ 2 - 1
conf/groups.conf

@@ -123,13 +123,13 @@ groups: (
 		refresh: true
 		refresh: true
 		noask: true
 		noask: true
 		noks: true
 		noks: true
-		main: true
 		autoloot: true
 		autoloot: true
 		alootid: true
 		alootid: true
 		autotrade: true
 		autotrade: true
 		request: true
 		request: true
 		go: true
 		go: true
 		breakguild: true
 		breakguild: true
+		channel: true
 	}
 	}
 	permissions: {
 	permissions: {
 	}
 	}
@@ -272,6 +272,7 @@ groups: (
 		use_check: true
 		use_check: true
 		use_changemaptype: true
 		use_changemaptype: true
 		all_commands: true
 		all_commands: true
+		channel_admin: true
 	}
 	}
 }
 }
 )
 )

+ 0 - 1
conf/help.txt

@@ -6,7 +6,6 @@
 // This file uses libconfig syntax.
 // This file uses libconfig syntax.
 
 
 help: "Params: <command>\n" "Shows help for specified command."
 help: "Params: <command>\n" "Shows help for specified command."
-main: "Params: [on|off|<message>]\n" "Turns on or off main (server-wide) chat. Sends message to main chat."
 noask: "Auto rejects deals/invites."
 noask: "Auto rejects deals/invites."
 gmotd: "Broadcasts the Message of The Day to all players."
 gmotd: "Broadcasts the Message of The Day to all players."
 me: "Params: <message>\n" "Displays normal text as a message in this format: *name message* (like /me in mIRC)."
 me: "Params: <message>\n" "Displays normal text as a message in this format: *name message* (like /me in mIRC)."

+ 0 - 3
conf/inter_athena.conf

@@ -116,7 +116,4 @@ mapreg_db: mapreg
 // Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no)
 // Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no)
 use_sql_db: no
 use_sql_db: no
 
 
-// Nick for sending main chat messages, similar to a whisper.
-main_chat_nick: Main
-
 import: conf/import/inter_conf.txt
 import: conf/import/inter_conf.txt

+ 41 - 0
conf/msg_conf/map_msg.conf

@@ -1410,5 +1410,46 @@
 // @skillid (extension)
 // @skillid (extension)
 1398: -- Displaying first %d partial matches:
 1398: -- Displaying first %d partial matches:
 
 
+// @join
+1399: Unknown Channel (usage: %s <#channel_name>)
+1400: Unknown Channel '%s' (usage: %s <#channel_name>)
+1401: '%s' Channel is password protected (usage: %s <#channel_name> <password>)
+1402: You're not in that channel, type '@join <#channel_name>'
+1403: You're now in the '%s' channel.
+
+// @channel
+1404: %s failed.
+1405: Channel name must start with '#'.
+1406: Channel length must be between 3 and %d.
+1407: Channel '%s' is not available.
+1408: Channel password may not contain spaces.
+1409: - #%s (%d users)
+1410: ---- Public Channels ----
+1411: Unknown color '%s'.
+1412: You're not the owner of channel '%s'.
+1413: '%s' channel color updated to '%s'.
+1414: ---- Available options:
+1415: * %s create <#channel_name> <channel_password>
+1416: -- Creates a new channel.
+1417: * %s list
+1418: -- Lists all public channels.
+1419: * %s list colors
+1420: -- Lists all available colors for custom channels.
+1421: * %s setcolor <#channel_name> <color_name>
+1422: -- Changes channel text to the specified color (channel owners only).
+1423: * %s leave <#channel_name>
+1424: -- Leaves the specified channel.
+1425: You're not part of the '%s' channel.
+1426: You've left the '%s' channel.
+1427: * %s bindto <#channel_name>
+1428: -- Binds your global chat to the specified channel, sending all global messages to that channel.
+1429: * %s unbind
+1430: -- Unbinds your global chat from the attached channel, if any.
+1431: Your global chat is now binded to the '%s' channel.
+1432: Your global chat is not binded to any channel.
+1433: Your global chat is now unbinded from the '#%s' channel.
+1434: You're already in the '%s' channel.
+1435: You're now in the '#%s' channel for '%s'.
+
 //Custom translations
 //Custom translations
 import: conf/import/msg_conf.txt
 import: conf/import/msg_conf.txt

+ 51 - 8
doc/atcommands.txt

@@ -24,6 +24,7 @@ The format of this file is as follows:
 	7. Guild Commands
 	7. Guild Commands
 	8. Pet Commands
 	8. Pet Commands
 	9. Homunculus Commands
 	9. Homunculus Commands
+	10. Channel Commands
 
 
 ======================
 ======================
 | 1. System Commands |
 | 1. System Commands |
@@ -537,13 +538,6 @@ Displays the text as a normal message with the format "*name <message>*" instead
 
 
 ---------------------------------------
 ---------------------------------------
 
 
-@main {<message>}
-
-Broadcasts a message to all players with @main enabled.
-Using the command without a message will enable or disable main chat.
-
----------------------------------------
-
 @storage
 @storage
 
 
 Opens your Kafra storage.
 Opens your Kafra storage.
@@ -1428,4 +1422,53 @@ Sets the intimacy level of your homunculus, with 1000 being "Loyal".
 
 
 Sets the hunger level of your homunculus, with 100 being "Stuffed".
 Sets the hunger level of your homunculus, with 100 being "Stuffed".
 
 
----------------------------------------
+---------------------------------------
+
+========================
+| 10. Channel Commands |
+========================
+
+@join <#channel_name> {<password>}
+
+Joins the specified channel.
+
+---------------------------------------
+
+@channel create <#channel_name> <channel_password>
+
+Creates a new channel.
+'allow_user_channel_creation' must be enabled in '/conf/channels.conf'.
+
+---------------------------------------
+
+@channel list
+
+Displays a list of all public channels.
+
+---------------------------------------
+
+@channel list colors
+
+Displays a list of all available colors for custom channels.
+
+---------------------------------------
+
+@channel setcolor <#channel_name> <color_name>
+
+Changes the text color of the specified channel.
+You must either be the channel's owner or have the channel_admin permission.
+
+---------------------------------------
+
+@channel leave <#channel_name>
+
+Leaves the specified channel.
+
+---------------------------------------
+
+@channel bindto <#channel_name>
+@channel unbind
+
+Binds or unbinds your global chat with the specified channel, which sends all global messages to the specified channel.
+
+---------------------------------------

+ 4 - 2
doc/permissions.txt

@@ -3,7 +3,7 @@
 //===== By: ==================================================
 //===== By: ==================================================
 //= rAthena Dev Team
 //= rAthena Dev Team
 //===== Current Version: =====================================
 //===== Current Version: =====================================
-//= 20120606
+//= 20130402
 //===== Description: =========================================
 //===== Description: =========================================
 //= Player group permissions, configured in /conf/groups.conf.
 //= Player group permissions, configured in /conf/groups.conf.
 //============================================================
 //============================================================
@@ -30,4 +30,6 @@ receive_requests : Ability to receive @requests.
 show_bossmobs : Ability to see boss mobs with @showmobs.
 show_bossmobs : Ability to see boss mobs with @showmobs.
 disable_pvm : Ability to disable Player vs. Monster.
 disable_pvm : Ability to disable Player vs. Monster.
 disable_pvp : Ability to disable Player vs. Player.
 disable_pvp : Ability to disable Player vs. Player.
-disable_commands_when_dead : Ability to disable @command usage when dead.
+disable_commands_when_dead : Ability to disable @command usage when dead.
+channel_admin : Ability to modify channel settings regardless of ownership and join password-protected
+                channels without a password.

+ 1 - 1
src/char/char.c

@@ -1484,7 +1484,7 @@ int check_char_name(char * name, char * esc_name)
 		return -2; // control chars in name
 		return -2; // control chars in name
 
 
 	// check for reserved names
 	// check for reserved names
-	if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 )
+	if( strcmpi(name, wisp_server_name) == 0 )
 		return -1; // nick reserved for internal server messages
 		return -1; // nick reserved for internal server messages
 
 
 	// Check Authorised letters/symbols in the name of the character
 	// Check Authorised letters/symbols in the name of the character

+ 0 - 3
src/char/inter.c

@@ -43,7 +43,6 @@ char default_codepage[32] = ""; //Feature by irmin.
 
 
 static struct accreg *accreg_pt;
 static struct accreg *accreg_pt;
 unsigned int party_share_level = 10;
 unsigned int party_share_level = 10;
-char main_chat_nick[16] = "Main";
 
 
 // recv. packet list
 // recv. packet list
 int inter_recv_packet_length[] = {
 int inter_recv_packet_length[] = {
@@ -667,8 +666,6 @@ static int inter_config_read(const char* cfgName)
 			party_share_level = atoi(w2);
 			party_share_level = atoi(w2);
 		else if(!strcmpi(w1,"log_inter"))
 		else if(!strcmpi(w1,"log_inter"))
 			log_inter = atoi(w2);
 			log_inter = atoi(w2);
-		else if(!strcmpi(w1,"main_chat_nick"))
-			safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
 		else if(!strcmpi(w1,"import"))
 		else if(!strcmpi(w1,"import"))
 			inter_config_read(w2);
 			inter_config_read(w2);
 	}
 	}

+ 0 - 2
src/char/inter.h

@@ -23,8 +23,6 @@ extern unsigned int party_share_level;
 extern Sql* sql_handle;
 extern Sql* sql_handle;
 extern Sql* lsql_handle;
 extern Sql* lsql_handle;
 
 
-extern char main_chat_nick[16];
-
 int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type);
 int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type);
 
 
 uint64 inter_chk_lastuid(int8 flag, uint64 value);
 uint64 inter_chk_lastuid(int8 flag, uint64 value);

+ 3 - 0
src/common/mmo.h

@@ -5,6 +5,7 @@
 #define	_MMO_H_
 #define	_MMO_H_
 
 
 #include "cbasetypes.h"
 #include "cbasetypes.h"
+#include "../common/db.h"
 #include <time.h>
 #include <time.h>
 
 
 // server->client protocol version
 // server->client protocol version
@@ -514,7 +515,9 @@ struct guild {
 	struct guild_expulsion expulsion[MAX_GUILDEXPULSION];
 	struct guild_expulsion expulsion[MAX_GUILDEXPULSION];
 	struct guild_skill skill[MAX_GUILDSKILL];
 	struct guild_skill skill[MAX_GUILDSKILL];
 
 
+	/* TODO: still used for something? */
 	unsigned short save_flag; // for TXT saving
 	unsigned short save_flag; // for TXT saving
+	void *channel;
 };
 };
 
 
 struct guild_castle {
 struct guild_castle {

+ 306 - 62
src/map/atcommand.c

@@ -597,7 +597,7 @@ ACMD_FUNC(who)
 				}
 				}
 				default: {
 				default: {
 					struct party_data *p = party_search(pl_sd->status.party_id);
 					struct party_data *p = party_search(pl_sd->status.party_id);
-					struct guild *g = guild_search(pl_sd->status.guild_id);
+					struct guild *g = pl_sd->guild;
 
 
 					StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s "
 					StringBuf_Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s "
 					if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
 					if (pc_get_group_id(pl_sd) > 0) // Player title, if exists
@@ -700,7 +700,7 @@ ACMD_FUNC(whogm)
 		clif_displaymessage(fd, atcmd_output);
 		clif_displaymessage(fd, atcmd_output);
 
 
 		p = party_search(pl_sd->status.party_id);
 		p = party_search(pl_sd->status.party_id);
-		g = guild_search(pl_sd->status.guild_id);
+		g = pl_sd->guild;
 
 
 		sprintf(atcmd_output,msg_txt(916),	// Party: '%s' | Guild: '%s'
 		sprintf(atcmd_output,msg_txt(916),	// Party: '%s' | Guild: '%s'
 			p?p->party.name:msg_txt(917), g?g->name:msg_txt(917));	// None.
 			p?p->party.name:msg_txt(917), g?g->name:msg_txt(917));	// None.
@@ -3244,7 +3244,7 @@ ACMD_FUNC(breakguild)
 
 
 	if (sd->status.guild_id) { // Check if the player has a guild
 	if (sd->status.guild_id) { // Check if the player has a guild
 		struct guild *g;
 		struct guild *g;
-		g = guild_search(sd->status.guild_id); // Search the guild
+		g = sd->guild; // Search the guild
 		if (g) { // Check if guild was found
 		if (g) { // Check if guild was found
 			if (sd->state.gmaster_flag) { // Check if player is guild master
 			if (sd->state.gmaster_flag) { // Check if player is guild master
 				int ret = 0;
 				int ret = 0;
@@ -5246,7 +5246,7 @@ ACMD_FUNC(cleargstorage)
 	struct guild_storage *gstorage;
 	struct guild_storage *gstorage;
 	nullpo_retr(-1, sd);
 	nullpo_retr(-1, sd);
 
 
-	g = guild_search(sd->status.guild_id);
+	g = sd->guild;
 
 
 	if (g == NULL) {
 	if (g == NULL) {
 		clif_displaymessage(fd, msg_txt(43));
 		clif_displaymessage(fd, msg_txt(43));
@@ -6163,7 +6163,7 @@ ACMD_FUNC(npctalk)
 	snprintf(temp, sizeof(temp), "%s : %s", name, mes);
 	snprintf(temp, sizeof(temp), "%s : %s", name, mes);
 
 
 	if(ifcolor) clif_messagecolor(&nd->bl,color,temp);
 	if(ifcolor) clif_messagecolor(&nd->bl,color,temp);
-	else clif_message(&nd->bl, temp);
+	else clif_disp_overhead(&nd->bl, temp);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -6227,7 +6227,7 @@ ACMD_FUNC(pettalk)
 	}
 	}
 
 
 	snprintf(temp, sizeof temp ,"%s : %s", pd->pet.name, mes);
 	snprintf(temp, sizeof temp ,"%s : %s", pd->pet.name, mes);
-	clif_message(&pd->bl, temp);
+	clif_disp_overhead(&pd->bl, temp);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -7017,7 +7017,7 @@ ACMD_FUNC(homtalk)
 	}
 	}
 
 
 	snprintf(temp, sizeof temp ,"%s : %s", sd->hd->homunculus.name, mes);
 	snprintf(temp, sizeof temp ,"%s : %s", sd->hd->homunculus.name, mes);
-	clif_message(&sd->hd->bl, temp);
+	clif_disp_overhead(&sd->hd->bl, temp);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -7399,7 +7399,7 @@ ACMD_FUNC(me)
 	}
 	}
 
 
 	sprintf(atcmd_output, msg_txt(270), sd->status.name, tempmes);	// *%s %s*
 	sprintf(atcmd_output, msg_txt(270), sd->status.name, tempmes);	// *%s %s*
-	clif_disp_overhead(sd, atcmd_output);
+	clif_disp_overhead(&sd->bl, atcmd_output);
 
 
 	return 0;
 	return 0;
 
 
@@ -7944,58 +7944,6 @@ ACMD_FUNC(clone)
 	return 0;
 	return 0;
 }
 }
 
 
-/*===================================
- * Main chat [LuzZza]
- * Usage: @main <on|off|message>
- *-----------------------------------*/
-ACMD_FUNC(main)
-{
-	if( message[0] ) {
-
-		if(strcmpi(message, "on") == 0) {
-			if(!sd->state.mainchat) {
-				sd->state.mainchat = 1;
-				clif_displaymessage(fd, msg_txt(380)); // Main chat has been activated.
-			} else {
-				clif_displaymessage(fd, msg_txt(381)); // Main chat already activated.
-			}
-		} else if(strcmpi(message, "off") == 0) {
-			if(sd->state.mainchat) {
-				sd->state.mainchat = 0;
-				clif_displaymessage(fd, msg_txt(382)); // Main chat has been disabled.
-			} else {
-				clif_displaymessage(fd, msg_txt(383)); // Main chat already disabled.
-			}
-		} else {
-			if(!sd->state.mainchat) {
-				sd->state.mainchat = 1;
-				clif_displaymessage(fd, msg_txt(380)); // Main chat has been activated.
-			}
-			if (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) {
-				clif_displaymessage(fd, msg_txt(387));
-				return -1;
-			}
-
-			if ( battle_config.min_chat_delay ) {
-				if( DIFF_TICK(sd->cantalk_tick, gettick()) > 0 )
-					return 0;
-				sd->cantalk_tick = gettick() + battle_config.min_chat_delay;
-			}
-
-			// send the message using inter-server system
-			intif_main_message( sd, message );
-		}
-
-	} else {
-
-		if(sd->state.mainchat)
-			clif_displaymessage(fd, msg_txt(384)); // Main chat currently enabled. Usage: @main <on|off>, @main <message>.
-		else
-			clif_displaymessage(fd, msg_txt(385)); // Main chat currently disabled. Usage: @main <on|off>, @main <message>.
-	}
-	return 0;
-}
-
 /*=====================================
 /*=====================================
  * Autorejecting Invites/Deals [LuzZza]
  * Autorejecting Invites/Deals [LuzZza]
  * Usage: @noask
  * Usage: @noask
@@ -8796,6 +8744,300 @@ ACMD_FUNC(cart) {
 	#undef MC_CART_MDFY
 	#undef MC_CART_MDFY
 }
 }
 
 
+/* Channel System [Ind] */
+ACMD_FUNC(join) {
+	struct raChSysCh *channel;
+	char name[RACHSYS_NAME_LENGTH], pass[RACHSYS_NAME_LENGTH];
+	DBMap* channel_db = clif_get_channel_db();
+	
+	if( !message || !*message || sscanf(message, "%s %s", name, pass) < 1 ) {
+		sprintf(atcmd_output, msg_txt(1399),command); // Unknown Channel (usage: %s <#channel_name>)
+		clif_displaymessage(fd, atcmd_output);
+		return -1;
+	}
+	if( raChSys.local && strcmpi(name + 1, raChSys.local_name) == 0 ) {
+		if( !map[sd->bl.m].channel ) {
+			clif_chsys_mjoin(sd);
+			return 0;
+		} else
+			channel = map[sd->bl.m].channel;
+	} else if( raChSys.ally && sd->status.guild_id && strcmpi(name + 1, raChSys.ally_name) == 0 ) {
+		struct guild *g = sd->guild;
+		if( !g ) return -1;/* unlikely, but we wont let it crash anyway. */
+		channel = (struct raChSysCh *)g->channel;
+	} else if( !( channel = strdb_get(channel_db, name + 1) ) ) {
+		sprintf(atcmd_output, msg_txt(1400),name,command); // Unknown Channel '%s' (usage: %s <#channel_name>)
+		clif_displaymessage(fd, atcmd_output);
+		return -1;
+	}
+
+	if( idb_exists(channel->users, sd->status.char_id) ) {
+		sprintf(atcmd_output, msg_txt(1434),name); // You're already in the '%s' channel.
+		clif_displaymessage(fd, atcmd_output);
+		return -1;
+	}
+	if( channel->pass[0] != '\0'  && strcmp(channel->pass,pass) != 0 ) {
+		if( pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
+			sd->stealth = true;
+		} else {
+			sprintf(atcmd_output, msg_txt(1401),name,command); // '%s' Channel is password protected (usage: %s <#channel_name> <password>)
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+	}
+
+	if( !( channel->opt & raChSys_OPT_ANNOUNCE_JOIN ) ) {
+		sprintf(atcmd_output, msg_txt(1403),name); // You're now in the '%s' channel.
+		clif_displaymessage(fd, atcmd_output);
+	}
+
+	clif_chsys_join(channel,sd);
+
+	return 0;
+}
+
+inline void atcmd_channel_help(int fd, const char *command, bool can_create) {
+	clif_displaymessage(fd, msg_txt(1414));// ---- Available options:
+	if( can_create ) {
+		sprintf(atcmd_output, msg_txt(1415),command);// * %s create <#channel_name> <channel_password>
+		clif_displaymessage(fd, atcmd_output);
+		clif_displaymessage(fd, msg_txt(1416));// -- Creates a new channel.
+	}
+	sprintf(atcmd_output, msg_txt(1417),command);// * %s list
+	clif_displaymessage(fd, atcmd_output);
+	clif_displaymessage(fd, msg_txt(1418));// -- Lists all public channels.
+	if( can_create ) {
+		sprintf(atcmd_output, msg_txt(1419),command);// * %s list colors
+		clif_displaymessage(fd, atcmd_output);
+		clif_displaymessage(fd, msg_txt(1420));// -- Lists all available colors for custom channels.
+		sprintf(atcmd_output, msg_txt(1421),command);// * %s setcolor <#channel_name> <color_name>
+		clif_displaymessage(fd, atcmd_output);
+		clif_displaymessage(fd, msg_txt(1422));// -- Changes channel text to the specified color (channel owners only).
+	}
+	sprintf(atcmd_output, msg_txt(1423),command);// * %s leave <#channel_name>
+	clif_displaymessage(fd, atcmd_output);
+	clif_displaymessage(fd, msg_txt(1424));// -- Leaves the specified channel.
+	sprintf(atcmd_output, msg_txt(1427),command);// * %s bindto <#channel_name>
+	clif_displaymessage(fd, atcmd_output);
+	clif_displaymessage(fd, msg_txt(1428));// -- Binds your global chat to the specified channel, sending all global messages to that channel.
+	sprintf(atcmd_output, msg_txt(1429),command);// * %s unbind
+	clif_displaymessage(fd, atcmd_output);
+	clif_displaymessage(fd, msg_txt(1430));// -- Unbinds your global chat from the attached channel, if any.
+	sprintf(atcmd_output, msg_txt(1404),command); // %s failed.
+	clif_displaymessage(fd, atcmd_output);
+}
+
+ACMD_FUNC(channel) {
+	struct raChSysCh *channel;
+	char key[RACHSYS_NAME_LENGTH], sub1[RACHSYS_NAME_LENGTH], sub2[RACHSYS_NAME_LENGTH], sub3[RACHSYS_NAME_LENGTH];
+	unsigned char k = 0;
+	DBMap* channel_db = clif_get_channel_db();
+	sub1[0] = sub2[0] = sub3[0] = '\0';
+
+	if( !message || !*message || sscanf(message, "%s %s %s %s", key, sub1, sub2, sub3) < 1 ) {
+		atcmd_channel_help(fd,command,( raChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ));
+		return 0;
+	}
+
+	if( strcmpi(key,"create") == 0 && ( raChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) ) {
+		if( sub1[0] != '#' ) {
+			clif_displaymessage(fd, msg_txt(1405));// Channel name must start with '#'.
+			return -1;
+		} else if ( strlen(sub1) < 3 || strlen(sub1) > RACHSYS_NAME_LENGTH ) {
+			sprintf(atcmd_output, msg_txt(1406), RACHSYS_NAME_LENGTH);// Channel length must be between 3 and %d.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		} else if ( sub3[0] != '\0' ) {
+			clif_displaymessage(fd, msg_txt(1408)); // Channel password may not contain spaces.
+			return -1;
+		}
+		if( strcmpi(sub1 + 1,raChSys.local_name) == 0 || strcmpi(sub1 + 1,raChSys.ally_name) == 0 || strdb_exists(channel_db, sub1 + 1) ) {
+			sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+
+		CREATE( channel, struct raChSysCh, 1 );
+
+		clif_chsys_create(channel,sub1 + 1,sub2,0);
+
+		channel->owner = sd->status.char_id;
+		channel->type = raChSys_PRIVATE;
+
+		if( !( channel->opt & raChSys_OPT_ANNOUNCE_JOIN ) ) {
+			sprintf(atcmd_output, msg_txt(1403),sub1); // You're now in the '%s' channel.
+			clif_displaymessage(fd, atcmd_output);
+		}
+
+		clif_chsys_join(channel,sd);
+
+	} else if ( strcmpi(key,"list") == 0 ) {
+		if( sub1[0] != '\0' && strcmpi(sub1,"colors") == 0 ) {
+			char mout[40];
+			for( k = 0; k < raChSys.colors_count; k++ ) {
+				unsigned short msg_len = 1;
+				msg_len += sprintf(mout, "[ %s list colors ] : %s",command,raChSys.colors_name[k]);
+
+				WFIFOHEAD(fd,msg_len + 12);
+				WFIFOW(fd,0) = 0x2C1;
+				WFIFOW(fd,2) = msg_len + 12;
+				WFIFOL(fd,4) = 0;
+				WFIFOL(fd,8) = raChSys.colors[k];
+				safestrncpy((char*)WFIFOP(fd,12), mout, msg_len);
+				WFIFOSET(fd, msg_len + 12);
+			}
+		} else {
+			DBIterator *iter = db_iterator(channel_db);
+			bool show_all = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false;
+			clif_displaymessage(fd, msg_txt(1410)); // ---- Public Channels ----
+			if( raChSys.local ) {
+				sprintf(atcmd_output, msg_txt(1409), raChSys.local_name, map[sd->bl.m].channel ? db_size(map[sd->bl.m].channel->users) : 0);// - #%s ( %d users )
+				clif_displaymessage(fd, atcmd_output);
+			}
+			if( raChSys.ally && sd->status.guild_id ) {
+				struct guild *g = sd->guild;
+				if( !g ) return -1;
+				sprintf(atcmd_output, msg_txt(1409), raChSys.ally_name, db_size(((struct raChSysCh *)g->channel)->users));// - #%s ( %d users )
+				clif_displaymessage(fd, atcmd_output);
+			}
+			for(channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) {
+				if( show_all || channel->type == raChSys_PUBLIC ) {
+					sprintf(atcmd_output, msg_txt(1409), channel->name, db_size(channel->users));// - #%s (%d users)
+					clif_displaymessage(fd, atcmd_output);
+				}
+			}
+			dbi_destroy(iter);
+		}
+	} else if ( strcmpi(key,"setcolor") == 0 ) {
+
+		if( sub1[0] != '#' ) {
+			clif_displaymessage(fd, msg_txt(1405));// Channel name must start with '#'.
+			return -1;
+		}
+
+		if( !(channel = strdb_get(channel_db, sub1 + 1)) ) {
+			sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+
+		if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
+			sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s'.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+
+		for( k = 0; k < raChSys.colors_count; k++ ) {
+			if( strcmpi(sub2,raChSys.colors_name[k]) == 0 )
+				break;
+		}
+		if( k == raChSys.colors_count ) {
+			sprintf(atcmd_output, msg_txt(1411), sub2);// Unknown color '%s'.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+		channel->color = k;
+		sprintf(atcmd_output, msg_txt(1413),sub1,raChSys.colors_name[k]);// '%s' channel color updated to '%s'.
+		clif_displaymessage(fd, atcmd_output);
+	} else if ( strcmpi(key,"leave") == 0 ) {
+
+		if( sub1[0] != '#' ) {
+			clif_displaymessage(fd, msg_txt(1405));// Channel name must start with '#'.
+			return -1;
+		}
+
+		for(k = 0; k < sd->channel_count; k++) {
+			if( strcmpi(sub1+1,sd->channels[k]->name) == 0 )
+				break;
+		}
+		if( k == sd->channel_count ) {
+			sprintf(atcmd_output, msg_txt(1425),sub1);// You're not part of the '%s' channel.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+		clif_chsys_left(sd->channels[k],sd);
+		sprintf(atcmd_output, msg_txt(1426),sub1); // You've left the '%s' channel.
+		clif_displaymessage(fd, atcmd_output);
+	} else if ( strcmpi(key,"bindto") == 0 ) {
+
+		if( sub1[0] != '#' ) {
+			clif_displaymessage(fd, msg_txt(1405));// Channel name must start with '#'.
+			return -1;
+		}
+
+		for(k = 0; k < sd->channel_count; k++) {
+			if( strcmpi(sub1+1,sd->channels[k]->name) == 0 )
+				break;
+		}
+		if( k == sd->channel_count ) {
+			sprintf(atcmd_output, msg_txt(1425),sub1);// You're not part of the '%s' channel.
+			clif_displaymessage(fd, atcmd_output);
+			return -1;
+		}
+
+		sd->gcbind = sd->channels[k];
+		sprintf(atcmd_output, msg_txt(1431),sub1); // Your global chat is now binded to the '%s' channel.
+		clif_displaymessage(fd, atcmd_output);
+	} else if ( strcmpi(key,"unbind") == 0 ) {
+
+		if( sd->gcbind == NULL ) {
+			clif_displaymessage(fd, msg_txt(1432));// Your global chat is not binded to any channel.
+			return -1;
+		}
+
+		sprintf(atcmd_output, msg_txt(1433),sd->gcbind->name); // Your global chat is now unbinded from the '#%s' channel.
+		clif_displaymessage(fd, atcmd_output);
+
+		sd->gcbind = NULL;
+	} else {
+		atcmd_channel_help(fd,command,( raChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ));
+	}
+
+	return 0;
+}
+/* debug only, delete after */
+ACMD_FUNC(fontcolor) {
+	unsigned char k;
+
+	if( !message || !*message ) {
+		char mout[40];
+		for( k = 0; k < raChSys.colors_count; k++ ) {
+			unsigned short msg_len = 1;
+			msg_len += sprintf(mout, "[ %s ] : %s",command,raChSys.colors_name[k]);
+
+			WFIFOHEAD(fd,msg_len + 12);
+			WFIFOW(fd,0) = 0x2C1;
+			WFIFOW(fd,2) = msg_len + 12;
+			WFIFOL(fd,4) = 0;
+			WFIFOL(fd,8) = raChSys.colors[k];
+			safestrncpy((char*)WFIFOP(fd,12), mout, msg_len);
+			WFIFOSET(fd, msg_len + 12);
+		}
+		return -1;
+	}
+
+	if( message[0] == '0' ) {
+		sd->fontcolor = 0;
+		pc_disguise(sd,0);
+		return 0;
+	}
+
+	for( k = 0; k < raChSys.colors_count; k++ ) {
+		if( strcmpi(message,raChSys.colors_name[k]) == 0 )
+			break;
+	}
+	if( k == raChSys.colors_count ) {
+		sprintf(atcmd_output, msg_txt(1411), message);// Unknown color '%s'.
+		clif_displaymessage(fd, atcmd_output);
+		return -1;
+	}
+
+	sd->fontcolor = k + 1;
+	pc_disguise(sd,sd->status.class_);
+
+	return 0;
+}
+
 /**
 /**
  * Fills the reference of available commands in atcommand DBMap
  * Fills the reference of available commands in atcommand DBMap
  **/
  **/
@@ -9008,7 +9250,6 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(leave),
 		ACMD_DEF(leave),
 		ACMD_DEF(accept),
 		ACMD_DEF(accept),
 		ACMD_DEF(reject),
 		ACMD_DEF(reject),
-		ACMD_DEF(main),
 		ACMD_DEF(clone),
 		ACMD_DEF(clone),
 		ACMD_DEF2("slaveclone", clone),
 		ACMD_DEF2("slaveclone", clone),
 		ACMD_DEF2("evilclone", clone),
 		ACMD_DEF2("evilclone", clone),
@@ -9056,7 +9297,10 @@ void atcommand_basecommands(void) {
 		ACMD_DEF2("rmvperm", addperm),
 		ACMD_DEF2("rmvperm", addperm),
 		ACMD_DEF(unloadnpcfile),
 		ACMD_DEF(unloadnpcfile),
 		ACMD_DEF(cart),
 		ACMD_DEF(cart),
-		ACMD_DEF(mount2)
+		ACMD_DEF(mount2),
+		ACMD_DEF(join),
+		ACMD_DEF(channel),
+		ACMD_DEF(fontcolor)
 	};
 	};
 	AtCommandInfo* atcommand;
 	AtCommandInfo* atcommand;
 	int i;
 	int i;

+ 1 - 1
src/map/battle.c

@@ -1326,7 +1326,7 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama
 			}
 			}
 		}
 		}
 		if(src->type != BL_MOB) {
 		if(src->type != BL_MOB) {
-			struct guild *g = guild_search(status_get_guild_id(src));
+			struct guild *g = src->type == BL_PC ? ((TBL_PC *)src)->guild : guild_search(status_get_guild_id(src));
 
 
 			if (class_ == MOBID_EMPERIUM && (!g || guild_checkskill(g,GD_APPROVAL) <= 0 ))
 			if (class_ == MOBID_EMPERIUM && (!g || guild_checkskill(g,GD_APPROVAL) <= 0 ))
 				return 0;
 				return 0;

File diff suppressed because it is too large
+ 423 - 180
src/map/clif.c


+ 53 - 4
src/map/clif.h

@@ -5,6 +5,7 @@
 #define _CLIF_H_
 #define _CLIF_H_
 
 
 #include "../common/cbasetypes.h"
 #include "../common/cbasetypes.h"
+#include "../common/db.h" //dbmap
 //#include "../common/mmo.h"
 //#include "../common/mmo.h"
 struct item;
 struct item;
 struct storage_data;
 struct storage_data;
@@ -73,8 +74,8 @@ typedef enum send_target {
 	GUILD_NOBG,
 	GUILD_NOBG,
 	DUEL,
 	DUEL,
 	DUEL_WOS,
 	DUEL_WOS,
-	CHAT_MAINCHAT,		// everyone on main chat
 	SELF,
 	SELF,
+
 	BG,					// BattleGround System
 	BG,					// BattleGround System
 	BG_WOS,
 	BG_WOS,
 	BG_SAMEMAP,
 	BG_SAMEMAP,
@@ -573,7 +574,6 @@ void clif_displaymessage(const int fd, const char* mes);
 void clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len);
 void clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len);
 void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target);
 void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target);
 void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target);
 void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target);
-void clif_MainChatMessage(const char* message);
 void clif_broadcast2(struct block_list* bl, const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target);
 void clif_broadcast2(struct block_list* bl, const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target);
 void clif_heal(int fd,int type,int val);
 void clif_heal(int fd,int type,int val);
 void clif_resurrection(struct block_list *bl,int type);
 void clif_resurrection(struct block_list *bl,int type);
@@ -604,7 +604,6 @@ void clif_weather(int16 m); // [Valaris]
 void clif_specialeffect(struct block_list* bl, int type, enum send_target target); // special effects [Valaris]
 void clif_specialeffect(struct block_list* bl, int type, enum send_target target); // special effects [Valaris]
 void clif_specialeffect_single(struct block_list* bl, int type, int fd);
 void clif_specialeffect_single(struct block_list* bl, int type, int fd);
 void clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg); // Mob/Npc color talk [SnakeDrak]
 void clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg); // Mob/Npc color talk [SnakeDrak]
-void clif_message(struct block_list* bl, const char* msg);
 void clif_specialeffect_value(struct block_list* bl, int effect_id, int num, send_target target);
 void clif_specialeffect_value(struct block_list* bl, int effect_id, int num, send_target target);
 
 
 void clif_GM_kickack(struct map_session_data *sd, int id);
 void clif_GM_kickack(struct map_session_data *sd, int id);
@@ -612,7 +611,7 @@ void clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd);
 void clif_manner_message(struct map_session_data* sd, uint32 type);
 void clif_manner_message(struct map_session_data* sd, uint32 type);
 void clif_GM_silence(struct map_session_data* sd, struct map_session_data* tsd, uint8 type);
 void clif_GM_silence(struct map_session_data* sd, struct map_session_data* tsd, uint8 type);
 
 
-void clif_disp_overhead(struct map_session_data *sd, const char* mes);
+void clif_disp_overhead(struct block_list *bl, const char* mes);
 
 
 void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand);
 void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand);
 
 
@@ -767,6 +766,56 @@ enum clif_colors {
 unsigned long color_table[COLOR_MAX];
 unsigned long color_table[COLOR_MAX];
 int clif_colormes(struct map_session_data * sd, enum clif_colors color, const char* msg);
 int clif_colormes(struct map_session_data * sd, enum clif_colors color, const char* msg);
 
 
+/**
+ * Channel System
+ **/
+#define RACHSYS_NAME_LENGTH 20
+
+enum raChSysChOpt {
+	raChSys_OPT_BASE				= 0,
+	raChSys_OPT_ANNOUNCE_JOIN	= 1,
+};
+
+enum raChSysChType {
+	raChSys_PUBLIC	= 0,
+	raChSys_PRIVATE	= 1,
+	raChSys_MAP		= 2,
+	raChSys_ALLY		= 3,
+};
+
+struct {
+	unsigned long *colors;
+	char **colors_name;
+	unsigned char colors_count;
+	bool local, ally;
+	bool local_autojoin, ally_autojoin;
+	char local_name[RACHSYS_NAME_LENGTH], ally_name[RACHSYS_NAME_LENGTH];
+	unsigned char local_color, ally_color;
+	bool closing;
+	bool allow_user_channel_creation;
+} raChSys;
+
+struct raChSysCh {
+	char name[RACHSYS_NAME_LENGTH];
+	char pass[RACHSYS_NAME_LENGTH];
+	unsigned char color;
+	DBMap *users;
+	unsigned int opt;
+	unsigned int owner;
+	enum raChSysChType type;
+	uint16 m;
+};
+
+struct DBMap* clif_get_channel_db(void);
+void clif_chsys_create(struct raChSysCh *channel, char *name, char *pass, unsigned char color);
+void clif_chsys_msg(struct raChSysCh *channel, struct map_session_data *sd, char *msg);
+void clif_chsys_send(struct raChSysCh *channel, struct map_session_data *sd, char *msg);
+void clif_chsys_join(struct raChSysCh *channel, struct map_session_data *sd);
+void clif_chsys_left(struct raChSysCh *channel, struct map_session_data *sd);
+void clif_chsys_delete(struct raChSysCh *channel);
+void clif_chsys_mjoin(struct map_session_data *sd);
+void clif_read_channels_config(void);
+
 #define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0;
 #define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0;
 
 
 #endif /* _CLIF_H_ */
 #endif /* _CLIF_H_ */

+ 111 - 44
src/map/guild.c

@@ -259,7 +259,7 @@ int guild_getposition(struct guild* g, struct map_session_data* sd)
 {
 {
 	int i;
 	int i;
 
 
-	if( g == NULL && (g=guild_search(sd->status.guild_id)) == NULL )
+	if( g == NULL && (g=sd->guild) == NULL )
 		return -1;
 		return -1;
 	
 	
 	ARR_FIND( 0, g->max_member, i, g->member[i].account_id == sd->status.account_id && g->member[i].char_id == sd->status.char_id );
 	ARR_FIND( 0, g->max_member, i, g->member[i].account_id == sd->status.account_id && g->member[i].char_id == sd->status.char_id );
@@ -481,8 +481,7 @@ int guild_recv_noinfo(int guild_id)
 	struct s_mapiterator* iter;
 	struct s_mapiterator* iter;
 
 
 	iter = mapit_getallusers();
 	iter = mapit_getallusers();
-	for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
-	{
+	for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) ) {
 		if( sd->status.guild_id == guild_id )
 		if( sd->status.guild_id == guild_id )
 			sd->status.guild_id = 0; // erase guild
 			sd->status.guild_id = 0; // erase guild
 	}
 	}
@@ -499,20 +498,52 @@ int guild_recv_info(struct guild *sg)
 	DBData data;
 	DBData data;
 	struct map_session_data *sd;
 	struct map_session_data *sd;
 	bool guild_new = false;
 	bool guild_new = false;
+	void *aChSysSave = NULL;
 
 
 	nullpo_ret(sg);
 	nullpo_ret(sg);
 
 
-	if((g = (struct guild*)idb_get(guild_db,sg->guild_id))==NULL)
-	{
+	if((g = guild_search(sg->guild_id))==NULL) {
 		guild_new = true;
 		guild_new = true;
 		g=(struct guild *)aCalloc(1,sizeof(struct guild));
 		g=(struct guild *)aCalloc(1,sizeof(struct guild));
 		idb_put(guild_db,sg->guild_id,g);
 		idb_put(guild_db,sg->guild_id,g);
-		before=*sg;
+		if( raChSys.ally ) {
+			struct raChSysCh *channel;
+
+			CREATE(channel, struct raChSysCh , 1);
+			safestrncpy(channel->name, raChSys.ally_name, RACHSYS_NAME_LENGTH);
+			channel->type = raChSys_ALLY;
+
+			clif_chsys_create(channel,NULL,NULL,raChSys.ally_color);
+			if( raChSys.ally_autojoin ) {
+				struct s_mapiterator* iter = mapit_getallusers();
+
+				for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) ) {
+					if( sd->status.guild_id ) {
+						if( sd->status.guild_id == sg->guild_id ) {
+							clif_chsys_join(channel,sd);
+							sd->guild = g;
+							continue;
+						}
+
+						for (i = 0; i < MAX_GUILDALLIANCE; i++) {
+							if( sg->alliance[i].guild_id == sd->status.guild_id ) {
+								clif_chsys_join(channel,sd);
+								break;
+							}
+						}
+					}
+				}
 
 
-        //Perform the check on the user because the first load
+				mapit_free(iter);
+			}
+
+			aChSysSave = (void*)channel;
+
+		}
+		before=*sg;
+		//Perform the check on the user because the first load
 		guild_check_member(sg);
 		guild_check_member(sg);
-		if ((sd = map_nick2sd(sg->master)) != NULL)
-		{
+		if ((sd = map_nick2sd(sg->master)) != NULL) {
 			//If the guild master is online the first time the guild_info is received,
 			//If the guild master is online the first time the guild_info is received,
 			//that means he was the first to join, so apply guild skill blocking here.
 			//that means he was the first to join, so apply guild skill blocking here.
 			if( battle_config.guild_skill_relog_delay )
 			if( battle_config.guild_skill_relog_delay )
@@ -523,12 +554,16 @@ int guild_recv_info(struct guild *sg)
 			clif_charnameupdate(sd); // [LuzZza]
 			clif_charnameupdate(sd); // [LuzZza]
 			clif_guild_masterormember(sd);
 			clif_guild_masterormember(sd);
 		}
 		}
-	}else
+	} else {
 		before=*g;
 		before=*g;
+		if( g->channel )
+			aChSysSave = g->channel;
+	}
 	memcpy(g,sg,sizeof(struct guild));
 	memcpy(g,sg,sizeof(struct guild));
 
 
-	if(g->max_member > MAX_GUILD)
-	{
+	g->channel = aChSysSave;
+
+	if(g->max_member > MAX_GUILD) {
 		ShowError("guild_recv_info: Received guild with %d members, but MAX_GUILD is only %d. Extra guild-members have been lost!\n", g->max_member, MAX_GUILD);
 		ShowError("guild_recv_info: Received guild with %d members, but MAX_GUILD is only %d. Extra guild-members have been lost!\n", g->max_member, MAX_GUILD);
 		g->max_member = MAX_GUILD;
 		g->max_member = MAX_GUILD;
 	}
 	}
@@ -570,10 +605,9 @@ int guild_recv_info(struct guild *sg)
     }
     }
 
 
     //Occurrence of an event
     //Occurrence of an event
-	if (guild_infoevent_db->remove(guild_infoevent_db, db_i2key(sg->guild_id), &data))
-	{
+	if (guild_infoevent_db->remove(guild_infoevent_db, db_i2key(sg->guild_id), &data)) {
 		struct eventlist *ev = db_data2ptr(&data), *ev2;
 		struct eventlist *ev = db_data2ptr(&data), *ev2;
-		while(ev){
+		while(ev) {
 			npc_event_do(ev->name);
 			npc_event_do(ev->name);
 			ev2=ev->next;
 			ev2=ev->next;
 			aFree(ev);
 			aFree(ev);
@@ -593,7 +627,7 @@ int guild_invite(struct map_session_data *sd, struct map_session_data *tsd) {
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	g=guild_search(sd->status.guild_id);
+	g=sd->guild;
 
 
 	if(tsd==NULL || g==NULL)
 	if(tsd==NULL || g==NULL)
 		return 0;
 		return 0;
@@ -684,6 +718,7 @@ int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag)
 			return 0;
 			return 0;
 		}
 		}
 
 
+		sd->guild = g;
 		guild_makemember(&m,sd);
 		guild_makemember(&m,sd);
 		intif_guild_addmember(guild_id, &m);
 		intif_guild_addmember(guild_id, &m);
 		//TODO: send a minimap update to this player
 		//TODO: send a minimap update to this player
@@ -705,8 +740,7 @@ void guild_member_joined(struct map_session_data *sd)
 		guild_request_info(sd->status.guild_id);
 		guild_request_info(sd->status.guild_id);
 		return;
 		return;
 	}
 	}
-	if (strcmp(sd->status.name,g->master) == 0)
-	{	// set the Guild Master flag
+	if (strcmp(sd->status.name,g->master) == 0) {	// set the Guild Master flag
 		sd->state.gmaster_flag = g;
 		sd->state.gmaster_flag = g;
 		// prevent Guild Skills from being used directly after relog
 		// prevent Guild Skills from being used directly after relog
 		if( battle_config.guild_skill_relog_delay )
 		if( battle_config.guild_skill_relog_delay )
@@ -715,8 +749,22 @@ void guild_member_joined(struct map_session_data *sd)
 	i = guild_getindex(g, sd->status.account_id, sd->status.char_id);
 	i = guild_getindex(g, sd->status.account_id, sd->status.char_id);
 	if (i == -1)
 	if (i == -1)
 		sd->status.guild_id = 0;
 		sd->status.guild_id = 0;
-	else
+	else {
 		g->member[i].sd = sd;
 		g->member[i].sd = sd;
+		sd->guild = g;
+
+		if( raChSys.ally && raChSys.ally_autojoin ) {
+			struct guild* sg = NULL;
+			clif_chsys_join((struct raChSysCh*)g->channel,sd);
+
+			for (i = 0; i < MAX_GUILDALLIANCE; i++) {
+				if( g->alliance[i].guild_id && (sg = guild_search(g->alliance[i].guild_id) ) ) {
+					clif_chsys_join((struct raChSysCh*)sg->channel,sd);
+					break;
+				}
+			}
+		}
+	}
 }
 }
 
 
 /*==========================================
 /*==========================================
@@ -775,7 +823,7 @@ int guild_leave(struct map_session_data* sd, int guild_id, int account_id, int c
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	g = guild_search(sd->status.guild_id);
+	g = sd->guild;
 
 
 	if(g==NULL)
 	if(g==NULL)
 		return 0;
 		return 0;
@@ -800,7 +848,7 @@ int guild_expulsion(struct map_session_data* sd, int guild_id, int account_id, i
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	g = guild_search(sd->status.guild_id);
+	g = sd->guild;
 
 
 	if(g==NULL)
 	if(g==NULL)
 		return 0;
 		return 0;
@@ -859,8 +907,14 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c
 		if (sd->state.storage_flag == 2) //Close the guild storage.
 		if (sd->state.storage_flag == 2) //Close the guild storage.
 			storage_guild_storageclose(sd);
 			storage_guild_storageclose(sd);
 		guild_send_dot_remove(sd);
 		guild_send_dot_remove(sd);
-
+		if( raChSys.ally ) {
+			for (i = 0; i < sd->channel_count; i++) {
+				if( sd->channels[i] && sd->channels[i]->type == raChSys_ALLY )
+					clif_chsys_left(sd->channels[i],sd);
+			}
+		}
 		sd->status.guild_id = 0;
 		sd->status.guild_id = 0;
+		sd->guild = NULL;
 		sd->guild_emblem_id = 0;
 		sd->guild_emblem_id = 0;
 		
 		
 		clif_charnameupdate(sd); //Update display name [Skotlex]
 		clif_charnameupdate(sd); //Update display name [Skotlex]
@@ -878,7 +932,7 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online)
 	if(sd->status.guild_id <= 0)
 	if(sd->status.guild_id <= 0)
 		return 0;
 		return 0;
 
 
-	if(!(g = guild_search(sd->status.guild_id)))
+	if(!(g = sd->guild))
 		return 0;
 		return 0;
 
 
 	intif_guild_memberinfoshort(g->guild_id,
 	intif_guild_memberinfoshort(g->guild_id,
@@ -1097,7 +1151,7 @@ int guild_change_emblem(struct map_session_data *sd,int len,const char *data)
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
 	if (battle_config.require_glory_guild &&
 	if (battle_config.require_glory_guild &&
-		!((g = guild_search(sd->status.guild_id)) && guild_checkskill(g, GD_GLORYGUILD)>0)) {
+		!((g = sd->guild) && guild_checkskill(g, GD_GLORYGUILD)>0)) {
 		clif_skill_fail(sd,GD_GLORYGUILD,USESKILL_FAIL_LEVEL,0);
 		clif_skill_fail(sd,GD_GLORYGUILD,USESKILL_FAIL_LEVEL,0);
 		return 0;
 		return 0;
 	}
 	}
@@ -1196,7 +1250,7 @@ unsigned int guild_payexp(struct map_session_data *sd,unsigned int exp)
 	if (!exp) return 0;
 	if (!exp) return 0;
 	
 	
 	if (sd->status.guild_id == 0 ||
 	if (sd->status.guild_id == 0 ||
-		(g = guild_search(sd->status.guild_id)) == NULL ||
+		(g = sd->guild) == NULL ||
 		(per = guild_getposition(g,sd)) < 0 ||
 		(per = guild_getposition(g,sd)) < 0 ||
 		(per = g->position[per].exp_mode) < 1)
 		(per = g->position[per].exp_mode) < 1)
 		return 0;
 		return 0;
@@ -1226,7 +1280,7 @@ int guild_getexp(struct map_session_data *sd,int exp)
 	struct guild_expcache *c;
 	struct guild_expcache *c;
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	if (sd->status.guild_id == 0 || guild_search(sd->status.guild_id) == NULL)
+	if (sd->status.guild_id == 0 || sd->guild == NULL)
 		return 0;
 		return 0;
 
 
 	c = db_data2ptr(guild_expcache_db->ensure(guild_expcache_db, db_i2key(sd->status.char_id), create_expcache, sd));
 	c = db_data2ptr(guild_expcache_db->ensure(guild_expcache_db, db_i2key(sd->status.char_id), create_expcache, sd));
@@ -1249,7 +1303,7 @@ int guild_skillup(TBL_PC* sd, uint16 skill_id)
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
 	if( idx < 0 || idx >= MAX_GUILDSKILL || // not a guild skill
 	if( idx < 0 || idx >= MAX_GUILDSKILL || // not a guild skill
-			sd->status.guild_id == 0 || (g=guild_search(sd->status.guild_id)) == NULL || // no guild
+			sd->status.guild_id == 0 || (g=sd->guild) == NULL || // no guild
 			strcmp(sd->status.name, g->master) ) // not the guild master
 			strcmp(sd->status.name, g->master) ) // not the guild master
 		return 0;
 		return 0;
 
 
@@ -1380,8 +1434,8 @@ int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd)
 	if(tsd==NULL || tsd->status.guild_id<=0)
 	if(tsd==NULL || tsd->status.guild_id<=0)
 		return 0;
 		return 0;
 
 
-	g[0]=guild_search(sd->status.guild_id);
-	g[1]=guild_search(tsd->status.guild_id);
+	g[0]=sd->guild;
+	g[1]=tsd->guild;
 
 
 	if(g[0]==NULL || g[1]==NULL)
 	if(g[0]==NULL || g[1]==NULL)
 		return 0;
 		return 0;
@@ -1433,15 +1487,15 @@ int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag)
 		return 0;
 		return 0;
 	}
 	}
 
 
-    if (sd->guild_alliance != tsd->status.guild_id) // proposed guild_id alliance doesn't match tsd guildid
+	if (sd->guild_alliance != tsd->status.guild_id) // proposed guild_id alliance doesn't match tsd guildid
 		return 0;
 		return 0;
 
 
-    if (flag == 1) { // consent
+	if (flag == 1) { // consent
 		int i;
 		int i;
 
 
-        struct guild *g, *tg; // Reconfirm the number of alliance
-		g=guild_search(sd->status.guild_id);
-		tg=guild_search(tsd->status.guild_id);
+	struct guild *g, *tg; // Reconfirm the number of alliance
+		g=sd->guild;
+		tg=tsd->guild;
 		
 		
 		if(g==NULL || guild_get_alliance_count(g,0) >= battle_config.max_guild_alliance){
 		if(g==NULL || guild_get_alliance_count(g,0) >= battle_config.max_guild_alliance){
 			clif_guild_allianceack(sd,4);
 			clif_guild_allianceack(sd,4);
@@ -1467,11 +1521,11 @@ int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag)
 					tsd->status.account_id,sd->status.account_id,9 );
 					tsd->status.account_id,sd->status.account_id,9 );
 		}
 		}
 
 
-        // inform other servers
+	// inform other servers
 		intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
 		intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
 			sd->status.account_id,tsd->status.account_id,0 );
 			sd->status.account_id,tsd->status.account_id,0 );
 		return 0;
 		return 0;
-    } else { // deny
+	} else { // deny
 		sd->guild_alliance=0;
 		sd->guild_alliance=0;
 		sd->guild_alliance_account=0;
 		sd->guild_alliance_account=0;
 		if(tsd!=NULL)
 		if(tsd!=NULL)
@@ -1506,7 +1560,7 @@ int guild_opposition(struct map_session_data *sd,struct map_session_data *tsd)
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	g=guild_search(sd->status.guild_id);
+	g=sd->guild;
 	if(g==NULL || tsd==NULL)
 	if(g==NULL || tsd==NULL)
 		return 0;
 		return 0;
 
 
@@ -1683,6 +1737,7 @@ int guild_broken(int guild_id,int flag)
 			if(sd->state.storage_flag == 2)
 			if(sd->state.storage_flag == 2)
 				storage_guild_storage_quit(sd,1);
 				storage_guild_storage_quit(sd,1);
 			sd->status.guild_id=0;
 			sd->status.guild_id=0;
+			sd->guild = NULL;
 			clif_guild_broken(g->member[i].sd,0);
 			clif_guild_broken(g->member[i].sd,0);
 			clif_charnameupdate(sd); // [LuzZza]
 			clif_charnameupdate(sd); // [LuzZza]
 		}
 		}
@@ -1691,6 +1746,11 @@ int guild_broken(int guild_id,int flag)
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
 	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
 	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
 	guild_storage_delete(guild_id);
 	guild_storage_delete(guild_id);
+	if( raChSys.ally ) {
+		if( g->channel != NULL ) {
+			clif_chsys_delete(( struct raChSysCh * )g->channel);
+		}
+	}
 	idb_remove(guild_db,guild_id);
 	idb_remove(guild_db,guild_id);
 	return 0;
 	return 0;
 }
 }
@@ -1743,14 +1803,12 @@ int guild_gm_changed(int guild_id, int account_id, int char_id)
 	g->member[0].position = 0; //Position 0: guild Master.
 	g->member[0].position = 0; //Position 0: guild Master.
 	strcpy(g->master, g->member[0].name);
 	strcpy(g->master, g->member[0].name);
 
 
-	if (g->member[pos].sd && g->member[pos].sd->fd)
-	{
+	if (g->member[pos].sd && g->member[pos].sd->fd) {
 		clif_displaymessage(g->member[pos].sd->fd, msg_txt(678)); //"You no longer are the Guild Master."
 		clif_displaymessage(g->member[pos].sd->fd, msg_txt(678)); //"You no longer are the Guild Master."
 		g->member[pos].sd->state.gmaster_flag = 0;
 		g->member[pos].sd->state.gmaster_flag = 0;
 	}
 	}
 	
 	
-	if (g->member[0].sd && g->member[0].sd->fd)
-	{
+	if (g->member[0].sd && g->member[0].sd->fd) {
 		clif_displaymessage(g->member[0].sd->fd, msg_txt(679)); //"You have become the Guild Master!"
 		clif_displaymessage(g->member[0].sd->fd, msg_txt(679)); //"You have become the Guild Master!"
 		g->member[0].sd->state.gmaster_flag = g;
 		g->member[0].sd->state.gmaster_flag = g;
 		//Block his skills for 5 minutes to prevent abuse.
 		//Block his skills for 5 minutes to prevent abuse.
@@ -1780,7 +1838,7 @@ int guild_break(struct map_session_data *sd,char *name)
 
 
 	nullpo_ret(sd);
 	nullpo_ret(sd);
 
 
-	if( (g=guild_search(sd->status.guild_id))==NULL )
+	if( (g=sd->guild)==NULL )
 		return 0;
 		return 0;
 	if(strcmp(g->name,name)!=0)
 	if(strcmp(g->name,name)!=0)
 		return 0;
 		return 0;
@@ -2136,12 +2194,21 @@ void do_init_guild(void) {
 }
 }
 
 
 void do_final_guild(void) {
 void do_final_guild(void) {
-	
+	DBIterator *iter = db_iterator(guild_db);
+	struct guild *g;
+
+	for( g = dbi_first(iter); dbi_exists(iter); g = dbi_next(iter) ) {
+		if( g->channel != NULL )
+			clif_chsys_delete((struct raChSysCh *)g->channel);
+	}
+
+	dbi_destroy(iter);
+
 	db_destroy(guild_db);
 	db_destroy(guild_db);
 	castle_db->destroy(castle_db,guild_castle_db_final);
 	castle_db->destroy(castle_db,guild_castle_db_final);
 	guild_expcache_db->destroy(guild_expcache_db,guild_expcache_db_final);
 	guild_expcache_db->destroy(guild_expcache_db,guild_expcache_db_final);
 	guild_infoevent_db->destroy(guild_infoevent_db,eventlist_db_final);
 	guild_infoevent_db->destroy(guild_infoevent_db,eventlist_db_final);
 	ers_destroy(expcache_ers);
 	ers_destroy(expcache_ers);
-			
+		
 	aFree(guild_flags);/* never empty; created on boot */
 	aFree(guild_flags);/* never empty; created on boot */
 }
 }

+ 1 - 6
src/map/intif.c

@@ -170,10 +170,7 @@ int intif_broadcast(const char* mes, int len, int type)
 int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY)
 int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY)
 {
 {
 	// Send to the local players
 	// Send to the local players
-	if (fontColor == 0xFE000000) // This is main chat message [LuzZza]
-		clif_MainChatMessage(mes);
-	else
-		clif_broadcast2(NULL, mes, len, fontColor, fontType, fontSize, fontAlign, fontY, ALL_CLIENT);
+	clif_broadcast2(NULL, mes, len, fontColor, fontType, fontSize, fontAlign, fontY, ALL_CLIENT);
 
 
 	if (CheckForCharServer())
 	if (CheckForCharServer())
 		return 0;
 		return 0;
@@ -2183,8 +2180,6 @@ int intif_parse(int fd)
 	case 0x3800:
 	case 0x3800:
 		if (RFIFOL(fd,4) == 0xFF000000) //Normal announce.
 		if (RFIFOL(fd,4) == 0xFF000000) //Normal announce.
 			clif_broadcast(NULL, (char *) RFIFOP(fd,16), packet_len-16, 0, ALL_CLIENT);
 			clif_broadcast(NULL, (char *) RFIFOP(fd,16), packet_len-16, 0, ALL_CLIENT);
-		else if (RFIFOL(fd,4) == 0xFE000000) //Main chat message [LuzZza]
-			clif_MainChatMessage((char *)RFIFOP(fd,16));
 		else //Color announce.
 		else //Color announce.
 			clif_broadcast2(NULL, (char *) RFIFOP(fd,16), packet_len-16, RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), ALL_CLIENT);
 			clif_broadcast2(NULL, (char *) RFIFOP(fd,16), packet_len-16, RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), ALL_CLIENT);
 		break;
 		break;

+ 26 - 9
src/map/map.c

@@ -81,10 +81,6 @@ char log_db_pw[32] = "ragnarok";
 char log_db_db[32] = "log";
 char log_db_db[32] = "log";
 Sql* logmysql_handle;
 Sql* logmysql_handle;
 
 
-// This param using for sending mainchat
-// messages like whispers to this nick. [LuzZza]
-char main_chat_nick[16] = "Main";
-
 // DBMap declaartion
 // DBMap declaartion
 static DBMap* id_db=NULL; // int id -> struct block_list*
 static DBMap* id_db=NULL; // int id -> struct block_list*
 static DBMap* pc_db=NULL; // int id -> struct map_session_data*
 static DBMap* pc_db=NULL; // int id -> struct map_session_data*
@@ -1698,10 +1694,33 @@ int map_quit(struct map_session_data *sd) {
 		unit_remove_map(&sd->ed->bl,CLR_TELEPORT);
 		unit_remove_map(&sd->ed->bl,CLR_TELEPORT);
 	}
 	}
 
 
+	if( raChSys.ally && sd->status.guild_id ) {
+		struct guild *g = sd->guild, *sg;
+		if( g ) {
+			if( idb_exists(((struct raChSysCh *)g->channel)->users, sd->status.char_id) )
+				clif_chsys_left((struct raChSysCh *)g->channel,sd);
+			for (i = 0; i < MAX_GUILDALLIANCE; i++) {
+				if( g->alliance[i].guild_id && (sg = guild_search(g->alliance[i].guild_id) ) ) {
+					if( idb_exists(((struct raChSysCh *)sg->channel)->users, sd->status.char_id) )
+						clif_chsys_left((struct raChSysCh *)sg->channel,sd);
+					break;
+				}
+			}
+		}
+	}
+
+	if( sd->channel_count ) {
+		for( i = 0; i < sd->channel_count; i++ ) {
+			if( sd->channels[i] != NULL )
+				clif_chsys_left(sd->channels[i],sd);
+		}
+		if( raChSys.closing )
+			aFree(sd->channels);
+	}
+
 	unit_remove_map_pc(sd,CLR_TELEPORT);
 	unit_remove_map_pc(sd,CLR_TELEPORT);
 
 
-	if( map[sd->bl.m].instance_id )
-	{ // Avoid map conflicts and warnings on next login
+	if( map[sd->bl.m].instance_id ) { // Avoid map conflicts and warnings on next login
 		int16 m;
 		int16 m;
 		struct point *pt;
 		struct point *pt;
 		if( map[sd->bl.m].save.map )
 		if( map[sd->bl.m].save.map )
@@ -3354,9 +3373,6 @@ int inter_config_read(char *cfgName)
 		if( sscanf(line,"%[^:]: %[^\r\n]",w1,w2) < 2 )
 		if( sscanf(line,"%[^:]: %[^\r\n]",w1,w2) < 2 )
 			continue;
 			continue;
 
 
-		if(strcmpi(w1, "main_chat_nick")==0)
-			safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
-		else
 		if(strcmpi(w1,"item_db_db")==0)
 		if(strcmpi(w1,"item_db_db")==0)
 			strcpy(item_db_db,w2);
 			strcpy(item_db_db,w2);
 		else
 		else
@@ -3553,6 +3569,7 @@ void do_final(void)
 	struct s_mapiterator* iter;
 	struct s_mapiterator* iter;
 
 
 	ShowStatus("Terminating...\n");
 	ShowStatus("Terminating...\n");
+	raChSys.closing = true;
 
 
 	//Ladies and babies first.
 	//Ladies and babies first.
 	iter = mapit_getallusers();
 	iter = mapit_getallusers();

+ 5 - 2
src/map/map.h

@@ -20,6 +20,7 @@
 
 
 struct npc_data;
 struct npc_data;
 struct item_data;
 struct item_data;
+struct raChSysCh;
 
 
 enum E_MAPSERVER_ST
 enum E_MAPSERVER_ST
 {
 {
@@ -573,6 +574,7 @@ struct map_data {
 		unsigned guildlock :1;
 		unsigned guildlock :1;
 		unsigned src4instance : 1; // To flag this map when it's used as a src map for instances
 		unsigned src4instance : 1; // To flag this map when it's used as a src map for instances
 		unsigned reset :1; // [Daegaladh]
 		unsigned reset :1; // [Daegaladh]
+		unsigned chsysnolocalaj : 1;
 	} flag;
 	} flag;
 	struct point save;
 	struct point save;
 	struct npc_data *npc[MAX_NPC_PER_MAP];
 	struct npc_data *npc[MAX_NPC_PER_MAP];
@@ -598,6 +600,9 @@ struct map_data {
 	// Instance Variables
 	// Instance Variables
 	int instance_id;
 	int instance_id;
 	int instance_src_map;
 	int instance_src_map;
+
+	/* rAthena Local Chat */
+	struct raChSysCh *channel;
 };
 };
 
 
 /// Stores information about a remote map (for multi-mapserver setups).
 /// Stores information about a remote map (for multi-mapserver setups).
@@ -775,8 +780,6 @@ typedef struct elemental_data	TBL_ELEM;
 	( ((bl) == (struct block_list*)NULL || (bl)->type != (type_)) ? (T ## type_ *)NULL : (T ## type_ *)(bl) )
 	( ((bl) == (struct block_list*)NULL || (bl)->type != (type_)) ? (T ## type_ *)NULL : (T ## type_ *)(bl) )
 
 
 
 
-extern char main_chat_nick[16];
-
 #ifdef BETA_THREAD_TEST
 #ifdef BETA_THREAD_TEST
 
 
 extern char default_codepage[32];
 extern char default_codepage[32];

+ 2 - 0
src/map/npc.c

@@ -3424,6 +3424,8 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
 		map[m].flag.guildlock=state;
 		map[m].flag.guildlock=state;
 	else if (!strcmpi(w3,"reset"))
 	else if (!strcmpi(w3,"reset"))
 		map[m].flag.reset=state;
 		map[m].flag.reset=state;
+	else if (!strcmpi(w3,"nomapchannelautojoin"))
+		map[m].flag.chsysnolocalaj = state;
 	else
 	else
 		ShowError("npc_parse_mapflag: unrecognized mapflag '%s' (file '%s', line '%d').\n", w3, filepath, strline(buffer,start-buffer));
 		ShowError("npc_parse_mapflag: unrecognized mapflag '%s' (file '%s', line '%d').\n", w3, filepath, strline(buffer,start-buffer));
 
 

+ 9 - 9
src/map/pc.c

@@ -1228,8 +1228,7 @@ int pc_reg_received(struct map_session_data *sd)
 	intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
 	intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
 	intif_request_questlog(sd);
 	intif_request_questlog(sd);
 
 
-	if (sd->state.connect_new == 0 && sd->fd)
-	{	//Character already loaded map! Gotta trigger LoadEndAck manually.
+	if (sd->state.connect_new == 0 && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually.
 		sd->state.connect_new = 1;
 		sd->state.connect_new = 1;
 		clif_parse_LoadEndAck(sd->fd, sd);
 		clif_parse_LoadEndAck(sd->fd, sd);
 	}
 	}
@@ -4743,6 +4742,10 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
 			clif_displaymessage (sd->fd, msg_txt(276)); // "You can't open a shop on this map"
 			clif_displaymessage (sd->fd, msg_txt(276)); // "You can't open a shop on this map"
 			vending_closevending(sd);
 			vending_closevending(sd);
 		}
 		}
+
+		if( raChSys.local && map[sd->bl.m].channel && idb_exists(map[sd->bl.m].channel->users, sd->status.char_id) ) {
+			clif_chsys_left(map[sd->bl.m].channel,sd);
+		}
 	}
 	}
 
 
 	if( m < 0 )
 	if( m < 0 )
@@ -4924,16 +4927,13 @@ int pc_memo(struct map_session_data* sd, int pos)
 int pc_checkskill(struct map_session_data *sd,uint16 skill_id)
 int pc_checkskill(struct map_session_data *sd,uint16 skill_id)
 {
 {
 	if(sd == NULL) return 0;
 	if(sd == NULL) return 0;
-	if( skill_id >= GD_SKILLBASE && skill_id < GD_MAX )
-	{
+	if( skill_id >= GD_SKILLBASE && skill_id < GD_MAX ) {
 		struct guild *g;
 		struct guild *g;
 
 
-		if( sd->status.guild_id>0 && (g=guild_search(sd->status.guild_id))!=NULL)
+		if( sd->status.guild_id>0 && (g=sd->guild)!=NULL)
 			return guild_checkskill(g,skill_id);
 			return guild_checkskill(g,skill_id);
 		return 0;
 		return 0;
-	}
-	else if(skill_id >= ARRAYLENGTH(sd->status.skill) )
-	{
+	} else if(skill_id >= ARRAYLENGTH(sd->status.skill) ) {
 		ShowError("pc_checkskill: Invalid skill id %d (char_id=%d).\n", skill_id, sd->status.char_id);
 		ShowError("pc_checkskill: Invalid skill id %d (char_id=%d).\n", skill_id, sd->status.char_id);
 		return 0;
 		return 0;
 	}
 	}
@@ -8570,7 +8570,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos)
 	}
 	}
 	if(pos & EQP_SHOES)
 	if(pos & EQP_SHOES)
 		clif_changelook(&sd->bl,LOOK_SHOES,0);
 		clif_changelook(&sd->bl,LOOK_SHOES,0);
-	if(pos&EQP_GARMENT) {
+	if(pos&EQP_GARMENT && pc_checkequip(sd,EQP_COSTUME_GARMENT) == -1) {
 		sd->status.robe = id ? id->look : 0;
 		sd->status.robe = id ? id->look : 0;
 		clif_changelook(&sd->bl, LOOK_ROBE, sd->status.robe);
 		clif_changelook(&sd->bl, LOOK_ROBE, sd->status.robe);
 	}
 	}

+ 8 - 1
src/map/pc.h

@@ -136,7 +136,6 @@ struct map_session_data {
 		unsigned int showdelay :1;
 		unsigned int showdelay :1;
 		unsigned int showexp :1;
 		unsigned int showexp :1;
 		unsigned int showzeny :1;
 		unsigned int showzeny :1;
-		unsigned int mainchat :1; //[LuzZza]
 		unsigned int noask :1; // [LuzZza]
 		unsigned int noask :1; // [LuzZza]
 		unsigned int trading :1; //[Skotlex] is 1 only after a trade has started.
 		unsigned int trading :1; //[Skotlex] is 1 only after a trade has started.
 		unsigned int deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE
 		unsigned int deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE
@@ -386,6 +385,7 @@ struct map_session_data {
 	int party_invite, party_invite_account; // for handling party invitation (holds party id and account id)
 	int party_invite, party_invite_account; // for handling party invitation (holds party id and account id)
 	int adopt_invite; // Adoption
 	int adopt_invite; // Adoption
 
 
+	struct guild *guild; // [Ind] speed everything up
 	int guild_invite,guild_invite_account;
 	int guild_invite,guild_invite_account;
 	int guild_emblem_id,guild_alliance,guild_alliance_account;
 	int guild_emblem_id,guild_alliance,guild_alliance_account;
 	short guild_x,guild_y; // For guildmate position display. [Skotlex] should be short [zzo]
 	short guild_x,guild_y; // For guildmate position display. [Skotlex] should be short [zzo]
@@ -496,6 +496,13 @@ struct map_session_data {
 
 
 	int shadowform_id;
 	int shadowform_id;
 
 
+	/* Channel System [Ind] */
+	struct raChSysCh **channels;
+	unsigned char channel_count;
+	struct raChSysCh *gcbind;
+	bool stealth;
+	unsigned char fontcolor; /* debug-only */
+
 	// temporary debugging of bug #3504
 	// temporary debugging of bug #3504
 	const char* delunit_prevfile;
 	const char* delunit_prevfile;
 	int delunit_prevline;
 	int delunit_prevline;

+ 5 - 3
src/map/pc_groups.h

@@ -39,10 +39,11 @@ enum e_pc_permission {
 	PC_PERM_USE_CHANGEMAPTYPE   = 0x004000,
 	PC_PERM_USE_CHANGEMAPTYPE   = 0x004000,
 	PC_PERM_USE_ALL_COMMANDS    = 0x008000,
 	PC_PERM_USE_ALL_COMMANDS    = 0x008000,
 	PC_PERM_RECEIVE_REQUESTS    = 0x010000,
 	PC_PERM_RECEIVE_REQUESTS    = 0x010000,
-	PC_PERM_SHOW_BOSS			= 0x020000,
-	PC_PERM_DISABLE_PVM			= 0x040000,
-	PC_PERM_DISABLE_PVP			= 0x080000,
+	PC_PERM_SHOW_BOSS           = 0x020000,
+	PC_PERM_DISABLE_PVM         = 0x040000,
+	PC_PERM_DISABLE_PVP         = 0x080000,
 	PC_PERM_DISABLE_CMD_DEAD    = 0x100000,
 	PC_PERM_DISABLE_CMD_DEAD    = 0x100000,
+	PC_PERM_CHANNEL_ADMIN       = 0x200000,
 };
 };
 
 
 static const struct {
 static const struct {
@@ -70,6 +71,7 @@ static const struct {
 	{ "disable_pvm", PC_PERM_DISABLE_PVM },
 	{ "disable_pvm", PC_PERM_DISABLE_PVM },
 	{ "disable_pvp", PC_PERM_DISABLE_PVP },
 	{ "disable_pvp", PC_PERM_DISABLE_PVP },
 	{ "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD },
 	{ "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD },
+	{ "channel_admin", PC_PERM_CHANNEL_ADMIN },
 };
 };
 
 
 #endif // _PC_GROUPS_H_
 #endif // _PC_GROUPS_H_

+ 6 - 12
src/map/script.c

@@ -7259,22 +7259,16 @@ BUILDIN_FUNC(strcharinfo)
 			script_pushstrcopy(st,sd->status.name);
 			script_pushstrcopy(st,sd->status.name);
 			break;
 			break;
 		case 1:
 		case 1:
-			if( ( p = party_search(sd->status.party_id) ) != NULL )
-			{
+			if( ( p = party_search(sd->status.party_id) ) != NULL ) {
 				script_pushstrcopy(st,p->party.name);
 				script_pushstrcopy(st,p->party.name);
-			}
-			else
-			{
+			} else {
 				script_pushconststr(st,"");
 				script_pushconststr(st,"");
 			}
 			}
 			break;
 			break;
 		case 2:
 		case 2:
-			if( ( g = guild_search(sd->status.guild_id) ) != NULL )
-			{
+			if( ( g = guild_search(sd->status.guild_id) ) != NULL ) {
 				script_pushstrcopy(st,g->name);
 				script_pushstrcopy(st,g->name);
-			}
-			else
-			{
+			} else {
 				script_pushconststr(st,"");
 				script_pushconststr(st,"");
 			}
 			}
 			break;
 			break;
@@ -12973,7 +12967,7 @@ BUILDIN_FUNC(npctalk)
 		safestrncpy(name, nd->name, sizeof(name));
 		safestrncpy(name, nd->name, sizeof(name));
 		strtok(name, "#"); // discard extra name identifier if present
 		strtok(name, "#"); // discard extra name identifier if present
 		safesnprintf(message, sizeof(message), "%s : %s", name, str);
 		safesnprintf(message, sizeof(message), "%s : %s", name, str);
-		clif_message(&nd->bl, message);
+		clif_disp_overhead(&nd->bl, message);
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -15459,7 +15453,7 @@ BUILDIN_FUNC(unittalk)
 		struct StringBuf sbuf;
 		struct StringBuf sbuf;
 		StringBuf_Init(&sbuf);
 		StringBuf_Init(&sbuf);
 		StringBuf_Printf(&sbuf, "%s : %s", status_get_name(bl), message);
 		StringBuf_Printf(&sbuf, "%s : %s", status_get_name(bl), message);
-		clif_message(bl, StringBuf_Value(&sbuf));
+		clif_disp_overhead(bl, StringBuf_Value(&sbuf));
 		if( bl->type == BL_PC )
 		if( bl->type == BL_PC )
 			clif_displaymessage(((TBL_PC*)bl)->fd, StringBuf_Value(&sbuf));
 			clif_displaymessage(((TBL_PC*)bl)->fd, StringBuf_Value(&sbuf));
 		StringBuf_Destroy(&sbuf);
 		StringBuf_Destroy(&sbuf);

+ 1 - 1
src/map/skill.c

@@ -5992,7 +5992,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			//NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches)
 			//NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches)
 			char temp[70];
 			char temp[70];
 			snprintf(temp, sizeof(temp), "%s : %s !!",md->name,skill_db[skill_id].desc);
 			snprintf(temp, sizeof(temp), "%s : %s !!",md->name,skill_db[skill_id].desc);
-			clif_message(&md->bl,temp);
+			clif_disp_overhead(&md->bl,temp);
 		}
 		}
 		break;
 		break;
 
 

Some files were not shown because too many files changed in this diff