/** * Attempt to set item or zeny to a mail * @param sd : player attaching the content * @param idx 0 - Zeny; >= 2 - Inventory item * @param amount : amout of zeny or number of item * @return True if item/zeny can be set, False if failed */ bool mail_setitem(struct map_session_data *sd, short idx, uint32 amount) { 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; } }
/*========================================== * 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 ; } target_sd->trade_partner = sd->status.account_id; sd->trade_partner = target_sd->status.account_id; clif_traderequest(target_sd, sd->status.name); }
unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { if( pc_istrading(sd) ) return 1; if( idx == 0 ) { // Zeny Transfer if( amount < 0 || !pc_can_give_items(sd) ) return 1; if( amount > sd->status.zeny ) amount = sd->status.zeny; sd->mail.zeny = amount; // clif->updatestatus(sd, SP_ZENY); return 0; } else { // Item Transfer idx -= 2; mail->removeitem(sd, 0); if( idx < 0 || idx >= MAX_INVENTORY ) return 1; if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time || !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) || (sd->status.inventory[idx].bound && !pc_can_give_bound_items(sd)) ) return 1; sd->mail.index = idx; sd->mail.nameid = sd->status.inventory[idx].nameid; sd->mail.amount = amount; return 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->state.vending ) 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; } sd->vended_id = vsd->vender_id; // register vending uid if( battle_config.vending_zeny_id && vsd->vend_coin ) { // Extended Vending System char output[256]; sprintf(output,msg_txt(914),itemdb_jname(vsd->vend_coin)); clif_displaymessage(sd->fd,output); } clif_vendinglist(sd, id, vsd->vending); }
/*========================================== * 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 (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 ((target_sd->trade_partner != 0) || (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); }
/** * Request to open premium storage * @param sd Player who request * @param num Storage number * @param mode Storage mode @see enum e_storage_mode * @return 1:Success to request, 0:Failed * @author [Cydh] **/ bool storage_premiumStorage_load(struct map_session_data *sd, uint8 num, uint8 mode) { nullpo_ret(sd); if (sd->state.storage_flag) return 0; if (sd->state.vending || sd->state.buyingstore || sd->state.prevend || sd->state.autotrade) return 0; if (sd->state.banking || sd->state.callshop) return 0; 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 0; } if (!&sd->premiumStorage || sd->premiumStorage.stor_id != num) return intif_storage_request(sd, TABLE_STORAGE, num, mode); else { sd->premiumStorage.state.put = (mode&STOR_MODE_PUT) ? 1 : 0; sd->premiumStorage.state.get = (mode&STOR_MODE_GET) ? 1 : 0; storage_premiumStorage_open(sd); } return 1; }
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(pc_isGM(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; } 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 return; } // success clif_buyingstore_itemlist(sd, pl_sd); }
/*========================================== * Attempt to open guild storage for sd * return * 0 : success (open or req to create a new one) * 1 : fail * 2 : no guild for sd *------------------------------------------*/ int storage_guild_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 = guild2storage2(sd->status.guild_id)) == NULL) { intif_request_guild_storage(sd->status.account_id,sd->status.guild_id); return 0; } if(gstor->storage_status) return 1; if( gstor->lock ) return 1; gstor->storage_status = 1; 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; }
int storage_guild_storageopen(struct map_session_data* sd) { struct guild_storage *gstor; nullpo_retr(0, 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(pc_isGM(sd)) ) { //check is this GM level can open guild storage and store items [Lupus] clif_displaymessage(sd->fd, msg_txt(246)); return 1; } if((gstor = guild2storage2(sd->status.guild_id)) == NULL) { intif_request_guild_storage(sd->status.account_id,sd->status.guild_id); return 0; } if(gstor->storage_status) return 1; gstor->storage_status = 1; sd->state.storage_flag = 2; clif_guildstoragelist(sd,gstor); clif_updateguildstorageamount(sd,gstor->storage_amount); return 0; }
void buyingstore_open(struct map_session_data* sd, int account_id) { struct map_session_data* pl_sd; nullpo_retv(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->message(sd->fd, msg_sd(sd,246)); // Your GM level doesn't authorize you to perform this action. return; } if( ( pl_sd = map->id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore ) { // not online or not buying 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 return; } // success clif->buyingstore_itemlist(sd, pl_sd); }
unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { if (idx == 0) { // Zeny Transfer if( amount < 0 ) return 0; if( amount > sd->status.zeny ) amount = sd->status.zeny; if( !pc_can_give_items(pc_isGM(sd)) ) amount = 0; sd->mail.zeny = amount; // clif_updatestatus(sd, SP_ZENY); return 0; } else { // Item Transfer idx -= 2; mail_removeitem(sd, 0); if( idx < 0 || idx >= MAX_INVENTORY ) return 1; if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; if( !pc_candrop(sd, &sd->status.inventory[idx]) ) return 1; sd->mail.index = idx; sd->mail.nameid = sd->status.inventory[idx].nameid; sd->mail.amount = amount; return 0; } }
/*========================================== * Opens a storage. Returns: * 0 - success * 1 - fail * 2 - Storage requested from char-server (will open automatically later) *------------------------------------------ */ int storage_storageopen(struct map_session_data *sd) { struct storage *stor; nullpo_retr(0, sd); if(sd->state.finalsave) //Refuse to open storage when you had your last save done. return 1; if(sd->state.storage_flag) return 1; //Already open? 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; } if((stor = idb_get(storage_db,sd->status.account_id)) == NULL) { //Request storage. intif_request_storage(sd->status.account_id); return 2; } if (stor->storage_status) return 1; //Already open/player already has it open... stor->storage_status = 1; sd->state.storage_flag = 1; clif_storagelist(sd,stor); clif_updatestorageamount(sd,stor); return 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.secure_items ) { clif_displaymessage(sd->fd, "You can't attach. Blocked with @security"); return 1; } if( pc_istrading(sd) ) return false; if( battle_config.super_woe_enable ) { clif_displaymessage(sd->fd, "Super WoE don't allow send items/zeny with attachments"); return 1; } 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; } }
/*========================================== * 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); }
/*========================================== * 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); }
/*========================================== * 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 clif->message(sd->fd, msg_sd(sd,246)); // Your GM level doesn't authorize you to perform this action. return; } sd->vended_id = vsd->vender_id; // register vending uid clif->vendinglist(sd, id, vsd->vending); }
/*========================================== * Solicitando uma lista de itens de venda *------------------------------------------*/ 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; // nao vendendo if (!pc_can_give_items(sd) || !pc_can_give_items(vsd)) { //checando se ambos GMs sao permitidos negociar // GM nao esta permitido negociar clif->message(sd->fd, msg_txt(246)); return; } sd->vended_id = vsd->vender_id; // registra uid de venda clif->vendinglist(sd, id, vsd->vending); }
/*========================================== * 取引要請を相手に送る *------------------------------------------ */ void trade_traderequest(struct map_session_data *sd, int target_id) { 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 ((target_sd = map_id2sd(target_id)) != NULL) { if (!battle_config.invite_request_check) { if (target_sd->guild_invite > 0 || target_sd->party_invite > 0) { clif_tradestart(sd, 2); // 相手はPT要請中かGuild要請中 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)); trade_tradecancel(sd); // GM is not allowed to trade } else if ((target_sd->trade_partner != 0) || (sd->trade_partner != 0)) { trade_tradecancel(sd); // person is in another trade } else { //Fixed. Only real GMs can request trade from far away! [Lupus] if (level < lowest_gm_level && (sd->bl.m != target_sd->bl.m || (sd->bl.x - target_sd->bl.x <= -5 || sd->bl.x - target_sd->bl.x >= 5) || (sd->bl.y - target_sd->bl.y <= -5 || sd->bl.y - target_sd->bl.y >= 5))) { clif_tradestart(sd, 0); // too far } else if (sd != target_sd) { target_sd->trade_partner = sd->status.account_id; sd->trade_partner = target_sd->status.account_id; clif_traderequest(target_sd, sd->status.name); } } } else { clif_tradestart(sd, 1); // character does not exist } }
unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { if( sd->state.secure_items ) { clif_displaymessage(sd->fd, "You can't attach. Blocked with @security"); return 1; } if( battle_config.super_woe_enable ) { clif_displaymessage(sd->fd, "Super WoE don't allow send items/zeny with attachments"); return 1; } if( idx == 0 ) { // Zeny Transfer if( amount < 0 || !pc_can_give_items(pc_isGM(sd)) ) return 1; if( amount > sd->status.zeny ) amount = sd->status.zeny; sd->mail.zeny = amount; // pc_onstatuschanged(sd, SP_ZENY); return 0; } else { // Item Transfer idx -= 2; mail_removeitem(sd, 0); if( idx < 0 || idx >= MAX_INVENTORY ) return 1; if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; if( !pc_candrop(sd, &sd->status.inventory[idx]) ) return 1; sd->mail.index = idx; sd->mail.nameid = sd->status.inventory[idx].nameid; sd->mail.amount = amount; return 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(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, sd->storage_size); return 0; }
/*========================================== * Opens a storage. Returns: * 0 - success * 1 - fail *------------------------------------------*/ int storage_storageopen(struct map_session_data *sd) { nullpo_retr(0, sd); if(sd->state.storage_flag) return 1; //Already open? 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 = 1; clif_storagelist(sd,&sd->status.storage); clif_updatestorageamount(sd,sd->status.storage.storage_amount); return 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; }
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; }
/** * 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, 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; 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(246)); clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0); return; } // Not online, not buying or not same store if( (pl_sd = map_id2sd(account_id)) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id ) { 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 && !pc_can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->status.inventory[index], pc_get_group_level(sd), pc_get_group_level(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); // There is no such item or the buyer has already bought all of them if( listidx == pl_sd->buyingstore.slots || pl_sd->buyingstore.items[listidx].amount == 0 ) { clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid); return; } // Buyer does not need that much of the item if( pl_sd->buyingstore.items[listidx].amount < amount ) { clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_COUNT, nameid); return; } // Buyer does not have enough space for this item if( pc_checkadditem(pl_sd, nameid, amount) == CHKADDITEM_OVERAMOUNT ) { clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid); return; } // Normally this is not supposed to happen, as the total weight is // checked upon creation, but the buyer could have gained items if( amount * (unsigned int)sd->inventory_data[index]->weight > pl_sd->max_weight - weight ) { clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid); return; } weight += amount * sd->inventory_data[index]->weight; // Buyer does not have enough zeny if( amount * pl_sd->buyingstore.items[listidx].price > pl_sd->buyingstore.zenylimit - 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->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; 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_db, 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_db, 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); } if( save_settings&128 ) { chrif_save(sd, 0); chrif_save(pl_sd, 0); } // 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_db, 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); }
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); }
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); } }
/// Attaches an item to a message being written /// @param sd : The player who's writting /// @param idx : the inventory idx of the item /// @param amount : Amount of the item to be attached void rodex_add_item(struct map_session_data *sd, int16 idx, int16 amount) { int i; bool is_stack = false; nullpo_retv(sd); if (idx < 0 || idx >= MAX_INVENTORY) { clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_FATAL_ERROR); return; } if (amount < 0 || amount > sd->status.inventory[idx].amount) { clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_FATAL_ERROR); return; } if (!pc_can_give_items(sd) || sd->status.inventory[idx].expire_time || !itemdb_canmail(&sd->status.inventory[idx], pc_get_group_level(sd)) || (sd->status.inventory[idx].bound && !pc_can_give_bound_items(sd))) { clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_NOT_TRADEABLE); return; } if (itemdb->isstackable(sd->status.inventory[idx].nameid) == 1) { for (i = 0; i < RODEX_MAX_ITEM; ++i) { if (sd->rodex.tmp.items[i].idx == idx) { if (sd->status.inventory[idx].nameid == sd->rodex.tmp.items[i].item.nameid && sd->status.inventory[idx].unique_id == sd->rodex.tmp.items[i].item.unique_id) { is_stack = true; break; } } } if (i == RODEX_MAX_ITEM && sd->rodex.tmp.items_count < RODEX_MAX_ITEM) { ARR_FIND(0, RODEX_MAX_ITEM, i, sd->rodex.tmp.items[i].idx == 0); } } else if (sd->rodex.tmp.items_count < RODEX_MAX_ITEM) { ARR_FIND(0, RODEX_MAX_ITEM, i, sd->rodex.tmp.items[i].idx == 0); } else { i = RODEX_MAX_ITEM; } if (i == RODEX_MAX_ITEM) { clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_NO_SPACE); return; } if (sd->rodex.tmp.items[i].item.amount + amount > sd->status.inventory[idx].amount) { clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_FATAL_ERROR); return; } if (sd->rodex.tmp.weight + sd->inventory_data[idx]->weight * amount > RODEX_WEIGHT_LIMIT) { clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_FATAL_ERROR); return; } sd->rodex.tmp.items[i].idx = idx; sd->rodex.tmp.weight += sd->inventory_data[idx]->weight * amount; if (is_stack == false) { sd->rodex.tmp.items[i].item = sd->status.inventory[idx]; sd->rodex.tmp.items[i].item.amount = amount; sd->rodex.tmp.items_count++; } else { sd->rodex.tmp.items[i].item.amount += amount; } sd->rodex.tmp.type |= MAIL_TYPE_ITEM; clif->rodex_add_item_result(sd, idx, amount, RODEX_ADD_ITEM_SUCCESS); }
/** * Attempt to set item or zeny to a mail * @param sd : player attaching the content * @param idx 0 - Zeny; >= 2 - Inventory item * @param amount : amout of zeny or number of item * @return see enum mail_attach_result in mail.h */ enum mail_attach_result mail_setitem(struct map_session_data *sd, short idx, uint32 amount) { if( pc_istrading(sd) ) return MAIL_ATTACH_ERROR; if( idx == 0 ) { // Zeny Transfer if( !pc_can_give_items(sd) ) return MAIL_ATTACH_UNTRADEABLE; #if PACKETVER < 20150513 if( amount > sd->status.zeny ) amount = sd->status.zeny; // TODO: confirm this behavior for old mail system #else if( ( amount + battle_config.mail_zeny_fee / 100 * amount ) > sd->status.zeny ) return MAIL_ATTACH_ERROR; #endif sd->mail.zeny = amount; // clif_updatestatus(sd, SP_ZENY); return MAIL_ATTACH_SUCCESS; } else { // Item Transfer int i, j, total = 0; idx -= 2; if( idx < 0 || idx >= MAX_INVENTORY ) return MAIL_ATTACH_ERROR; #if PACKETVER < 20150513 i = 0; // Remove existing item mail_removeitem(sd, 0, sd->mail.item[i].index + 2, sd->mail.item[i].amount); #else ARR_FIND(0, MAIL_MAX_ITEM, i, sd->mail.item[i].index == idx && sd->mail.item[i].nameid > 0 ); // The same item had already been added to the mail if( i < MAIL_MAX_ITEM ){ // Check if it is stackable if( !itemdb_isstackable(sd->mail.item[i].nameid) ){ return MAIL_ATTACH_ERROR; } // Check if it exceeds the total amount if( ( amount + sd->mail.item[i].amount ) > sd->inventory.u.items_inventory[idx].amount ){ return MAIL_ATTACH_ERROR; } // Check if it exceeds the total weight if( battle_config.mail_attachment_weight ){ for( j = 0; j < i; j++ ){ total += sd->mail.item[j].amount * ( sd->inventory_data[sd->mail.item[j].index]->weight / 10 ); } total += amount * sd->inventory_data[idx]->weight / 10; if( total > battle_config.mail_attachment_weight ){ return MAIL_ATTACH_WEIGHT; } } sd->mail.item[i].amount += amount; return MAIL_ATTACH_SUCCESS; }else{ ARR_FIND(0, MAIL_MAX_ITEM, i, sd->mail.item[i].nameid == 0); if( i == MAIL_MAX_ITEM ){ return MAIL_ATTACH_SPACE; } // Check if it exceeds the total weight if( battle_config.mail_attachment_weight ){ for( j = 0; j < i; j++ ){ total += sd->mail.item[j].amount * ( sd->inventory_data[sd->mail.item[j].index]->weight / 10 ); } total += amount * sd->inventory_data[idx]->weight / 10; if( total > battle_config.mail_attachment_weight ){ return MAIL_ATTACH_WEIGHT; } } } #endif if( amount > sd->inventory.u.items_inventory[idx].amount ) return MAIL_ATTACH_ERROR; if( !pc_can_give_items(sd) || sd->inventory.u.items_inventory[idx].expire_time || !itemdb_available(sd->inventory.u.items_inventory[idx].nameid) || !itemdb_canmail(&sd->inventory.u.items_inventory[idx],pc_get_group_level(sd)) || (sd->inventory.u.items_inventory[idx].bound && !pc_can_give_bounded_items(sd)) ) return MAIL_ATTACH_UNTRADEABLE; sd->mail.item[i].index = idx; sd->mail.item[i].nameid = sd->inventory.u.items_inventory[idx].nameid; sd->mail.item[i].amount = amount; return MAIL_ATTACH_SUCCESS; } }
/** * 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; }