/** * Attempt to add an item in guild storage from cart, then refresh it * @param sd : player * @param index : index of item in cart * @param amount : number of item to transfer * @return 1:fail, 0:success */ void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount) { struct guild_storage *stor; nullpo_retv(sd); nullpo_retv(stor=guild2storage2(sd->status.guild_id)); if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE ) return; if( index < 0 || index >= MAX_CART ) return; if( sd->status.cart[index].nameid == 0 ) return; if( amount < 1 || amount > sd->status.cart[index].amount ) return; if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0) pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE); else { clif_storageitemremoved(sd,index,0); clif_dropitem(sd,index,0); } }
/** * Move an item from cart to storage. * @param sd : player * @param stor : Storage data * @param index : cart index to take the item from * @param amount : number of item to take * @return 0:fail, 1:success */ void storage_storageaddfromcart(struct map_session_data *sd, struct s_storage *stor, int index, int amount) { enum e_storage_add result; nullpo_retv(sd); result = storage_canAddItem(stor, index, sd->cart.u.items_inventory, amount, MAX_INVENTORY); if (result == STORAGE_ADD_INVALID) return; else if (result == STORAGE_ADD_OK && storage_additem(sd,stor,&sd->cart.u.items_cart[index],amount) == 0) { pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE); return; } clif_storageitemremoved(sd,index,0); clif_dropitem(sd,index,0); }
/*========================================== * Move an item from cart to storage. * @index : cart inventory index * return * 0 : fail * 1 : success *------------------------------------------*/ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amount) { nullpo_ret(sd); if( sd->status.storage.storage_amount > MAX_STORAGE ) return 0; // storage full / storage closed if( index < 0 || index >= MAX_CART ) return 0; if( sd->status.cart[index].nameid <= 0 ) return 0; //No item there. if( amount < 1 || amount > sd->status.cart[index].amount ) return 0; if( storage_additem(sd,&sd->status.cart[index],amount) == 0 ) pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE); return 1; }
/*========================================== * カプラ倉庫へカートから入れる *------------------------------------------ */ void storage_storageaddfromcart(struct map_session_data *sd, int idx, int amount) { struct storage *stor; nullpo_retv(sd); nullpo_retv(stor = (struct storage *)numdb_search(storage_db,sd->status.account_id)); if(!stor->storage_status) return; if(idx < 0 || idx >= MAX_CART) return; if(itemdb_isstorageable(sd->status.cart[idx].nameid) == 0) return; if(amount < 1 || amount > sd->status.cart[idx].amount) return; if(storage_additem(sd, stor, &sd->status.cart[idx], amount) == 0) pc_cart_delitem(sd, idx, amount, 0); return; }
/** * Move an item from cart to storage. * @param sd : player * @param index : cart index to take the item from * @param amount : number of item to take * @return 0:fail, 1:success */ void storage_storageaddfromcart(struct map_session_data* sd, int index, int amount) { nullpo_retv(sd); if( sd->status.storage.storage_amount > sd->storage_size ) return; // storage full / storage closed if( index < 0 || index >= MAX_CART ) return; if( sd->status.cart[index].nameid <= 0 ) return; //No item there. if( amount < 1 || amount > sd->status.cart[index].amount ) return; if( storage_additem(sd,&sd->status.cart[index],amount) == 0 ) pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE); else { clif_storageitemremoved(sd,index,0); clif_dropitem(sd,index,0); } }
/*========================================== * Move an item from cart to storage. *------------------------------------------ */ int storage_storageaddfromcart(struct map_session_data *sd,int index,int amount) { struct storage *stor; nullpo_retr(0, sd); nullpo_retr(0, stor=account2storage2(sd->status.account_id)); if(stor->storage_amount > MAX_STORAGE || !stor->storage_status) return 0; // storage full / storage closed if(index< 0 || index>=MAX_CART) return 0; if(sd->status.cart[index].nameid <= 0) return 0; //No item there. if(amount < 1 || amount > sd->status.cart[index].amount) return 0; if(storage_additem(sd,stor,&sd->status.cart[index],amount)==0) pc_cart_delitem(sd,index,amount,0); return 1; }
int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount) { struct guild_storage *stor; nullpo_retr(0, sd); nullpo_retr(0, stor=guild2storage2(sd->status.guild_id)); if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE ) return 0; if( index < 0 || index >= MAX_CART ) return 0; if( sd->status.cart[index].nameid <= 0 ) return 0; if( amount < 1 || amount > sd->status.cart[index].amount ) return 0; if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0) pc_cart_delitem(sd,index,amount,0); return 1; }
/** * Move an item from cart to storage. * @param sd : player * @param stor : Storage data * @param index : cart index to take the item from * @param amount : number of item to take * @return 0:fail, 1:success */ void storage_storageaddfromcart(struct map_session_data *sd, struct s_storage *stor, int index, int amount) { enum e_storage_add result; nullpo_retv(sd); result = storage_canAddItem(stor, index, sd->cart.u.items_inventory, amount, MAX_CART); if (result == STORAGE_ADD_INVALID) return; else if (result == STORAGE_ADD_OK) { switch( storage_additem(sd, stor, &sd->cart.u.items_cart[index], amount) ){ case 0: pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE); return; case 1: break; case 2: result = STORAGE_ADD_NOROOM; break; } } clif_storageitemremoved(sd,index,0); clif_dropitem(sd,index,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 \n * 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->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 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); 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; 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->status.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->status.cart[idx].id ) != SQL_SUCCESS ){ Sql_ShowDebug( mmysql_handle ); } } 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(sd,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: customer (buyer) and vender 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? } } }
/*========================================== * 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? } } }