void party_created(uint32 account_id,uint32 char_id,int fail,int party_id,char *name) { struct map_session_data *sd; sd = map_id2sd(account_id); if (!sd || sd->status.char_id != char_id || !sd->party_creating ) { // Character logged off before creation ack? if (!fail) // break up party since player could not be added to it. intif_party_leave(party_id,account_id,char_id,"",PARTY_MEMBER_WITHDRAW_LEAVE); return; } sd->party_creating = false; if( !fail ) { sd->status.party_id = party_id; clif_party_created(sd,0); // Success message achievement_update_objective(sd, AG_PARTY, 1, 1); // We don't do any further work here because the char-server sends a party info packet right after creating the party if(party_create_byscript) { // returns party id in $@party_create_id if party is created by script mapreg_setreg(add_str("$@party_create_id"),party_id); party_create_byscript = 0; } } else clif_party_created(sd,1); // "party name already exists" }
/** * Player chat room creation. * @param sd : player requesting * @param title : title of chat room * @param pass : password for chat room * @param limit : amount allowed to enter * @param pub : public or private * @return 0 */ int chat_createpcchat(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub) { struct chat_data* cd; nullpo_ret(sd); if( sd->chatID ) return 0; //Prevent people abusing the chat system by creating multiple chats, as pointed out by End of Exam. [Skotlex] if( sd->state.vending || sd->state.buyingstore ) // not chat, when you already have a store open return 0; if( map_getmapflag(sd->bl.m, MF_NOCHAT) ) { clif_displaymessage(sd->fd, msg_txt(sd,281)); return 0; //Can't create chatrooms on this map. } if( map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOCHAT) ) { clif_displaymessage (sd->fd, msg_txt(sd,665)); return 0; } pc_stop_walking(sd,1); cd = chat_createchat(&sd->bl, title, pass, limit, pub, 0, "", 0, 1, MAX_LEVEL); if( cd ) { cd->users = 1; cd->usersd[0] = sd; pc_setchatid(sd,cd->bl.id); pc_stop_attack(sd); clif_createchat(sd,0); clif_dispchat(cd,0); if (status_isdead(&sd->bl)) achievement_update_objective(sd, AG_CHAT_DYING, 1, 1); else achievement_update_objective(sd, AG_CHAT_CREATE, 1, 1); } else clif_createchat(sd,1); return 0; }
/** * Join an existing chat room. * @param sd : player requesting * @param chatid : ID of the chat room * @param pass : password of chat room * @return 0 */ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) { struct chat_data* cd; nullpo_ret(sd); cd = (struct chat_data*)map_id2bl(chatid); if( cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->state.vending || sd->state.buyingstore || sd->chatID || ((cd->owner->type == BL_NPC) ? cd->users+1 : cd->users) >= cd->limit ) { clif_joinchatfail(sd,0); return 0; } if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) ) { clif_joinchatfail(sd,1); return 0; } if( sd->status.base_level < cd->minLvl || sd->status.base_level > cd->maxLvl ) { if(sd->status.base_level < cd->minLvl) clif_joinchatfail(sd,5); else clif_joinchatfail(sd,6); return 0; } if( sd->status.zeny < cd->zeny ) { clif_joinchatfail(sd,4); return 0; } if( cd->owner->type != BL_NPC && idb_exists(cd->kick_list,sd->status.char_id) ) { clif_joinchatfail(sd,2);//You have been kicked out of the room. return 0; } pc_stop_walking(sd,1); cd->usersd[cd->users] = sd; cd->users++; pc_setchatid(sd,cd->bl.id); clif_joinchatok(sd, cd); //To the person who newly joined the list of all clif_addchat(cd, sd); //Reports To the person who already in the chat clif_dispchat(cd, 0); //Reported number of changes to the people around if (cd->owner->type == BL_PC) achievement_update_objective(map_id2sd(cd->owner->id), AG_CHAT_COUNT, 1, cd->users); chat_triggerevent(cd); //Event return 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->cart.u.items_cart[idx].nameid) * amount; if( w + sd->weight > sd->max_weight ) { clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight return; } //Check to see if cart/vend info is in sync. if( vending[j].amount > vsd->cart.u.items_cart[idx].amount ) vending[j].amount = vsd->cart.u.items_cart[idx].amount; // if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples). // here, we check cumulative amounts if( vending[j].amount < amount ) { // send more quantity is not a hack (an other player can have buy items just before) clif_buyvending(sd, idx, vsd->vending[j].amount, 4); // not enough quantity return; } vending[j].amount -= amount; switch( pc_checkadditem(sd, vsd->cart.u.items_cart[idx].nameid, amount) ) { case CHKADDITEM_EXIST: break; //We'd add this item to the existing one (in buyers inventory) case CHKADDITEM_NEW: new_++; if (new_ > blank) return; //Buyer has no space in his inventory break; case CHKADDITEM_OVERAMOUNT: return; //too many items } } pc_payzeny(sd, (int)z, LOG_TYPE_VENDING, vsd); achievement_update_objective(sd, AG_SPEND_ZENY, 1, (int)z); 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; z = 0.; // zeny counter // vending item pc_additem(sd, &vsd->cart.u.items_cart[idx], amount, LOG_TYPE_VENDING); vsd->vending[vend_list[i]].amount -= amount; z += ((double)vsd->vending[i].value * (double)amount); if( vsd->vending[vend_list[i]].amount ) { if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_table, vsd->vending[vend_list[i]].amount, vsd->vender_id, vsd->cart.u.items_cart[idx].id ) != SQL_SUCCESS ) { Sql_ShowDebug( mmysql_handle ); } } else { if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_table, vsd->vender_id, vsd->cart.u.items_cart[idx].id ) != SQL_SUCCESS ) { Sql_ShowDebug( mmysql_handle ); } } pc_cart_delitem(vsd, idx, amount, 0, LOG_TYPE_VENDING); if( battle_config.vending_tax ) z -= z * (battle_config.vending_tax/10000.); clif_vendingreport(vsd, idx, amount, sd->status.char_id, (int)z); //print buyer's name if( battle_config.buyer_name ) { char temp[256]; sprintf(temp, msg_txt(sd,265), sd->status.name); clif_messagecolor(&vsd->bl, color_table[COLOR_LIGHT_GREEN], temp, false, SELF); } } // compact the vending list for( i = 0, cursor = 0; i < vsd->vend_num; i++ ) { if( vsd->vending[i].amount == 0 ) continue; if( cursor != i ) { // speedup vsd->vending[cursor].index = vsd->vending[i].index; vsd->vending[cursor].amount = vsd->vending[i].amount; vsd->vending[cursor].value = vsd->vending[i].value; } cursor++; } vsd->vend_num = cursor; //Always save BOTH: customer (buyer) and vender if( save_settings&CHARSAVE_VENDING ) { chrif_save(sd, CSAVE_INVENTORY|CSAVE_CART); chrif_save(vsd, CSAVE_INVENTORY|CSAVE_CART); } //check for @AUTOTRADE users [durf] if( vsd->state.autotrade ) { //see if there is anything left in the shop ARR_FIND( 0, vsd->vend_num, i, vsd->vending[i].amount > 0 ); if( i == vsd->vend_num ) { //Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex] vending_closevending(vsd); map_quit(vsd); //They have no reason to stay around anymore, do they? } } }