void channel_close(struct channel_data *cd) { int j; char output[128]; struct map_session_data *pl_sd; DBIterator* iter; if( cd == NULL || cd->type != CHN_USER ) return; sprintf(output, msg_txt(804), cd->name); clif_channel_message(cd, output, -1); iter = db_iterator(cd->users_db); for( pl_sd = (struct map_session_data *)dbi_first(iter); dbi_exists(iter); pl_sd = (struct map_session_data *)dbi_next(iter) ) { idb_remove(cd->users_db, pl_sd->bl.id); ARR_FIND(0, MAX_USER_CHANNELS, j, pl_sd->cd[j] == cd); if( j == MAX_USER_CHANNELS ) continue; pl_sd->cd[j] = NULL; } dbi_destroy(iter); db_destroy(cd->users_db); strdb_remove(channel_db, cd->name); }
bool channel_create(struct map_session_data *sd, const char* name, const char* pass, short type, short color, int op) { struct channel_data *cd; int i = 0; if( !name || strlen(name) < 2 || strlen(name) >= NAME_LENGTH || name[0] != '#' ) { if( sd ) clif_displaymessage(sd->fd, msg_txt(801)); return false; } if( type == CHN_USER && !sd ) return false; // Operator required for user channels if( sd && type == CHN_USER && (i = channel_slot_free(sd)) < 0 ) { clif_displaymessage(sd->fd, msg_txt(800)); return false; } if( (cd = (struct channel_data *)strdb_get(channel_db, name)) != NULL ) { if( sd ) clif_displaymessage(sd->fd, msg_txt(802)); return false; // Already exists } CREATE(cd, struct channel_data, 1); cd->channel_id = ++channel_counter; safestrncpy(cd->name, name, sizeof(cd->name)); safestrncpy(cd->pass, pass, sizeof(cd->pass)); cd->type = type; cd->color = channel_color[cap_value(color,0,38)]; cd->users = 0; cd->op = 0; cd->users_db = idb_alloc(DB_OPT_BASE); if( type == CHN_USER ) { char output[128]; sprintf(output, msg_txt(803), cd->name, sd->status.name); sd->cd[i] = cd; cd->op = sd->bl.id; idb_put(cd->users_db, sd->bl.id, sd); cd->users++; clif_channel_message(cd, output, -1); } else if( type < CHN_USER ) { server_channel[type] = cd; // Quick access to main channels ShowInfo("Channel System : New channel %s created.\n", cd->name); } else cd->op = op; // Server Channel strdb_put(channel_db, cd->name, cd); return true; }
int channel_invite_timer(int tid, unsigned int tick, int id, intptr_t data) { struct channel_data *cd; struct map_session_data* sd = map_id2sd(id); char output[CHAT_SIZE_MAX]; char *name = (char *)data; if( sd && (cd = (struct channel_data *)strdb_get(channel_db, name)) != NULL ) { sprintf(output, msg_txt(701), cd->name, sd->status.name); clif_channel_message(cd, output, -1); } if( sd ) { clif_disp_onlyself(sd, msg_txt(702), strlen(msg_txt(702))); sd->channel_invite_timer = INVALID_TIMER; } if( name ) aFree(name); return 1; }
/*========================================== * Open shop * data := {<index>.w <amount>.w <value>.l}[count] *------------------------------------------*/ void vending_openvending(struct map_session_data* sd, const char* message, bool flag, const uint8* data, int count) { int i, j, char_id; int vending_skill_lvl; nullpo_retv(sd); if( !flag ) // cancelled return; // nothing to do if (pc_istrading(sd)) return; // can't have 2 shops at once vending_skill_lvl = pc_checkskill(sd, MC_VENDING); // skill level and cart check if( !vending_skill_lvl || !pc_iscarton(sd) ) { clif_skill_fail(sd, MC_VENDING, 0, 0); return; } // check number of items in shop if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // invalid item count clif_skill_fail(sd, MC_VENDING, 0, 0); return; } if((sd->bl.m == map_mapname2mapid("mercadores") && ( ((sd->bl.x != 65) && (sd->bl.x != 74) && (sd->bl.x != 85) && (sd->bl.x != 94) && (sd->bl.x != 34) && (sd->bl.x != 25) && (sd->bl.x != 14) && (sd->bl.x != 5) && (sd->bl.x != 44) && (sd->bl.x != 55)) ))) { clif_displaymessage(sd->fd,"Você não pode abrir lojas no meio da Sala."); return; } // filter out invalid items i = 0; for( j = 0; j < count; j++ ) { short index = *(uint16*)(data + 8*j + 0); short amount = *(uint16*)(data + 8*j + 2); unsigned int value = *(uint32*)(data + 8*j + 4); index -= 2; // offset adjustment (client says that the first cart position is 2) if( index < 0 || index >= MAX_CART // invalid position || pc_cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity //NOTE: official server does not do any of the following checks! || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case || sd->status.cart[index].bound // Can't Trade Account bound items || ( sd->status.cart[index].card[0] == CARD0_CREATE && (char_id = MakeDWord(sd->status.cart[index].card[2],sd->status.cart[index].card[3])) > 0 && ((battle_config.bg_reserved_char_id && char_id == battle_config.bg_reserved_char_id) || (battle_config.ancient_reserved_char_id && char_id == battle_config.ancient_reserved_char_id)) ) || !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item continue; sd->vending[i].index = index; sd->vending[i].amount = amount; sd->vending[i].value = cap_value(value, 0, (unsigned int)battle_config.vending_max_value); i++; // item successfully added } if( i != j ) clif_displaymessage (sd->fd, msg_txt(266)); //"Some of your items cannot be vended and were removed from the shop." if( i == 0 ) { // no valid item found clif_skill_fail(sd, MC_VENDING, 0, 0); // custom reply packet return; } sd->state.vending = true; sd->vender_id = vending_getuid(); sd->vend_num = i; safestrncpy(sd->message, message, MESSAGE_SIZE); pc_stop_walking(sd,1); clif_openvending(sd,sd->bl.id,sd->vending); clif_showvendingboard(&sd->bl,message,0); if( battle_config.channel_announces&0x10 ) { char chat_message[256]; sprintf(chat_message, msg_txt(820), vending_chat_nick, sd->status.name, sd->message, map[sd->bl.m].name, sd->bl.x, sd->bl.y); clif_channel_message(server_channel[CHN_VENDING], chat_message, 27); } if( map[sd->bl.m].flag.vending_cell ) map_setcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_NOBOARDS, false); }
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); }
void channel_leave(struct map_session_data *sd, const char* name, bool msg) { struct channel_data *cd; char output[128]; int i; if( (cd = (struct channel_data *)strdb_get(channel_db, name)) == NULL ) return; if( (i = channel_slot_get(sd, cd)) != -1 ) { sd->cd[i] = NULL; clif_displaymessage(sd->fd, msg_txt(809)); if( cd->type != CHN_USER && msg ) { 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); } } if( idb_get(cd->users_db, sd->bl.id) != NULL ) { idb_remove(cd->users_db, sd->bl.id); cd->users--; if( msg ) { sprintf(output, msg_txt(810), cd->name, sd->status.name); clif_channel_message(cd, output, -1); } } if( cd->type != CHN_USER ) return; if( cd->users < 1 ) { // No more users in the channel channel_close(cd); return; } if( sd->bl.id == cd->op ) { // Select another Operator struct map_session_data *pl_sd; DBIterator* iter = db_iterator(cd->users_db); cd->op = 0; if( (pl_sd = (struct map_session_data *)dbi_first(iter)) != NULL && dbi_exists(iter) ) { cd->op = pl_sd->bl.id; sprintf(output, msg_txt(811), cd->name, pl_sd->status.name); clif_channel_message(cd, output, -1); } dbi_destroy(iter); } if( cd->users <= 0 ) { ShowWarning("Channel '%s' with no users reporting %d users. Destroying it!!.\n", cd->name, cd->users); channel_close(cd); } }
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); } }