예제 #1
0
파일: chrif.c 프로젝트: Judasu/rAthena-1
int chrif_changesex(struct map_session_data *sd) {
	chrif_check(-1);
	
	WFIFOHEAD(char_fd,44);
	WFIFOW(char_fd,0) = 0x2b0e;
	WFIFOL(char_fd,2) = sd->status.account_id;
	safestrncpy((char*)WFIFOP(char_fd,6), sd->status.name, NAME_LENGTH);
	WFIFOW(char_fd,30) = 5;
	WFIFOSET(char_fd,44);

	clif_displaymessage(sd->fd, msg_txt(410)); //"Need disconnection to perform change-sex request..."

	if (sd->fd)
		clif_authfail_fd(sd->fd, 15);
	else
		map_quit(sd);
	return 0;
}
예제 #2
0
파일: channel.c 프로젝트: Chocolate31/eamod
void channel_list(struct map_session_data *sd)
{ // Display a list of all channels
	char output[256];
	struct channel_data *cd;
	DBIterator* iter;
	DBKey key;

	iter = channel_db->iterator(channel_db);
	for( cd = (struct channel_data *)iter->first(iter,&key); iter->exists(iter); cd = (struct channel_data *)iter->next(iter,&key) )
	{
		if( cd->users < 1 && cd->type == CHN_USER )
			continue;

		sprintf(output, msg_txt(812), cd->name, cd->users, !cd->pass[0] ? msg_txt(813) : msg_txt(814));
		clif_displaymessage(sd->fd, output);
	}
	iter->destroy(iter);
	return;
}
예제 #3
0
/*==========================================
 * Request a shop's item list
 *------------------------------------------*/
void vending_vendinglistreq(struct map_session_data* sd, int id)
{
	struct map_session_data* vsd;

	nullpo_retv(sd);

	if( (vsd = map_id2sd(id)) == NULL )
		return;
	if( vsd->vender_id == 0 )
		return; // not vending

	if ( !pc_can_give_items(pc_isGM(sd)) || !pc_can_give_items(pc_isGM(vsd)) ) //check if both GMs are allowed to trade
	{	// GM is not allowed to trade
		clif_displaymessage(sd->fd, msg_txt(246));
		return;
	}

	clif_vendinglist(sd, id, vsd->vending);
}
예제 #4
0
/*==========================================
 * Request a shop's item list
 *------------------------------------------*/
void vending_vendinglistreq(struct map_session_data *sd, unsigned int id) {
	struct map_session_data *vsd;
	nullpo_retv(sd);

	if((vsd = map->id2sd(id)) == NULL)
		return;
	if(!vsd->state.vending)
		return; // not vending

	if(!pc_can_give_items(sd) || !pc_can_give_items(vsd)) { //check if both GMs are allowed to trade
		// GM is not allowed to trade
		clif_displaymessage(sd->fd, msg_txt(246));
		return;
	}

	sd->vended_id = vsd->vender_id;  // register vending uid

	clif_vendinglist(sd, id, vsd->vending);
}
예제 #5
0
파일: pet.c 프로젝트: BlazingSpear/rathena
int pet_change_name_ack(struct map_session_data *sd, char* name, int flag)
{
	struct pet_data *pd = sd->pd;
	if (!pd) return 0;

	normalize_name(name," ");//bugreport:3032

	if ( !flag || !strlen(name) ) {
		clif_displaymessage(sd->fd, msg_txt(sd,280)); // You cannot use this name for your pet.
		clif_send_petstatus(sd); //Send status so client knows oet name change got rejected.
		return 0;
	}
	memcpy(pd->pet.name, name, NAME_LENGTH);
	clif_charnameack (0,&pd->bl);
	pd->pet.rename_flag = 1;
	clif_pet_equip_area(pd);
	clif_send_petstatus(sd);
	return 1;
}
예제 #6
0
/**
 * Player attempt tp open his storage.
 * @param sd : player
 * @return  0:success, 1:fail
 */
int storage_storageopen(struct map_session_data *sd)
{
	nullpo_ret(sd);

	if(sd->state.storage_flag)
		return 1; //Already open?

	if( !pc_can_give_items(sd) ) { // check is this GM level is allowed to put items to storage
		clif_displaymessage(sd->fd, msg_txt(sd,246));
		return 1;
	}

	sd->state.storage_flag = 1;
	storage_sortitem(sd->storage.u.items_storage, sd->storage.max_amount);
	clif_storagelist(sd, sd->storage.u.items_storage, sd->storage.max_amount, storage_getName(0));
	clif_updatestorageamount(sd, sd->storage.amount, sd->storage.max_amount);

	return 0;
}
예제 #7
0
int bg_send_xy_timer_sub(DBKey key, void *data, va_list ap)
{
	struct battleground_data *bg = (struct battleground_data *)data;
	struct map_session_data *sd;
	char output[128];
	int i, m;

	nullpo_ret(bg);
	m = map_mapindex2mapid(bg->mapindex);
	bg->reveal_flag = !bg->reveal_flag; // Switch

	for( i = 0; i < MAX_BG_MEMBERS; i++ )
	{
		if( (sd = bg->members[i].sd) == NULL )
			continue;
		if( battle_config.bg_idle_autokick && DIFF_TICK(last_tick, sd->idletime) >= battle_config.bg_idle_autokick && bg->g )
		{
			sprintf(output, "- AFK [%s] Kicked -", sd->status.name);
			clif_broadcast2(&sd->bl, output, (int)strlen(output)+1, bg->color, 0x190, 20, 0, 0, BG);

			bg_team_leave(sd,3);
			clif_displaymessage(sd->fd, "You have been kicked from Battleground because of your AFK status.");
			pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
			continue;
		}

		if( sd->bl.x != bg->members[i].x || sd->bl.y != bg->members[i].y )
		{ // xy update
			bg->members[i].x = sd->bl.x;
			bg->members[i].y = sd->bl.y;
			clif_bg_xy(sd);
		}
		if( bg->reveal_pos && bg->reveal_flag && sd->bl.m == m ) // Reveal each 4 seconds
			map_foreachinmap(bg_reveal_pos,m,BL_PC,sd,1,bg->color);
		if( battle_config.bg_idle_announce && !sd->state.bg_afk && DIFF_TICK(last_tick, sd->idletime) >= battle_config.bg_idle_announce && bg->g )
		{ // Idle announces
			sd->state.bg_afk = 1;
			sprintf(output, "%s : %s seens to be away. AFK Warning - Can be kicked out with @reportafk", bg->g->name, sd->status.name);
			clif_bg_message(bg, bg->bg_id, bg->g->name, output, strlen(output) + 1);
		}
	}
	return 0;
}
예제 #8
0
/*==========================================
 * Opens a storage. Returns:
 * 0 - success
 * 1 - fail
 *------------------------------------------*/
int storage_storageopen(struct map_session_data *sd)
{
	nullpo_ret(sd);

	if(sd->state.storage_flag)
		return 1; //Already open?

	if( !pc_can_give_items(sd) )
	{ //check is this GM level is allowed to put items to storage
		clif_displaymessage(sd->fd, msg_txt(sd,246));
		return 1;
	}

	sd->state.storage_flag = 1;
	storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
	clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
	clif_updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
	return 0;
}
예제 #9
0
int ext_storage_open(struct map_session_data *sd)
{
	nullpo_ret(sd);

	if(sd->state.storage_flag)
		return 1;

	if( !pc_can_give_items(pc_isGM(sd)) )
  	{ //check is this GM level is allowed to put items to storage
		clif_displaymessage(sd->fd, msg_txt(246));
		return 1;
	}

	sd->state.storage_flag = 3;
	storage_sortitem(sd->status.ext_storage.items, ARRAYLENGTH(sd->status.ext_storage.items));
	clif_storagelist(sd, sd->status.ext_storage.items, ARRAYLENGTH(sd->status.ext_storage.items));
	clif_updateextrastorageamount(sd,sd->status.ext_storage.storage_amount);
	return 0;
}
예제 #10
0
// ギルド敵対
int guild_opposition(struct map_session_data *sd,struct map_session_data *tsd)
{
	struct guild *g;
	int i;

	nullpo_retr(0, sd);

	g=guild_search(sd->status.guild_id);
	if(g==NULL || tsd==NULL)
		return 0;

	// Prevent creation opposition with same guilds [LuzZza]
	if(sd->status.guild_id == tsd->status.guild_id)
		return 0;

	if( guild_get_alliance_count(g,1)>=3 )	{
		clif_guild_oppositionack(sd,1);
		return 0;
	}

	if(agit_flag)	{
		clif_displaymessage(sd->fd,"You cannot make oppositions during Guild Wars!");
		return 0;
	}

	for(i=0;i<MAX_GUILDALLIANCE;i++){	// すでに関係を持っているか確認
		if(g->alliance[i].guild_id==tsd->status.guild_id){
			if(g->alliance[i].opposition==1){	// すでに敵対
				clif_guild_oppositionack(sd,2);
				return 0;
			}
			//Change alliance to opposition.
			intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
				sd->status.account_id,tsd->status.account_id,8 );
		}
	}

	// inter鯖に敵対要請
	intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id,
			sd->status.account_id,tsd->status.account_id,1 );
	return 0;
}
예제 #11
0
파일: pet.c 프로젝트: philg666/Latest_eAmod
int pet_birth_process(struct map_session_data *sd, struct s_pet *pet)
{
	char pet_output[1024]; // Declaracion de char para Invocacion Pet's [Tab]
	nullpo_retr(1, sd);

	Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); 

	if(sd->status.pet_id && pet->incuvate == 1) {
		sd->status.pet_id = 0;
		return 1;
	}

	pet->incuvate = 0;
	pet->account_id = sd->status.account_id;
	pet->char_id = sd->status.char_id;
	sd->status.pet_id = pet->pet_id;
	if(pet_data_init(sd, pet)) {
		sd->status.pet_id = 0;
		return 1;
	}

	intif_save_petdata(sd->status.account_id,pet);
	if (save_settings&8)
		chrif_save(sd,0); //is it REALLY Needed to save the char for hatching a pet? [Skotlex]

	if(sd->bl.prev != NULL) {
		map_addblock(&sd->pd->bl);
		clif_spawn(&sd->pd->bl);
		clif_send_petdata(sd,sd->pd, 0,0);
		clif_send_petdata(sd,sd->pd, 5,battle_config.pet_hair_style);
		clif_pet_equip_area(sd->pd);
		clif_send_petstatus(sd);
	}
	Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); 

	clif_misceffect(&sd->pd->bl, 0); // Efecto 1 de nacimiento [Tab]
	clif_misceffect(&sd->pd->bl, 344); // Efecto 2 de nacimiento [Tab]
	sprintf(pet_output,"Get Out %s... NOW!",pet->name); // Cuidado aca con el nombre del pet
	clif_displaymessage(sd->fd, pet_output); // Frase nacimiento [Tab]

	return 0;
}
예제 #12
0
파일: chrif.cpp 프로젝트: Rosalila/tswa
/*==========================================
 * 性別変化終了 (modified by Yor)
 *------------------------------------------
 */
static
void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed)
{
    dumb_ptr<map_session_data> sd;

    AccountId acc = fixed.account_id;
    SEX sex = fixed.sex;
    if (battle_config.etc_log)
        PRINTF("chrif_changedsex %d.\n"_fmt, acc);
    sd = map_id2sd(account_to_block(acc));
    if (acc)
    {
        if (sd != nullptr && sd->status.sex != sex)
        {
            if (sd->status.sex == SEX::MALE)
                sd->sex = sd->status.sex = SEX::FEMALE;
            else if (sd->status.sex == SEX::FEMALE)
                sd->sex = sd->status.sex = SEX::MALE;
            // to avoid any problem with equipment and invalid sex, equipment is unequiped.
            for (IOff0 i : IOff0::iter())
            {
                if (sd->status.inventory[i].nameid
                    && bool(sd->status.inventory[i].equip))
                    pc_unequipitem(sd, i, CalcStatus::NOW);
            }
            // save character
            chrif_save(sd);
            sd->login_id1++;    // change identify, because if player come back in char within the 5 seconds, he can change its characters
            // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it)
            clif_displaymessage(sd->sess,
                                 "Your sex has been changed (need disconexion by the server)..."_s);
            clif_setwaitclose(sd->sess); // forced to disconnect for the change
        }
    }
    else
    {
        if (sd != nullptr)
        {
            PRINTF("chrif_changedsex failed.\n"_fmt);
        }
    }
}
예제 #13
0
/*==========================================
 * R 2b0f <accid>.l <name>.24B <type>.w <answer>.w
 * Reply to chrif_char_ask_name() (request to do some character operation)
 * type of operation:
 *   1: block, 2: ban, 3: unblock, 4: unban, 5: changesex
 * type of answer:
 *   0: login-server request done
 *   1: player not found
 *   2: gm level too low
 *   3: login-server offline
 *------------------------------------------*/
int chrif_char_ask_name_answer(int fd)
{
	struct map_session_data* sd;
	char* action;
	char output[256];
	int acc = RFIFOL(fd,2); // account_id of who has asked (-1 if nobody)
	char* player_name = (char*)RFIFOP(fd,6);
	uint16 type;
	uint16 answer;
	
	type = RFIFOW(fd,30);
	answer = RFIFOW(fd,32);
	
	sd = map_id2sd(acc);
	if (acc < 0 || sd == NULL) {
		ShowError("chrif_char_ask_name_answer failed - player not online.\n");
		return 0;
	}

	switch(type)
	{
	case 1: action = "block"; break;
	case 2: action = "ban"; break;
	case 3: action = "unblock"; break;
	case 4: action = "unban"; break;
	case 5: action = "change the sex of"; break;
	default: action = "???"; break;
	}
	
	switch(answer)
	{
	case 0: sprintf(output, "Login-server has been asked to %s the player '%20s'.", action, player_name); break;
	case 1: sprintf(output, "The player '%20s' doesn't exist.", player_name); break;
	case 2: sprintf(output, "Your GM level don't authorise you to %s the player '%20s'.", action, player_name); break;
	case 3: sprintf(output, "Login-server is offline. Impossible to %s the player '%20s'.", action, player_name); break;
	default: output[0] = '\0'; break;
	}
	
	clif_displaymessage(sd->fd, output);
	return 0;
}
예제 #14
0
파일: pet.c 프로젝트: Chocolate31/eamod
/**
 * Pet menu options.
 * @param sd : player requesting
 * @param menunum : menu option chosen
 * @return 0:success, 1:failure
 */
int pet_menu(struct map_session_data *sd,int menunum)
{
	struct item_data *egg_id;
	nullpo_ret(sd);

	if (sd->pd == NULL)
		return 1;

	//You lost the pet already.
	if(!sd->status.pet_id || sd->pd->pet.intimate <= 0 || sd->pd->pet.incubate)
		return 1;

	egg_id = itemdb_exists(sd->pd->petDB->EggID);

	if (egg_id) {
		if ((egg_id->flag.trade_restriction&0x01) && !pc_inventoryblank(sd)) {
			clif_displaymessage(sd->fd, msg_txt(sd, 451)); // You can't return your pet because your inventory is full.
			return 1;
		}
	}

	switch(menunum) {
		case 0:
			clif_send_petstatus(sd);
			break;
		case 1:
			pet_food(sd, sd->pd);
			break;
		case 2:
			pet_performance(sd, sd->pd);
			break;
		case 3:
			pet_return_egg(sd, sd->pd);
			break;
		case 4:
			pet_unequipitem(sd, sd->pd);
			break;
	}

	return 0;
}
예제 #15
0
파일: mail.c 프로젝트: bossemoja/5.0
/**
* Attempt to set item or zeny
* @param sd
* @param idx 0 - Zeny; >= 2 - Inventory item
* @param amount
* @return True if item/zeny can be set, False if failed
*/
bool mail_setitem(struct map_session_data *sd, short idx, int amount) {

	if( sd->state.account_protection ) {
		clif_displaymessage(sd->fd, "Your Account is Locked.");
		return 1;
	}

	if( pc_istrading(sd) )
		return false;

	if( idx == 0 ) { // Zeny Transfer
		if( !pc_can_give_items(sd) )
			return false;

		if( amount > sd->status.zeny )
			amount = sd->status.zeny;

		sd->mail.zeny = amount;
		// clif_updatestatus(sd, SP_ZENY);
		return true;
	} else { // Item Transfer
		idx -= 2;
		mail_removeitem(sd, 0);

		if( idx < 0 || idx >= MAX_INVENTORY )
			return false;
		if( amount > sd->status.inventory[idx].amount )
			return false;
		if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time
			|| !itemdb_available(sd->status.inventory[idx].nameid)
			|| !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd))
			|| (sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) )
			return false;

		sd->mail.index = idx;
		sd->mail.nameid = sd->status.inventory[idx].nameid;
		sd->mail.amount = amount;
		return true;
	}
}
예제 #16
0
/*==========================================
 * Disconnection of a player (account has been deleted in login-server) by [Yor]
 *------------------------------------------*/
int chrif_accountdeletion(int fd)
{
	int acc;
	struct map_session_data *sd;

	acc = RFIFOL(fd,2);
	if (battle_config.etc_log)
		ShowNotice("chrif_accountdeletion %d.\n", acc);
	sd = map_id2sd(acc);
	if (acc > 0) {
		if (sd != NULL) {
			sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters
			clif_displaymessage(sd->fd, "Your account has been deleted (disconnection)...");
			clif_setwaitclose(sd->fd); // forced to disconnect for the change
		}
	} else {
		if (sd != NULL)
			ShowError("chrif_accountdeletion failed - player not online.\n");
	}

	return 0;
}
예제 #17
0
void buyingstore_open(struct map_session_data* sd, int account_id) {
	struct map_session_data* pl_sd;

	if( !battle_config.feature_buying_store || pc_istrading(sd) ) // Not allowed to sell
		return;

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

	if( (pl_sd = map_id2sd(account_id)) == NULL || !pl_sd->state.buyingstore ) // Not online or not buying
		return;

	// Out of view range
	if( !searchstore_queryremote(sd, account_id) && (sd->bl.m != pl_sd->bl.m ||
		!check_distance_bl(&sd->bl, &pl_sd->bl, AREA_SIZE)) )
		return;

	// Success
	clif_buyingstore_itemlist(sd, pl_sd);
}
예제 #18
0
/*==========================================
 * Reloads the instance in runtime (reloadscript)
 *------------------------------------------*/
void do_reload_instance(void)
{
	struct instance_data *im;
	struct instance_db *db;
	struct s_mapiterator* iter;
	struct map_session_data *sd;
	int i;

	for( i = 1; i < MAX_INSTANCE_DATA; i++ ) {
		im = &instance_data[i];
		if(!im->cnt_map)
			continue;
		else {
			// First we load the NPCs again
			instance_addnpc(im);

			// Create new keep timer
			if((db = instance_searchtype_db(im->type)) != NULL)
				im->keep_limit = (unsigned int)time(NULL) + db->limit;
		}
	}

	// Reset player to instance beginning
	iter = mapit_getallusers();
	for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
		if(sd && map[sd->bl.m].instance_id) {
			struct party_data *p;
			if(!(p = party_search(sd->status.party_id)) || p->instance_id != map[sd->bl.m].instance_id) // Someone not in party is on instance map
				continue;
			im = &instance_data[p->instance_id];
			if((db = instance_searchtype_db(im->type)) != NULL && !instance_enter(sd,db->name)) { // All good
				clif_displaymessage(sd->fd, msg_txt(sd,515)); // Instance has been reloaded
				instance_reqinfo(sd,p->instance_id);
			} else // Something went wrong
				ShowError("do_reload_instance: Error setting character at instance start: character_id=%d instance=%s.\n",sd->status.char_id,db->name);
		}
	mapit_free(iter);
}
예제 #19
0
파일: channel.cpp 프로젝트: Atemo/rathena
/**
 * A player is attempting to change the channel color
 * @param sd: Player data
 * @param chname: Channel name
 * @param color: New color
 * @return 0 on success or -1 on failure
 */
int channel_pccolor(struct map_session_data *sd, char *chname, char *color){
	struct Channel *channel;
	char output[CHAT_SIZE_MAX];
	int k;

	if(!sd)
		return 0;

	if( channel_chk(chname,NULL,1) ) {
		clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
		return -1;
	}


	channel = channel_name2channel(chname,sd,0);
	if( !channel ) {
		sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available.
		clif_displaymessage(sd->fd, output);
		return -1;
	}

	if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
		if (channel->char_id != sd->status.char_id) {
			sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'.
			clif_displaymessage(sd->fd, output);
			return -1;
		}
		else if (!(channel->opt&CHAN_OPT_COLOR_OVERRIDE)) {
			sprintf(output, msg_txt(sd,764), chname); // You cannot change the color for channel '%s'.
			clif_displaymessage(sd->fd, output);
			return -1;
		}
	}

	ARR_FIND(0,channel_config.colors_count,k,( strcmpi(color,channel_config.colors_name[k]) == 0 ) );
	if( k >= channel_config.colors_count ) {
		sprintf(output, msg_txt(sd,1411), color);// Unknown color '%s'.
		clif_displaymessage(sd->fd, output);
		return -1;
	}
	channel->color = channel_config.colors[k];
	sprintf(output, msg_txt(sd,1413),chname,channel_config.colors_name[k]);// '%s' channel color updated to '%s'.
	clif_displaymessage(sd->fd, output);
	return 0;
}
예제 #20
0
/**
 * Attempt to open guild storage for player
 * @param sd : player
 * @return 0 : success, 1 : fail, 2 : no guild found
 */
char gstorage_storageopen(struct map_session_data* sd)
{
	struct guild_storage *gstor;

	nullpo_ret(sd);

	if(sd->status.guild_id <= 0)
		return 2;

	if(sd->state.storage_flag)
		return 1; //Can't open both storages at a time.

	if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
		clif_displaymessage(sd->fd, msg_txt(sd,246));
		return 1;
	}

	if((gstor = gstorage_get_storage(sd->status.guild_id)) == NULL) {
		intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
		return 0;
	}

	if(gstor->opened)
		return 1;

	if( gstor->locked )
		return 1;

	gstor->opened = sd->status.char_id;
	sd->state.storage_flag = 2;
	storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
	clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
	clif_updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE);

	return 0;
}
예제 #21
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 || map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
	{// custom: no vending maps/cells
		clif_displaymessage(sd->fd, msg_txt(276)); // "You can't open a shop on this map"
		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);
}
예제 #22
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;
	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 || !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;
		}

		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_pick_pc(sd, LOG_TYPE_BUYING_STORE, nameid, -((int)amount), &sd->status.inventory[index]);
		log_pick_pc(pl_sd, LOG_TYPE_BUYING_STORE, nameid, amount, &sd->status.inventory[index]);
		log_zeny(sd, LOG_TYPE_BUYING_STORE, pl_sd, zeny);

		// move item
		pc_additem(pl_sd, &sd->status.inventory[index], amount);
		pc_delitem(sd, index, amount, 1, 0);
		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);
	}
}
예제 #23
0
파일: vending.c 프로젝트: Escada28/rathena
/**
 * Player setup a new shop
 * @param sd : player opening the shop
 * @param message : shop title
 * @param data : itemlist data \n
 *	data := {<index>.w <amount>.w <value>.l}[count]
 * @param count : number of different items
 * @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
 */
char vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) {
	int i, j;
	int vending_skill_lvl;
	char message_sql[MESSAGE_SIZE*2];
	
	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&2) // Avoid invalid data from saving
		chrif_save(sd, 0);

	// 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 && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission
		||  !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 = min(value, (unsigned int)battle_config.vending_max_value);

		// Player just moved item to cart and we don't have the correct cart ID yet.
		if (sd->status.cart[sd->vending[i].index].id == 0) {
			struct item_data *idb = itemdb_search(sd->status.cart[index].nameid);
			char msg[256];

			sprintf(msg, msg_txt(sd, 733), idb->jname);
			clif_displaymessage(sd->fd, msg);
			clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0);
			return 4;
		}

		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->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_db, sd->vender_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->state.autotrade, sd->ud.dir, sd->head_dir, pc_issit(sd) ) != SQL_SUCCESS ){
		Sql_ShowDebug(mmysql_handle);
	}

	for( i = 0; i < count; i++ ) {
		if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`vending_id`,`index`,`cartinventory_id`,`amount`,`price`) VALUES( %d, %d, %d, %d, %d );", vending_items_db, sd->vender_id, i, sd->status.cart[sd->vending[i].index].id, sd->vending[i].amount, sd->vending[i].value ) != SQL_SUCCESS ){
			Sql_ShowDebug(mmysql_handle);
		}
	}

	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;
}
예제 #24
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);
	char output[256];

	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( !vsd->vend_coin || vsd->vend_coin == battle_config.vending_zeny_id )
		{ // Normal Vending - Zeny Option
			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;
			}
 		}
		else if( battle_config.vending_cash_id && vsd->vend_coin == battle_config.vending_cash_id )
		{ // Cash Shop
			if( z > (double)sd->cashPoints || z < 0. || z > (double)MAX_ZENY )
			{
				sprintf(output,msg_txt(915),itemdb_jname(vsd->vend_coin));
				clif_displaymessage(sd->fd,output);
				return;
			}
			if( z + (double)vsd->cashPoints > (double)MAX_ZENY && !battle_config.vending_over_max )
			{
				sprintf(output,msg_txt(916),itemdb_jname(vsd->vend_coin));
				clif_displaymessage(sd->fd,output);
				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
		}
	}

	// Payments
	if( !vsd->vend_coin || vsd->vend_coin == battle_config.vending_zeny_id )
	{
		if( log_config.zeny > 0 )
			log_zeny(vsd, "V", sd, (int)z); //Logs (V)ending Zeny [Lupus]

		pc_payzeny(sd, (int)z);

		if( battle_config.vending_tax || (vsd->state.autotrade && battle_config.at_tax && !pc_isPremium(vsd)) )
			z -= z * ((battle_config.vending_tax + ((vsd->state.autotrade && !pc_isPremium(vsd)) ? battle_config.at_tax : 0)) / 10000.);

		pc_getzeny(vsd, (int)z);
	}
	else if( battle_config.vending_cash_id && vsd->vend_coin == battle_config.vending_cash_id )
	{
		pc_paycash(sd,(int)z,0);
		pc_getcash(vsd,(int)z,0);
	}
	else
	{
		if( z < 0. || (i = pc_search_inventory(sd,vsd->vend_coin)) < 0 || z > (double)sd->status.inventory[i].amount )
		{
			sprintf(output,msg_txt(915),itemdb_jname(vsd->vend_coin));
			clif_displaymessage(sd->fd,output);
			return;
		}

		switch( pc_checkadditem(vsd,vsd->vend_coin,(int)z) )
		{
		case ADDITEM_NEW:
			if( pc_inventoryblank(vsd) > 0 )
				break;
		case ADDITEM_OVERAMOUNT:
			sprintf(output,msg_txt(916),itemdb_jname(vsd->vend_coin));
			clif_displaymessage(sd->fd,output);
			return;
		}

		pc_additem(vsd,&sd->status.inventory[i],(int)z);
		pc_delitem(sd,i,(int)z,0,6);
	}
	for( i = 0; i < count; i++ )
	{
		short amount = *(uint16*)(data + 4*i + 0);
		short idx    = *(uint16*)(data + 4*i + 2);
		idx -= 2;

		//Logs sold (V)ending items [Lupus]
		if(log_config.enable_logs&0x4) {
			log_pick_pc(vsd, "V", vsd->status.cart[idx].nameid, -amount, &vsd->status.cart[idx], vsd->status.cart[idx].serial );
			log_pick_pc( sd, "V", vsd->status.cart[idx].nameid,  amount, &vsd->status.cart[idx], vsd->status.cart[idx].serial );
		}

		// vending item
		pc_additem(sd, &vsd->status.cart[idx], amount);
		vsd->vending[vend_list[i]].amount -= amount;
		pc_cart_delitem(vsd, idx, amount, 0);
		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?
		}
	}
}
예제 #25
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, 0, 0);
		return;
	}

	// check number of items in shop
	if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl )
	{	// invalid item count
		clif_skill_fail(sd, MC_VENDING, 0, 0);
		return;
	}

	if((sd->bl.m == map_mapname2mapid("mercadores") 
 	 && (
	((sd->bl.x != 65) && (sd->bl.x != 74) && (sd->bl.x != 85) && (sd->bl.x != 94)
	&& (sd->bl.x != 34) && (sd->bl.x != 25) && (sd->bl.x != 14) && (sd->bl.x != 5)
	&& (sd->bl.x != 44) && (sd->bl.x != 55))
 	))) {
	clif_displaymessage(sd->fd,"Você não pode abrir lojas no meio da Sala."); 
	return; 
	}

	// filter out invalid items
	i = 0;
	for( j = 0; j < count; j++ )
	{
		short index        = *(uint16*)(data + 8*j + 0);
		short amount       = *(uint16*)(data + 8*j + 2);
		unsigned int value = *(uint32*)(data + 8*j + 4);

		index -= 2; // offset adjustment (client says that the first cart position is 2)

		if( index < 0 || index >= MAX_CART // invalid position
		||  pc_cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity
		//NOTE: official server does not do any of the following checks!
		||  !sd->status.cart[index].identify // unidentified item
		||  sd->status.cart[index].attribute == 1 // broken item
		||  sd->status.cart[index].expire_time // It should not be in the cart but just in case
		||  sd->status.cart[index].bound // Can't Trade Account bound items
		||  ( sd->status.cart[index].card[0] == CARD0_CREATE && (char_id = MakeDWord(sd->status.cart[index].card[2],sd->status.cart[index].card[3])) > 0 && ((battle_config.bg_reserved_char_id && char_id == battle_config.bg_reserved_char_id) || (battle_config.ancient_reserved_char_id && char_id == battle_config.ancient_reserved_char_id)) )
		||  !itemdb_cantrade(&sd->status.cart[index], pc_isGM(sd), pc_isGM(sd)) ) // untradeable item
			continue;

		sd->vending[i].index = index;
		sd->vending[i].amount = amount;
		sd->vending[i].value = cap_value(value, 0, (unsigned int)battle_config.vending_max_value);

		i++; // item successfully added
	}

	if( i != j )
		clif_displaymessage (sd->fd, msg_txt(266)); //"Some of your items cannot be vended and were removed from the shop."

	if( i == 0 )
	{	// no valid item found
		clif_skill_fail(sd, MC_VENDING, 0, 0); // custom reply packet
		return;
	}

	sd->state.vending = true;
	sd->vender_id = vending_getuid();
	sd->vend_num = i;
	safestrncpy(sd->message, message, MESSAGE_SIZE);

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

	if( battle_config.channel_announces&0x10 )
	{
		char chat_message[256];
		sprintf(chat_message, msg_txt(820), vending_chat_nick, sd->status.name, sd->message, map[sd->bl.m].name, sd->bl.x, sd->bl.y);
		clif_channel_message(server_channel[CHN_VENDING], chat_message, 27);
	}

	if( map[sd->bl.m].flag.vending_cell )
		map_setcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_NOBOARDS, false);
}
예제 #26
0
파일: trade.c 프로젝트: Celso1415/Fusion
/*==========================================
 * Initiates a trade request.
 *------------------------------------------*/
void trade_traderequest (struct map_session_data *sd, struct map_session_data *target_sd)
{
	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 (target_sd == NULL || sd == target_sd) {
		clif_tradestart (sd, 1); // character does not exist
		return;
	}

	if (target_sd->npc_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 (sd->trade_partner != 0) {   // If a character tries to trade to another one then cancel the previous one
		struct map_session_data *previous_sd = map_id2sd (sd->trade_partner);

		if (previous_sd) {
			previous_sd->trade_partner = 0;
			clif_tradecancelled (previous_sd);
		} // Once cancelled then continue to the new one.

		sd->trade_partner = 0;
		clif_tradecancelled (sd);
	}

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

	if (!pc_can_give_items (sd) || !pc_can_give_items (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;
	}

	// Players can not request trade from far away, unless they are allowed to use @trade.
	if (!pc_can_use_command (sd, "trade", COMMAND_ATCOMMAND) &&
			(sd->bl.m != target_sd->bl.m || !check_distance_bl (&sd->bl, &target_sd->bl, TRADE_DISTANCE))) {
		clif_tradestart (sd, 0); // too far
		return ;
	}

	if (target_sd->weight > target_sd->max_weight || sd->weight > sd->max_weight) {
		clif_tradestart (sd, 2); // trade failed (overweight)
		return;
	}

	if (sd->trade_partner != 0)
		trade_tradecancel (sd);

	if (sd->state.vending || target_sd->state.vending)
		return; // ignore request at the last minute (official)

	target_sd->state.can_tradeack = 1;
	target_sd->trade_partner = sd->status.account_id;
	sd->trade_partner = target_sd->status.account_id;
	clif_traderequest (target_sd, sd->status.name);
}
예제 #27
0
int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
{
	struct party_data *p=party_search(sd->status.party_id);
	int i,flag=0;
	
	nullpo_retr(0, sd);
	if (p==NULL)
		return 0;

	if(tsd==NULL) {	//TODO: Find the correct reply packet.
		clif_displaymessage(sd->fd, msg_txt(3));
		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;
}
예제 #28
0
파일: buyingstore.c 프로젝트: AsaK/rathena
/**
* 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
* @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
*/
char 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;
	char message_sql[MESSAGE_SIZE*2];

	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->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 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_db, 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, sd->ud.dir, sd->head_dir, pc_issit(sd) ) != SQL_SUCCESS ){
		Sql_ShowDebug(mmysql_handle);
	}

	for( i = 0; i < sd->buyingstore.slots; i++ ){
		if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`buyingstore_id`,`index`,`item_id`,`amount`,`price`) VALUES( %d, %d, %hu, %d, %d );", buyingstore_items_db, sd->buyer_id, i, sd->buyingstore.items[i].nameid, sd->buyingstore.items[i].amount, sd->buyingstore.items[i].price ) != SQL_SUCCESS ){
			Sql_ShowDebug(mmysql_handle);
		}
	}

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

	return 0;
}
예제 #29
0
파일: trade.c 프로젝트: Celso1415/Fusion
/*==========================================
 * 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_get_group_level (sd);
	dst_lv = pc_get_group_level (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;
	}

	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);
}
예제 #30
0
파일: party.c 프로젝트: julius5/rathena
///! 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;
}