Index: conf/msg_conf/map_msg.conf =================================================================== --- conf/msg_conf/map_msg.conf (revision 17267) +++ conf/msg_conf/map_msg.conf (working copy) @@ -1457,6 +1457,7 @@ 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'. +1436: Channel pass can't be higher then %d. //Custom translations //import: conf/msg_conf/import/map_msg_eng_conf.txt Index: src/map/unit.c =================================================================== --- src/map/unit.c (revision 17267) +++ src/map/unit.c (working copy) @@ -18,6 +18,7 @@ #include "mercenary.h" #include "elemental.h" #include "skill.h" +#include "channel.h" #include "clif.h" #include "duel.h" #include "npc.h" @@ -2294,31 +2295,8 @@ if( sd->duel_invite > 0 ) duel_reject(sd->duel_invite, sd); - 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; - } - } - } - } + channel_pcquit(sd,0xF); //leave all chan - if( sd->channel_count ) { - uint8 ch_count = sd->channel_count; - for( i = 0; i < ch_count; i++ ) { - if( sd->channels[i] != NULL ) - clif_chsys_left(sd->channels[i],sd); - } - if( raChSys.closing ) - aFree(sd->channels); - } - // Notify friends that this char logged out. [Skotlex] map_foreachpc(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0); party_send_logout(sd); Index: src/map/status.c =================================================================== --- src/map/status.c (revision 17267) +++ src/map/status.c (working copy) @@ -10091,7 +10091,7 @@ int hp = rnd()%600 + 200; struct block_list* src = map_id2bl(sce->val2); if( src && bl && bl->type == BL_MOB ){ - mob_log_damage( (TBL_MOB*)bl, src, sd || hp < status->hp ? hp : status->hp - 1 ); + mob_log_damage( (TBL_MOB*)bl, src, sd || hp < status->hp ? hp : status->hp - 1 ); } map_freeblock_lock(); status_fix_damage(src, bl, sd||hphp?hp:status->hp-1, 1); Index: src/map/Makefile.in =================================================================== --- src/map/Makefile.in (revision 17267) +++ src/map/Makefile.in (working copy) @@ -17,7 +17,7 @@ storage.o skill.o atcommand.o battle.o battleground.o \ intif.o trade.o party.o vending.o guild.o pet.o \ log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \ - buyingstore.o searchstore.o duel.o pc_groups.o elemental.o cashshop.o + buyingstore.o searchstore.o duel.o pc_groups.o elemental.o cashshop.o channel.o MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \ obj_sql/mapreg_sql.o MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ @@ -25,7 +25,7 @@ storage.h skill.h atcommand.h battle.h battleground.h \ intif.h trade.h party.h vending.h guild.h pet.h \ log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \ - buyingstore.h searchstore.h duel.h pc_groups.h elemental.h cashshop.h \ + buyingstore.h searchstore.h duel.h pc_groups.h elemental.h cashshop.h channel.h\ ../config/core.h ../config/renewal.h ../config/secure.h ../config/const.h \ ../config/classes/general.h @@ -91,10 +91,10 @@ # missing object files ../common/obj_all/common.a: @$(MAKE) -C ../common sql - + ../common/obj_sql/common_sql.a: @$(MAKE) -C ../common sql - + MT19937AR_OBJ: @$(MAKE) -C ../../3rdparty/mt19937ar Index: src/map/pc.c =================================================================== --- src/map/pc.c (revision 17267) +++ src/map/pc.c (working copy) @@ -16,6 +16,7 @@ #include "atcommand.h" // get_atcommand_level() #include "battle.h" // battle_config #include "battleground.h" +#include "channel.h" #include "chrif.h" #include "clif.h" #include "date.h" // is_day_of_*() @@ -1249,7 +1250,7 @@ } clif_changeoption( &sd->bl ); - } + } return 1; } @@ -4782,9 +4783,7 @@ 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); - } + channel_pcquit(sd,4); //quit map chan } if( m < 0 ) @@ -9604,7 +9603,7 @@ FILE *fp; char line[24000],*p; - //reset + //reset memset(exp_table,0,sizeof(exp_table)); memset(max_level,0,sizeof(max_level)); @@ -9651,7 +9650,7 @@ //Reverse check in case the array has a bunch of trailing zeros... [Skotlex] //The reasoning behind the -2 is this... if the max level is 5, then the array //should look like this: - //0: x, 1: x, 2: x: 3: x 4: 0 <- last valid value is at 3. + //0: x, 1: x, 2: x: 3: x 4: 0 <- last valid value is at 3. while ((ui = max_level[job][type]) >= 2 && exp_table[job][type][ui-2] <= 0) max_level[job][type]--; if (max_level[job][type] < maxlv) { @@ -9762,7 +9761,7 @@ fclose(fp); ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","attr_fix.txt"); - // reset then read statspoint + // reset then read statspoint memset(statp,0,sizeof(statp)); i=1; Index: src/map/atcommand.c =================================================================== --- src/map/atcommand.c (revision 17267) +++ src/map/atcommand.c (working copy) @@ -17,6 +17,7 @@ #include "atcommand.h" #include "battle.h" #include "chat.h" +#include "channel.h" #include "clif.h" #include "chrif.h" #include "duel.h" @@ -5621,28 +5622,7 @@ status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0); } - // Leave all chat channels. - 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 ) { //quit all chan - uint8 count = sd->channel_count; - for( i = 0; i < count; i++ ) { - if( sd->channels[i] != NULL ) - clif_chsys_left(sd->channels[i],sd); - } - } + channel_pcquit(sd,0xF); //leave all chan clif_authfail_fd(sd->fd, 15); return 0; @@ -8782,251 +8762,113 @@ } /* 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(); +ACMD_FUNC(join){ + struct Channel *channel; + char chname[CHAN_NAME_LENGTH], pass[CHAN_NAME_LENGTH]; - if( !message || !*message || sscanf(message, "%s %s", name, pass) < 1 ) { + if( !message || !*message || sscanf(message, "%s %s", chname, pass) < 1 ) { sprintf(atcmd_output, msg_txt(sd,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(sd,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(sd,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(sd,1401),name,command); // '%s' Channel is password protected (usage: %s <#channel_name> ) - clif_displaymessage(fd, atcmd_output); - return -1; - } - } - - if( !( channel->opt & raChSys_OPT_ANNOUNCE_JOIN ) ) { - sprintf(atcmd_output, msg_txt(sd,1403),name); // You're now in the '%s' channel. - clif_displaymessage(fd, atcmd_output); - } - - clif_chsys_join(channel,sd); - - return 0; + return channel_pcjoin(sd, chname, pass); } -static inline void atcmd_channel_help(struct map_session_data *sd, const char *command, bool can_create) +static inline void atcmd_channel_help(struct map_session_data *sd, const char *command) { int fd = sd->fd; + bool can_delete = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN); + bool can_create = can_delete|Channel_Config.user_chenable; clif_displaymessage(fd, msg_txt(sd,1414));// ---- Available options: + + //option create if( can_create ) { sprintf(atcmd_output, msg_txt(sd,1415),command);// * %s create <#channel_name> clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1416));// -- Creates a new channel. } + + //option delete + if(can_delete){ + sprintf(atcmd_output, "* %s delete ",command);// * %s delete + clif_displaymessage(fd, atcmd_output); + clif_displaymessage(fd, "Force people leave and destroy the specified channel"); + } + + //option list sprintf(atcmd_output, msg_txt(sd,1417),command);// * %s list clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1418));// -- Lists all public channels. + sprintf(atcmd_output, "* %s list mine",command);// * %s list mine + clif_displaymessage(fd, atcmd_output); + clif_displaymessage(fd, "List all your joined channel"); if( can_create ) { sprintf(atcmd_output, msg_txt(sd,1419),command);// * %s list colors clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1420));// -- Lists all available colors for custom channels. + } + + //option setcolor + if(can_create){ sprintf(atcmd_output, msg_txt(sd,1421),command);// * %s setcolor <#channel_name> clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1422));// -- Changes channel text to the specified color (channel owners only). } + + //option join + sprintf(atcmd_output, "* %s join ",command);// * %s delete + clif_displaymessage(fd, atcmd_output); + clif_displaymessage(fd, "join specified channel"); + + //option leave sprintf(atcmd_output, msg_txt(sd,1423),command);// * %s leave <#channel_name> clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1424));// -- Leaves the specified channel. + + //option bindto sprintf(atcmd_output, msg_txt(sd,1427),command);// * %s bindto <#channel_name> clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1428));// -- Binds your global chat to the specified channel, sending all global messages to that channel. + + //option unbind sprintf(atcmd_output, msg_txt(sd,1429),command);// * %s unbind clif_displaymessage(fd, atcmd_output); clif_displaymessage(fd, msg_txt(sd,1430));// -- Unbinds your global chat from the attached channel, if any. + sprintf(atcmd_output, msg_txt(sd,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]; +ACMD_FUNC(channel) { + struct Channel *channel; + char key[CHAN_NAME_LENGTH], sub1[CHAN_NAME_LENGTH], sub2[CHAN_NAME_LENGTH], sub3[CHAN_NAME_LENGTH]; unsigned char k = 0; - DBMap* channel_db = clif_get_channel_db(); + DBMap* channel_db = channel_get_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(sd,command,( raChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) )); + atcmd_channel_help(sd,command); 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(sd,1405));// Channel name must start with '#'. - return -1; - } else if ( strlen(sub1) < 3 || strlen(sub1) > RACHSYS_NAME_LENGTH ) { - sprintf(atcmd_output, msg_txt(sd,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(sd,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(sd,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(sd,1403),sub1); // You're now in the '%s' channel. - clif_displaymessage(fd, atcmd_output); - } - - clif_chsys_join(channel,sd); - + if( strcmpi(key,"create") == 0 && ( Channel_Config.user_chenable || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) ) { + return channel_pccreate(sd,sub1,sub2); + } else if( strcmpi(key,"delete") == 0 && pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) { + return channel_pcdelete(sd,sub1); } 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; - bool show_all = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false; - clif_displaymessage(fd, msg_txt(sd,1410)); // ---- Public Channels ---- - if( raChSys.local ) { - sprintf(atcmd_output, msg_txt(sd,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(sd,1409), raChSys.ally_name, db_size(((struct raChSysCh *)g->channel)->users));// - #%s ( %d users ) - clif_displaymessage(fd, atcmd_output); - } - iter = db_iterator(channel_db); - for(channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) { - if( show_all || channel->type == raChSys_PUBLIC ) { - sprintf(atcmd_output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users) - clif_displaymessage(fd, atcmd_output); - } - } - dbi_destroy(iter); - } + return channel_display_list(sd,sub1); } else if ( strcmpi(key,"setcolor") == 0 ) { - - if( sub1[0] != '#' ) { - clif_displaymessage(fd, msg_txt(sd,1405));// Channel name must start with '#'. - return -1; - } - - if( !(channel = strdb_get(channel_db, sub1 + 1)) ) { - sprintf(atcmd_output, msg_txt(sd,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(sd,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(sd,1411), sub2);// Unknown color '%s'. - clif_displaymessage(fd, atcmd_output); - return -1; - } - channel->color = k; - sprintf(atcmd_output, msg_txt(sd,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(sd,1405));// Channel name must start with '#'. - return -1; - } - - ARR_FIND(0, sd->channel_count, k, strcmpi(sub1+1,sd->channels[k]->name) == 0); - if( k == sd->channel_count ) { - sprintf(atcmd_output, msg_txt(sd,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(sd,1426),sub1); // You've left the '%s' channel. - clif_displaymessage(fd, atcmd_output); + return channel_pccolor(sd, sub1, sub2); + } else if ( strcmpi(key,"join") == 0 ) { + return channel_pcjoin(sd, sub1, sub2); + }else if ( strcmpi(key,"leave") == 0 ) { + return channel_pcleave(sd, sub1); } else if ( strcmpi(key,"bindto") == 0 ) { - - if( sub1[0] != '#' ) { - clif_displaymessage(fd, msg_txt(sd,1405));// Channel name must start with '#'. - return -1; - } - - ARR_FIND(0, sd->channel_count, k, strcmpi(sub1+1,sd->channels[k]->name) == 0); - if( k == sd->channel_count ) { - sprintf(atcmd_output, msg_txt(sd,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(sd,1431),sub1); // Your global chat is now binded to the '%s' channel. - clif_displaymessage(fd, atcmd_output); + return channel_pcbind(sd, sub1); } else if ( strcmpi(key,"unbind") == 0 ) { - - if( sd->gcbind == NULL ) { - clif_displaymessage(fd, msg_txt(sd,1432));// Your global chat is not binded to any channel. - return -1; - } - - sprintf(atcmd_output, msg_txt(sd,1433),sd->gcbind->name); // Your global chat is now unbinded from the '#%s' channel. - clif_displaymessage(fd, atcmd_output); - - sd->gcbind = NULL; + return channel_pcunbind(sd); } else { - atcmd_channel_help(sd,command,( raChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) )); + atcmd_channel_help(sd,command); } return 0; @@ -9038,17 +8880,9 @@ 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); + for( k = 0; k < Channel_Config.colors_count; k++ ) { + sprintf(mout, "[ %s ] : %s",command,Channel_Config.colors_name[k]); + clif_colormes(sd,k,mout); } return -1; } @@ -9059,11 +8893,8 @@ return 0; } - for( k = 0; k < raChSys.colors_count; k++ ) { - if( strcmpi(message,raChSys.colors_name[k]) == 0 ) - break; - } - if( k == raChSys.colors_count ) { + ARR_FIND(0,Channel_Config.colors_count,k,( strcmpi(message,Channel_Config.colors_name[k]) == 0 )); + if( k == Channel_Config.colors_count ) { sprintf(atcmd_output, msg_txt(sd,1411), message);// Unknown color '%s'. clif_displaymessage(fd, atcmd_output); return -1; Index: src/map/pc.h =================================================================== --- src/map/pc.h (revision 17267) +++ src/map/pc.h (working copy) @@ -499,9 +499,9 @@ int shadowform_id; /* Channel System [Ind] */ - struct raChSysCh **channels; + struct Channel **channels; unsigned char channel_count; - struct raChSysCh *gcbind; + struct Channel *gcbind; bool stealth; unsigned char fontcolor; /* debug-only */ Index: src/map/clif.c =================================================================== --- src/map/clif.c (revision 17267) +++ src/map/clif.c (working copy) @@ -44,6 +44,7 @@ #include "mail.h" #include "quest.h" #include "cashshop.h" +#include "channel.h" #include #include @@ -53,8 +54,6 @@ /* for clif_clearunit_delayed */ static struct eri *delay_clearunit_ers; -static DBMap* channel_db; // channels -DBMap* clif_get_channel_db(void){ return channel_db; } //#define DUMP_UNKNOWN_PACKET //#define DUMP_INVALID_PACKET @@ -5490,52 +5489,11 @@ aFree(buf); } -/*========================================== - * Channel System - *------------------------------------------*/ -void clif_chsys_create(struct raChSysCh *channel, char *name, char *pass, unsigned char color) { - channel->users = idb_alloc(DB_OPT_BASE); - if( name ) - safestrncpy(channel->name, name, RACHSYS_NAME_LENGTH); - channel->color = color; - if( !pass ) - channel->pass[0] = '\0'; - else - safestrncpy(channel->pass, pass, RACHSYS_NAME_LENGTH); - - channel->opt = raChSys_OPT_BASE; - - if( channel->type != raChSys_MAP && channel->type != raChSys_ALLY ) - strdb_put(channel_db, channel->name, channel); -} - -void clif_chsys_join(struct raChSysCh *channel, struct map_session_data *sd) { - RECREATE(sd->channels, struct raChSysCh *, ++sd->channel_count); - sd->channels[ sd->channel_count - 1 ] = channel; - idb_put(channel->users, sd->status.char_id, sd); - - if( sd->stealth ) { - sd->stealth = false; - } else if( channel->opt & raChSys_OPT_ANNOUNCE_JOIN ) { - char message[60]; - sprintf(message, "#%s '%s' joined",channel->name,sd->status.name); - clif_chsys_msg(channel,sd,message); - } - - /* someone is cheating, we kindly disconnect the bastard */ - if( sd->channel_count > 200 ) { - set_eof(sd->fd); - } -} - -void clif_chsys_send(struct raChSysCh *channel, struct map_session_data *sd, char *msg) { - char message[150]; - snprintf(message, 150, "[ #%s ] %s : %s",channel->name,sd->status.name, msg); - clif_chsys_msg(channel,sd,message); -} - -void clif_chsys_msg(struct raChSysCh *channel, struct map_session_data *sd, char *msg) { - DBIterator *iter = db_iterator(channel->users); +/* + * Display *msg from *sd to all *users in channel + */ +void clif_channel_msg(struct Channel *channel, struct map_session_data *sd, char *msg) { + DBIterator *iter; struct map_session_data *user; unsigned short msg_len = strlen(msg) + 1; @@ -5543,9 +5501,10 @@ WFIFOW(sd->fd,0) = 0x2C1; WFIFOW(sd->fd,2) = msg_len + 12; WFIFOL(sd->fd,4) = 0; - WFIFOL(sd->fd,8) = raChSys.colors[channel->color]; + WFIFOL(sd->fd,8) = Channel_Config.colors[channel->color]; safestrncpy((char*)WFIFOP(sd->fd,12), msg, msg_len); + iter = db_iterator(channel->users); for( user = dbi_first(iter); dbi_exists(iter); user = dbi_next(iter) ) { if( user->fd == sd->fd ) continue; @@ -5553,231 +5512,11 @@ memcpy(WFIFOP(user->fd,0), WFIFOP(sd->fd,0), msg_len + 12); WFIFOSET(user->fd, msg_len + 12); } + dbi_destroy(iter); WFIFOSET(sd->fd, msg_len + 12); - - dbi_destroy(iter); } -void clif_chsys_mjoin(struct map_session_data *sd) { - if( !map[sd->bl.m].channel ) { - CREATE(map[sd->bl.m].channel, struct raChSysCh , 1); - safestrncpy(map[sd->bl.m].channel->name, raChSys.local_name, RACHSYS_NAME_LENGTH); - map[sd->bl.m].channel->type = raChSys_MAP; - map[sd->bl.m].channel->m = sd->bl.m; - - clif_chsys_create(map[sd->bl.m].channel,NULL,NULL,raChSys.local_color); - } - clif_chsys_join(map[sd->bl.m].channel,sd); - - if( !( map[sd->bl.m].channel->opt & raChSys_OPT_ANNOUNCE_JOIN ) ) { - char mout[60]; - sprintf(mout, msg_txt(sd,1435),raChSys.local_name,map[sd->bl.m].name); // You're now in the '#%s' channel for '%s'. - clif_disp_onlyself(sd, mout, strlen(mout)); - } -} - -void clif_chsys_left(struct raChSysCh *channel, struct map_session_data *sd) { - unsigned char i; - idb_remove(channel->users,sd->status.char_id); - - if( channel == sd->gcbind ) - sd->gcbind = NULL; - - if( !db_size(channel->users) && channel->type == raChSys_PRIVATE ) { - clif_chsys_delete(channel); - } else if( !raChSys.closing && (channel->opt & raChSys_OPT_ANNOUNCE_JOIN) ) { - char message[60]; - sprintf(message, "#%s '%s' left",channel->name,sd->status.name); - clif_chsys_msg(channel,sd,message); - } - - ARR_FIND(0, sd->channel_count, i, sd->channels[i] == channel); - if( i < sd->channel_count ) { - unsigned char cursor = 0; - sd->channels[i] = NULL; - for( i = 0; i < sd->channel_count; i++ ) { - if( sd->channels[i] == NULL ) - continue; - if( cursor != i ) - sd->channels[cursor] = sd->channels[i]; - cursor++; - } - if ( !(sd->channel_count = cursor) ) { - aFree(sd->channels); - sd->channels = NULL; - } - } - -} - -void clif_chsys_delete(struct raChSysCh *channel) { - if( db_size(channel->users) && !raChSys.closing ) { - struct map_session_data *sd; - unsigned char i; - DBIterator *iter = db_iterator(channel->users); - for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) ) { //for all users - ARR_FIND(0, sd->channel_count, i, sd->channels[i] == channel); //found cur chan - if( i < sd->channel_count ) { - unsigned char cursor = 0; - sd->channels[i] = NULL; - for( i = 0; i < sd->channel_count; i++ ) { //move down links - if( sd->channels[i] == NULL ) - continue; - if( cursor != i ) - sd->channels[cursor] = sd->channels[i]; - cursor++; - } - if ( !(sd->channel_count = cursor) ) { //news chan count = total - aFree(sd->channels); - sd->channels = NULL; - } - } - } - dbi_destroy(iter); - } - db_destroy(channel->users); - if( channel->m ) { - map[channel->m].channel = NULL; - aFree(channel); - } else if ( channel->type == raChSys_ALLY ) - aFree(channel); - else if( !raChSys.closing ) - strdb_remove(channel_db, channel->name); -} - -void clif_read_channels_config(void) { - config_t channels_conf; - config_setting_t *chsys = NULL; - const char *config_filename = "conf/channels.conf"; // FIXME hardcoded name - - if (conf_read_file(&channels_conf, config_filename)) - return; - - chsys = config_lookup(&channels_conf, "chsys"); - - if (chsys != NULL) { - config_setting_t *settings = config_setting_get_elem(chsys, 0); - config_setting_t *channels; - config_setting_t *colors; - int i,k; - const char *local_name, *ally_name, - *local_color, *ally_color; - int ally_enabled = 0, local_enabled = 0, - local_autojoin = 0, ally_autojoin = 0, - allow_user_channel_creation = 0; - - if( !config_setting_lookup_string(settings, "map_local_channel_name", &local_name) ) - local_name = "map"; - safestrncpy(raChSys.local_name, local_name, RACHSYS_NAME_LENGTH); - - if( !config_setting_lookup_string(settings, "ally_channel_name", &ally_name) ) - ally_name = "ally"; - safestrncpy(raChSys.ally_name, ally_name, RACHSYS_NAME_LENGTH); - - config_setting_lookup_bool(settings, "map_local_channel", &local_enabled); - config_setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled); - - if( local_enabled ) - raChSys.local = true; - if( ally_enabled ) - raChSys.ally = true; - - config_setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); - config_setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); - - if( local_autojoin ) - raChSys.local_autojoin = true; - if( ally_autojoin ) - raChSys.ally_autojoin = true; - - config_setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); - - if( allow_user_channel_creation ) - raChSys.allow_user_channel_creation = true; - - if( (colors = config_setting_get_member(settings, "colors")) != NULL ) { - int color_count = config_setting_length(colors); - CREATE( raChSys.colors, unsigned long, color_count ); - CREATE( raChSys.colors_name, char *, color_count ); - for(i = 0; i < color_count; i++) { - config_setting_t *color = config_setting_get_elem(colors, i); - - CREATE( raChSys.colors_name[i], char, RACHSYS_NAME_LENGTH ); - - safestrncpy(raChSys.colors_name[i], config_setting_name(color), RACHSYS_NAME_LENGTH); - - raChSys.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0); - raChSys.colors[i] = (raChSys.colors[i] & 0x0000FF) << 16 | (raChSys.colors[i] & 0x00FF00) | (raChSys.colors[i] & 0xFF0000) >> 16;//RGB to BGR - } - raChSys.colors_count = color_count; - } - - config_setting_lookup_string(settings, "map_local_channel_color", &local_color); - - for (k = 0; k < raChSys.colors_count; k++) { - if( strcmpi(raChSys.colors_name[k],local_color) == 0 ) - break; - } - - if( k < raChSys.colors_count ) { - raChSys.local_color = k; - } else { - ShowError("channels.conf: unknown color '%s' for channel 'map_local_channel_color', disabling '#%s'...\n",local_color,local_name); - raChSys.local = false; - } - - config_setting_lookup_string(settings, "ally_channel_color", &ally_color); - - for (k = 0; k < raChSys.colors_count; k++) { - if( strcmpi(raChSys.colors_name[k],ally_color) == 0 ) - break; - } - - if( k < raChSys.colors_count ) { - raChSys.ally_color = k; - } else { - ShowError("channels.conf: unknown color '%s' for channel 'ally_channel_color', disabling '#%s'...\n",local_color,ally_name); - raChSys.ally = false; - } - - if( (channels = config_setting_get_member(settings, "default_channels")) != NULL ) { - int channel_count = config_setting_length(channels); - - for(i = 0; i < channel_count; i++) { - config_setting_t *channel = config_setting_get_elem(channels, i); - const char *name = config_setting_name(channel); - const char *color = config_setting_get_string_elem(channels,i); - struct raChSysCh *chd; - - for (k = 0; k < raChSys.colors_count; k++) { - if( strcmpi(raChSys.colors_name[k],color) == 0 ) - break; - } - if( k == raChSys.colors_count ) { - ShowError("channels.conf: unknown color '%s' for channel '%s', skipping channel...\n",color,name); - continue; - } - if( strcmpi(name,raChSys.local_name) == 0 || strcmpi(name,raChSys.ally_name) == 0 || strdb_exists(channel_db, name) ) { - ShowError("channels.conf: duplicate channel '%s', skipping channel...\n",name); - continue; - - } - CREATE( chd, struct raChSysCh, 1 ); - - safestrncpy(chd->name, name, RACHSYS_NAME_LENGTH); - chd->type = raChSys_PUBLIC; - - clif_chsys_create(chd,NULL,NULL,k); - } - } - - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' channels in '"CL_WHITE"%s"CL_RESET"'.\n", db_size(channel_db), config_filename); - config_destroy(&channels_conf); - } -} - - /// Displays heal effect (ZC_RECOVERY). /// 013d .W .W /// var id: @@ -9564,8 +9303,8 @@ status_calc_pc(sd, false); // Some conditions are map-dependent so we must recalculate sd->state.changemap = false; - if( raChSys.local && raChSys.local_autojoin && !map[sd->bl.m].flag.chsysnolocalaj ) { - clif_chsys_mjoin(sd); + if( Channel_Config.map_enable && Channel_Config.map_autojoin && !map[sd->bl.m].flag.chmautojoin) { + channel_mjoin(sd); //join new map } } @@ -9867,23 +9606,12 @@ } if( sd->gcbind ) { - clif_chsys_send(sd->gcbind,sd,message); + channel_send(sd->gcbind,sd,message); return; } else if ( sd->fontcolor && !sd->chatID ) { char mout[200]; - unsigned char mylen = 1; - - mylen += snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message); - - WFIFOHEAD(fd,mylen + 12); - WFIFOW(fd,0) = 0x2C1; - WFIFOW(fd,2) = mylen + 12; - WFIFOL(fd,4) = sd->bl.id; - WFIFOL(fd,8) = raChSys.colors[sd->fontcolor - 1]; - safestrncpy((char*)WFIFOP(fd,12), mout, mylen); - clif_send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, AREA_WOS); - WFIFOL(fd,4) = -sd->bl.id; - WFIFOSET(fd, mylen + 12); + snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message); + clif_colormes(sd,sd->fontcolor-1,mout); return; } @@ -10256,30 +9984,32 @@ return; } } else if( target[0] == '#' ) { - struct raChSysCh *channel = NULL; + struct Channel *channel = NULL; char* chname = target; - chname++; - - if( raChSys.local && strcmpi(chname, raChSys.local_name) == 0 ) { - if( !map[sd->bl.m].channel ) { - clif_chsys_mjoin(sd); - } + if(Channel_Config.map_enable + && (strcmpi(chname + 1,Channel_Config.map_chname) == 0)) { + if( !map[sd->bl.m].channel ) channel_mjoin(sd); channel = map[sd->bl.m].channel; - } else if( raChSys.ally && sd->status.guild_id && strcmpi(chname, raChSys.ally_name) == 0 ) { - struct guild *g = sd->guild; - if( !g ) return; - channel = (struct raChSysCh *)g->channel; } - if( channel || (channel = strdb_get(channel_db,chname)) ) { - unsigned char k; - ARR_FIND(0, sd->channel_count, k, sd->channels[k] == channel); - if( k < sd->channel_count ) { - clif_chsys_send(channel,sd,message); - } else if( channel->pass[0] == '\0' ) { - clif_chsys_join(channel,sd); - clif_chsys_send(channel,sd,message); - } else { + else if(Channel_Config.ally_enable + && (strcmpi(chname + 1,Channel_Config.ally_chname) == 0) + && sd->guild) { + struct guild *g=sd->guild; + if(g->channel == NULL) channel_gjoin(sd,3); + channel = g->channel; + } + else channel = channel_name2channel(chname); + + if(channel){ + if(channel_pc_haschan(sd,channel)>=0){ //we are in the chan + channel_send(channel,sd,message); + } + else if( channel->pass[0] == '\0' ) { //no pass needed + channel_join(channel,sd); + channel_send(channel,sd,message); + } + else { clif_displaymessage(fd, msg_txt(sd,1402)); //You're not in that channel, type '@join <#channel_name>' } return; @@ -17374,34 +17104,9 @@ add_timer_func_list(clif_delayquit, "clif_delayquit"); delay_clearunit_ers = ers_new(sizeof(struct block_list),"clif.c::delay_clearunit_ers",ERS_OPT_CLEAR); - - channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, RACHSYS_NAME_LENGTH); - raChSys.ally = raChSys.local = raChSys.ally_autojoin = raChSys.local_autojoin = false; - clif_read_channels_config(); - return 0; } void do_final_clif(void) { - DBIterator *iter = db_iterator(channel_db); - struct raChSysCh *channel; - unsigned char i; - - for( channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter) ) { - clif_chsys_delete(channel); - } - - dbi_destroy(iter); - - for(i = 0; i < raChSys.colors_count; i++) { - aFree(raChSys.colors_name[i]); - } - - if( raChSys.colors_count ) { - aFree(raChSys.colors_name); - aFree(raChSys.colors); - } - - db_destroy(channel_db); ers_destroy(delay_clearunit_ers); } Index: src/map/npc.c =================================================================== --- src/map/npc.c (revision 17267) +++ src/map/npc.c (working copy) @@ -2138,7 +2138,7 @@ return strchr(start,'\n');// skip and continue } - if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) { + if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) { ShowWarning("npc_parse_warp: coordinates %d/%d are out of bounds in map %s(%dx%d), in file '%s', line '%d'\n", x, y, map[m].name, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer)); } @@ -2209,7 +2209,7 @@ if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) { ShowWarning("npc_parse_shop: coordinates %d/%d are out of bounds in map %s(%dx%d), in file '%s', line '%d'\n", x, y, map[m].name, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer)); - } + } if( !strcasecmp(w2,"cashshop") ) type = CASHSHOP; @@ -3429,7 +3429,7 @@ else if (!strcmpi(w3,"reset")) map[m].flag.reset=state; else if (!strcmpi(w3,"nomapchannelautojoin")) - map[m].flag.chsysnolocalaj = state; + map[m].flag.chmautojoin = state; else ShowError("npc_parse_mapflag: unrecognized mapflag '%s' (file '%s', line '%d').\n", w3, filepath, strline(buffer,start-buffer)); Index: src/map/clif.h =================================================================== --- src/map/clif.h (revision 17267) +++ src/map/clif.h (working copy) @@ -6,7 +6,9 @@ #include "../common/cbasetypes.h" #include "../common/db.h" //dbmap + //#include "../common/mmo.h" +struct Channel; struct item; struct storage_data; struct guild_storage; @@ -775,56 +777,8 @@ unsigned long color_table[COLOR_MAX]; int clif_colormes(struct map_session_data * sd, enum clif_colors color, const char* msg); -/** - * Channel System - **/ -#define RACHSYS_NAME_LENGTH 20 +void clif_channel_msg(struct Channel *channel, struct map_session_data *sd, char *msg); -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; #endif /* _CLIF_H_ */ Index: src/map/battle.c =================================================================== --- src/map/battle.c (revision 17267) +++ src/map/battle.c (working copy) @@ -3460,7 +3460,7 @@ #ifdef RENEWAL if( flag.cri ){ - ATK_ADDRATE( sd->bonus.crit_atk_rate >= 100 ? sd->bonus.crit_atk_rate - 60 : 40 ); + ATK_ADDRATE( sd->bonus.crit_atk_rate >= 100 ? sd->bonus.crit_atk_rate - 60 : 40 ); } #endif Index: src/map/map.c =================================================================== --- src/map/map.c (revision 17267) +++ src/map/map.c (working copy) @@ -48,6 +48,8 @@ #include "log.h" #include "mail.h" #include "cashshop.h" +#include "channel.h" + #include #include #include @@ -1429,6 +1431,7 @@ nullpo_ret(item_data); + if(!map_searchrandfreecell(m,&x,&y,flags&2?1:0)) return 0; r=rnd(); @@ -3546,7 +3549,7 @@ struct s_mapiterator* iter; ShowStatus("Terminating...\n"); - raChSys.closing = true; + Channel_Config.closing = true; //Ladies and babies first. iter = mapit_getallusers(); @@ -3562,8 +3565,7 @@ ShowStatus("Cleaning up maps [%d/%d]: %s..."CL_CLL"\r", i+1, map_num, map[i].name); if (map[i].m >= 0) { map_foreachinmap(cleanup_sub, i, BL_ALL); - if( map[i].channel != NULL ) - clif_chsys_delete((struct raChSysCh *)map[i].channel); + channel_delete((struct Channel *)map[i].channel); } } ShowStatus("Cleaned up %d maps."CL_CLL"\n", map_num); @@ -3594,6 +3596,7 @@ do_final_duel(); do_final_elemental(); do_final_cashshop(); + do_final_channel(); //should be called after final guild map_db->destroy(map_db, map_db_final); @@ -3876,6 +3879,7 @@ do_init_atcommand(); do_init_battle(); do_init_instance(); + do_init_channel(); do_init_chrif(); do_init_clif(); do_init_script(); Index: src/map/map.h =================================================================== --- src/map/map.h (revision 17267) +++ src/map/map.h (working copy) @@ -17,7 +17,7 @@ struct npc_data; struct item_data; -struct raChSysCh; +struct Channel; enum E_MAPSERVER_ST { MAPSERVER_ST_RUNNING = CORE_ST_LAST, @@ -567,7 +567,7 @@ unsigned guildlock :1; unsigned src4instance : 1; // To flag this map when it's used as a src map for instances unsigned reset :1; // [Daegaladh] - unsigned chsysnolocalaj : 1; + unsigned chmautojoin : 1; //prevent to auto join map channel } flag; struct point save; struct npc_data *npc[MAX_NPC_PER_MAP]; @@ -595,7 +595,7 @@ int instance_src_map; /* rAthena Local Chat */ - struct raChSysCh *channel; + struct Channel *channel; }; /// Stores information about a remote map (for multi-mapserver setups). Index: src/map/guild.c =================================================================== --- src/map/guild.c (revision 17267) +++ src/map/guild.c (working copy) @@ -21,6 +21,7 @@ #include "mob.h" #include "intif.h" #include "clif.h" +#include "channel.h" #include "skill.h" #include "log.h" @@ -499,7 +500,7 @@ DBData data; struct map_session_data *sd; bool guild_new = false; - void *aChSysSave = NULL; + struct Channel *channel; nullpo_ret(sg); @@ -507,40 +508,6 @@ guild_new = true; g=(struct guild *)aCalloc(1,sizeof(struct guild)); idb_put(guild_db,sg->guild_id,g); - 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; - } - } - } - } - - mapit_free(iter); - } - - aChSysSave = (void*)channel; - - } before=*sg; //Perform the check on the user because the first load guild_check_member(sg); @@ -558,13 +525,9 @@ } } else { before=*g; - if( g->channel ) - aChSysSave = g->channel; } memcpy(g,sg,sizeof(struct 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); g->max_member = MAX_GUILD; @@ -581,11 +544,23 @@ bm++; } + if(Channel_Config.ally_enable){ + channel = g->channel; + if(!channel){ + channel = channel_create(Channel_Config.ally_chname,NULL,Channel_Config.ally_chcolor,CHAN_TYPE_ALLY); + channel->gid = g->guild_id; + g->channel = channel; + channel_ajoin(g); + } + } for (i = 0; i < g->max_member; i++) { //Transmission of information at all members sd = g->member[i].sd; if( sd==NULL ) continue; sd->guild = g; + if(Channel_Config.ally_autojoin ) { + channel_gjoin(sd,3); //make all member join guildchan+allieschan + } if (before.guild_lv != g->guild_lv || bm != m || before.max_member != g->max_member) { @@ -755,16 +730,8 @@ 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; - } - } + if( Channel_Config.ally_enable && Channel_Config.ally_autojoin ) { + channel_gjoin(sd,3); } } } @@ -909,13 +876,7 @@ if (sd->state.storage_flag == 2) //Close the guild storage. storage_guild_storageclose(sd); guild_send_dot_remove(sd); - if( raChSys.ally ) { - uint8 ch_count = sd->channel_count; - for (i = 0; i < ch_count; i++) { - if( sd->channels[i] && sd->channels[i]->type == raChSys_ALLY ) - clif_chsys_left(sd->channels[i],sd); - } - } + channel_pcquit(sd,3); //leave guild and ally chan sd->status.guild_id = 0; sd->guild = NULL; sd->guild_emblem_id = 0; @@ -1578,9 +1539,9 @@ return 0; } - for (i = 0; i < MAX_GUILDALLIANCE; i++) { // checking relations + for (i = 0; i < MAX_GUILDALLIANCE; i++) { // checking relations if(g->alliance[i].guild_id==tsd->status.guild_id){ - if (g->alliance[i].opposition == 1) { // check if not already hostile + if (g->alliance[i].opposition == 1) { // check if not already hostile clif_guild_oppositionack(sd,2); return 0; } @@ -1592,7 +1553,7 @@ } } - // inform other serv + // inform other serv intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, sd->status.account_id,tsd->status.account_id,1 ); return 0; @@ -1624,14 +1585,14 @@ sd[0]->guild_alliance_account=0; } - if (flag & 0x70) { // failure + if (flag & 0x70) { // failure for(i=0;i<2-(flag&1);i++) if( sd[i]!=NULL ) clif_guild_allianceack(sd[i],((flag>>4)==i+1)?3:4); return 0; } - if (!(flag & 0x08)) { // new relationship + if (!(flag & 0x08)) { // new relationship for(i=0;i<2-(flag&1);i++) { if(g[i]!=NULL) @@ -1645,35 +1606,38 @@ } } } - } else { // remove relationship + } else { // remove relationship for(i=0;i<2-(flag&1);i++) { if(g[i]!=NULL) { + for(j=0;jmax_member;j++) channel_pcquit(g[i]->member[j].sd,2); //leave all alliance chan ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == guild_id[1-i] && g[i]->alliance[j].opposition == (flag&1) ); if( j < MAX_GUILDALLIANCE ) g[i]->alliance[j].guild_id = 0; } - if (sd[i] != NULL) // notify players + if (sd[i] != NULL) // notify players clif_guild_delalliance(sd[i],guild_id[1-i],(flag&1)); } } - if ((flag & 0x0f) == 0) { // alliance notification + if ((flag & 0x0f) == 0) { // alliance notification if( sd[1]!=NULL ) clif_guild_allianceack(sd[1],2); - } else if ((flag & 0x0f) == 1) { // enemy notification + } else if ((flag & 0x0f) == 1) { // enemy notification if( sd[0]!=NULL ) clif_guild_oppositionack(sd[0],0); } - for (i = 0; i < 2 - (flag & 1); i++) { // Retransmission of the relationship list to all members + for (i = 0; i < 2 - (flag & 1); i++) { // Retransmission of the relationship list to all members struct map_session_data *sd; if(g[i]!=NULL) for(j=0;jmax_member;j++) - if((sd=g[i]->member[j].sd)!=NULL) + if((sd=g[i]->member[j].sd)!=NULL){ clif_guild_allianceinfo(sd); + channel_gjoin(sd,2); //join ally join + } } return 0; } @@ -1751,10 +1715,8 @@ guild_db->foreach(guild_db,guild_broken_sub,guild_id); castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id); guild_storage_delete(guild_id); - if( raChSys.ally ) { - if( g->channel != NULL ) { - clif_chsys_delete(( struct raChSysCh * )g->channel); - } + if( Channel_Config.ally_enable ) { + channel_delete(( struct Channel * )g->channel); } idb_remove(guild_db,guild_id); return 0; @@ -2203,10 +2165,8 @@ 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); + channel_delete((struct Channel *)g->channel); } - dbi_destroy(iter); db_destroy(guild_db); Index: src/map/channel.c =================================================================== --- src/map/channel.c (revision 0) +++ src/map/channel.c (revision 0) @@ -0,0 +1,803 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/conf.h" //libconfig +#include "../common/showmsg.h" +#include "../common/strlib.h" //safestrncpy +#include "../common/socket.h" //set_eof +#include "../common/nullpo.h" //nullpo chk + +#include "map.h" //msg_conf +#include "clif.h" //clif_chsys_msg +#include "channel.h" +#include "pc.h" + +#include +#include + +static DBMap* channel_db; // channels +DBMap* channel_get_db(void){ return channel_db; } //private or public chat + +/* + * Create *channel + * - then add it in channel_db if type not map or ally + */ +struct Channel* channel_create(char *name, char *pass, unsigned char color, enum Channel_Type chantype) { + struct Channel* channel; + CREATE( channel, struct Channel, 1 ); //will exit on fail allocation + + channel->opt = CHAN_OPT_BASE; + channel->type = chantype; + channel->users = idb_alloc(DB_OPT_BASE); + if( name ) + safestrncpy(channel->name, name, CHAN_NAME_LENGTH); + channel->color = color; + if( !pass ) + channel->pass[0] = '\0'; + else + safestrncpy(channel->pass, pass, CHAN_NAME_LENGTH); + + ShowInfo("Create channel %s\n",channel->name); + + if( channel->type != CHAN_TYPE_MAP && channel->type != CHAN_TYPE_ALLY) + strdb_put(channel_db, channel->name, channel); + return channel; +} + +/* + * Delete *channel + * - check if ramin user in channel and make them all quit + * -@TODO add return value + */ +void channel_delete(struct Channel *channel) { + if(!channel) + return; + else if( db_size(channel->users)) { + struct map_session_data *sd; + DBIterator *iter = db_iterator(channel->users); + for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) ) { //for all users + channel_clean(channel,sd,1); //make all quit + } + dbi_destroy(iter); + } + ShowInfo("Deleting channel %s\n",channel->name); + + db_destroy(channel->users); + switch(channel->type){ + case CHAN_TYPE_MAP: + map[channel->m].channel = NULL; + aFree(channel); + break; + case CHAN_TYPE_ALLY: { + struct guild *g = guild_search(channel->gid); + if(g) g->channel = NULL; + aFree(channel); + break; + } + default: + strdb_remove(channel_db, channel->name); + break; + } +} + +/* + * Make *sd join *channel + * - add charid to channel user list + * - add *channel to user channel list + */ +void channel_join(struct Channel *channel, struct map_session_data *sd) { + if(!channel || !sd) + return; + if(channel_haspc(channel,sd)) //already in here + return; + + RECREATE(sd->channels, struct Channel *, ++sd->channel_count); + sd->channels[ sd->channel_count - 1 ] = channel; + idb_put(channel->users, sd->status.char_id, sd); + + if( sd->stealth ) { + sd->stealth = false; + } else if( channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) { + char message[60]; + sprintf(message, "#%s '%s' joined",channel->name,sd->status.name); + clif_channel_msg(channel,sd,message); + } + + if(channel->type == CHAN_TYPE_ALLY) ShowDebug("sd=%d join chan %s guilid %d\n", + sd->bl.id,channel->name,channel->gid); + else ShowDebug("sd=%d join chan %s\n",sd->bl.id,channel->name); + + /* someone is cheating, we kindly disconnect the bastard */ + if( sd->channel_count > 200 ) { + set_eof(sd->fd); + } +} + +/* + * Make *sd join the map channel + * create the map_channel if not exist + */ +void channel_mjoin(struct map_session_data *sd) { + if(!sd) return; + + if( !map[sd->bl.m].channel ) { + map[sd->bl.m].channel = channel_create(Channel_Config.map_chname,NULL,Channel_Config.map_chcolor,CHAN_TYPE_MAP); + map[sd->bl.m].channel->m = sd->bl.m; //associate map + } + channel_join(map[sd->bl.m].channel,sd); + + if( !( map[sd->bl.m].channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) ) { + char mout[60]; + sprintf(mout, msg_txt(sd,1435),Channel_Config.map_chname,map[sd->bl.m].name); // You're now in the '#%s' channel for '%s'. + clif_disp_onlyself(sd, mout, strlen(mout)); + } +} + +/* + * Make all ally member of guild g join our guild chan + */ +void channel_ajoin(struct guild *g){ + int i; + struct map_session_data *pl_sd; + + if(!g || !g->channel) return; + for (i = 0; i < MAX_GUILDALLIANCE; i++){ + struct guild *ag; //allied guld + struct guild_alliance *ga = &g->alliance[i]; //guild alliance + if(ga->guild_id && (ga->opposition==0) && (ag=guild_search(ga->guild_id))){ + for (i = 0; i < ag->max_member; i++){ //load all guildmember + pl_sd = ag->member[i].sd; + if(channel_haspc(ag->channel,pl_sd) ) //only if they are in there own guildchan + channel_join(g->channel,pl_sd); + } + } + } +} + +/* + * Make *sd join the guild channel + * create a chan guild if not exist + */ +void channel_gjoin(struct map_session_data *sd, int flag){ + struct Channel *channel; + struct guild *g; + int i; + + if(!sd) return; + + g = sd->guild; + if(!g) return; + + channel = g->channel; + if(!channel){ + channel = channel_create(Channel_Config.ally_chname,NULL,Channel_Config.ally_chcolor,CHAN_TYPE_ALLY); + channel->gid = g->guild_id; + g->channel = channel; + channel_ajoin(g); + } + if(flag&1) { + ShowDebug("join guild chan\n",sd->guild->guild_id); + channel_join(channel,sd); //join our guild chat + } + if(flag&2){ + ShowDebug("join all alliance chan\n"); //join allies chat + for (i = 0; i < MAX_GUILDALLIANCE; i++){ + struct guild *ag; //allied guld + struct guild_alliance *ga = &g->alliance[i]; //guild alliance + if(ga->guild_id && (ga->opposition==0) && (ag=guild_search(ga->guild_id)) ) //only join allies + channel_join(ag->channel,sd); + } + } +} + +/* + * Make *sd leave *channel and cleanup association. + * if no one remain in chat delete it (PRIVATE only atm) + * @flag&1 called from delete do not recall delete + */ +void channel_clean(struct Channel *channel, struct map_session_data *sd, int flag) { + unsigned char i; + + if(!channel || !sd) + return; + + if( channel == sd->gcbind ) + sd->gcbind = NULL; + + ARR_FIND(0, sd->channel_count, i, sd->channels[i] == channel); + if( i < sd->channel_count ) { + unsigned char cursor = i; + sd->channels[i] = NULL; + for(; i < sd->channel_count; i++ ) { //slice move list down + if( sd->channels[i] == NULL ) + continue; + if(i != cursor) + sd->channels[cursor] = sd->channels[i]; + cursor++; + } + if ( !(sd->channel_count = cursor) ) { //if in no more chan delete db + aFree(sd->channels); + sd->channels = NULL; + } + } + + if(channel->type == CHAN_TYPE_ALLY) ShowDebug("sd=%d left chan %s guilid %d\n", + sd->bl.id,channel->name,channel->gid); + else ShowDebug("sd=%d left chan %s\n",sd->bl.id,channel->name); + + idb_remove(channel->users,sd->status.char_id); //remove user for channel user list + if( !db_size(channel->users) && !(flag&1) ) + channel_delete(channel); +} + +/* + * type&1 : quit guild chan + * type&2 : quit ally chans + * type&4 : quit map chan + * type&8 : quit all users joined chan + */ +void channel_pcquit(struct map_session_data *sd, int type){ + int i; + + //On closing state we could have clean all chan by sd but pcquit is more used to free unit when + //he quit a map_server, not call in map_quit cause we need to cleanup when we switch map-server as well + if(!sd) return; + + // Leave all chat channels. + if(type&(1|2) && Channel_Config.ally_enable && sd->guild){ //quit guild and ally chan + struct guild *g = sd->guild; + if(type&1 && channel_haspc(g->channel,sd) ){ //leave guild chan + ShowDebug("leave all guild chan\n"); + channel_clean(g->channel,sd,0); + } + if(type&2){ + struct guild *ag; //allied guild + ShowDebug("leave all alliance chan\n"); + for (i = 0; i < MAX_GUILDALLIANCE; i++) { //leave all alliance chan + if( g->alliance[i].guild_id && (ag = guild_search(g->alliance[i].guild_id) ) ) { + if( channel_haspc(ag->channel,sd) ) + channel_clean(ag->channel,sd,0); + break; + } + } + } + } + if(type&4 && Channel_Config.map_enable && channel_haspc(map[sd->bl.m].channel,sd)){ //quit map chan + channel_clean(map[sd->bl.m].channel,sd,0); + } + if(type&8 && sd->channel_count ) { //quit all chan + uint8 count = sd->channel_count; + for( i = count-1; i >= 0; i--) { //going backward to avoid shifting + channel_clean(sd->channels[i],sd,0); + } + } +} + +/* + * Format *msg from *sd to send it in *channel + * Also truncate extra char if msg too long (max=RACHSYS_MSG_LENGTH) + */ +void channel_send(struct Channel *channel, struct map_session_data *sd, char *msg) { + char message[CHAN_MSG_LENGTH]; + snprintf(message, CHAN_MSG_LENGTH, "[ #%s ] %s : %s",channel->name,sd->status.name, msg); + clif_channel_msg(channel,sd,message); +} + +/* + * Chk parameter for channel creation + * @type (bitflag) + * 1 : check name # + lenght + * 2 : check if already exist, need 1 + * 4 : check pass lenght + * return + * 0 : success + * -1 : bad chan name + * -2 : bad chan name lenght + * -3 : pass given too long + * -4 : chan already exist + */ +int channel_chk(char *chname, char *chpass, int type){ + if(type&1){ //check name + if( chname[0] != '#' ) return -1; // Channel name must start with '#' + if ( strlen(chname) < 3 || strlen(chname) > CHAN_NAME_LENGTH ) + return -2; // Channel length must be between 3 and %d. + if( (type&2) && ( + strcmpi(chname + 1,Channel_Config.map_chname) == 0 + || strcmpi(chname + 1,Channel_Config.ally_chname) == 0 + || strdb_exists(channel_db, chname + 1) ) + ) { + return -4; // Channel '%s' already exist + } + } + if (type&4 && (chpass != '\0' && strlen(chpass) > CHAN_NAME_LENGTH ) ) { + return -3; // Channel pass can't be higher then %d. + } + + return 0; +} + +struct Channel* channel_name2channel(char *chname){ + struct Channel *channel; + if(channel_chk(chname, NULL, 1)) return NULL; + if( !(channel = strdb_get(channel_db, chname + 1)) ) { + return NULL; + } + return channel; +} + +int channel_haspc(struct Channel *channel,struct map_session_data *sd){ + if(!channel || !sd) return 0; + return (idb_exists(channel->users, sd->status.char_id))?1:0; +} + +int channel_pc_haschan(struct map_session_data *sd, struct Channel *channel){ + int k; + if(!channel || !sd) return -2; //channel or player doesn't exist + ARR_FIND(0, sd->channel_count, k, strcmpi(channel->name,sd->channels[k]->name) == 0); + if( k >= sd->channel_count ) return -1; + return k; +} + +int channel_display_list(struct map_session_data *sd, char *options){ + struct Channel *channel; + char output[128]; + int k; + + if(!sd || !options) + return 0; + + //display availaible colors + if( options[0] != '\0' && strcmpi(options,"colors") == 0 ) { + char msg[40]; + for( k = 0; k < Channel_Config.colors_count; k++ ) { + sprintf(msg, "[ Channel list colors ] : %s",Channel_Config.colors_name[k]); + clif_colormes(sd, k, msg); + } + } + else if( options[0] != '\0' && strcmpi(options,"mine") == 0 ) { //display chan I'm into + clif_displaymessage(sd->fd, " ---- Joined Channels ----"); // ---- Joined Channels ---- + if(!sd->channel_count) + clif_displaymessage(sd->fd, "You have not joined any channel yet"); + else { + for(k=0; kchannel_count; k++){ + channel = sd->channels[k]; + sprintf(output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users) + clif_displaymessage(sd->fd, output); + } + } + } + else { //display public chanels + DBIterator *iter; + bool show_all = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false; + clif_displaymessage(sd->fd, msg_txt(sd,1410)); // ---- Public Channels ---- + if( Channel_Config.map_enable ) { + sprintf(output, msg_txt(sd,1409), Channel_Config.map_chname, map[sd->bl.m].channel ? db_size(map[sd->bl.m].channel->users) : 0);// - #%s ( %d users ) + clif_displaymessage(sd->fd, output); + } + if( Channel_Config.ally_enable && sd->status.guild_id ) { + struct guild *g = sd->guild; + if( !g ) return -1; //how can this happen if status.guild_id true ? + sprintf(output, msg_txt(sd,1409), Channel_Config.ally_chname, db_size(((struct Channel *)g->channel)->users));// - #%s ( %d users ) + clif_displaymessage(sd->fd, output); + } + iter = db_iterator(channel_db); + for(channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) { + if( show_all || channel->type == CHAN_TYPE_PUBLIC ) { + sprintf(output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users) + clif_displaymessage(sd->fd, output); + } + } + dbi_destroy(iter); + } + return 0; +} + + + +int channel_pccreate(struct map_session_data *sd, char *chname, char *chpass){ + struct Channel *channel; + char output[128]; + int8 res; + + if(!sd || !chname) + return 0; + + res = channel_chk(chname,chpass,7); + if(res==0){ //succes + channel = channel_create(chname + 1,chpass,0,CHAN_TYPE_PRIVATE); + channel->owner = sd->status.char_id; + channel_join(channel,sd); + if( !( channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) ) { + sprintf(output, msg_txt(sd,1403),chname); // You're now in the '%s' channel. + clif_displaymessage(sd->fd, output); + } + } else { //failure display cause + switch(res){ + case -1: sprintf(output, msg_txt(sd,1405), CHAN_NAME_LENGTH); break;// Channel name must start with '#'. + case -2: sprintf(output, msg_txt(sd,1406), CHAN_NAME_LENGTH); break;// Channel length must be between 3 and %d. + case -3: sprintf(output, msg_txt(sd,1436), CHAN_NAME_LENGTH); break;// Channel pass can't be higher then %d. + case -4: sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available. + } + clif_displaymessage(sd->fd, output); + return -1; + } + return 0; +} + +int channel_pcdelete(struct map_session_data *sd, char *chname){ + struct Channel *channel; + char output[128]; + + if(!sd || !chname) return 0; + + if( channel_chk(chname,NULL,1) ) { + clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'. + return -1; + } + if(strcmpi(chname + 1,Channel_Config.map_chname) == 0) channel = map[sd->bl.m].channel; + else if((strcmpi(chname + 1,Channel_Config.ally_chname) == 0) + && sd->guild) channel = sd->guild->channel; + else channel = channel_name2channel(chname); + + if(!channel){ + sprintf(output, "Channel %s doesn't exist",chname);// You're not part of the '%s' channel. + clif_displaymessage(sd->fd, output); + return -2; //channel doesn't exist or player don't have it + } + channel_delete(channel); + + sprintf(output, "Channel %s deleted",chname); // You've left the '%s' channel. + clif_displaymessage(sd->fd, output); + + return 0; +} + +int channel_pcleave(struct map_session_data *sd, char *chname){ + struct Channel *channel; + char output[128]; + + if(!sd || !chname) + return 0; + + if( channel_chk(chname,NULL,1) ) { + clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'. + return -1; + } + if(strcmpi(chname + 1,Channel_Config.map_chname) == 0){ + channel_pcquit(sd,4); //quit map chan + return 0; + } + else if((strcmpi(chname + 1,Channel_Config.ally_chname) == 0) + && sd->guild) { + channel_pcquit(sd,3); //leave guild and ally chan + return 0; + } + else channel = channel_name2channel(chname); + + if(channel_pc_haschan(sd,channel)<0){ + sprintf(output, msg_txt(sd,1425),chname);// You're not part of the '%s' channel. + clif_displaymessage(sd->fd, output); + return -2; //channel doesn't exist or player don't have it + } + + if( !Channel_Config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_JOIN) ) { + char message[60]; + sprintf(message, "#%s '%s' left",channel->name,sd->status.name); + clif_channel_msg(channel,sd,message); + } + channel_clean(channel,sd,0); + + sprintf(output, msg_txt(sd,1426),chname); // You've left the '%s' channel. + clif_displaymessage(sd->fd, output); + return 0; +} + +int channel_pcjoin(struct map_session_data *sd, char *chname, char *pass){ + struct Channel *channel; + char output[128]; + + if(!sd || !chname) + return 0; + + if( channel_chk(chname,NULL,1) ) { + clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'. + return -1; + } + + if(Channel_Config.map_enable + && (strcmpi(chname + 1,Channel_Config.map_chname) == 0)) { + if( !map[sd->bl.m].channel ) { + channel_mjoin(sd); + return 0; + } + channel = map[sd->bl.m].channel; + } + else if(Channel_Config.ally_enable + && (strcmpi(chname + 1,Channel_Config.ally_chname) == 0) + && sd->guild) { + if(!sd->guild->channel) { + channel_gjoin(sd,3); + return 0; + } + channel = sd->guild->channel; + } + else channel = channel_name2channel(chname); + + if(channel){ + if(channel_haspc(channel,sd)) { + sprintf(output, msg_txt(sd,1434),chname); // You're already in the '%s' channel. + clif_displaymessage(sd->fd, output); + return -1; + } + else if( channel->pass[0] != '\0') { //chan has a pass + if(strcmp(channel->pass,pass) != 0){ //wrong pass entry + if( pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) { + sd->stealth = true; + } else { + sprintf(output, msg_txt(sd,1401),chname,"Join"); // '%s' Channel is password protected (usage: %s <#channel_name> ) + clif_displaymessage(sd->fd, output); + return -1; + } + } + } + } + else { + sprintf(output, msg_txt(sd,1400),chname,"Join"); // Unknown Channel '%s' (usage: %s <#channel_name>) + clif_displaymessage(sd->fd, output); + return -1; + } + + if( !( channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) ) { + sprintf(output, msg_txt(sd,1403),chname); // You're now in the '%s' channel. + clif_displaymessage(sd->fd, output); + } + + channel_join(channel,sd); + + return 0; +} + +int channel_pccolor(struct map_session_data *sd, char *chname, char *color){ + struct Channel *channel; + char output[128]; + int k; + + if(!sd) + return 0; + + if( channel_chk(chname,NULL,1) ) { + clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'. + return -1; + } + channel = channel_name2channel(chname); //only search those in db since map and ally ain't ours + if( !channel ) { + sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available. + clif_displaymessage(sd->fd, output); + return -1; + } + + if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) { + sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'. + clif_displaymessage(sd->fd, output); + return -1; + } + + ARR_FIND(0,Channel_Config.colors_count,k,( strcmpi(color,Channel_Config.colors_name[k]) == 0 ) ); + if( k >= Channel_Config.colors_count ) { + sprintf(output, msg_txt(sd,1411), color);// Unknown color '%s'. + clif_displaymessage(sd->fd, output); + return -1; + } + channel->color = k; + sprintf(output, msg_txt(sd,1413),chname,Channel_Config.colors_name[k]);// '%s' channel color updated to '%s'. + clif_displaymessage(sd->fd, output); + return 0; +} + +int channel_pcbind(struct map_session_data *sd, char *chname){ + struct Channel *channel; + char output[128]; + + if(!sd) + return 0; + + if( channel_chk(chname,NULL,1) ) { + clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'. + return -1; + } + if(strcmpi(chname + 1,Channel_Config.map_chname) == 0) channel = map[sd->bl.m].channel; + else if((strcmpi(chname + 1,Channel_Config.ally_chname) == 0) + && sd->guild) channel = sd->guild->channel; + else channel = channel_name2channel(chname); + if(channel_pc_haschan(sd,channel)<0){ + sprintf(output, msg_txt(sd,1425),chname);// You're not part of the '%s' channel. + clif_displaymessage(sd->fd, output); + return -2; //channel doesn't exist or player don't have it + } + sd->gcbind = channel; + sprintf(output, msg_txt(sd,1431),chname); // Your global chat is now binded to the '%s' channel. + clif_displaymessage(sd->fd, output); + return 0; +} + +int channel_pcunbind(struct map_session_data *sd){ + char output[128]; + + if(!sd) + return 0; + + if( sd->gcbind == NULL ) { + clif_displaymessage(sd->fd, msg_txt(sd,1432));// Your global chat is not binded to any channel. + return -1; + } + sprintf(output, msg_txt(sd,1433),sd->gcbind->name); // Your global chat is now unbinded from the '#%s' channel. + clif_displaymessage(sd->fd, output); + sd->gcbind = NULL; + return 0; +} + +/* + * Read and verify configuration in confif_filename + * Assign table value with value + */ +void channel_read_config(void) { + config_t channels_conf; + config_setting_t *chsys = NULL; + const char *config_filename = "conf/channels.conf"; // FIXME hardcoded name + + if (conf_read_file(&channels_conf, config_filename)) + return; + + chsys = config_lookup(&channels_conf, "chsys"); + + if (chsys != NULL) { + config_setting_t *settings = config_setting_get_elem(chsys, 0); + config_setting_t *channels; + config_setting_t *colors; + int i,k; + const char *map_chname, *ally_chname,*map_color, *ally_color; + int ally_enabled = 0, local_enabled = 0; + int local_autojoin = 0, ally_autojoin = 0; + int allow_user_channel_creation = 0; + + if( !config_setting_lookup_string(settings, "map_local_channel_name", &map_chname) ) + map_chname = "map"; + safestrncpy(Channel_Config.map_chname, map_chname, CHAN_NAME_LENGTH); + + if( !config_setting_lookup_string(settings, "ally_channel_name", &ally_chname) ) + ally_chname = "ally"; + safestrncpy(Channel_Config.ally_chname, ally_chname, CHAN_NAME_LENGTH); + + config_setting_lookup_bool(settings, "map_local_channel", &local_enabled); + config_setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled); + + if( local_enabled ) + Channel_Config.map_enable = true; + if( ally_enabled ) + Channel_Config.ally_enable = true; + + config_setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); + config_setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); + + if( local_autojoin ) + Channel_Config.map_autojoin = true; + if( ally_autojoin ) + Channel_Config.ally_autojoin = true; + + config_setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); + + if( allow_user_channel_creation ) + Channel_Config.user_chenable = true; + + if( (colors = config_setting_get_member(settings, "colors")) != NULL ) { + int color_count = config_setting_length(colors); + CREATE( Channel_Config.colors, unsigned long, color_count ); + CREATE( Channel_Config.colors_name, char *, color_count ); + for(i = 0; i < color_count; i++) { + config_setting_t *color = config_setting_get_elem(colors, i); + CREATE( Channel_Config.colors_name[i], char, CHAN_NAME_LENGTH ); + + safestrncpy(Channel_Config.colors_name[i], config_setting_name(color), CHAN_NAME_LENGTH); + Channel_Config.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0); + Channel_Config.colors[i] = (Channel_Config.colors[i] & 0x0000FF) << 16 | (Channel_Config.colors[i] & 0x00FF00) | (Channel_Config.colors[i] & 0xFF0000) >> 16;//RGB to BGR + } + Channel_Config.colors_count = color_count; + } + + config_setting_lookup_string(settings, "map_local_channel_color", &map_color); + + for (k = 0; k < Channel_Config.colors_count; k++) { + if( strcmpi(Channel_Config.colors_name[k],map_color) == 0 ) + break; + } + + if( k < Channel_Config.colors_count ) { + Channel_Config.map_chcolor = k; + } else { + ShowError("channels.conf: unknown color '%s' for channel 'map_local_channel_color', disabling '#%s'...\n",map_color,map_chname); + Channel_Config.map_enable = false; + } + + config_setting_lookup_string(settings, "ally_channel_color", &ally_color); + + for (k = 0; k < Channel_Config.colors_count; k++) { + if( strcmpi(Channel_Config.colors_name[k],ally_color) == 0 ) + break; + } + + if( k < Channel_Config.colors_count ) { + Channel_Config.ally_chcolor = k; + } else { + ShowError("channels.conf: unknown color '%s' for channel 'ally_channel_color', disabling '#%s'...\n",map_color,ally_chname); + Channel_Config.ally_enable = false; + } + + if( (channels = config_setting_get_member(settings, "default_channels")) != NULL ) { + int channel_count = config_setting_length(channels); + + for(i = 0; i < channel_count; i++) { + config_setting_t *channel = config_setting_get_elem(channels, i); + const char *color = config_setting_get_string_elem(channels,i); + char *name = config_setting_name(channel); + struct Channel *chd; + + for (k = 0; k < Channel_Config.colors_count; k++) { + if( strcmpi(Channel_Config.colors_name[k],color) == 0 ) + break; + } + if( k == Channel_Config.colors_count ) { + ShowError("channels.conf: unknown color '%s' for channel '%s', skipping channel...\n",color,name); + continue; + } + if( strcmpi(name,Channel_Config.map_chname) == 0 || strcmpi(name,Channel_Config.ally_chname) == 0 || strdb_exists(channel_db, name) ) { + ShowError("channels.conf: duplicate channel '%s', skipping channel...\n",name); + continue; + } + chd = channel_create(name,NULL,k,CHAN_TYPE_PUBLIC); + } + } + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' channels in '"CL_WHITE"%s"CL_RESET"'.\n", db_size(channel_db), config_filename); + config_destroy(&channels_conf); + } +} + +/* + * Initialise db and read config + */ +int do_init_channel(void) { + channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, CHAN_NAME_LENGTH); + Channel_Config.ally_enable = Channel_Config.map_enable = Channel_Config.ally_autojoin = Channel_Config.map_autojoin = false; + channel_read_config(); + return 0; +} + +/* + * Close all and cleanup + * NB map and guild need to cleanup their chan as well + */ +void do_final_channel(void) { + DBIterator *iter; + struct Channel *channel; + struct guild *g; + int i=0; + + //delete all in remaining chan db + iter = db_iterator(channel_db); + for( channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter) ) { + channel_delete(channel); + } + dbi_destroy(iter); + db_destroy(channel_db); + + //delete all color thing + if( Channel_Config.colors_count ) { + for(i = 0; i < Channel_Config.colors_count; i++) { + aFree(Channel_Config.colors_name[i]); + } + aFree(Channel_Config.colors_name); + aFree(Channel_Config.colors); + } +} \ No newline at end of file Index: src/map/channel.h =================================================================== --- src/map/channel.h (revision 0) +++ src/map/channel.h (revision 0) @@ -0,0 +1,88 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef CHANNEL_H +#define CHANNEL_H + +#include "pc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CHAN_NAME_LENGTH 20 +#define CHAN_MSG_LENGTH 150 + +enum Channel_Opt { + CHAN_OPT_BASE = 0, + CHAN_OPT_ANNOUNCE_JOIN = 1, //display message when join or leave +}; + +enum Channel_Type { + CHAN_TYPE_PUBLIC = 0, //config file made + CHAN_TYPE_PRIVATE = 1, //user made + CHAN_TYPE_MAP = 2, //made by map + CHAN_TYPE_ALLY = 3, //guild +}; + +struct { + unsigned long *colors; //color avail int list + char **colors_name; //colors avail name list + unsigned char colors_count; //color avail count + unsigned char map_chcolor, ally_chcolor; //msg color for map, ally + bool map_enable, ally_enable, user_chenable; //map, ally, users channels enable ? + bool map_autojoin, ally_autojoin; //do user auto join in mapchange, guildjoin ? + char map_chname[CHAN_NAME_LENGTH], ally_chname[CHAN_NAME_LENGTH]; //channel name for map and ally + bool closing; //server is closing +} Channel_Config; + +struct Channel { + char name[CHAN_NAME_LENGTH]; //channel name + char pass[CHAN_NAME_LENGTH]; //channel password + unsigned char color; //msg color + DBMap *users; //user charid list + enum Channel_Opt opt; //flag for some treatement + unsigned int owner; //if private type charid of who create the chan, + enum Channel_Type type; //type of channel + uint16 m; + int gid; //if guild type guild_id +}; + +DBMap* channel_get_db(void); + +struct Channel* channel_create(char *name, char *pass, unsigned char color, enum Channel_Type chantype); +void channel_delete(struct Channel *channel); + +void channel_join(struct Channel *channel, struct map_session_data *sd); +void channel_mjoin(struct map_session_data *sd); +void channel_gjoin(struct map_session_data *sd, int flag); +void channel_ajoin(struct guild *g); +void channel_clean(struct Channel *channel, struct map_session_data *sd, int flag); +void channel_pcquit(struct map_session_data *sd, int type); + +void channel_send(struct Channel *channel, struct map_session_data *sd, char *msg); +void channel_read_config(void); + +int channel_chk(char *name, char *pass, int type); +struct Channel* channel_name2channel(char *name); +int channel_haspc(struct Channel *channel,struct map_session_data *sd); +int channel_pc_haschan(struct map_session_data *sd, struct Channel *channel); +int channel_display_list(struct map_session_data *sd, char *option); + +int channel_pccreate(struct map_session_data *sd, char *name, char *pass); +int channel_pcdelete(struct map_session_data *sd, char *chname); +int channel_pcjoin(struct map_session_data *sd, char *chname, char *pass); +int channel_pcleave(struct map_session_data *sd, char *chname); +int channel_pccolor(struct map_session_data *sd, char *chname, char *color); +int channel_pcbind(struct map_session_data *sd, char *chname); +int channel_pcunbind(struct map_session_data *sd); + +int do_init_channel(void); +void do_final_channel(void); + +#ifdef __cplusplus +} +#endif + +#endif /* CHANNEL_H */ +