Ejemplo n.º 1
0
/**
* Attempt to send mail
* @param sd Sender
* @param dest_name Destination name
* @param title Mail title
* @param body_msg Mail message
* @param body_len Message's length
*/
void mail_send(struct map_session_data *sd, const char *dest_name, const char *title, const char *body_msg, int body_len) {
	struct mail_message msg;

	nullpo_retv(sd);

	if( sd->state.trading )
		return;

	if( DIFF_TICK(sd->cansendmail_tick, gettick()) > 0 ) {
		clif_displaymessage(sd->fd,msg_txt(sd,675)); //"Cannot send mails too fast!!."
		clif_Mail_send(sd, WRITE_MAIL_FAILED); // fail
		return;
	}

	if( battle_config.mail_daily_count ){
		mail_refresh_remaining_amount(sd);

		// After calling mail_refresh_remaining_amount the status should always be there
		if( sd->sc.data[SC_DAILYSENDMAILCNT] == NULL || sd->sc.data[SC_DAILYSENDMAILCNT]->val2 >= battle_config.mail_daily_count ){
			clif_Mail_send(sd, WRITE_MAIL_FAILED_CNT);
			return;
		}else{
			sc_start2( &sd->bl, &sd->bl, SC_DAILYSENDMAILCNT, 100, date_get_dayofyear(), sd->sc.data[SC_DAILYSENDMAILCNT]->val2 + 1, -1 );
		}
	}

	if( body_len > MAIL_BODY_LENGTH )
		body_len = MAIL_BODY_LENGTH;

	if( !mail_setattachment(sd, &msg) ) { // Invalid Append condition
		int i;

		clif_Mail_send(sd, WRITE_MAIL_FAILED); // fail
		for( i = 0; i < MAIL_MAX_ITEM; i++ ){
			mail_removeitem(sd,0,sd->mail.item[i].index + 2, sd->mail.item[i].amount);
		}
		mail_removezeny(sd,false);
		return;
	}

	msg.id = 0; // id will be assigned by charserver
	msg.send_id = sd->status.char_id;
	msg.dest_id = 0; // will attempt to resolve name
	safestrncpy(msg.send_name, sd->status.name, NAME_LENGTH);
	safestrncpy(msg.dest_name, (char*)dest_name, NAME_LENGTH);
	safestrncpy(msg.title, (char*)title, MAIL_TITLE_LENGTH);
	msg.type = MAIL_INBOX_NORMAL;

	if (msg.title[0] == '\0') {
		return; // Message has no length and somehow client verification was skipped.
	}

	if (body_len)
		safestrncpy(msg.body, (char*)body_msg, body_len + 1);
	else
		memset(msg.body, 0x00, MAIL_BODY_LENGTH);

	msg.timestamp = time(NULL);
	if( !intif_Mail_send(sd->status.account_id, &msg) )
		mail_deliveryfail(sd, &msg);

	sd->cansendmail_tick = gettick() + battle_config.mail_delay; // Flood Protection
}
Ejemplo n.º 2
0
/*==========================================
 * Adds an item/qty to the trade window
 *------------------------------------------*/
void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
{
	struct map_session_data *target_sd;
	struct item *item;
	int trade_i, trade_weight;
	int src_lv, dst_lv;

	nullpo_retv(sd);
	if( !sd->state.trading || sd->state.deal_locked > 0 )
		return; //Can't add stuff.

	if( (target_sd = map_id2sd(sd->trade_partner)) == NULL )
	{
		trade_tradecancel(sd);
		return;
	}

	if( amount == 0 )
	{	//Why do this.. ~.~ just send an ack, the item won't display on the trade window.
		clif_tradeitemok(sd, index, 0);
		return;
	}

	index -= 2; // 0 is for zeny, 1 is unknown. Gravity, go figure...

	//Item checks...
	if( index < 0 || index >= MAX_INVENTORY )
		return;
	if( amount < 0 || amount > sd->status.inventory[index].amount )
		return;

	item = &sd->status.inventory[index];
	src_lv = pc_isGM(sd);
	dst_lv = pc_isGM(target_sd);
	if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade
		(pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade
	{
		clif_displaymessage (sd->fd, msg_txt(260));
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	//Locate a trade position
	ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
	if( trade_i == 10 ) //No space left
	{
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	trade_weight = sd->inventory_data[index]->weight * amount;
	if( target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight )
	{	//fail to add item -- the player was over weighted.
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	if( sd->deal.item[trade_i].index == index )
	{	//The same item as before is being readjusted.
		if( sd->deal.item[trade_i].amount + amount > sd->status.inventory[index].amount )
		{	//packet deal exploit check
			amount = sd->status.inventory[index].amount - sd->deal.item[trade_i].amount;
			trade_weight = sd->inventory_data[index]->weight * amount;
		}
		sd->deal.item[trade_i].amount += amount;
	}
	else
	{	//New deal item
		sd->deal.item[trade_i].index = index;
		sd->deal.item[trade_i].amount = amount;
	}
	sd->deal.weight += trade_weight;

	clif_tradeitemok(sd, index+2, 0); // Return the index as it was received
	clif_tradeadditem(sd, target_sd, index+2, amount);
}
Ejemplo n.º 3
0
/*==========================================
 * 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;
	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;
	}

	// filter out invalid items
	i = 0;
	for( j = 0; j < count; j++ )
	{
		int index           = *(uint16*)(data + 8*j + 0);
		unsigned int 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
		||  !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, 1, (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->vender_id = sd->bl.id;
	sd->vend_num = i;
	safestrncpy(sd->message, message, MESSAGE_SIZE);

	pc_stop_walking(sd,1);
	clif_openvending(sd,sd->vender_id,sd->vending);
	clif_showvendingboard(&sd->bl,message,0);
}
Ejemplo n.º 4
0
/*==========================================
 * Open shop
 * data := {<index>.w <amount>.w <value>.l}[count]
 *------------------------------------------*/
void vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) {
	int i, j;
	int vending_skill_lvl;
	nullpo_retv(sd);

	if ( pc_isdead(sd) || !sd->state.prevend || pc_istrading(sd))
		return; // can't open vendings lying dead || didn't use via the skill (wpe/hack) || 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, USESKILL_FAIL_LEVEL, 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, USESKILL_FAIL_LEVEL, 0);
		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
		||  !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(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->message (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, USESKILL_FAIL_LEVEL, 0); // custom reply packet
		return;
	}
	sd->state.prevend = 0;
	sd->state.vending = true;
	sd->vender_id = vending_getuid();
	sd->vend_num = i;
	safestrncpy(sd->message, message, MESSAGE_SIZE);

	clif->openvending(sd,sd->bl.id,sd->vending);
	clif->showvendingboard(&sd->bl,message,0);
}
Ejemplo n.º 5
0
/*==========================================
 * Initiates a trade request.
 *------------------------------------------*/
void trade_traderequest(struct map_session_data *sd, struct map_session_data *target_sd)
{
	int level;

	nullpo_retv(sd);

	if (map[sd->bl.m].flag.notrade) {
		clif_displaymessage (sd->fd, msg_txt(272));
		return; //Can't trade in notrade mapflag maps.
	}

	if( sd->state.secure_items ) {
		clif_displaymessage(sd->fd, "You can't trade. Blocked with @security");
		return;
	}

	if (target_sd == NULL || sd == target_sd) {
		clif_tradestart(sd, 1); // character does not exist
		return;
	}

	if( target_sd->state.secure_items ) {
		clif_displaymessage(sd->fd, "Target can't trade. Blocked with @security");
		return;
	}

	if( !battle_config.faction_allow_trade && sd->status.faction_id != target_sd->status.faction_id )
	{
		clif_displaymessage(sd->fd,"You cannot trade with other faction members.");
		return;
	}

	if( target_sd->npc_id || target_sd->buyer_id )
	{	//Trade fails if you are using an NPC.
		clif_tradestart(sd, 2);
		return;
	}

	if (!battle_config.invite_request_check) {
		if (target_sd->guild_invite > 0 || target_sd->party_invite > 0 || target_sd->adopt_invite) {
			clif_tradestart(sd, 2);
			return;
		}
	}

	if (target_sd->trade_partner != 0) {
		clif_tradestart(sd, 2); // person is in another trade
		return;
	}

	level = pc_isGM(sd);
	if ( !pc_can_give_items(level) || !pc_can_give_items(pc_isGM(target_sd)) ) //check if both GMs are allowed to trade
	{
		clif_displaymessage(sd->fd, msg_txt(246));
		clif_tradestart(sd, 2); // GM is not allowed to trade
		return;
	} 
	
	//Fixed. Only real GMs can request trade from far away! [Lupus] 
	if (level < battle_config.lowest_gm_level && (sd->bl.m != target_sd->bl.m ||
		!check_distance_bl(&sd->bl, &target_sd->bl, TRADE_DISTANCE)
	)) {
		clif_tradestart(sd, 0); // too far
		return ;
	}
	
	target_sd->trade_partner = sd->status.account_id;
	sd->trade_partner = target_sd->status.account_id;
	clif_traderequest(target_sd, sd->status.name);
}
Ejemplo n.º 6
0
/**
 * Show account info from login-server to user
 */
void mapif_accinfo_ack(bool success, int map_fd, int u_fd, int u_aid, int account_id, int8 type,
	int group_id, int logincount, int state, const char *email, const char *last_ip, const char *lastlogin,
	const char *birthdate, const char *user_pass, const char *pincode, const char *userid)
{
	
	if (map_fd <= 0 || !session_isActive(map_fd))
		return; // check if we have a valid fd

	if (!success) {
		inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(216), account_id);
		return;
	}

	if (type == 1) { //type 1 we don't want all the info [lighta] @CHECKME
		mapif_acc_info_ack(map_fd, u_fd, account_id, userid);
		return;
	}

	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(217), account_id);
	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(218), userid, group_id, state);
	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(219), user_pass[0] != '\0' ? user_pass : msg_txt(220), pincode[0] != '\0' ? msg_txt(220) : pincode);
	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(221), email, birthdate);
	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(222), last_ip, geoip_getcountry(str2ip(last_ip)));
	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(223), logincount, lastlogin);
	inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(224));

	if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`, `name`, `char_num`, `class`, `base_level`, `job_level`, `online` FROM `%s` WHERE `account_id` = '%d' ORDER BY `char_num` LIMIT %d", schema_config.char_db, account_id, MAX_CHARS)
		|| Sql_NumRows(sql_handle) == 0 )
	{
		if( Sql_NumRows(sql_handle) == 0 )
			inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(226));
		else {
			inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(213));
			Sql_ShowDebug(sql_handle);
		}
	} else {
		while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) {
			int char_id, class_;
			short char_num, base_level, job_level, online;
			char name[NAME_LENGTH];
			char *data;

			Sql_GetData(sql_handle, 0, &data, NULL); char_id = atoi(data);
			Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
			Sql_GetData(sql_handle, 2, &data, NULL); char_num = atoi(data);
			Sql_GetData(sql_handle, 3, &data, NULL); class_ = atoi(data);
			Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data);
			Sql_GetData(sql_handle, 5, &data, NULL); job_level = atoi(data);
			Sql_GetData(sql_handle, 6, &data, NULL); online = atoi(data);

			inter_to_fd(map_fd, u_fd, u_aid, (char *)msg_txt(225), char_num, char_id, name, job_name(class_), base_level, job_level, online?"Online":"Offline");
		}
	}
	Sql_FreeResult(sql_handle);
}
Ejemplo n.º 7
0
/**
* Attempt to create new buying store
* @param sd
* @param zenylimit
* @param result
* @param storename
* @param *itemlist { <nameid>.W, <amount>.W, <price>.L }*
* @param count Number of item on the itemlist
* @param at Autotrader info, or NULL if requetsed not from autotrade persistance
* @return 0 If success, 1 - Cannot open, 2 - Manner penalty, 3 - Mapflag restiction, 4 - Cell restriction, 5 - Invalid count/result, 6 - Cannot give item, 7 - Will be overweight
*/
int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count, struct s_autotrader *at)
{
	unsigned int i, weight, listidx;
	char message_sql[MESSAGE_SIZE*2];
	StringBuf buf;

	nullpo_retr(1, sd);

	if( !result || count == 0 )
	{// canceled, or no items
		return 5;
	}

	if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] )
	{// disabled or invalid input
		sd->buyingstore.slots = 0;
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
		return 1;
	}

	if( !pc_can_give_items(sd) )
	{// custom: GM is not allowed to buy (give zeny)
		sd->buyingstore.slots = 0;
		clif_displaymessage(sd->fd, msg_txt(sd,246));
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
		return 6;
	}

	if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) )
	{// custom: mute limitation
		return 2;
	}

	if( map[sd->bl.m].flag.novending )
	{// custom: no vending maps
		clif_displaymessage(sd->fd, msg_txt(sd,276)); // "You can't open a shop on this map"
		return 3;
	}

	if( map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
	{// custom: no vending cells
		clif_displaymessage(sd->fd, msg_txt(sd,204)); // "You can't open a shop on this cell."
		return 4;
	}

	weight = sd->weight;

	// check item list
	for( i = 0; i < count; i++ )
	{// itemlist: <name id>.W <amount>.W <price>.L
		unsigned short nameid, amount;
		int price, idx;
		struct item_data* id;

		nameid = RBUFW(itemlist,i*8+0);
		amount = RBUFW(itemlist,i*8+2);
		price  = RBUFL(itemlist,i*8+4);

		if( ( id = itemdb_exists(nameid) ) == NULL || amount == 0 )
		{// invalid input
			break;
		}

		if( price <= 0 || price > BUYINGSTORE_MAX_PRICE )
		{// invalid price: unlike vending, items cannot be bought at 0 Zeny
			break;
		}

		if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
		{// restrictions: allowed, no character-bound items and at least one must be owned
			break;
		}

		if( sd->inventory.u.items_inventory[idx].amount + amount > BUYINGSTORE_MAX_AMOUNT )
		{// too many items of same kind
			break;
		}

		if( i )
		{// duplicate check. as the client does this too, only malicious intent should be caught here
			ARR_FIND( 0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid );
			if( listidx != i )
			{// duplicate
				ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id);
				break;
			}
		}

		weight+= id->weight*amount;
		sd->buyingstore.items[i].nameid = nameid;
		sd->buyingstore.items[i].amount = amount;
		sd->buyingstore.items[i].price  = price;
	}

	if( i != count )
	{// invalid item/amount/price
		sd->buyingstore.slots = 0;
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
		return 5;
	}

	if( (sd->max_weight*90)/100 < weight )
	{// not able to carry all wanted items without getting overweight (90%)
		sd->buyingstore.slots = 0;
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE_OVERWEIGHT, weight);
		return 7;
	}

	// success
	sd->state.buyingstore = true;
	sd->buyer_id = buyingstore_getuid();
	sd->buyingstore.zenylimit = zenylimit;
	sd->buyingstore.slots = i;  // store actual amount of items
	safestrncpy(sd->message, storename, sizeof(sd->message));

	Sql_EscapeString( mmysql_handle, message_sql, sd->message );

	if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`id`, `account_id`, `char_id`, `sex`, `map`, `x`, `y`, `title`, `limit`, `autotrade`, `body_direction`, `head_direction`, `sit`) "
		"VALUES( %d, %d, %d, '%c', '%s', %d, %d, '%s', %d, %d, '%d', '%d', '%d' );",
		buyingstores_table, sd->buyer_id, sd->status.account_id, sd->status.char_id, sd->status.sex == 0 ? 'F' : 'M', map[sd->bl.m].name, sd->bl.x, sd->bl.y, message_sql, sd->buyingstore.zenylimit, sd->state.autotrade, at ? at->dir : sd->ud.dir, at ? at->head_dir : sd->head_dir, at ? at->sit : pc_issit(sd) ) != SQL_SUCCESS ){
		Sql_ShowDebug(mmysql_handle);
	}

	StringBuf_Init(&buf);
	StringBuf_Printf(&buf, "INSERT INTO `%s`(`buyingstore_id`,`index`,`item_id`,`amount`,`price`) VALUES", buyingstore_items_table);
	for (i = 0; i < sd->buyingstore.slots; i++){
		StringBuf_Printf(&buf, "(%d,%d,%hu,%d,%d)", sd->buyer_id, i, sd->buyingstore.items[i].nameid, sd->buyingstore.items[i].amount, sd->buyingstore.items[i].price);
		if (i < sd->buyingstore.slots-1)
			StringBuf_AppendStr(&buf, ",");
	}
	if (SQL_ERROR == Sql_QueryStr(mmysql_handle, StringBuf_Value(&buf)))
		Sql_ShowDebug(mmysql_handle);
	StringBuf_Destroy(&buf);

	clif_buyingstore_myitemlist(sd);
	clif_buyingstore_entry(sd);
	idb_put(buyingstore_db, sd->status.char_id, sd);

	return 0;
}
Ejemplo n.º 8
0
/**
 * 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 && cbe->char_name[0] != '\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;
}
Ejemplo n.º 9
0
/**
 * Purchase item(s) from a shop
 * @param sd : buyer player session
 * @param aid : account id of vender
 * @param uid : shop unique id
 * @param data : items data who would like to purchase
 *  data := {<index>.w <amount>.w }[count]
 * @param count : number of different items he's trying to buy
 */
void vending_purchasereq(struct map_session_data *sd, int aid, int uid, const uint8 *data, int count)
{
	int i, j, cursor, w, new_ = 0, blank, vend_list[MAX_VENDING];
	double z;
	struct s_vending vending[MAX_VENDING]; //Against duplicate packets
	struct map_session_data *vsd = map_id2sd(aid);

	nullpo_retv(sd);

	if( vsd == NULL || !vsd->state.vending || vsd->bl.id == sd->bl.id )
		return; //Invalid shop

	if( vsd->vender_id != uid ) { //Shop has changed
		clif_buyvending(sd, 0, 0, 6);  //Store information was incorrect
		return;
	}

	if( !searchstore_queryremote(sd, aid) && ( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) ) )
		return; //Shop too far away

	searchstore_clearremote(sd);

	if( count < 1 || count > MAX_VENDING || count > vsd->vend_num )
		return; //Invalid amount of purchased items

	blank = pc_inventoryblank(sd); //Number of free cells in the buyer's inventory

	//Duplicate item in vending to check hacker with multiple packets
	memcpy(&vending, &vsd->vending, sizeof(vsd->vending)); //Copy vending list

	//Some checks
	z = 0.; //Zeny counter
	w = 0;  //Weight counter
	for( i = 0; i < count; i++ ) {
		short amount = *(uint16 *)(data + 4 * i + 0);
		short idx    = *(uint16 *)(data + 4 * i + 2);

		idx -= 2;
		if( amount <= 0 )
			return;

		//Check of item index in the cart
		if( idx < 0 || idx >= MAX_CART )
			return;

		ARR_FIND(0, vsd->vend_num, j, vsd->vending[j].index == idx);
		if( j == vsd->vend_num )
			return; //Picked non-existing item
		else
			vend_list[i] = j;

		z += ((double)vsd->vending[j].value * (double)amount);
		if( z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY ) {
			clif_buyvending(sd, idx, amount, 1); //You don't have enough zeny
			return;
		}
		if( z + (double)vsd->status.zeny > (double)MAX_ZENY && !battle_config.vending_over_max ) {
			clif_buyvending(sd, idx, vsd->vending[j].amount, 4); //Too much zeny = overflow
			return;

		}
		w += itemdb_weight(vsd->cart.u.items_cart[idx].nameid) * amount;
		if( w + sd->weight > sd->max_weight ) {
			clif_buyvending(sd, idx, amount, 2); //You can not buy, because overweight
			return;
		}

		//Check to see if cart/vend info is in sync.
		if( vending[j].amount > vsd->cart.u.items_cart[idx].amount )
			vending[j].amount = vsd->cart.u.items_cart[idx].amount;

		//If they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples).
		//Here, we check cumulative amounts
		if( vending[j].amount < amount ) {
			//Send more quantity is not a hack (an other player can have buy items just before)
			clif_buyvending(sd, idx, vsd->vending[j].amount, 4); //Not enough quantity
			return;
		}

		vending[j].amount -= amount;

		switch( pc_checkadditem(sd, vsd->cart.u.items_cart[idx].nameid, amount) ) {
			case CHKADDITEM_EXIST:
				break; //We'd add this item to the existing one (in buyers inventory)
			case CHKADDITEM_NEW:
				new_++;
				if (new_ > blank)
					return; //Buyer has no space in his inventory
				break;
			case CHKADDITEM_OVERAMOUNT:
				return; //too many items
		}
	}

	pc_payzeny(sd, (int)z, LOG_TYPE_VENDING, vsd);
	achievement_update_objective(sd, AG_SPEND_ZENY, 1, (int)z);
	z = vending_calc_tax(sd, z);
	pc_getzeny(vsd, (int)z, LOG_TYPE_VENDING, sd);

	for( i = 0; i < count; i++ ) {
		short amount = *(uint16 *)(data + 4 * i + 0);
		short idx    = *(uint16 *)(data + 4 * i + 2);

		idx -= 2;
		z = 0.; //Zeny counter
		//Vending item
		pc_additem(sd, &vsd->cart.u.items_cart[idx], amount, LOG_TYPE_VENDING);
		vsd->vending[vend_list[i]].amount -= amount;
		z += ((double)vsd->vending[i].value * (double)amount);

		if( vsd->vending[vend_list[i]].amount ) {
			if( Sql_Query(mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `vending_id` = %d and `cartinventory_id` = %d",
				vending_items_db, vsd->vending[vend_list[i]].amount, vsd->vender_id, vsd->cart.u.items_cart[idx].id) != SQL_SUCCESS )
				Sql_ShowDebug(mmysql_handle);
		} else {
			if( Sql_Query(mmysql_handle, "DELETE FROM `%s` WHERE `vending_id` = %d and `cartinventory_id` = %d",
				vending_items_db, vsd->vender_id, vsd->cart.u.items_cart[idx].id) != SQL_SUCCESS )
				Sql_ShowDebug(mmysql_handle);
		}

		pc_cart_delitem(vsd, idx, amount, 0, LOG_TYPE_VENDING);
		z = vending_calc_tax(sd, z);
		clif_vendingreport(vsd, idx, amount, sd->status.char_id, (int)z);

		//Print buyer's name
		if( battle_config.buyer_name ) {
			char temp[256];

			sprintf(temp, msg_txt(265), sd->status.name);
			clif_messagecolor(&vsd->bl, color_table[COLOR_LIGHT_GREEN], temp, false, SELF);
		}
	}

	//Compact the vending list
	for( i = 0, cursor = 0; i < vsd->vend_num; i++ ) {
		if( vsd->vending[i].amount == 0 )
			continue;

		if( cursor != i ) { //Speedup
			vsd->vending[cursor].index = vsd->vending[i].index;
			vsd->vending[cursor].amount = vsd->vending[i].amount;
			vsd->vending[cursor].value = vsd->vending[i].value;
		}

		cursor++;
	}
	vsd->vend_num = cursor;

	//Always save BOTH: customer (buyer) and vender
	if( save_settings&CHARSAVE_VENDING ) {
		chrif_save(sd,CSAVE_INVENTORY|CSAVE_CART);
		chrif_save(vsd,CSAVE_INVENTORY|CSAVE_CART);
	}

	//Check for @AUTOTRADE users [durf]
	if( vsd->state.autotrade ) {
		//See if there is anything left in the shop
		ARR_FIND(0, vsd->vend_num, i, vsd->vending[i].amount > 0);
		if( i == vsd->vend_num ) {
			//Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex]
			vending_closevending(vsd);
			map_quit(vsd); //They have no reason to stay around anymore, do they?
		}
	}
}
Ejemplo n.º 10
0
/**
 * 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;
}
Ejemplo n.º 11
0
/**
 * 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, 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];

		clif_displaymessage(sd->fd, msg_txt(sd,1410)); // ---- Public Channels ----
		if( channel_config.map_tmpl.name != NULL && map[sd->bl.m].channel ) {
			sprintf(output, msg_txt(sd,1409), map[sd->bl.m].channel->name, db_size(map[sd->bl.m].channel->users));// - #%s (%d users)
			clif_displaymessage(sd->fd, output);
		}
		if( channel_config.ally_tmpl.name != NULL && 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;
}
Ejemplo n.º 12
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);
}
Ejemplo n.º 13
0
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);
	}
}
Ejemplo n.º 14
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);
	}
}
Ejemplo n.º 15
0
void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count)
{
	int zeny = 0, char_id;
	unsigned int i, weight, listidx, k;
	struct map_session_data* pl_sd;

	if( count == 0 )
	{// nothing to do
		return;
	}

	if( !battle_config.feature_buying_store || pc_istrading(sd) )
	{// not allowed to sell
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	if( !pc_can_give_items(pc_isGM(sd)) )
	{// custom: GM is not allowed to sell
		clif_displaymessage(sd->fd, msg_txt(246));
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	if( ( pl_sd = map_id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id )
	{// not online, not buying or not same store
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	if( !searchstore_queryremote(sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
	{// out of view range
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	searchstore_clearremote(sd);

	if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit )
	{// buyer lost zeny in the mean time? fix the limit
		pl_sd->buyingstore.zenylimit = pl_sd->status.zeny;
	}
	weight = pl_sd->weight;

	// check item list
	for( i = 0; i < count; i++ )
	{// itemlist: <index>.W <name id>.W <amount>.W
		unsigned short nameid, amount;
		int index;

		index  = RBUFW(itemlist,i*6+0)-2;
		nameid = RBUFW(itemlist,i*6+2);
		amount = RBUFW(itemlist,i*6+4);

		if( i )
		{// duplicate check. as the client does this too, only malicious intent should be caught here
			ARR_FIND( 0, i, k, RBUFW(itemlist,k*6+0)-2 == index );
			if( k != i )
			{// duplicate
				ShowWarning("buyingstore_trade: Found duplicate item on selling list (prevnameid=%hu, prevamount=%hu, nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n",
					RBUFW(itemlist,k*6+2), RBUFW(itemlist,k*6+4), nameid, amount, sd->status.account_id, sd->status.char_id);
				clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
				return;
			}
		}

		if( index < 0 || index >= ARRAYLENGTH(sd->status.inventory) || sd->inventory_data[index] == NULL || sd->status.inventory[index].nameid != nameid || sd->status.inventory[index].amount < amount )
		{// invalid input
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( sd->status.inventory[index].expire_time || sd->status.inventory[index].bound || !itemdb_cantrade(&sd->status.inventory[index], pc_isGM(sd), pc_isGM(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
		{// non-tradable item
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( sd->status.inventory[index].card[0] == CARD0_CREATE && (char_id = MakeDWord(sd->status.inventory[index].card[2],sd->status.inventory[index].card[3])) > 0 && (char_id == battle_config.bg_reserved_char_id || char_id == battle_config.ancient_reserved_char_id || char_id == battle_config.woe_reserved_char_id) )
		{ // Items where creator's ID is important
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			clif_displaymessage(sd->fd,"Cannot Trade event reserved Items (Battleground, WoE).");
			return;
		}

		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
		if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 )
		{// there is no such item or the buyer has already bought all of them
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( pl_sd->buyingstore.items[listidx].amount < amount )
		{// buyer does not need that much of the item
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_COUNT, nameid);
			return;
		}

		if( pc_checkadditem(pl_sd, nameid, amount) == ADDITEM_OVERAMOUNT )
		{// buyer does not have enough space for this item
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( amount*(unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight-weight )
		{// normally this is not supposed to happen, as the total weight is
		 // checked upon creation, but the buyer could have gained items
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}
		weight+= amount*sd->inventory_data[index]->weight;

		if( amount*pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit-zeny )
		{// buyer does not have enough zeny
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_ZENY, nameid);
			return;
		}
		zeny+= amount*pl_sd->buyingstore.items[listidx].price;
	}

	// process item list
	for( i = 0; i < count; i++ )
	{// itemlist: <index>.W <name id>.W <amount>.W
		unsigned short nameid, amount;
		int index;

		index  = RBUFW(itemlist,i*6+0)-2;
		nameid = RBUFW(itemlist,i*6+2);
		amount = RBUFW(itemlist,i*6+4);

		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
		zeny = amount*pl_sd->buyingstore.items[listidx].price;

		// log
		log_zeny(sd, LOG_TYPE_BUYING_STORE, pl_sd, zeny);

		// move item
		pc_additem(pl_sd, &sd->status.inventory[index], amount,LOG_TYPE_BUYING_STORE);
		pc_delitem(sd, index, amount, 1, 0, LOG_TYPE_BUYING_STORE);
		pl_sd->buyingstore.items[listidx].amount-= amount;

		// pay up
		pc_payzeny(pl_sd, zeny);
		pc_getzeny(sd, zeny);
		pl_sd->buyingstore.zenylimit-= zeny;

		// notify clients
		clif_buyingstore_delete_item(sd, index, amount, pl_sd->buyingstore.items[listidx].price);
		clif_buyingstore_update_item(pl_sd, nameid, amount);
	}

	// check whether or not there is still something to buy
	ARR_FIND( 0, pl_sd->buyingstore.slots, i, pl_sd->buyingstore.items[i].amount != 0 );
	if( i == pl_sd->buyingstore.slots )
	{// everything was bought
		clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_NO_ITEMS);
	}
	else if( pl_sd->buyingstore.zenylimit == 0 )
	{// zeny limit reached
		clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_ZENY);
	}
	else
	{// continue buying
		return;
	}

	// cannot continue buying
	buyingstore_close(pl_sd);

	// remove auto-trader
	if( pl_sd->state.autotrade )
	{
		map_quit(pl_sd);
	}
}
Ejemplo n.º 16
0
int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
{
	struct party_data *p;
	int i,flag=0;
	
	nullpo_ret(sd);
	if( ( p = party_search(sd->status.party_id) ) == NULL )
		return 0;
	if( tsd == NULL) {
		clif_party_inviteack(sd, "", 7);
		return 0;
	}
	
	if ( (pc_isGM(sd) >= battle_config.lowest_gm_level && pc_isGM(tsd) < battle_config.lowest_gm_level && !battle_config.gm_can_party && pc_isGM(sd) < battle_config.gm_cant_party_min_lv)
		|| ( pc_isGM(sd) < battle_config.lowest_gm_level && pc_isGM(tsd) >= battle_config.lowest_gm_level && !battle_config.gm_can_party && pc_isGM(tsd) < battle_config.gm_cant_party_min_lv) )
	{
		//GMs can't invite non GMs to the party if not above the invite trust level
		//Likewise, as long as gm_can_party is off, players can't invite GMs.
		clif_displaymessage(sd->fd, msg_txt(81));
		return 0;
	}
	
	//Only leader can invite.
	ARR_FIND(0, MAX_PARTY, i, p->data[i].sd == sd);
	if (i == MAX_PARTY || !p->party.member[i].leader)
	{	//TODO: Find the correct reply packet.
		clif_displaymessage(sd->fd, msg_txt(282));
		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;
	}
	for(i=0;i<MAX_PARTY;i++){
		if(p->party.member[i].account_id == 0) //Room for a new member.
			flag = 1;
	/* By default Aegis BLOCKS more than one char from the same account on a party.
	 * But eA does support it... so this check is left commented.
		if(p->party.member[i].account_id==tsd->status.account_id)
		{
			clif_party_inviteack(sd,tsd->status.name,4);
			return 0;
		}
	*/
	}
	if (!flag) { //Full party.
		clif_party_inviteack(sd,tsd->status.name,3);
		return 0;
	}
		
	tsd->party_invite=sd->status.party_id;
	tsd->party_invite_account=sd->status.account_id;

	clif_party_invite(sd,tsd);
	return 1;
}
Ejemplo n.º 17
0
void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count)
{
	unsigned int i, weight, listidx;
	struct item_data* id;

	if( !result || count == 0 )
	{// canceled, or no items
		return;
	}

	if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] )
	{// disabled or invalid input
		sd->buyingstore.slots = 0;
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
		return;
	}

	if( !pc_can_give_items(pc_isGM(sd)) )
	{// custom: GM is not allowed to buy (give zeny)
		sd->buyingstore.slots = 0;
		clif_displaymessage(sd->fd, msg_txt(246));
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
		return;
	}

	if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) )
	{// custom: mute limitation
		return;
	}

	if( map[sd->bl.m].flag.novending )
	{// custom: no vending maps
		clif_displaymessage(sd->fd, msg_txt(276)); // "You can't open a shop on this map"
		return;
	}

	if( map[sd->bl.m].flag.vending_cell != map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
	{// custom: no vending cells
		clif_displaymessage(sd->fd, msg_txt(204)); // "You can't open a shop on this cell."
		return;
	}

	weight = sd->weight;

	// check item list
	for( i = 0; i < count; i++ )
	{// itemlist: <name id>.W <amount>.W <price>.L
		unsigned short nameid, amount;
		int price, idx;

		nameid = RBUFW(itemlist,i*8+0);
		amount = RBUFW(itemlist,i*8+2);
		price  = RBUFL(itemlist,i*8+4);

		if( ( id = itemdb_exists(nameid) ) == NULL || amount == 0 )
		{// invalid input
			break;
		}

		if( price <= 0 || price > BUYINGSTORE_MAX_PRICE )
		{// invalid price: unlike vending, items cannot be bought at 0 Zeny
			break;
		}

		if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc_isGM(sd), pc_isGM(sd)) || ( idx = pc_search_inventory(sd, nameid) ) == -1 )
		{// restrictions: allowed, no character-bound items and at least one must be owned
			break;
		}

		if( sd->status.inventory[idx].amount+amount > BUYINGSTORE_MAX_AMOUNT )
		{// too many items of same kind
			break;
		}

		if( i )
		{// duplicate check. as the client does this too, only malicious intent should be caught here
			ARR_FIND( 0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid );
			if( listidx != i )
			{// duplicate
				ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id);
				break;
			}
		}

		weight+= id->weight*amount;
		sd->buyingstore.items[i].nameid = nameid;
		sd->buyingstore.items[i].amount = amount;
		sd->buyingstore.items[i].price  = price;
	}

	if( i != count )
	{// invalid item/amount/price
		sd->buyingstore.slots = 0;
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
		return;
	}

	if( (sd->max_weight*90)/100 < weight )
	{// not able to carry all wanted items without getting overweight (90%)
		sd->buyingstore.slots = 0;
		clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE_OVERWEIGHT, weight);
		return;
	}

	// success
	sd->state.buyingstore = true;
	sd->buyer_id = buyingstore_getuid();
	sd->buyingstore.zenylimit = zenylimit;
	sd->buyingstore.slots = i;  // store actual amount of items
	safestrncpy(sd->message, storename, sizeof(sd->message));
	clif_buyingstore_myitemlist(sd);
	clif_buyingstore_entry(sd);

	if( map[sd->bl.m].flag.vending_cell )
		map_setcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_NOVENDING, false);
}
Ejemplo n.º 18
0
/*==========================================
 * Check here hacker for duplicate item in trade
 * normal client refuse to have 2 same types of item (except equipment) in same trade window
 * normal client authorise only no equiped item and only from inventory
 *------------------------------------------
 */
int impossible_trade_check(struct map_session_data *sd) {
	struct item inventory[MAX_INVENTORY];
	char message_to_gm[200];
	int i, index;

	nullpo_retr(1, sd);
	
    if(sd->deal.zeny > sd->status.zeny)
	{
		pc_setglobalreg(sd,"ZENY_HACKER",1);
		return -1;
	}

	// get inventory of player
	memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY);

	// remove this part: arrows can be trade and equiped
	// re-added! [celest]
	// remove equiped items (they can not be trade)
	for (i = 0; i < MAX_INVENTORY; i++)
		if (inventory[i].nameid > 0 && inventory[i].equip && !(inventory[i].equip & 0x8000))
			memset(&inventory[i], 0, sizeof(struct item));

	// check items in player inventory
	for(i = 0; i < 10; i++)
		if (sd->deal.item[i].amount < 0) { // negativ? -> hack
//			printf("Negativ amount in trade, by hack!\n"); // normal client send cancel when we type negativ amount
			return -1;
		} else if (sd->deal.item[i].amount > 0) {
			index = sd->deal.item[i].index;
			inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory
//			printf("%d items left\n", inventory[index].amount);
			if (inventory[index].amount < 0) { // if more than the player have -> hack
//				printf("A player try to trade more items that he has: hack!\n");
				sprintf(message_to_gm, msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has.
				intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
				sprintf(message_to_gm, msg_txt(539), sd->status.inventory[index].amount, sd->status.inventory[index].nameid, sd->status.inventory[index].amount - inventory[index].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them.
				intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
				// if we block people
				if (battle_config.ban_hack_trade < 0) {
					chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block
					clif_setwaitclose(sd->fd); // forced to disconnect because of the hack
					// message about the ban
					sprintf(message_to_gm, msg_txt(540), battle_config.ban_spoof_namer); //  This player has been definitivly blocked.
				// if we ban people
				} else if (battle_config.ban_hack_trade > 0) {
					chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_hack_trade, 0); // type: 2 - ban (year, month, day, hour, minute, second)
					clif_setwaitclose(sd->fd); // forced to disconnect because of the hack
					// message about the ban
					sprintf(message_to_gm, msg_txt(507), battle_config.ban_spoof_namer); //  This player has been banned for %d minute(s).
				} else {
					// message about the ban
					sprintf(message_to_gm, msg_txt(508)); //  This player hasn't been banned (Ban option is disabled).
				}
				intif_wis_message_to_gm(wisp_server_name, battle_config.hack_info_GM_level, message_to_gm);
				return 1;
			}
		}

	return 0;
}
Ejemplo n.º 19
0
/* from pc.c due to @accinfo. any ideas to replace this crap are more than welcome. */
const char* job_name(int class_) {
	switch (class_) {
		case JOB_NOVICE:
		case JOB_SWORDMAN:
		case JOB_MAGE:
		case JOB_ARCHER:
		case JOB_ACOLYTE:
		case JOB_MERCHANT:
		case JOB_THIEF:
			return msg_txt(JOB_NOVICE+class_);

		case JOB_KNIGHT:
		case JOB_PRIEST:
		case JOB_WIZARD:
		case JOB_BLACKSMITH:
		case JOB_HUNTER:
		case JOB_ASSASSIN:
			return msg_txt(7 - JOB_KNIGHT+class_);

		case JOB_KNIGHT2:
			return msg_txt(7);

		case JOB_CRUSADER:
		case JOB_MONK:
		case JOB_SAGE:
		case JOB_ROGUE:
		case JOB_ALCHEMIST:
		case JOB_BARD:
		case JOB_DANCER:
			return msg_txt(13 - JOB_CRUSADER+class_);

		case JOB_CRUSADER2:
			return msg_txt(13);

		case JOB_WEDDING:
		case JOB_SUPER_NOVICE:
		case JOB_GUNSLINGER:
		case JOB_NINJA:
		case JOB_XMAS:
			return msg_txt(20 - JOB_WEDDING+class_);

		case JOB_SUMMER:
			return msg_txt(71);

		case JOB_HANBOK:
			return msg_txt(105);

		case JOB_NOVICE_HIGH:
		case JOB_SWORDMAN_HIGH:
		case JOB_MAGE_HIGH:
		case JOB_ARCHER_HIGH:
		case JOB_ACOLYTE_HIGH:
		case JOB_MERCHANT_HIGH:
		case JOB_THIEF_HIGH:
			return msg_txt(25 - JOB_NOVICE_HIGH+class_);

		case JOB_LORD_KNIGHT:
		case JOB_HIGH_PRIEST:
		case JOB_HIGH_WIZARD:
		case JOB_WHITESMITH:
		case JOB_SNIPER:
		case JOB_ASSASSIN_CROSS:
			return msg_txt(32 - JOB_LORD_KNIGHT+class_);

		case JOB_LORD_KNIGHT2:
			return msg_txt(32);

		case JOB_PALADIN:
		case JOB_CHAMPION:
		case JOB_PROFESSOR:
		case JOB_STALKER:
		case JOB_CREATOR:
		case JOB_CLOWN:
		case JOB_GYPSY:
			return msg_txt(38 - JOB_PALADIN + class_);

		case JOB_PALADIN2:
			return msg_txt(38);

		case JOB_BABY:
		case JOB_BABY_SWORDMAN:
		case JOB_BABY_MAGE:
		case JOB_BABY_ARCHER:
		case JOB_BABY_ACOLYTE:
		case JOB_BABY_MERCHANT:
		case JOB_BABY_THIEF:
			return msg_txt(45 - JOB_BABY + class_);

		case JOB_BABY_KNIGHT:
		case JOB_BABY_PRIEST:
		case JOB_BABY_WIZARD:
		case JOB_BABY_BLACKSMITH:
		case JOB_BABY_HUNTER:
		case JOB_BABY_ASSASSIN:
			return msg_txt(52 - JOB_BABY_KNIGHT + class_);

		case JOB_BABY_KNIGHT2:
			return msg_txt(52);

		case JOB_BABY_CRUSADER:
		case JOB_BABY_MONK:
		case JOB_BABY_SAGE:
		case JOB_BABY_ROGUE:
		case JOB_BABY_ALCHEMIST:
		case JOB_BABY_BARD:
		case JOB_BABY_DANCER:
			return msg_txt(58 - JOB_BABY_CRUSADER + class_);

		case JOB_BABY_CRUSADER2:
			return msg_txt(58);

		case JOB_SUPER_BABY:
			return msg_txt(65);

		case JOB_TAEKWON:
			return msg_txt(66);
		case JOB_STAR_GLADIATOR:
		case JOB_STAR_GLADIATOR2:
			return msg_txt(67);
		case JOB_SOUL_LINKER:
			return msg_txt(68);

		case JOB_GANGSI:
		case JOB_DEATH_KNIGHT:
		case JOB_DARK_COLLECTOR:
			return msg_txt(72 - JOB_GANGSI+class_);

		case JOB_RUNE_KNIGHT:
		case JOB_WARLOCK:
		case JOB_RANGER:
		case JOB_ARCH_BISHOP:
		case JOB_MECHANIC:
		case JOB_GUILLOTINE_CROSS:
			return msg_txt(75 - JOB_RUNE_KNIGHT+class_);

		case JOB_RUNE_KNIGHT_T:
		case JOB_WARLOCK_T:
		case JOB_RANGER_T:
		case JOB_ARCH_BISHOP_T:
		case JOB_MECHANIC_T:
		case JOB_GUILLOTINE_CROSS_T:
			return msg_txt(75 - JOB_RUNE_KNIGHT_T+class_);

		case JOB_ROYAL_GUARD:
		case JOB_SORCERER:
		case JOB_MINSTREL:
		case JOB_WANDERER:
		case JOB_SURA:
		case JOB_GENETIC:
		case JOB_SHADOW_CHASER:
			return msg_txt(81 - JOB_ROYAL_GUARD+class_);

		case JOB_ROYAL_GUARD_T:
		case JOB_SORCERER_T:
		case JOB_MINSTREL_T:
		case JOB_WANDERER_T:
		case JOB_SURA_T:
		case JOB_GENETIC_T:
		case JOB_SHADOW_CHASER_T:
			return msg_txt(81 - JOB_ROYAL_GUARD_T+class_);

		case JOB_RUNE_KNIGHT2:
		case JOB_RUNE_KNIGHT_T2:
			return msg_txt(75);

		case JOB_ROYAL_GUARD2:
		case JOB_ROYAL_GUARD_T2:
			return msg_txt(81);

		case JOB_RANGER2:
		case JOB_RANGER_T2:
			return msg_txt(77);

		case JOB_MECHANIC2:
		case JOB_MECHANIC_T2:
			return msg_txt(79);

		case JOB_BABY_RUNE:
		case JOB_BABY_WARLOCK:
		case JOB_BABY_RANGER:
		case JOB_BABY_BISHOP:
		case JOB_BABY_MECHANIC:
		case JOB_BABY_CROSS:
		case JOB_BABY_GUARD:
		case JOB_BABY_SORCERER:
		case JOB_BABY_MINSTREL:
		case JOB_BABY_WANDERER:
		case JOB_BABY_SURA:
		case JOB_BABY_GENETIC:
		case JOB_BABY_CHASER:
			return msg_txt(88 - JOB_BABY_RUNE+class_);

		case JOB_BABY_RUNE2:
			return msg_txt(88);

		case JOB_BABY_GUARD2:
			return msg_txt(94);

		case JOB_BABY_RANGER2:
			return msg_txt(90);

		case JOB_BABY_MECHANIC2:
			return msg_txt(92);

		case JOB_SUPER_NOVICE_E:
		case JOB_SUPER_BABY_E:
			return msg_txt(101 - JOB_SUPER_NOVICE_E+class_);

		case JOB_KAGEROU:
		case JOB_OBORO:
			return msg_txt(103 - JOB_KAGEROU+class_);

		default:
			return msg_txt(106);
	}
}
Ejemplo n.º 20
0
/*==========================================
 * Adds an item/qty to the trade window [rewrite by Skotlex] 
 *------------------------------------------
 */
void trade_tradeadditem(struct map_session_data *sd, int index, int amount) {
	struct map_session_data *target_sd;
	int trade_i, trade_weight, nameid;

	nullpo_retv(sd);
	if (!sd->state.trading || (target_sd = map_id2sd(sd->trade_partner)) == NULL || sd->state.deal_locked > 0)
		return; //Can't add stuff.

	if (index == 0)
	{	//Adding Zeny
		if (amount >= 0 && amount <= MAX_ZENY && amount <= sd->status.zeny && // check amount
			(target_sd->status.zeny + amount) <= MAX_ZENY) // fix positiv overflow
		{	//Check Ok
			sd->deal.zeny = amount;
			clif_tradeadditem(sd, target_sd, 0, amount);
		} else //Cancel Transaction
			trade_tradecancel(sd);
		return;
	}
	//Add an Item
	index = index -2; //Why the actual index used is -2?
	//Item checks...
	if (index < 0 || index > MAX_INVENTORY)
		return;
	if (amount < 0 || amount > sd->status.inventory[index].amount)
		return;

	nameid = sd->inventory_data[index]->nameid;

	if (!itemdb_cantrade(nameid, pc_isGM(sd), pc_isGM(target_sd)) &&	//Can't trade
		(pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(nameid, pc_isGM(sd), pc_isGM(target_sd))))	//Can't partner-trade
	{
		clif_displaymessage (sd->fd, msg_txt(260));
		return;
	}

	for(trade_i = 0; trade_i < 10; trade_i++)
	{	//Locate a trade position
		if (sd->deal.item[trade_i].index == index ||
			sd->deal.item[trade_i].amount == 0)
			break;
	}
	if (trade_i >= 10)	//No space left
		return;

	trade_weight = sd->inventory_data[index]->weight * amount;
	if (target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight)
	{	//fail to add item -- the player was over weighted.
		clif_tradeitemok(sd, index, 1);
		return;
	}

	if (sd->deal.item[trade_i].index == index)
	{	//The same item as before is being readjusted.
		if (sd->deal.item[trade_i].amount + amount > sd->status.inventory[index].amount)
		{	//packet deal exploit check
			amount = sd->status.inventory[index].amount - sd->deal.item[trade_i].amount;
			trade_weight = sd->inventory_data[index]->weight * amount;
		}
		sd->deal.item[trade_i].amount += amount;
	} else {	//New deal item
		sd->deal.item[trade_i].index = index;
		sd->deal.item[trade_i].amount = amount;
	}
	sd->deal.weight += trade_weight;

	if (impossible_trade_check(sd))
	{ // check exploit (trade more items that you have)
		trade_tradecancel(sd);
		return;
	}

	clif_tradeitemok(sd, index+2, 0); // Return the index as it was received
	clif_tradeadditem(sd, target_sd, index+2, amount); //index fix
}
Ejemplo n.º 21
0
/**
* Start transaction
* @param sd Player/Seller
* @param account_id Buyer account ID
* @param *itemlist List of sold items { <index>.W, <nameid>.W, <amount>.W }*
* @param count Number of item on the itemlist
*/
void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count)
{
	int zeny = 0;
	unsigned int i, weight, listidx, k;
	struct map_session_data* pl_sd;

	nullpo_retv(sd);

	if( count == 0 )
	{// nothing to do
		return;
	}

	if( !battle_config.feature_buying_store || pc_istrading(sd) )
	{// not allowed to sell
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	if( !pc_can_give_items(sd) )
	{// custom: GM is not allowed to sell
		clif_displaymessage(sd->fd, msg_txt(sd,246));
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	if( ( pl_sd = map_id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id )
	{// not online, not buying or not same store
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	if( !searchstore_queryremote(sd, account_id) && ( sd->bl.m != pl_sd->bl.m || !check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE) ) )
	{// out of view range
		clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
		return;
	}

	searchstore_clearremote(sd);

	if( pl_sd->status.zeny < pl_sd->buyingstore.zenylimit )
	{// buyer lost zeny in the mean time? fix the limit
		pl_sd->buyingstore.zenylimit = pl_sd->status.zeny;
	}
	weight = pl_sd->weight;

	// check item list
	for( i = 0; i < count; i++ )
	{// itemlist: <index>.W <name id>.W <amount>.W
		unsigned short nameid, amount;
		int index;

		index  = RBUFW(itemlist,i*6+0)-2;
		nameid = RBUFW(itemlist,i*6+2);
		amount = RBUFW(itemlist,i*6+4);

		if( i )
		{// duplicate check. as the client does this too, only malicious intent should be caught here
			ARR_FIND( 0, i, k, RBUFW(itemlist,k*6+0)-2 == index );
			if( k != i )
			{// duplicate
				ShowWarning("buyingstore_trade: Found duplicate item on selling list (prevnameid=%hu, prevamount=%hu, nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n",
					RBUFW(itemlist,k*6+2), RBUFW(itemlist,k*6+4), nameid, amount, sd->status.account_id, sd->status.char_id);
				clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
				return;
			}
		}

		if( index < 0 || index >= ARRAYLENGTH(sd->inventory.u.items_inventory) || sd->inventory_data[index] == NULL || sd->inventory.u.items_inventory[index].nameid != nameid || sd->inventory.u.items_inventory[index].amount < amount )
		{// invalid input
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( sd->inventory.u.items_inventory[index].expire_time || (sd->inventory.u.items_inventory[index].bound && !pc_can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->inventory.u.items_inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->inventory.u.items_inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
		{// non-tradable item
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
		if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 )
		{// there is no such item or the buyer has already bought all of them
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( pl_sd->buyingstore.items[listidx].amount < amount )
		{// buyer does not need that much of the item
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_COUNT, nameid);
			return;
		}

		if( pc_checkadditem(pl_sd, nameid, amount) == CHKADDITEM_OVERAMOUNT )
		{// buyer does not have enough space for this item
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}

		if( amount*(unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight-weight )
		{// normally this is not supposed to happen, as the total weight is
		 // checked upon creation, but the buyer could have gained items
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
			return;
		}
		weight+= amount*sd->inventory_data[index]->weight;

		if( amount*pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit-zeny )
		{// buyer does not have enough zeny
			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_ZENY, nameid);
			return;
		}
		zeny+= amount*pl_sd->buyingstore.items[listidx].price;
	}

	// process item list
	for( i = 0; i < count; i++ )
	{// itemlist: <index>.W <name id>.W <amount>.W
		unsigned short nameid, amount;
		int index;

		index  = RBUFW(itemlist,i*6+0)-2;
		nameid = RBUFW(itemlist,i*6+2);
		amount = RBUFW(itemlist,i*6+4);

		ARR_FIND( 0, pl_sd->buyingstore.slots, listidx, pl_sd->buyingstore.items[listidx].nameid == nameid );
		zeny = amount*pl_sd->buyingstore.items[listidx].price;

		// move item
		pc_additem(pl_sd, &sd->inventory.u.items_inventory[index], amount, LOG_TYPE_BUYING_STORE);
		pc_delitem(sd, index, amount, 1, 0, LOG_TYPE_BUYING_STORE);
		pl_sd->buyingstore.items[listidx].amount-= amount;

		if( pl_sd->buyingstore.items[listidx].amount > 0 ){
			if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `buyingstore_id` = %d AND `index` = %d;", buyingstore_items_table, pl_sd->buyingstore.items[listidx].amount, pl_sd->buyer_id, listidx ) != SQL_SUCCESS ){
				Sql_ShowDebug( mmysql_handle );
			}
		}else{
			if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `buyingstore_id` = %d AND `index` = %d;", buyingstore_items_table, pl_sd->buyer_id, listidx ) != SQL_SUCCESS ){
				Sql_ShowDebug( mmysql_handle );
			}
		}

		// pay up
		pc_payzeny(pl_sd, zeny, LOG_TYPE_BUYING_STORE, sd);
		pc_getzeny(sd, zeny, LOG_TYPE_BUYING_STORE, pl_sd);
		pl_sd->buyingstore.zenylimit-= zeny;

		// notify clients
		clif_buyingstore_delete_item(sd, index, amount, pl_sd->buyingstore.items[listidx].price);
		clif_buyingstore_update_item(pl_sd, nameid, amount, sd->status.char_id, zeny);
	}

	if( save_settings&CHARSAVE_BANK ) {
		chrif_save(sd, CSAVE_NORMAL);
		chrif_save(pl_sd, CSAVE_NORMAL);
	}
	
	// check whether or not there is still something to buy
	ARR_FIND( 0, pl_sd->buyingstore.slots, i, pl_sd->buyingstore.items[i].amount != 0 );
	if( i == pl_sd->buyingstore.slots )
	{// everything was bought
		clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_NO_ITEMS);
	}
	else if( pl_sd->buyingstore.zenylimit == 0 )
	{// zeny limit reached
		clif_buyingstore_trade_failed_buyer(pl_sd, BUYINGSTORE_TRADE_BUYER_ZENY);
	}
	else
	{// continue buying
		if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `limit` = %d WHERE `id` = %d;", buyingstores_table, pl_sd->buyingstore.zenylimit, pl_sd->buyer_id ) != SQL_SUCCESS ){
			Sql_ShowDebug( mmysql_handle );
		}

		return;
	}

	// cannot continue buying
	buyingstore_close(pl_sd);

	// remove auto-trader
	if( pl_sd->state.autotrade )
	{
		map_quit(pl_sd);
	}
}
Ejemplo n.º 22
0
/*==========================================
 * 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, USESKILL_FAIL_LEVEL, 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, USESKILL_FAIL_LEVEL, 0);
		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, USESKILL_FAIL_LEVEL, 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&16 && server_channel[CHN_VENDING] )
	{
		char chat_message[256];
		sprintf(chat_message, msg_txt(820), server_channel[CHN_VENDING]->name, 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);
}
Ejemplo n.º 23
0
/*==========================================
 * Purchase item(s) from a shop
 *------------------------------------------*/
void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const uint8* data, int count)
{
	int i, j, cursor, w, new_ = 0, blank, vend_list[MAX_VENDING];
	double z;
	struct s_vending vending[MAX_VENDING]; // against duplicate packets
	struct map_session_data* vsd = map_id2sd(aid);

	nullpo_retv(sd);
	if( vsd == NULL || !vsd->state.vending || vsd->bl.id == sd->bl.id )
		return; // invalid shop

	if( vsd->vender_id != uid )
	{// shop has changed
		clif->buyvending(sd, 0, 0, 6);  // store information was incorrect
		return;
	}

	if( !searchstore_queryremote(sd, aid) && ( sd->bl.m != vsd->bl.m || !check_distance_bl(&sd->bl, &vsd->bl, AREA_SIZE) ) )
		return; // shop too far away

	searchstore_clearremote(sd);

	if( count < 1 || count > MAX_VENDING || count > vsd->vend_num )
		return; // invalid amount of purchased items

	blank = pc_inventoryblank(sd); //number of free cells in the buyer's inventory

	// duplicate item in vending to check hacker with multiple packets
	memcpy(&vending, &vsd->vending, sizeof(vsd->vending)); // copy vending list

	// some checks
	z = 0.; // zeny counter
	w = 0;  // weight counter
	for( i = 0; i < count; i++ )
	{
		short amount = *(uint16*)(data + 4*i + 0);
		short idx    = *(uint16*)(data + 4*i + 2);
		idx -= 2;

		if( amount <= 0 )
			return;

		// check of item index in the cart
		if( idx < 0 || idx >= MAX_CART )
			return;

		ARR_FIND( 0, vsd->vend_num, j, vsd->vending[j].index == idx );
		if( j == vsd->vend_num )
			return; //picked non-existing item
		else
			vend_list[i] = j;

		z += ((double)vsd->vending[j].value * (double)amount);
		if( z > (double)sd->status.zeny || z < 0. || z > (double)MAX_ZENY )
		{
			clif->buyvending(sd, idx, amount, 1); // you don't have enough zeny
			return;
		}
		if( z + (double)vsd->status.zeny > (double)MAX_ZENY && !battle_config.vending_over_max )
		{
			clif->buyvending(sd, idx, vsd->vending[j].amount, 4); // too much zeny = overflow
			return;

		}
		w += itemdb_weight(vsd->status.cart[idx].nameid) * amount;
		if( w + sd->weight > sd->max_weight )
		{
			clif->buyvending(sd, idx, amount, 2); // you can not buy, because overweight
			return;
		}
		
		//Check to see if cart/vend info is in sync.
		if( vending[j].amount > vsd->status.cart[idx].amount )
			vending[j].amount = vsd->status.cart[idx].amount;
		
		// if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples).
		// here, we check cumulative amounts
		if( vending[j].amount < amount )
		{
			// send more quantity is not a hack (an other player can have buy items just before)
			clif->buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity
			return;
		}
		
		vending[j].amount -= amount;

		switch( pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount) ) {
		case ADDITEM_EXIST:
			break;	//We'd add this item to the existing one (in buyers inventory)
		case ADDITEM_NEW:
			new_++;
			if (new_ > blank)
				return; //Buyer has no space in his inventory
			break;
		case ADDITEM_OVERAMOUNT:
			return; //too many items
		}
	}

	pc_payzeny(sd, (int)z, LOG_TYPE_VENDING, vsd);
	if( battle_config.vending_tax )
		z -= z * (battle_config.vending_tax/10000.);
	pc_getzeny(vsd, (int)z, LOG_TYPE_VENDING, sd);

	for( i = 0; i < count; i++ )
	{
		short amount = *(uint16*)(data + 4*i + 0);
		short idx    = *(uint16*)(data + 4*i + 2);
		idx -= 2;

		// vending item
		pc_additem(sd, &vsd->status.cart[idx], amount, LOG_TYPE_VENDING);
		vsd->vending[vend_list[i]].amount -= amount;
		pc_cart_delitem(vsd, idx, amount, 0, LOG_TYPE_VENDING);
		clif->vendingreport(vsd, idx, amount);

		//print buyer's name
		if( battle_config.buyer_name )
		{
			char temp[256];
			sprintf(temp, msg_txt(265), sd->status.name);
			clif->disp_onlyself(vsd,temp,strlen(temp));
		}
	}

	// compact the vending list
	for( i = 0, cursor = 0; i < vsd->vend_num; i++ )
	{
		if( vsd->vending[i].amount == 0 )
			continue;
		
		if( cursor != i ) // speedup
		{
			vsd->vending[cursor].index = vsd->vending[i].index;
			vsd->vending[cursor].amount = vsd->vending[i].amount;
			vsd->vending[cursor].value = vsd->vending[i].value;
		}

		cursor++;
	}
	vsd->vend_num = cursor;

	//Always save BOTH: buyer and customer
	if( save_settings&2 )
	{
		chrif_save(sd,0);
		chrif_save(vsd,0);
	}

	//check for @AUTOTRADE users [durf]
	if( vsd->state.autotrade )
	{
		//see if there is anything left in the shop
		ARR_FIND( 0, vsd->vend_num, i, vsd->vending[i].amount > 0 );
		if( i == vsd->vend_num )
		{
			//Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex]
			vending_closevending(vsd);
			map_quit(vsd);	//They have no reason to stay around anymore, do they?
		}
	}
}
Ejemplo n.º 24
0
/*==========================================
 * Adds an item/qty to the trade window
 *------------------------------------------*/
void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
{
	struct map_session_data *target_sd;
	struct item *item;
	struct homun_data *hd;
	char atcmd_output[CHAT_SIZE_MAX];
	int trade_i, trade_weight;
	int src_lv, dst_lv;
	int i, p, tid, amttsd = 0, amtt = 0;

	hd = sd->hd;
	
	nullpo_retv(sd);
	if( !sd->state.trading || sd->state.deal_locked > 0 )
		return; //Can't add stuff.

	if( (target_sd = map_id2sd(sd->trade_partner)) == NULL )
	{
		trade_tradecancel(sd);
		return;
	}

	if( amount == 0 )
	{	//Why do this.. ~.~ just send an ack, the item won't display on the trade window.
		clif_tradeitemok(sd, index, 0);
		return;
	}

	index -= 2; // 0 is for zeny, 1 is unknown. Gravity, go figure...

	//Item checks...
	if( index < 0 || index >= MAX_INVENTORY )
		return;
	if( amount < 0 || amount > sd->status.inventory[index].amount )
		return;

	item = &sd->status.inventory[index];
	src_lv = pc_isGM(sd);
	dst_lv = pc_isGM(target_sd);
	if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade
		(pc_get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade
	{
		clif_displaymessage (sd->fd, msg_txt(260));
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	if( item->expire_time )
	{ // Rental System
		clif_displaymessage (sd->fd, msg_txt(260));
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	//Locate a trade position
	ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
	if( trade_i == 10 ) //No space left
	{
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	
	
	//-------------| Bloquear Donates dias de semana |-------------//                     by: [Brunno Thadeu]
			
	//Abaixo, defini-se os dias (Falta testar isso, creio eu que 1 seja domingo, 2 segunda etc..)
//	if(t->tm_wday != 1 && t->tm_wday != 7){
	
		//Abaixo, defini-se o range de ID's dos Donates.
//		if(sd->status.inventory[index].nameid >= 5000 && sd->status.inventory[index].nameid <= 5500) {

//			clif_tradeitemok(sd, index+2, 1);
//			return;
//		}
//	}																
	//--------------------------------------------------------------//
	
	if(sd->status.inventory[index].nameid == 690)
		return ;	
	
	
	if(sd->status.inventory[index].nameid >= 8031 && sd->status.inventory[index].nameid <= 8181) {

		for(i = 8031; i <= 8181; i++)
			amttsd += pc_countitem(target_sd, i);

		for(i = 0; i < 10; i++) {
			tid = sd->status.inventory[sd->deal.item[i].index].nameid;
			if(tid >= 8031 && tid <= 8181)
				amtt += sd->deal.item[i].amount;
		}

		p = 6;
		if((hd = target_sd->hd) == NULL ){
			p = 7;
			}

		if((amttsd + amount + amtt) >= p) {
			clif_tradeitemok(sd, index+2, 1);
			return;
		}
	}


	if(sd->status.inventory[index].nameid >= 8031 && sd->status.inventory[index].nameid <= 8181){
		snprintf(atcmd_output, sizeof(atcmd_output) ,"Pokemon ID: %d ", MakeDWord(sd->status.inventory[index].card[1], sd->status.inventory[index].card[2]));
		clif_displaymessage(target_sd->fd, atcmd_output);
	}
	
	
	trade_weight = sd->inventory_data[index]->weight * amount;
	if( target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight )
	{	//fail to add item -- the player was over weighted.
		clif_tradeitemok(sd, index+2, 1);
		return;
	}

	if( sd->deal.item[trade_i].index == index )
	{	//The same item as before is being readjusted.
		if( sd->deal.item[trade_i].amount + amount > sd->status.inventory[index].amount )
		{	//packet deal exploit check
			amount = sd->status.inventory[index].amount - sd->deal.item[trade_i].amount;
			trade_weight = sd->inventory_data[index]->weight * amount;
		}
		sd->deal.item[trade_i].amount += amount;
	}
	else
	{	//New deal item
		sd->deal.item[trade_i].index = index;
		sd->deal.item[trade_i].amount = amount;
	}
	sd->deal.weight += trade_weight;

	clif_tradeitemok(sd, index+2, 0); // Return the index as it was received
	clif_tradeadditem(sd, target_sd, index+2, amount);
}
Ejemplo n.º 25
0
/* from pc.c due to @accinfo. any ideas to replace this crap are more than welcome. */
const char* job_name(int class_) {
	switch (class_) {
		case JOB_NOVICE:   // 550
		case JOB_SWORDMAN: // 551
		case JOB_MAGE:     // 552
		case JOB_ARCHER:   // 553
		case JOB_ACOLYTE:  // 554
		case JOB_MERCHANT: // 555
		case JOB_THIEF:    // 556
			return msg_txt(550 - JOB_NOVICE+class_);

		case JOB_KNIGHT:     // 557
		case JOB_PRIEST:     // 558
		case JOB_WIZARD:     // 559
		case JOB_BLACKSMITH: // 560
		case JOB_HUNTER:     // 561
		case JOB_ASSASSIN:   // 562
			return msg_txt(557 - JOB_KNIGHT+class_);

		case JOB_KNIGHT2:
			return msg_txt(557);

		case JOB_CRUSADER:  // 563
		case JOB_MONK:      // 564
		case JOB_SAGE:      // 565
		case JOB_ROGUE:     // 566
		case JOB_ALCHEMIST: // 567
		case JOB_BARD:      // 568
		case JOB_DANCER:    // 569
			return msg_txt(563 - JOB_CRUSADER+class_);

		case JOB_CRUSADER2:
			return msg_txt(563);

		case JOB_WEDDING:      // 570
		case JOB_SUPER_NOVICE: // 571
		case JOB_GUNSLINGER:   // 572
		case JOB_NINJA:        // 573
		case JOB_XMAS:         // 574
			return msg_txt(570 - JOB_WEDDING+class_);

		case JOB_SUMMER:
			return msg_txt(621);

		case JOB_NOVICE_HIGH:   // 575
		case JOB_SWORDMAN_HIGH: // 576
		case JOB_MAGE_HIGH:     // 577
		case JOB_ARCHER_HIGH:   // 578
		case JOB_ACOLYTE_HIGH:  // 579
		case JOB_MERCHANT_HIGH: // 580
		case JOB_THIEF_HIGH:    // 581
			return msg_txt(575 - JOB_NOVICE_HIGH+class_);

		case JOB_LORD_KNIGHT:    // 582
		case JOB_HIGH_PRIEST:    // 583
		case JOB_HIGH_WIZARD:    // 584
		case JOB_WHITESMITH:     // 585
		case JOB_SNIPER:         // 586
		case JOB_ASSASSIN_CROSS: // 587
			return msg_txt(582 - JOB_LORD_KNIGHT+class_);

		case JOB_LORD_KNIGHT2:
			return msg_txt(582);

		case JOB_PALADIN:   // 588
		case JOB_CHAMPION:  // 589
		case JOB_PROFESSOR: // 590
		case JOB_STALKER:   // 591
		case JOB_CREATOR:   // 592
		case JOB_CLOWN:     // 593
		case JOB_GYPSY:     // 594
			return msg_txt(588 - JOB_PALADIN + class_);

		case JOB_PALADIN2:
			return msg_txt(588);

		case JOB_BABY:          // 595
		case JOB_BABY_SWORDMAN: // 596
		case JOB_BABY_MAGE:     // 597
		case JOB_BABY_ARCHER:   // 598
		case JOB_BABY_ACOLYTE:  // 599
		case JOB_BABY_MERCHANT: // 600
		case JOB_BABY_THIEF:    // 601
			return msg_txt(595 - JOB_BABY + class_);

		case JOB_BABY_KNIGHT:     // 602
		case JOB_BABY_PRIEST:     // 603
		case JOB_BABY_WIZARD:     // 604
		case JOB_BABY_BLACKSMITH: // 605
		case JOB_BABY_HUNTER:     // 606
		case JOB_BABY_ASSASSIN:   // 607
			return msg_txt(602 - JOB_BABY_KNIGHT + class_);

		case JOB_BABY_KNIGHT2:
			return msg_txt(602);

		case JOB_BABY_CRUSADER:  // 608
		case JOB_BABY_MONK:      // 609
		case JOB_BABY_SAGE:      // 610
		case JOB_BABY_ROGUE:     // 611
		case JOB_BABY_ALCHEMIST: // 612
		case JOB_BABY_BARD:      // 613
		case JOB_BABY_DANCER:    // 614
			return msg_txt(608 - JOB_BABY_CRUSADER + class_);

		case JOB_BABY_CRUSADER2:
			return msg_txt(608);

		case JOB_SUPER_BABY:
			return msg_txt(615);

		case JOB_TAEKWON:
			return msg_txt(616);
		case JOB_STAR_GLADIATOR:
		case JOB_STAR_GLADIATOR2:
			return msg_txt(617);
		case JOB_SOUL_LINKER:
			return msg_txt(618);

		case JOB_GANGSI:         // 622
		case JOB_DEATH_KNIGHT:   // 623
		case JOB_DARK_COLLECTOR: // 624
			return msg_txt(622 - JOB_GANGSI+class_);

		case JOB_RUNE_KNIGHT:      // 625
		case JOB_WARLOCK:          // 626
		case JOB_RANGER:           // 627
		case JOB_ARCH_BISHOP:      // 628
		case JOB_MECHANIC:         // 629
		case JOB_GUILLOTINE_CROSS: // 630
			return msg_txt(625 - JOB_RUNE_KNIGHT+class_);

		case JOB_RUNE_KNIGHT_T:      // 656
		case JOB_WARLOCK_T:          // 657
		case JOB_RANGER_T:           // 658
		case JOB_ARCH_BISHOP_T:      // 659
		case JOB_MECHANIC_T:         // 660
		case JOB_GUILLOTINE_CROSS_T: // 661
			return msg_txt(656 - JOB_RUNE_KNIGHT_T+class_);

		case JOB_ROYAL_GUARD:   // 631
		case JOB_SORCERER:      // 632
		case JOB_MINSTREL:      // 633
		case JOB_WANDERER:      // 634
		case JOB_SURA:          // 635
		case JOB_GENETIC:       // 636
		case JOB_SHADOW_CHASER: // 637
			return msg_txt(631 - JOB_ROYAL_GUARD+class_);

		case JOB_ROYAL_GUARD_T:   // 662
		case JOB_SORCERER_T:      // 663
		case JOB_MINSTREL_T:      // 664
		case JOB_WANDERER_T:      // 665
		case JOB_SURA_T:          // 666
		case JOB_GENETIC_T:       // 667
		case JOB_SHADOW_CHASER_T: // 668
			return msg_txt(662 - JOB_ROYAL_GUARD_T+class_);

		case JOB_RUNE_KNIGHT2:
			return msg_txt(625);

		case JOB_RUNE_KNIGHT_T2:
			return msg_txt(656);

		case JOB_ROYAL_GUARD2:
			return msg_txt(631);

		case JOB_ROYAL_GUARD_T2:
			return msg_txt(662);

		case JOB_RANGER2:
			return msg_txt(627);

		case JOB_RANGER_T2:
			return msg_txt(658);

		case JOB_MECHANIC2:
			return msg_txt(629);

		case JOB_MECHANIC_T2:
			return msg_txt(660);

		case JOB_BABY_RUNE:     // 638
		case JOB_BABY_WARLOCK:  // 639
		case JOB_BABY_RANGER:   // 640
		case JOB_BABY_BISHOP:   // 641
		case JOB_BABY_MECHANIC: // 642
		case JOB_BABY_CROSS:    // 643
		case JOB_BABY_GUARD:    // 644
		case JOB_BABY_SORCERER: // 645
		case JOB_BABY_MINSTREL: // 646
		case JOB_BABY_WANDERER: // 647
		case JOB_BABY_SURA:     // 648
		case JOB_BABY_GENETIC:  // 649
		case JOB_BABY_CHASER:   // 650
			return msg_txt(638 - JOB_BABY_RUNE+class_);

		case JOB_BABY_RUNE2:
			return msg_txt(638);

		case JOB_BABY_GUARD2:
			return msg_txt(644);

		case JOB_BABY_RANGER2:
			return msg_txt(640);

		case JOB_BABY_MECHANIC2:
			return msg_txt(642);

		case JOB_SUPER_NOVICE_E: // 651
		case JOB_SUPER_BABY_E:   // 652
			return msg_txt(651 - JOB_SUPER_NOVICE_E+class_);

		case JOB_KAGEROU: // 653
		case JOB_OBORO:   // 654
			return msg_txt(653 - JOB_KAGEROU+class_);

		case JOB_REBELLION:
			return msg_txt(655);

		default:
			return msg_txt(620); // "Unknown Job"
	}
}
Ejemplo n.º 26
0
/**
 * Player setup a new shop
 * @param sd : player opening the shop
 * @param message : shop title
 * @param data : itemlist data
 *	data := {<index>.w <amount>.w <value>.l}[count]
 * @param count : number of different items
 * @param at Autotrader info, or NULL if requetsed not from autotrade persistance
 * @return 0 If success, 1 - Cannot open (die, not state.prevend, trading), 2 - No cart, 3 - Count issue, 4 - Cart data isn't saved yet, 5 - No valid item found
 */
int8 vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count, struct s_autotrader *at)
{
	int i, j;
	int vending_skill_lvl;
	char message_sql[MESSAGE_SIZE*2];
	StringBuf buf;
	
	nullpo_retr(false,sd);

	if ( pc_isdead(sd) || !sd->state.prevend || pc_istrading(sd)) {
		return 1; // can't open vendings lying dead || didn't use via the skill (wpe/hack) || 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, USESKILL_FAIL_LEVEL, 0);
		return 2;
	}

	// 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, USESKILL_FAIL_LEVEL, 0);
		return 3;
	}

	if (save_settings&CHARSAVE_VENDING) // Avoid invalid data from saving
		chrif_save(sd, CSAVE_INVENTORY|CSAVE_CART);

	// 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->cart.u.items_cart[index].identify // unidentified item
		||  sd->cart.u.items_cart[index].attribute == 1 // broken item
		||  sd->cart.u.items_cart[index].expire_time // It should not be in the cart but just in case
		||  (sd->cart.u.items_cart[index].bound && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission
		||  !itemdb_cantrade(&sd->cart.u.items_cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
			continue;

		sd->vending[i].index = index;
		sd->vending[i].amount = amount;
		sd->vending[i].value = min(value, (unsigned int)battle_config.vending_max_value);
		i++; // item successfully added
	}

	if( i != j )
		clif_displaymessage (sd->fd, msg_txt(sd,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, USESKILL_FAIL_LEVEL, 0); // custom reply packet
		return 5;
	}

	sd->state.prevend = 0;
	sd->state.vending = true;
	sd->state.workinprogress = WIP_DISABLE_NONE;
	sd->vender_id = vending_getuid();
	sd->vend_num = i;
	safestrncpy(sd->message, message, MESSAGE_SIZE);
	
	Sql_EscapeString( mmysql_handle, message_sql, sd->message );

	if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`id`, `account_id`, `char_id`, `sex`, `map`, `x`, `y`, `title`, `autotrade`, `body_direction`, `head_direction`, `sit`) "
		"VALUES( %d, %d, %d, '%c', '%s', %d, %d, '%s', %d, '%d', '%d', '%d' );",
		vendings_table, sd->vender_id, sd->status.account_id, sd->status.char_id, sd->status.sex == SEX_FEMALE ? 'F' : 'M', map[sd->bl.m].name, sd->bl.x, sd->bl.y, message_sql, sd->state.autotrade, at ? at->dir : sd->ud.dir, at ? at->head_dir : sd->head_dir, at ? at->sit : pc_issit(sd) ) != SQL_SUCCESS ) {
		Sql_ShowDebug(mmysql_handle);
	}

	StringBuf_Init(&buf);
	StringBuf_Printf(&buf, "INSERT INTO `%s`(`vending_id`,`index`,`cartinventory_id`,`amount`,`price`) VALUES", vending_items_table);
	for (j = 0; j < i; j++) {
		StringBuf_Printf(&buf, "(%d,%d,%d,%d,%d)", sd->vender_id, j, sd->cart.u.items_cart[sd->vending[j].index].id, sd->vending[j].amount, sd->vending[j].value);
		if (j < i-1)
			StringBuf_AppendStr(&buf, ",");
	}
	if (SQL_ERROR == Sql_QueryStr(mmysql_handle, StringBuf_Value(&buf)))
		Sql_ShowDebug(mmysql_handle);
	StringBuf_Destroy(&buf);

	clif_openvending(sd,sd->bl.id,sd->vending);
	clif_showvendingboard(&sd->bl,message,0);

	idb_put(vending_db, sd->status.char_id, sd);

	return 0;
}
Ejemplo n.º 27
0
///! TODO: Party invitation cross map-server through inter-server, so does with the reply.
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(sd,282));
		return 0;
	}

	if (tsd && battle_config.block_account_in_same_party) {
		ARR_FIND(0, MAX_PARTY, i, p->party.member[i].account_id == tsd->status.account_id);
		if (i < MAX_PARTY) {
			clif_party_invite_reply(sd, tsd->status.name, PARTY_REPLY_DUAL);
			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_invite_reply(sd, (tsd?tsd->status.name:""), PARTY_REPLY_FULL);
		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(sd,81)); // "Your GM level doesn't authorize you to preform this action on the specified player."
		return 0;
	}

	if( tsd == NULL) {
		clif_party_invite_reply(sd, "", PARTY_REPLY_OFFLINE);
		return 0;
	}

	if(!battle_config.invite_request_check) {
		if (tsd->guild_invite>0 || tsd->trade_partner || tsd->adopt_invite) {
			clif_party_invite_reply(sd,tsd->status.name,PARTY_REPLY_JOIN_OTHER_PARTY);
			return 0;
		}
	}

	if (!tsd->fd) { //You can't invite someone who has already disconnected.
		clif_party_invite_reply(sd,tsd->status.name,PARTY_REPLY_REJECTED);
		return 0;
	}

	if( tsd->status.party_id > 0 || tsd->party_invite > 0 )
	{// already associated with a party
		clif_party_invite_reply(sd,tsd->status.name,PARTY_REPLY_JOIN_OTHER_PARTY);
		return 0;
	}

	tsd->party_invite=sd->status.party_id;
	tsd->party_invite_account=sd->status.account_id;

	clif_party_invite(sd,tsd);
	return 1;
}
Ejemplo n.º 28
0
int party_changeleader(struct map_session_data *sd, struct map_session_data *tsd, struct party_data *p)
{
	int mi, tmi;

	if ( !p ) {
		if (!sd || !sd->status.party_id)
			return -1;

		if (!tsd || tsd->status.party_id != sd->status.party_id) {
			clif_displaymessage(sd->fd, msg_txt(sd,283));
			return -3;
		}

		if ( map[sd->bl.m].flag.partylock ) {
			clif_displaymessage(sd->fd, msg_txt(sd,287));
			return 0;
		}

		if ((p = party_search(sd->status.party_id)) == NULL )
			return -1;

		ARR_FIND( 0, MAX_PARTY, mi, p->data[mi].sd == sd );
		if (mi == MAX_PARTY)
			return 0; // Shouldn't happen

		if (!p->party.member[mi].leader) { // Need to be a party leader.
			clif_displaymessage(sd->fd, msg_txt(sd,282));
			return 0;
		}

		ARR_FIND( 0, MAX_PARTY, tmi, p->data[tmi].sd == tsd);
		if (tmi == MAX_PARTY)
			return 0; // Shouldn't happen

		if (battle_config.change_party_leader_samemap && p->party.member[mi].map != p->party.member[tmi].map) {
			clif_msg(sd, PARTY_MASTER_CHANGE_SAME_MAP);
			return 0;
		}
	} else {
		ARR_FIND(0,MAX_PARTY,mi,p->party.member[mi].leader);

		if (mi == MAX_PARTY)
			return 0; // Shouldn't happen

		ARR_FIND(0,MAX_PARTY,tmi,p->data[tmi].sd ==  tsd);

		if (tmi == MAX_PARTY)
			return 0; // Shouldn't happen
	}

	// Change leadership.
	p->party.member[mi].leader = 0;

	p->party.member[tmi].leader = 1;

	// Update members
	clif_party_leaderchanged(p->data[mi].sd, p->data[mi].sd->status.account_id, p->data[tmi].sd->status.account_id);

	// Update info.
	intif_party_leaderchange(p->party.party_id,p->party.member[tmi].account_id,p->party.member[tmi].char_id);
	clif_party_info(p,NULL);

	return 1;
}