/** * Bans a character from the given channel. * * @param chan The channel. * @param ssd The source character, if any. * @param tsd The target character. * @retval HCS_STATUS_OK if the operation succeeded. * @retval HCS_STATUS_ALREADY if the target character is already banned. * @retval HCS_STATUS_NOPERM if the source character doesn't have enough permissions. * @retval HCS_STATUS_FAIL in case of generic failure. */ enum channel_operation_status channel_ban(struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd) { struct channel_ban_entry *entry = NULL; nullpo_retr(HCS_STATUS_FAIL, chan); nullpo_retr(HCS_STATUS_FAIL, tsd); if (ssd && chan->owner != ssd->status.char_id && !pc_has_permission(ssd, PC_PERM_HCHSYS_ADMIN)) return HCS_STATUS_NOPERM; if (pc_has_permission(tsd, PC_PERM_HCHSYS_ADMIN)) return HCS_STATUS_FAIL; if (chan->banned && idb_exists(chan->banned, tsd->status.account_id)) return HCS_STATUS_ALREADY; if (!chan->banned) chan->banned = idb_alloc(DB_OPT_BASE|DB_OPT_ALLOW_NULL_DATA|DB_OPT_RELEASE_DATA); CREATE(entry, struct channel_ban_entry, 1); safestrncpy(entry->name, tsd->status.name, NAME_LENGTH); idb_put(chan->banned, tsd->status.account_id, entry); channel->leave(chan, tsd); return HCS_STATUS_OK; }
int party_invite (struct map_session_data *sd, struct map_session_data *tsd) { struct party_data *p; int i; nullpo_ret (sd); if ( (p = party_search (sd->status.party_id)) == NULL) return 0; // confirm if this player is a party leader ARR_FIND (0, MAX_PARTY, i, p->data[i].sd == sd); if (i == MAX_PARTY || !p->party.member[i].leader) { clif_displaymessage (sd->fd, msg_txt (282)); return 0; } // confirm if there is an open slot in the party ARR_FIND (0, MAX_PARTY, i, p->party.member[i].account_id == 0); if (i == MAX_PARTY) { clif_party_inviteack (sd, (tsd ? tsd->status.name : ""), 3); return 0; } // confirm whether the account has the ability to invite before checking the player if (!pc_has_permission (sd, PC_PERM_PARTY) || (tsd && !pc_has_permission (tsd, PC_PERM_PARTY))) { clif_displaymessage (sd->fd, msg_txt (81)); // "Your GM level doesn't authorize you to preform this action on the specified player." return 0; } if (tsd == NULL) { clif_party_inviteack (sd, "", 7); return 0; } if (!battle_config.invite_request_check) { if (tsd->guild_invite > 0 || tsd->trade_partner || tsd->adopt_invite) { clif_party_inviteack (sd, tsd->status.name, 0); return 0; } } if (!tsd->fd) { //You can't invite someone who has already disconnected. clif_party_inviteack (sd, tsd->status.name, 1); return 0; } if (tsd->status.party_id > 0 || tsd->party_invite > 0) { // already associated with a party clif_party_inviteack (sd, tsd->status.name, 0); return 0; } tsd->party_invite = sd->status.party_id; tsd->party_invite_account = sd->status.account_id; clif_party_invite (sd, tsd); return 1; }
/** * A player is attempting to join a channel * @param sd: Player data * @param chname: Channel name * @param pass: Channel password * @return 0 on success or -1 on failure */ int channel_pcjoin(struct map_session_data *sd, char *chname, char *pass){ struct Channel *channel; char output[CHAT_SIZE_MAX]; 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; } channel = channel_name2channel(chname,sd,1); if(channel){ if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id)) { sprintf(output, msg_txt(sd,1407), chname); // Channel '%s' is not available. clif_displaymessage(sd->fd, output); return -1; } if(channel_haspc(channel,sd)==1) { 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"); // Channel '%s' is password-protected (usage: %s <#channel_name> <password>). 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; } switch(channel->type){ case CHAN_TYPE_ALLY: channel_gjoin(sd,3); break; case CHAN_TYPE_MAP: channel_mjoin(sd); break; default: //private and public atm if (channel_join(channel,sd) != 0) return -1; } if( ( channel->opt & CHAN_OPT_ANNOUNCE_SELF ) ) { sprintf(output, msg_txt(sd,1403),chname); // You're now in the '%s' channel. clif_displaymessage(sd->fd, output); } return 0; }
/** * Unbans a character from the given channel. * * @param chan The channel. * @param ssd The source character, if any. * @param tsd The target character. If no target character is specified, all characters are unbanned. * @retval HCS_STATUS_OK if the operation succeeded. * @retval HCS_STATUS_ALREADY if the target character is not banned. * @retval HCS_STATUS_NOPERM if the source character doesn't have enough permissions. * @retval HCS_STATUS_FAIL in case of generic failure. */ enum channel_operation_status channel_unban(struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd) { nullpo_retr(HCS_STATUS_FAIL, chan); if (ssd && chan->owner != ssd->status.char_id && !pc_has_permission(ssd, PC_PERM_HCHSYS_ADMIN)) return HCS_STATUS_NOPERM; if (!chan->banned) return HCS_STATUS_ALREADY; if (!tsd) { // Unban all db_destroy(chan->banned); chan->banned = NULL; return HCS_STATUS_OK; } // Unban one if (!idb_exists(chan->banned, tsd->status.account_id)) return HCS_STATUS_ALREADY; idb_remove(chan->banned, tsd->status.account_id); if (!db_size(chan->banned)) { db_destroy(chan->banned); chan->banned = NULL; } return HCS_STATUS_OK; }
/** * Sends a message to a channel. * * @param chan The destination channel. * @param sd The source character. * @param msg The message to send. * * If no source character is specified, it'll send an anonymous message. */ void channel_send(struct channel_data *chan, struct map_session_data *sd, const char *msg) { char message[150]; nullpo_retv(chan); nullpo_retv(msg); if (sd && chan->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + chan->msg_delay*1000, timer->gettick()) > 0 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1455)); return; } else if (sd) { safesnprintf(message, 150, "[ #%s ] %s : %s", chan->name, sd->status.name, msg); clif->channel_msg(chan,sd,message); if (chan->type == HCS_TYPE_IRC) ircbot->relay(sd->status.name,msg); if (chan->msg_delay != 0) sd->hchsysch_tick = timer->gettick(); } else { safesnprintf(message, 150, "[ #%s ] %s", chan->name, msg); clif->channel_msg2(chan, message); if (chan->type == HCS_TYPE_IRC) ircbot->relay(NULL, msg); } }
/** * Sends a message to a channel. * * @param chan The destination channel. * @param sd The source character. * @param msg The message to send. * * If no source character is specified, it'll send an anonymous message. */ static void channel_send(struct channel_data *chan, struct map_session_data *sd, const char *msg) { char message[150]; nullpo_retv(chan); nullpo_retv(msg); if (sd && chan->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + chan->msg_delay*1000, timer->gettick()) > 0 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1455)); return; } else if (sd) { int i; safesnprintf(message, 150, "[ #%s ] %s : %s", chan->name, sd->status.name, msg); clif->channel_msg(chan,sd,message); if (chan->type == HCS_TYPE_IRC) ircbot->relay(sd->status.name,msg); if (chan->msg_delay != 0) sd->hchsysch_tick = timer->gettick(); for (i = 0; i < MAX_EVENTQUEUE; i++) { if (chan->handlers[i][0] != '\0') { pc->setregstr(sd, script->add_str("@channelmes$"), msg); npc->event(sd, chan->handlers[i], 0); } } } else { safesnprintf(message, 150, "[ #%s ] %s", chan->name, msg); clif->channel_msg2(chan, message); if (chan->type == HCS_TYPE_IRC) ircbot->relay(NULL, msg); } }
/** * Kick a member from a chat room. * @param sd : player requesting * @param kickusername : player name to be kicked * @retur 1:success, 0:failure */ int chat_kickchat(struct map_session_data* sd, const char* kickusername) { struct chat_data* cd; int i; nullpo_retr(1, sd); cd = (struct chat_data *)map_id2bl(sd->chatID); if( cd == NULL || (struct block_list *)sd != cd->owner ) return -1; ARR_FIND( 0, cd->users, i, strncmp(cd->usersd[i]->status.name, kickusername, NAME_LENGTH) == 0 ); if( i == cd->users ) return -1; if (pc_has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK)) return 0; //gm kick protection [Valaris] idb_put(cd->kick_list,cd->usersd[i]->status.char_id,(void*)1); chat_leavechat(cd->usersd[i],1); return 0; }
/** * A player is attemting to kick a player * @param sd: Player data * @param chname: Channel name * @param pname: Player name to kick * @return 0 on success or -1 on failure */ int channel_pckick(struct map_session_data *sd, char *chname, char *pname) { struct Channel *channel; char output[CHAT_SIZE_MAX]; struct map_session_data *tsd = map_nick2sd(pname,false); 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,sd,0); if( !channel ) { sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available. clif_displaymessage(sd->fd, output); return -1; } if (!tsd) { clif_displaymessage(sd->fd, msg_txt(sd,3)); return -1; } if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) { if (channel->char_id != sd->status.char_id) { sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'. clif_displaymessage(sd->fd, output); } else if (!channel_config.private_channel.kick) { sprintf(output, msg_txt(sd,766), chname); // You cannot kick a player from channel '%s'. clif_displaymessage(sd->fd, output); } return -1; } 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 -1; } if (channel->char_id == sd->status.char_id) { clif_displaymessage(sd->fd, msg_txt(sd, 767)); // You're not allowed to kick a player. return -1; } if( !channel_config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_LEAVE) ) { safesnprintf(output, CHAT_SIZE_MAX, msg_txt(sd,768), channel->alias, tsd->status.name); // %s %s has been kicked. clif_channel_msg(channel,output,channel->color); } switch(channel->type){ case CHAN_TYPE_ALLY: channel_pcquit(tsd,3); break; case CHAN_TYPE_MAP: channel_pcquit(tsd,4); break; default: //private and public atm channel_clean(channel,tsd,0); } return 1; }
/*========================================== * join an existing chatroom *------------------------------------------*/ bool chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) { struct chat_data* cd; nullpo_ret(sd); nullpo_ret(pass); cd = map->id2cd(chatid); if (cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->state.vending || sd->state.buyingstore || sd->chat_id != 0 || ((cd->owner->type == BL_NPC) ? cd->users+1 : cd->users) >= cd->limit ) { clif->joinchatfail(sd,0); // room full return false; } if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) ) { clif->joinchatfail(sd,1); // wrong password return false; } if( sd->status.base_level < cd->minLvl || sd->status.base_level > cd->maxLvl ) { if(sd->status.base_level < cd->minLvl) clif->joinchatfail(sd,5); // too low level else clif->joinchatfail(sd,6); // too high level return false; } if( sd->status.zeny < cd->zeny ) { clif->joinchatfail(sd,4); // not enough zeny return false; } if( cd->owner->type != BL_NPC && idb_exists(cd->kick_list,sd->status.char_id) ) { clif->joinchatfail(sd,2); // You have been kicked out of the room. return false; } pc_stop_walking(sd, STOPWALKING_FLAG_FIXPOS); cd->usersd[cd->users] = sd; cd->users++; pc_setchatid(sd,cd->bl.id); clif->joinchatok(sd, cd); //To the person who newly joined the list of all clif->addchat(cd, sd); //Reports To the person who already in the chat clif->dispchat(cd, 0); //Reported number of changes to the people around chat->trigger_event(cd); //Event return true; }
/** * Join an existing chat room. * @param sd : player requesting * @param chatid : ID of the chat room * @param pass : password of chat room * @return 0 */ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) { struct chat_data* cd; nullpo_ret(sd); cd = (struct chat_data*)map_id2bl(chatid); if( cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->state.vending || sd->state.buyingstore || sd->chatID || ((cd->owner->type == BL_NPC) ? cd->users+1 : cd->users) >= cd->limit ) { clif_joinchatfail(sd,0); return 0; } if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) ) { clif_joinchatfail(sd,1); return 0; } if( sd->status.base_level < cd->minLvl || sd->status.base_level > cd->maxLvl ) { if(sd->status.base_level < cd->minLvl) clif_joinchatfail(sd,5); else clif_joinchatfail(sd,6); return 0; } if( sd->status.zeny < cd->zeny ) { clif_joinchatfail(sd,4); return 0; } if( cd->owner->type != BL_NPC && idb_exists(cd->kick_list,sd->status.char_id) ) { clif_joinchatfail(sd,2);//You have been kicked out of the room. return 0; } pc_stop_walking(sd,1); cd->usersd[cd->users] = sd; cd->users++; pc_setchatid(sd,cd->bl.id); clif_joinchatok(sd, cd); //To the person who newly joined the list of all clif_addchat(cd, sd); //Reports To the person who already in the chat clif_dispchat(cd, 0); //Reported number of changes to the people around if (cd->owner->type == BL_PC) achievement_update_objective(map_id2sd(cd->owner->id), AG_CHAT_COUNT, 1, cd->users); chat_triggerevent(cd); //Event return 0; }
/** * Joins a channel. * * Ban and password checks are performed before joining the channel. * If the channel is an HCS_TYPE_ALLY channel, alliance channels are automatically joined. * * @param chan The channel to join * @param sd The character * @param password The specified join password, if any * @param silent If true, suppress the "You're now in the <x> channel" greeting message * @retval HCS_STATUS_OK if the operation succeeded * @retval HCS_STATUS_ALREADY if the character is already in the channel * @retval HCS_STATUS_NOPERM if the specified password doesn't match * @retval HCS_STATUS_BANNED if the character is in the channel's ban list * @retval HCS_STATUS_FAIL in case of generic error */ enum channel_operation_status channel_join(struct channel_data *chan, struct map_session_data *sd, const char *password, bool silent) { bool stealth = false; nullpo_retr(HCS_STATUS_FAIL, chan); nullpo_retr(HCS_STATUS_FAIL, sd); nullpo_retr(HCS_STATUS_FAIL, password); if (idb_exists(chan->users, sd->status.char_id)) { return HCS_STATUS_ALREADY; } if (chan->password[0] != '\0' && strcmp(chan->password, password) != 0) { if (pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { stealth = true; } else { return HCS_STATUS_NOPERM; } } if (chan->banned && idb_exists(chan->banned, sd->status.account_id)) { return HCS_STATUS_BANNED; } if (!silent && !(chan->options&HCS_OPT_ANNOUNCE_JOIN)) { char output[CHAT_SIZE_MAX]; if (chan->type == HCS_TYPE_MAP) { sprintf(output, msg_sd(sd,1435), chan->name, map->list[chan->m].name); // You're now in the '#%s' channel for '%s' } else { sprintf(output, msg_sd(sd,1403), chan->name); // You're now in the '%s' channel } clif->messagecolor_self(sd->fd, COLOR_DEFAULT, output); } if (chan->type == HCS_TYPE_ALLY) { struct guild *g = sd->guild; int i; for (i = 0; i < MAX_GUILDALLIANCE; i++) { struct guild *sg = NULL; if (g->alliance[i].opposition == 0 && g->alliance[i].guild_id && (sg = guild->search(g->alliance[i].guild_id)) != NULL) { if (!(sg->channel->banned && idb_exists(sg->channel->banned, sd->status.account_id))) { channel->join_sub(sg->channel, sd, stealth); } } } } channel->join_sub(chan, sd, stealth); return HCS_STATUS_OK; }
/** * A player is attempting to change the channel color * @param sd: Player data * @param chname: Channel name * @param color: New color * @return 0 on success or -1 on failure */ int channel_pccolor(struct map_session_data *sd, char *chname, char *color){ struct Channel *channel; char output[CHAT_SIZE_MAX]; 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,sd,0); if( !channel ) { sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available. clif_displaymessage(sd->fd, output); return -1; } if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) { if (channel->char_id != sd->status.char_id) { sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'. clif_displaymessage(sd->fd, output); return -1; } else if (!(channel->opt&CHAN_OPT_COLOR_OVERRIDE)) { sprintf(output, msg_txt(sd,764), chname); // You cannot change the color for 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 = channel_config.colors[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; }
/** * Make a player join a channel * - Add player to channel user list * - Add channel to user channel list * @param channel: Channel data * @param sd: Player data * @return * 0: Success * -1: Invalid channel or player * -2: Player already in channel * -3: Player banned * -4: Reached max limit */ int channel_join(struct Channel *channel, struct map_session_data *sd) { if(!channel || !sd) return -1; if(sd->state.autotrade) return 0; // fake success if(channel_haspc(channel,sd)==1) return -2; if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id)) return -2; if(channel_haspcbanned(channel,sd)==1){ char output[CHAT_SIZE_MAX]; sprintf(output, msg_txt(sd,1438),channel->name); //You're currently banned from the '%s' channel. clif_displaymessage(sd->fd, output); return -3; } if (channel->type == CHAN_TYPE_PRIVATE && db_size(channel->users) >= channel_config.private_channel.max_member) { char output[CHAT_SIZE_MAX]; sprintf(output, msg_txt(sd,760), channel->name, channel_config.private_channel.max_member); // You cannot join channel '%s'. Limit of %d has been met. clif_displaymessage(sd->fd, output); return -4; } RECREATE(sd->channels, struct Channel *, ++sd->channel_count); sd->channels[ sd->channel_count - 1 ] = channel; idb_put(channel->users, sd->status.char_id, sd); RECREATE(sd->channel_tick, t_tick, sd->channel_count); sd->channel_tick[sd->channel_count-1] = 0; if( sd->stealth ) { sd->stealth = false; } else if( channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) { char output[CHAT_SIZE_MAX]; safesnprintf(output, CHAT_SIZE_MAX, msg_txt(sd,761), channel->alias, sd->status.name); // %s %s has joined. clif_channel_msg(channel,output,channel->color); } /* someone is cheating, we kindly disconnect the bastard */ if( sd->channel_count > 200 ) { set_eof(sd->fd); } return 0; }
/** * Attempt to autojoin a player to a channel */ int channel_pcautojoin_sub(DBKey key, DBData *data, va_list ap) { struct Channel *channel = (struct Channel *)db_data2ptr(data); struct map_session_data *sd = NULL; char channame[CHAN_NAME_LENGTH+1]; nullpo_ret(channel); nullpo_ret((sd = va_arg(ap, struct map_session_data *))); if (channel->pass[0]) return 0; if (!(channel->opt&CHAN_OPT_AUTOJOIN)) return 0; if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id)) return 0; safesnprintf(channame, sizeof(channame), "#%s", channel->name); channel_pcjoin(sd, channame, NULL); return 1; }
/** * Format message from player to send to the channel * - Also truncate extra characters if message is too long * @param channel: Channel data * @param sd: Player data * @param msg: Message to send * @return * 0: Success * -1: Invalid player, channel, or message * -2: Delay message from last message */ int channel_send(struct Channel *channel, struct map_session_data *sd, const char *msg) { int idx = 0; if(!channel || !sd || !msg || (idx = channel_pc_haschan(sd, channel)) < 0) return -1; if(!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && channel->msg_delay != 0 && DIFF_TICK(sd->channel_tick[idx] + channel->msg_delay, gettick()) > 0) { clif_messagecolor(&sd->bl,color_table[COLOR_RED],msg_txt(sd,1455),false,SELF); //You're talking too fast! return -2; } else { char output[CHAT_SIZE_MAX]; unsigned long color = channel->color; if((channel->opt&CHAN_OPT_COLOR_OVERRIDE) && sd->fontcolor && sd->fontcolor < channel_config.colors_count && channel_config.colors[sd->fontcolor]) color = channel_config.colors[sd->fontcolor]; safesnprintf(output, CHAT_SIZE_MAX, "%s %s : %s", channel->alias, sd->status.name, msg); clif_channel_msg(channel,output,color); sd->channel_tick[idx] = gettick(); } return 0; }
/*========================================== * Kick an user from a chatroom * Return: * 0: User cannot be kicked (is gm)/Missing data * 1: Success *------------------------------------------*/ bool chat_kickchat(struct map_session_data* sd, const char* kickusername) { struct chat_data* cd; int i; nullpo_ret(sd); cd = (struct chat_data *)map->id2bl(sd->chatID); if( cd==NULL || (struct block_list *)sd != cd->owner ) return false; ARR_FIND( 0, cd->users, i, strncmp(cd->usersd[i]->status.name, kickusername, NAME_LENGTH) == 0 ); if( i == cd->users ) // User not found return false; if (pc_has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK)) return false; //gm kick protection [Valaris] idb_iput(cd->kick_list,cd->usersd[i]->status.char_id,1); chat->leave(cd->usersd[i], true); return true; }
/** * Display some information to users in channel * @param sd: Player data * @param options: * colors: Display available colors for channel system * mine: List of players in channel and number of users * void: List of public channel and map and guild and number of users * @return 0 on success or -1 on failure */ int channel_display_list(struct map_session_data *sd, const char *options){ if(!sd || !options) return -1; //display availaible colors if( options[0] != '\0' && strcmpi(options,"colors") == 0 ) { char msg[40]; unsigned char k; clif_displaymessage(sd->fd, msg_txt(sd,1444)); // ---- Available Colors ---- for( k = 0; k < channel_config.colors_count; k++ ) { if (channel_config.colors[k]) { sprintf(msg, msg_txt(sd,1445),channel_config.colors_name[k]);// - '%s' clif_messagecolor(&sd->bl,channel_config.colors[k],msg,false,SELF); } } } else if( options[0] != '\0' && strcmpi(options,"mine") == 0 ) { //display chan I'm into clif_displaymessage(sd->fd, msg_txt(sd,1475)); // ---- My Channels ---- if(!sd->channel_count) clif_displaymessage(sd->fd, msg_txt(sd,1476)); // You have not joined any channels. else { unsigned char k; for(k = 0; k < sd->channel_count; k++) { char output[CHAT_SIZE_MAX]; struct Channel *channel; if (!(channel = sd->channels[k])) continue; 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 has_perm = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false; struct Channel *channel; char output[CHAT_SIZE_MAX]; struct map_data *mapdata = map_getmapdata(sd->bl.m); clif_displaymessage(sd->fd, msg_txt(sd,1410)); // ---- Public Channels ---- if( channel_config.map_tmpl.name[0] && mapdata->channel ) { sprintf(output, msg_txt(sd,1409), mapdata->channel->name, db_size(mapdata->channel->users));// - #%s (%d users) clif_displaymessage(sd->fd, output); } if( channel_config.ally_tmpl.name[0] && sd->status.guild_id ) { struct guild *g = sd->guild; if (g && g->channel) { sprintf(output, msg_txt(sd,1409), g->channel->name, db_size(((struct Channel *)g->channel)->users));// - #%s (%d users) clif_displaymessage(sd->fd, output); } } iter = db_iterator(channel_db); for(channel = (struct Channel *)dbi_first(iter); dbi_exists(iter); channel = (struct Channel *)dbi_next(iter)) { if (!has_perm && !channel_pccheckgroup(channel, sd->group_id)) continue; if( has_perm || 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; }
void channel_join(struct map_session_data *sd, const char* name, const char* pass, bool invite) { char output[256]; struct channel_data *cd; int i = 0; if( !name || strlen(name) < 2 || strlen(name) >= NAME_LENGTH || name[0] != '#' ) { clif_displaymessage(sd->fd, msg_txt(801)); return; } if( (cd = (struct channel_data *)strdb_get(channel_db, name)) == NULL ) { clif_displaymessage(sd->fd, msg_txt(805)); return; } if( channel_slot_get(sd, cd) != -1 ) { clif_displaymessage(sd->fd, msg_txt(806)); return; } if( (i = channel_slot_free(sd)) < 0 ) { clif_displaymessage(sd->fd, msg_txt(800)); return; } if( !invite ) { if( cd->pass[0] && strcmp(cd->pass, pass) != 0 ) { // Check password only if not invited clif_displaymessage(sd->fd, msg_txt(808)); return; } if( cd->type == CHN_GAMEMASTER && pc_has_permission(sd,PC_PERM_CHANNEL_OPERATOR) ) { clif_displaymessage(sd->fd, msg_txt(703)); return; } } if( battle_config.channel_announce_join ) { sprintf(output, msg_txt(803), cd->name, sd->status.name); clif_channel_message(cd, output, -1); } sprintf(output, msg_txt(710), sd->status.name, cd->name); clif_wis_message(sd->fd, cd->name, output, strlen(output) + 1); // Joining Channel sd->cd[i] = cd; sd->canjoinchn_tick = gettick() + 10000; idb_put(cd->users_db, sd->bl.id, sd); cd->users++; if( sd->channel_invite_timer != INVALID_TIMER ) { const struct TimerData * td = get_timer(sd->channel_invite_timer); char *name = td ? (char *)td->data : NULL; if( strcmp(name, cd->name) == 0 ) channel_invite_clear(sd); // Invitation removed as the user joined the channel } if( cd->type != CHN_USER ) { switch( cd->type ) { case CHN_MAIN: sd->channels |= 1; break; case CHN_VENDING: sd->channels |= 2; break; case CHN_BATTLEGROUND: sd->channels |= 4; break; case CHN_GAMEMASTER: sd->channels |= 8; break; } pc_setaccountreg(sd, "#CHANNEL_CONF", sd->channels); } }
/** * A player is attempting to set an option on the channel * @param sd: Player data * @param chname: Channel name * @param option: Option to change * @param val: Option value * @return 0 on success or -1 on failure */ int channel_pcsetopt(struct map_session_data *sd, char *chname, const char *option, const char *val){ struct Channel *channel; char output[CHAT_SIZE_MAX]; int k, s = 0, opt; const char* opt_str[] = { "None", "SelfAnnounce", "JoinAnnounce", "LeaveAnnounce", "MessageDelay", "ColorOverride", "CanChat", "CanLeave", "Autojoin", }; if( channel_chk(chname,NULL,1) ) { clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'. return -1; } if (!sd) return - 1; channel = channel_name2channel(chname,sd,0); if( !channel ) { sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available. clif_displaymessage(sd->fd, output); return -1; } if( sd && channel->char_id != 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; } s = ARRAYLENGTH(opt_str); ARR_FIND(1,s,k,( strncmpi(option,opt_str[k],3) == 0 )); //we only cmp 3 letter atm if(!option || option[0] == '\0' || k >= s ) { sprintf(output, msg_txt(sd,1447), option);// Unknown channel option '%s'. clif_displaymessage(sd->fd, output); clif_displaymessage(sd->fd, msg_txt(sd,1414));// ---- Available options: for( k = 1; k < s; k++ ) { sprintf(output, msg_txt(sd,1445), opt_str[k]);// - '%s' clif_displaymessage(sd->fd, output); } return -1; } opt = 1<<(k-1); if (channel->type == CHAN_TYPE_PRIVATE && !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN)) { switch (opt) { case CHAN_OPT_MSG_DELAY: if (!channel_config.private_channel.change_delay) return -1; break; case CHAN_OPT_COLOR_OVERRIDE: if (!channel_config.private_channel.color_override) return -1; break; } } if( val[0] == '\0' ) { if ( opt == CHAN_OPT_MSG_DELAY ) { sprintf(output, msg_txt(sd,1466), opt_str[k]);// Input the number of seconds (0-10) for the '%s' option. clif_displaymessage(sd->fd, output); return -1; } else if( channel->opt & opt ) { sprintf(output, msg_txt(sd,1449), opt_str[k],opt_str[k]); // Option '%s' is already enabled (use '@channel setopt %s 0' to disable). clif_displaymessage(sd->fd, output); return -1; } else { channel->opt |= opt; sprintf(output, msg_txt(sd,1450), opt_str[k],channel->name);// Option '%s' is enabled for channel '#%s'. clif_displaymessage(sd->fd, output); } } else { int v = atoi(val); if( opt == CHAN_OPT_MSG_DELAY ) { if( v < 0 || v > 10 ) { sprintf(output, msg_txt(sd,1451), v, opt_str[k]);// Value '%d' for option '%s' is out of range (limit 0-10). clif_displaymessage(sd->fd, output); return -1; } if( v == 0 ) { channel->opt &=~ opt; channel->msg_delay = 0; sprintf(output, msg_txt(sd,1453), opt_str[k],channel->name,v);// Option '%s' is disabled for channel '#%s'. clif_displaymessage(sd->fd, output); } else { channel->opt |= opt; channel->msg_delay = v * 1000; sprintf(output, msg_txt(sd,1452), opt_str[k],channel->name,v);// Option '%s' is enabled for channel '#%s' at %d seconds. clif_displaymessage(sd->fd, output); } } else { if( v ) { if( channel->opt & opt ) { sprintf(output, msg_txt(sd,1449), opt_str[k],opt_str[k]); // Option '%s' is already enabled (use '@channel setopt %s 0' to disable). clif_displaymessage(sd->fd, output); return -1; } else { channel->opt |= opt; sprintf(output, msg_txt(sd,1450), opt_str[k],channel->name);// Option '%s' is enabled for channel '#%s'. clif_displaymessage(sd->fd, output); } } else { if( !(channel->opt & opt) ) { sprintf(output, msg_txt(sd,1450), opt_str[k],channel->name); // Option '%s' is enabled for channel '#%s'. clif_displaymessage(sd->fd, output); return -1; } else { channel->opt &=~ opt; sprintf(output, msg_txt(sd,1453), opt_str[k],channel->name);// Option '%s' is disabled for channel '#%s'. clif_displaymessage(sd->fd, output); } } } } return 0; }
void channel_message(struct map_session_data *sd, const char* channel, const char* message) { struct channel_data *cd; char output[CHAT_SIZE_MAX]; struct map_session_data *p_sd; if( !sd || !message || !*message || strlen(message) < 1 ) return; if( (cd = (struct channel_data *)strdb_get(channel_db, channel)) == NULL ) { clif_displaymessage(sd->fd, msg_txt(805)); clif_displaymessage(sd->fd, msg_txt(815)); return; } if( channel_slot_get(sd,cd) < 0 ) { clif_displaymessage(sd->fd, msg_txt(816)); return; } if( message[0] == '|' && strlen(message) >= 4 && message[3] == '.' ) message += 3; if( message[0] == '.' ) { // Channel commands size_t len = strlen(message); char* option_text; if( !strncasecmp(message, ".item ", 6) && len > 0 && cd->type == CHN_VENDING && server_channel[CHN_VENDING] && vendingbot_timer < gettick() ) { struct map_session_data *pl_sd, *b_sd[MAX_SEARCH]; struct s_mapiterator* iter; struct item_data *item_array[MAX_SEARCH]; int total[MAX_SEARCH], amount[MAX_SEARCH]; unsigned int MinPrice[MAX_SEARCH], MaxPrice[MAX_SEARCH]; int i, j, count = 1; option_text = (char *)message + 6; if( (item_array[0] = itemdb_exists(atoi(option_text))) == NULL ) count = itemdb_searchname_array(item_array, MAX_SEARCH, option_text); if( count < 1 ) { clif_displaymessage(sd->fd, msg_txt(19)); return; } if( count > MAX_SEARCH ) count = MAX_SEARCH; for( i = 0; i < MAX_SEARCH; i++ ) { total[i] = amount[i] = MaxPrice[i] = 0; MinPrice[i] = battle_config.vending_max_value + 1; b_sd[i] = NULL; } iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) ) { if( !pl_sd->vender_id ) continue; for( i = 0; i < pl_sd->vend_num; i++ ) { // Searching in the Vending List for( j = 0; j < count; j++ ) { // Compares with each search result if( pl_sd->status.cart[pl_sd->vending[i].index].nameid != item_array[j]->nameid ) continue; amount[j] += pl_sd->vending[i].amount; total[j]++; if( pl_sd->vending[i].value < MinPrice[j] ) { // Best Price MinPrice[j] = pl_sd->vending[i].value; b_sd[j] = pl_sd; } if( pl_sd->vending[i].value > MaxPrice[j] ) MaxPrice[j] = pl_sd->vending[i].value; } } } mapit_free(iter); for( i = 0; i < count; i++ ) { if( total[i] > 0 && b_sd[i] != NULL ) { sprintf(output, msg_txt(829), server_channel[CHN_VENDING]->name, item_array[i]->jname, MinPrice[i], b_sd[i]->status.name, map[b_sd[i]->bl.m].name, b_sd[i]->bl.x, b_sd[i]->bl.y, MaxPrice[i], total[i], amount[i]); clif_channel_message(cd, output, -1); } } vendingbot_timer = gettick() + 5000; // 5 Seconds Protection from flood } else if( !strncasecmp(message, ".exit", 5) ) channel_leave(sd, cd->name, true); else if( cd->op != sd->bl.id && pc_has_permission(sd,PC_PERM_CHANNEL_OPERATOR) ) return; else if( !strncasecmp(message, ".invite ", 8) && len > 11 ) { // Invite a User to the Channel option_text = (char *)message + 8; if( (p_sd = map_nick2sd(option_text)) == NULL ) clif_displaymessage(sd->fd, msg_txt(893)); else if( p_sd == sd ) clif_displaymessage(sd->fd, msg_txt(894)); else if( p_sd->state.noask ) clif_displaymessage(sd->fd, msg_txt(700)); else if( channel_slot_get(p_sd, cd) >= 0 ) clif_displaymessage(sd->fd, msg_txt(895)); else if( p_sd->channel_invite_timer != INVALID_TIMER ) clif_displaymessage(sd->fd, msg_txt(897)); else { sprintf(output, msg_txt(896), cd->name, sd->status.name, p_sd->status.name); clif_channel_message(cd, output, -1); // Notify about the invitation to the Channel sprintf(output, msg_txt(898), sd->status.name, cd->name); clif_disp_onlyself(p_sd, output, strlen(output)); // Notify Player p_sd->channel_invite_timer = add_timer(gettick() + 30000, channel_invite_timer, p_sd->bl.id, (intptr_t)aStrdup(cd->name)); } } else if( !strncasecmp(message, ".kick ", 6) && len > 9 ) { // Kick Users option_text = (char *)message + 6; if( (p_sd = map_nick2sd(option_text)) == NULL || channel_slot_get(p_sd, cd) < 0 ) clif_displaymessage(sd->fd, msg_txt(817)); else if( p_sd == sd ) clif_displaymessage(sd->fd, msg_txt(818)); else { channel_leave(p_sd, cd->name, false); sprintf(output, msg_txt(819), cd->name, p_sd->status.name); clif_channel_message(cd, output, -1); p_sd->canjoinchn_tick = gettick() + 10000; } } else if( !strncasecmp(message, ".color ", 7) && len > 7 ) { // Set Chat Room Color short color = atoi(message + 7); if( color < 1 || color > 39 ) clif_displaymessage(sd->fd, msg_txt(830)); else { cd->color = channel_color[color - 1]; sprintf(output, msg_txt(831), cd->name); clif_channel_message(cd, output, -1); } } else if( !strncasecmp(message, ".op ", 4) && len > 7 ) { option_text = (char *)message + 4; if( cd->type != CHN_USER ) clif_displaymessage(sd->fd, msg_txt(875)); else if( (p_sd = map_nick2sd(option_text)) == NULL || channel_slot_get(p_sd, cd) < 0 ) clif_displaymessage(sd->fd, msg_txt(817)); else if( p_sd == sd ) clif_displaymessage(sd->fd, msg_txt(832)); else { cd->op = p_sd->bl.id; sprintf(output, msg_txt(833), cd->name, p_sd->status.name); clif_channel_message(cd, output, -1); } } else if( !strncasecmp(message, ".pass ", 6) && len > 6 ) { option_text = trim((char *)message + 6); if( cd->type != CHN_USER ) clif_displaymessage(sd->fd, msg_txt(875)); else if( !strcmpi(option_text, "off") ) { memset(cd->pass, '\0', sizeof(cd->pass)); sprintf(output, msg_txt(834), cd->name); clif_channel_message(cd, output, -1); } else if( strlen(option_text) > 1 && strlen(option_text) < NAME_LENGTH ) { safestrncpy(cd->pass, option_text, sizeof(cd->pass)); sprintf(output, msg_txt(835), cd->name); clif_channel_message(cd, output, -1); } else clif_displaymessage(sd->fd, msg_txt(836)); } else if( !strncasecmp(message, ".close", 6) ) { if( cd->type != CHN_USER ) clif_displaymessage(sd->fd, msg_txt(875)); else channel_close(cd); } else if( !strncasecmp(message, ".list", 6) ) { DBIterator* iter = db_iterator(cd->users_db); clif_displaymessage(sd->fd, msg_txt(837)); for( p_sd = (struct map_session_data *)dbi_first(iter); dbi_exists(iter); p_sd = (struct map_session_data *)dbi_next(iter) ) clif_displaymessage(sd->fd, p_sd->status.name); dbi_destroy(iter); clif_displaymessage(sd->fd, msg_txt(838)); } else if( !strncasecmp(message, ".help", 5) ) { // Command List clif_displaymessage(sd->fd, msg_txt(839)); clif_displaymessage(sd->fd, msg_txt(840)); clif_displaymessage(sd->fd, msg_txt(841)); clif_displaymessage(sd->fd, msg_txt(842)); clif_displaymessage(sd->fd, msg_txt(843)); clif_displaymessage(sd->fd, msg_txt(844)); clif_displaymessage(sd->fd, msg_txt(845)); clif_displaymessage(sd->fd, msg_txt(846)); } else clif_displaymessage(sd->fd, msg_txt(847)); return; } snprintf(output, sizeof(output), "%s : [%s] %s", cd->name, sd->status.name, message); clif_channel_message(cd, output, -1); }
/** * A player is attempting to modify the banlist * @param sd: Player data * @param chname: Channel name * @param pname: Player to ban or unban * @param flag: Ban options (0 - Ban, 1 - Unban, 2 - Unban all, 3 - Ban list) * @return 0 on success or -1 on failure */ int channel_pcban(struct map_session_data *sd, char *chname, char *pname, int flag){ struct Channel *channel; char output[CHAT_SIZE_MAX]; struct map_session_data *tsd = map_nick2sd(pname,false); 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,sd,0); if( !channel ) { sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available. clif_displaymessage(sd->fd, output); return -1; } if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) { if (channel->char_id != sd->status.char_id) { sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'. clif_displaymessage(sd->fd, output); return -1; } else if (!channel_config.private_channel.ban) { sprintf(output, msg_txt(sd,765), chname); // You're not allowed to ban a player. clif_displaymessage(sd->fd, output); return -1; } } if(flag != 2 && flag != 3){ char banned; if(!tsd || pc_has_permission(tsd, PC_PERM_CHANNEL_ADMIN) ) { sprintf(output, msg_txt(sd,1464), pname);// Ban failed for player '%s'. clif_displaymessage(sd->fd, output); return -1; } banned = channel_haspcbanned(channel,tsd); if(!flag && banned==1) { sprintf(output, msg_txt(sd,1465), tsd->status.name);// Player '%s' is already banned from this channel. clif_displaymessage(sd->fd, output); return -1; } else if(flag==1 && banned==0) { sprintf(output, msg_txt(sd,1440), tsd->status.name);// Player '%s' is not banned from this channel. clif_displaymessage(sd->fd, output); return -1; } } else { if( !db_size(channel->banned) ) { sprintf(output, msg_txt(sd,1439), chname);// Channel '%s' contains no banned players. clif_displaymessage(sd->fd, output); return 0; } } //let properly alter the list now switch(flag){ case 0: { struct chan_banentry *cbe; if (!tsd) return -1; CREATE(cbe, struct chan_banentry, 1); cbe->char_id = tsd->status.char_id; strcpy(cbe->char_name,tsd->status.name); idb_put(channel->banned, tsd->status.char_id, cbe); channel_clean(channel,tsd,0); sprintf(output, msg_txt(sd,1437),tsd->status.name,chname); // Player '%s' is banned from the '%s' channel. break; } case 1: if (!tsd) return -1; idb_remove(channel->banned, tsd->status.char_id); sprintf(output, msg_txt(sd,1441),tsd->status.name,chname); // Player '%s' is unbanned from the '%s' channel. break; case 2: db_clear(channel->banned); sprintf(output, msg_txt(sd,1442),chname); // Cleared all bans from the '%s' channel. break; case 3: { DBIterator *iter = db_iterator(channel->banned); struct chan_banentry *cbe; sprintf(output, msg_txt(sd,1443), channel->name);// ---- '#%s' Ban List: clif_displaymessage(sd->fd, output); for( cbe = (struct chan_banentry *)dbi_first(iter); dbi_exists(iter); cbe = (struct chan_banentry *)dbi_next(iter) ) { //for all users if (cbe->char_name[0]) sprintf(output, "%d: %s",cbe->char_id,cbe->char_name); else sprintf(output, "%d: ****",cbe->char_id); clif_displaymessage(sd->fd, output); } dbi_destroy(iter); } return 0; } clif_displaymessage(sd->fd, output); return 0; }