// exp share and added zeny share [Valaris] int party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny) { struct map_session_data* sd[MAX_PARTY]; unsigned int i, c; nullpo_ret(p); // count the number of players eligible for exp sharing for (i = c = 0; i < MAX_PARTY; i++) { if( (sd[c] = p->data[i].sd) == NULL || sd[c]->bl.m != src->m || pc_isdead(sd[c]) || (battle_config.idle_no_share && pc_isidle(sd[c])) ) continue; c++; } if (c < 1) return 0; base_exp/=c; job_exp/=c; zeny/=c; if (battle_config.party_even_share_bonus && c > 1) { double bonus = 100 + battle_config.party_even_share_bonus*(c-1); if (base_exp) base_exp = (unsigned int) cap_value(base_exp * bonus/100, 0, UINT_MAX); if (job_exp) job_exp = (unsigned int) cap_value(job_exp * bonus/100, 0, UINT_MAX); if (zeny) zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX); } for (i = 0; i < c; i++) { #ifdef RENEWAL_EXP if( !(src && src->type == BL_MOB && ((TBL_MOB*)src)->db->mexp) ){ int rate = pc_level_penalty_mod(sd[i], (TBL_MOB*)src, 1); base_exp = (unsigned int)cap_value(base_exp * rate / 100, 1, UINT_MAX); job_exp = (unsigned int)cap_value(job_exp * rate / 100, 1, UINT_MAX); } #endif pc_gainexp(sd[i], src, base_exp, job_exp, false); if (zeny) // zeny from mobs [Valaris] pc_getzeny(sd[i],zeny,LOG_TYPE_PICKDROP_MONSTER,NULL); } return 0; }
// exp share and added zeny share [Valaris] int party_exp_share(struct party *p,int map,unsigned int base_exp,unsigned int job_exp,int zeny) { struct map_session_data* sd[MAX_PARTY]; int i; short c, bonus =100; // modified [Valaris] nullpo_retr(0, p); for (i = c = 0; i < MAX_PARTY; i++) if ((sd[c] = p->member[i].sd)!=NULL && sd[c]->bl.m == map && !pc_isdead(sd[c])) { if (battle_config.idle_no_share && (pc_issit(sd[c]) || sd[c]->chatID || (sd[c]->idletime < (last_tick - battle_config.idle_no_share)))) continue; c++; } if (c < 1) return 0; if (battle_config.party_even_share_bonus) //Valaris's even share exp bonus equation. bonus += (battle_config.party_even_share_bonus*c*(c-1)/10); //Changed Valaris's bonus switch to an equation [Skotlex] else //Official kRO/iRO sites state that the even share bonus is 10% per additional party member. bonus += (c-1)*10; base_exp/=c; job_exp/=c; if (base_exp/100 > UINT_MAX/bonus) base_exp= UINT_MAX; //Exp overflow else base_exp = base_exp*bonus/100; if (job_exp/100 > UINT_MAX/bonus) job_exp = UINT_MAX; else job_exp = job_exp*bonus/100; for (i = 0; i < c; i++) { pc_gainexp(sd[i], base_exp, job_exp); if (battle_config.zeny_from_mobs) // zeny from mobs [Valaris] pc_getzeny(sd[i],bonus*zeny/(c*100)); } return 0; }
// exp share and added zeny share [Valaris] int party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny) { struct map_session_data* sd[MAX_PARTY]; unsigned int i, c; nullpo_retr(0, p); // count the number of players eligible for exp sharing for (i = c = 0; i < MAX_PARTY; i++) { if( (sd[c] = p->data[i].sd) == NULL || sd[c]->bl.m != src->m || pc_isdead(sd[c]) || (battle_config.idle_no_share && pc_isidle(sd[c])) ) continue; c++; } if (c < 1) return 0; base_exp/=c; job_exp/=c; zeny/=c; if (battle_config.party_even_share_bonus && c > 1) { double bonus = 100 + battle_config.party_even_share_bonus*(c-1); if (base_exp) base_exp = (unsigned int) cap_value(base_exp * bonus/100, 0, UINT_MAX); if (job_exp) job_exp = (unsigned int) cap_value(job_exp * bonus/100, 0, UINT_MAX); if (zeny) zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX); } for (i = 0; i < c; i++) { pc_gainexp(sd[i], src, base_exp, job_exp); if (zeny) // zeny from mobs [Valaris] pc_getzeny(sd[i],zeny); } return 0; }
//Does party loot. first_charid holds the charid of the player who has time priority to take the item. int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item_data, int first_charid) { TBL_PC* target = NULL; int i; if (p && p->party.item&2 && (first_charid || !(battle_config.party_share_type&1))) { //item distribution to party members. if (battle_config.party_share_type&2) { //Round Robin TBL_PC* psd; i = p->itemc; do { i++; if (i >= MAX_PARTY) i = 0; // reset counter to 1st person in party so it'll stop when it reaches "itemc" if( (psd = p->data[i].sd) == NULL || sd->bl.m != psd->bl.m || pc_isdead(psd) || (battle_config.idle_no_share && pc_isidle(psd)) ) continue; if (pc_additem(psd,item_data,item_data->amount)) continue; //Chosen char can't pick up loot. //Successful pick. p->itemc = i; target = psd; break; } while (i != p->itemc); } else { //Random pick TBL_PC* psd[MAX_PARTY]; int count = 0; //Collect pick candidates for (i = 0; i < MAX_PARTY; i++) { if( (psd[count] = p->data[i].sd) == NULL || psd[count]->bl.m != sd->bl.m || pc_isdead(psd[count]) || (battle_config.idle_no_share && pc_isidle(psd[count])) ) continue; count++; } while (count > 0) { //Pick a random member. i = rand()%count; if (pc_additem(psd[i],item_data,item_data->amount)) { //Discard this receiver. psd[i] = psd[count-1]; count--; } else { //Successful pick. target = psd[i]; break; } } } } if (!target) { target = sd; //Give it to the char that picked it up if ((i=pc_additem(sd,item_data,item_data->amount))) return i; } if(log_config.enable_logs&0x8) //Logs items, taken by (P)layers [Lupus] log_pick_pc(target, "P", item_data->nameid, item_data->amount, item_data); if(battle_config.party_show_share_picker && target != sd) { char output[80]; sprintf(output, "%s acquired %s.",target->status.name, itemdb_jname(item_data->nameid)); clif_disp_onlyself(sd,output,strlen(output)); } return 0; }
/** * 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; }
/*========================================== * Abrir loja * data := {<index>.w <amount>.w <value>.l}[count] *------------------------------------------*/ void vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) { int i, j; int vending_skill_lvl; nullpo_retv(sd); if ( pc_isdead(sd) || !sd->state.prevend || pc_istrading(sd)) return; // nao pode abrir vendas deitado morto || não usou via habilidade (wpe/hack) || não pode ter 2 lojas ao mesmo tempo vending_skill_lvl = pc->checkskill(sd, MC_VENDING); // check de nivel de habilidade e carrinho if( !vending_skill_lvl || !pc_iscarton(sd) ) { clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return; } // checka numero de itens na loja if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // contagem de item invalida clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return; } // filtrar itens invalidos 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; // ajuste de equilibrio (cliente diz que a posição do primeiro carrinho é 2) if( index < 0 || index >= MAX_CART // posição inválida || pc->cartitem_amount(sd, index, amount) < 0 // item invalido ou quantidade insuficiente //NOT: servidores oficiais não fazem nenhum dos checks abaixo! || !sd->status.cart[index].identify // item não-identficado || sd->status.cart[index].attribute == 1 // item quebrado || sd->status.cart[index].expire_time // Isso não deveria estar no carrinho mas apenas no caso de estar || (sd->status.cart[index].bound && !pc_can_give_bound_items(sd)) // não pode trocar itens de recompensa, permissão w/o || !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // Itens não-trocaveis 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 adicionado com sucesso } if( i != j ) clif->message (sd->fd, msg_txt(266)); //"Alguns dos seus itens não pode ser vendido e foram removidos da loja." if( i == 0 ) { // nenhum item válido encontrado clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); // packet de resposta personalizada return; } sd->state.prevend = sd->state.workinprogress = 0; sd->state.vending = true; sd->vender_id = getid(); sd->vend_num = i; safestrncpy(sd->message, message, MESSAGE_SIZE); clif->openvending(sd,sd->bl.id,sd->vending); clif->showvendingboard(&sd->bl,message,0); idb_put(vending->db, sd->status.char_id, sd); }
//Does party loot. first_charid holds the charid of the player who has time priority to take the item. int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item, int first_charid) { TBL_PC* target = NULL; int i; if (p && p->party.item&2 && (first_charid || !(battle_config.party_share_type&1))) { //item distribution to party members. if (battle_config.party_share_type&2) { // Round Robin TBL_PC* psd; i = p->itemc; do { i++; if (i >= MAX_PARTY) i = 0; // reset counter to 1st person in party so it'll stop when it reaches "itemc" if( (psd = p->data[i].sd) == NULL || sd->bl.m != psd->bl.m || pc_isdead(psd) || (battle_config.idle_no_share && pc_isidle(psd)) ) continue; if (pc_additem(psd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER)) continue; //Chosen char can't pick up loot. //Successful pick. p->itemc = i; target = psd; break; } while (i != p->itemc); } else { // Random pick TBL_PC* psd[MAX_PARTY]; int count = 0; //Collect pick candidates for (i = 0; i < MAX_PARTY; i++) { if( (psd[count] = p->data[i].sd) == NULL || psd[count]->bl.m != sd->bl.m || pc_isdead(psd[count]) || (battle_config.idle_no_share && pc_isidle(psd[count])) ) continue; count++; } while (count > 0) { //Pick a random member. i = rnd()%count; if (pc_additem(psd[i],item,item->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver. psd[i] = psd[count-1]; count--; } else { // Successful pick. target = psd[i]; break; } } } } if (!target) { target = sd; //Give it to the char that picked it up if ((i = pc_additem(sd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER))) return i; } if( p && battle_config.party_show_share_picker && battle_config.show_picker_item_type&(1<<itemdb_type(item->nameid)) ) clif_party_show_picker(target, item); return 0; }
/*========================================== * Open shop * data := {<index>.w <amount>.w <value>.l}[count] *------------------------------------------*/ void vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) { int i, j; int vending_skill_lvl; nullpo_retv(sd); if ( pc_isdead(sd) || !sd->state.prevend || pc_istrading(sd)) return; // can't open vendings lying dead || didn't use via the skill (wpe/hack) || can't have 2 shops at once vending_skill_lvl = pc->checkskill(sd, MC_VENDING); // skill level and cart check if( !vending_skill_lvl || !pc_iscarton(sd) ) { clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return; } // check number of items in shop if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // invalid item count clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return; } // filter out invalid items i = 0; for( j = 0; j < count; j++ ) { short index = *(uint16*)(data + 8*j + 0); short amount = *(uint16*)(data + 8*j + 2); unsigned int value = *(uint32*)(data + 8*j + 4); index -= 2; // offset adjustment (client says that the first cart position is 2) if( index < 0 || index >= MAX_CART // invalid position || pc->cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity //NOTE: official server does not do any of the following checks! || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case || !itemdb_cantrade(&sd->status.cart[index], pc->get_group_level(sd), pc->get_group_level(sd)) ) // untradeable item continue; sd->vending[i].index = index; sd->vending[i].amount = amount; sd->vending[i].value = cap_value(value, 0, (unsigned int)battle_config.vending_max_value); i++; // item successfully added } if( i != j ) clif->message (sd->fd, msg_txt(266)); //"Some of your items cannot be vended and were removed from the shop." if( i == 0 ) { // no valid item found clif->skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); // custom reply packet return; } sd->state.prevend = sd->state.workinprogress = 0; sd->state.vending = true; sd->vender_id = getid(); sd->vend_num = i; safestrncpy(sd->message, message, MESSAGE_SIZE); clif->openvending(sd,sd->bl.id,sd->vending); clif->showvendingboard(&sd->bl,message,0); idb_put(vending->db, sd->status.char_id, sd); }
/** * Player setup a new shop * @param sd : player opening the shop * @param message : shop title * @param data : itemlist data * data := {<index>.w <amount>.w <value>.l}[count] * @param count : number of different items * @param at Autotrader info, or NULL if requetsed not from autotrade persistance * @return 0 If success, 1 - Cannot open (die, not state.prevend, trading), 2 - No cart, 3 - Count issue, 4 - Cart data isn't saved yet, 5 - No valid item found */ int8 vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count, struct s_autotrader *at) { int i, j, k, n; int vending_skill_lvl; char message_sql[MESSAGE_SIZE*2]; int item_bad_price[MAX_VENDING]; StringBuf buf; struct item_data *item; nullpo_retr(false,sd); if ( pc_isdead(sd) || !sd->state.prevend || pc_istrading(sd)) { return 1; // can't open vendings lying dead || didn't use via the skill (wpe/hack) || can't have 2 shops at once } vending_skill_lvl = pc_checkskill(sd, MC_VENDING); // skill level and cart check if( !vending_skill_lvl || !pc_iscarton(sd) ) { clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return 2; } // check number of items in shop if( count < 1 || count > MAX_VENDING || count > 2 + vending_skill_lvl ) { // invalid item count clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); return 3; } if (save_settings&CHARSAVE_VENDING) // Avoid invalid data from saving chrif_save(sd, 0); // filter out invalid items i = k = 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; item = itemdb_search(sd->status.cart[index].nameid); if (item->value_buy_min > 0 && value > item->value_buy_min) { if (battle_config.vending_price_min_overflow > 0 ) { if (value > item->value_buy_min + (item->value_buy_min * (battle_config.vending_price_min_overflow / 10000.))) { item_bad_price[k++] = sd->status.cart[index].nameid; continue; } } else { item_bad_price[k++] = sd->status.cart[index].nameid; 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) { char msg[256]; snprintf(msg, 256, "äÍà·çÁ %s ÂѧäÁèä´éºÑ¹·Ö¡. ¡ÃسÒÍÍ¡à¢éÒãËÁè à¾×èÍãËéäÍà·çÁ·Ó¡ÒÃ૿ŧÃéÒ¹¤éÒ", item->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." for (n = 0; n < k; n++) { char msg[512]; item = itemdb_search(item_bad_price[n]); if (battle_config.vending_price_min_overflow > 0) sprintf(msg, "%s µÑé§ÃÒ¤Ò¢ÒÂÊÙ§¡ÇèÒ·Õè NPC ÁÕ¢ÒÂÍÂÙèà¡Ô¹ %d%% ¨Ð¶Ù¡µÑ´ÍÍ¡¨Ò¡ÃÒ¡ÒÃà¾×èÍ»éͧ¡Ñ¹¡ÒÃâ¡è§ÃÒ¤Ò", item->jname, battle_config.vending_price_min_overflow/100); else sprintf(msg, "%s µÑé§ÃÒ¤Ò¢ÒÂÊÙ§¡ÇèÒ·Õè NPC ÁÕ¢ÒÂÍÂÙè ¨Ð¶Ù¡µÑ´ÍÍ¡¨Ò¡ÃÒ¡ÒÃà¾×èÍ»éͧ¡Ñ¹¡ÒÃâ¡è§ÃÒ¤Ò", item->jname); clif_displaymessage(sd->fd, msg); } 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, at ? at->dir : sd->ud.dir, at ? at->head_dir : sd->head_dir, at ? at->sit : pc_issit(sd) ) != SQL_SUCCESS ) { Sql_ShowDebug(mmysql_handle); } StringBuf_Init(&buf); StringBuf_Printf(&buf, "INSERT INTO `%s`(`vending_id`,`index`,`cartinventory_id`,`amount`,`price`) VALUES", vending_items_db); for (i = 0; i < count; i++) { StringBuf_Printf(&buf, "(%d,%d,%d,%d,%d)", sd->vender_id, i, sd->status.cart[sd->vending[i].index].id, sd->vending[i].amount, sd->vending[i].value); if (i < count-1) StringBuf_AppendStr(&buf, ","); } if (SQL_ERROR == Sql_QueryStr(mmysql_handle, StringBuf_Value(&buf))) Sql_ShowDebug(mmysql_handle); StringBuf_Destroy(&buf); clif_openvending(sd,sd->bl.id,sd->vending); clif_showvendingboard(&sd->bl,message,0); idb_put(vending_db, sd->status.char_id, sd); return 0; }
int magic_message (character_t * caster, char *spell_, size_t spell_len) { if (pc_isdead (caster)) return 0; int power = caster->matk1; char *invocation_base = spell_ + 8; char *source_invocation = 1 + invocation_base + strlen (caster->status.name); spell_t *spell; char *parameter; char *spell_invocation; if (!source_invocation) return 0; /* Pre-message filter in case some spell alters output */ source_invocation = magic_preprocess_message (caster, invocation_base, source_invocation); spell_invocation = magic_tokenise (source_invocation, ¶meter); parameter = parameter ? strdup (parameter) : strdup (""); spell = magic_find_spell (spell_invocation); free (spell_invocation); if (spell) { int near_miss; env_t *env = spell_create_env (&magic_conf, spell, caster, power, parameter); effect_set_t *effects; if ((spell->flags & SPELL_FLAG_NONMAGIC) || (power >= 1)) effects = spell_trigger (spell, caster, env, &near_miss); else effects = NULL; #ifdef DEBUG fprintf (stderr, "Found spell `%s', triggered = %d\n", spell_, effects != NULL); #endif if (caster->status.option & OPTION_HIDE) return 0; // No spellcasting while hidden MAP_LOG_PC (caster, "CAST %s %s", spell->name, effects ? "SUCCESS" : "FAILURE"); if (effects) { invocation_t *invocation = spell_instantiate (effects, env); spell_bind (caster, invocation); spell_execute (invocation); return (spell->flags & SPELL_FLAG_SILENT) ? -1 : 1; } else magic_free_env (env); return 1; } else free (parameter); return 0; /* Not a spell */ }
/*========================================== * PCのquit処理 map.c内分 * * quit処理の主体が違うような気もしてきた *------------------------------------------ */ int map_quit(struct map_session_data *sd) { if(sd->chatID) // チャットから出る chat_leavechat(sd); if(sd->trade_partner) // 取引を中断する trade_tradecancel(sd); if(sd->party_invite>0) // パーティ勧誘を拒否する party_reply_invite(sd,sd->party_invite_account,0); if(sd->guild_invite>0) // ギルド勧誘を拒否する guild_reply_invite(sd,sd->guild_invite,0); if(sd->guild_alliance>0) // ギルド同盟勧誘を拒否する guild_reply_reqalliance(sd,sd->guild_alliance_account,0); party_send_logout(sd); // パーティのログアウトメッセージ送信 guild_send_memberinfoshort(sd,0); // ギルドのログアウトメッセージ送信 pc_cleareventtimer(sd); // イベントタイマを破棄する storage_storage_quit(sd); // 倉庫を開いてるなら保存する skill_castcancel(&sd->bl,0); // 詠唱を中断する skill_status_change_clear(&sd->bl); // ステータス異常を解除する skill_clear_unitgroup(&sd->bl); // スキルユニットグループの削除 skill_cleartimerskill(&sd->bl); pc_stop_walking(sd,0); pc_stopattack(sd); pc_delinvincibletimer(sd); pc_delspiritball(sd,sd->spiritball,1); skill_gangsterparadise(sd,0); pc_calcstatus(sd,4); clif_clearchar_area(&sd->bl,2); if(sd->status.pet_id && sd->pd) { pet_remove_map(sd); if(sd->pet.intimate <= 0) { intif_delete_petdata(sd->status.pet_id); sd->status.pet_id = 0; sd->pd = NULL; sd->petDB = NULL; } else intif_save_petdata(sd->status.account_id,&sd->pet); } if(pc_isdead(sd)) pc_setrestartvalue(sd,2); pc_makesavestatus(sd); chrif_save(sd); storage_storage_save(sd); map_delblock(&sd->bl); numdb_erase(id_db,sd->bl.id); strdb_erase(nick_db,sd->status.name); return 0; }
// exp share and added zeny share [Valaris] int party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny) { struct map_session_data* sd[MAX_PARTY]; unsigned int i, c; nullpo_ret(p); // count the number of players eligible for exp sharing for( i = c = 0; i < MAX_PARTY; i++ ) { if( (sd[c] = p->data[i].sd) == NULL || sd[c]->bl.m != src->m || pc_isdead(sd[c]) || (battle_config.idle_no_share && pc_isidle(sd[c])) ) continue; c++; } if(c < 1) return 0; if (battle_config.renewal_party_exp_nerf) { int nerf; if (c == 2) { nerf = 50; } else if (c == 3) { nerf = 37; } else if (c == 4) { nerf = 30; } else if (c == 5) { nerf = 26; } else if (c == 6) { nerf = 23; } else if (c == 7) { nerf = 21; } else if (c == 8) { nerf = 20; } else if (c == 9) { nerf = 19; } else if (c == 10) { nerf = 18; } else if (c == 11) { nerf = 17; } else if (c == 12) { nerf = 17; } else { nerf = 0; } if (nerf) { base_exp = base_exp * nerf / 100; job_exp = job_exp * nerf / 100; zeny = zeny * nerf / 100; } } else { base_exp /= c; job_exp /= c; zeny /= c; } if( battle_config.party_even_share_bonus && c > 1 ) { double bonus = 100 + battle_config.party_even_share_bonus*(c-1); if (base_exp) base_exp = (unsigned int) cap_value(base_exp * bonus/100, 0, UINT_MAX); if (job_exp) job_exp = (unsigned int) cap_value(job_exp * bonus/100, 0, UINT_MAX); if (zeny) zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX); } for( i = 0; i < c; i++ ) { pc_gainexp(sd[i], src, base_exp, job_exp, false); if( zeny ) // zeny from mobs [Valaris] pc_getzeny(sd[i],zeny); } return 0; }
/** * Player setup a new shop * @param sd : player opening the shop * @param message : shop title * @param data : itemlist data * data := {<index>.w <amount>.w <value>.l}[count] * @param count : number of different items * @param at Autotrader info, or NULL if requetsed not from autotrade persistance * @return 0 If success, 1 - Cannot open (die, not state.prevend, trading), 2 - No cart, 3 - Count issue, 4 - No valid item found */ int8 vending_openvending(struct map_session_data *sd, const char *message, const uint8 *data, int count, struct s_autotrader *at) { int i, j; int vending_skill_lvl; char message_sql[MESSAGE_SIZE * 2]; StringBuf buf; nullpo_retr(1, 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, 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, 0); return 3; } if( save_settings&CHARSAVE_VENDING ) // Avoid invalid data from saving chrif_save(sd, CSAVE_INVENTORY|CSAVE_CART); //Filter out invalid items i = 0; for( j = 0; j < count; j++ ) { short index = *(uint16 *)(data + 8 * j + 0); short amount = *(uint16 *)(data + 8 * j + 2); unsigned int value = *(uint32 *)(data + 8 * j + 4); index -= 2; //Offset adjustment (client says that the first cart position is 2) if( index < 0 || index >= MAX_CART || //Invalid position pc_cartitem_amount(sd, index, amount) < 0 || //Invalid item or insufficient quantity //NOTE: Official server does not do any of the following checks! !sd->cart.u.items_cart[index].identify || //Unidentified item sd->cart.u.items_cart[index].attribute || //Broken item sd->cart.u.items_cart[index].expire_time || //It should not be in the cart but just in case (sd->cart.u.items_cart[index].bound && !pc_can_give_bounded_items(sd)) || //Can't trade account bound items and has no permission !itemdb_cantrade(&sd->cart.u.items_cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) //Untradeable item continue; sd->vending[i].index = index; sd->vending[i].amount = amount; sd->vending[i].value = umin(value, (unsigned int)battle_config.vending_max_value); i++; //Item successfully added } if( i != j ) clif_displaymessage(sd->fd, msg_txt(266)); // "Some of your items cannot be vended and were removed from the shop." if( i == 0 ) { //No valid item found clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0, 0); //Custom reply packet return 4; } sd->state.prevend = 0; sd->state.vending = 1; 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 ? 'F' : 'M'), map[sd->bl.m].name, sd->bl.x, sd->bl.y, message_sql, sd->state.autotrade, (at ? at->dir : sd->ud.dir), (at ? at->head_dir : sd->head_dir), (at ? at->sit : pc_issit(sd))) != SQL_SUCCESS ) Sql_ShowDebug(mmysql_handle); StringBuf_Init(&buf); StringBuf_Printf(&buf, "INSERT INTO `%s`(`vending_id`,`index`,`cartinventory_id`,`amount`,`price`) VALUES", vending_items_db); for( j = 0; j < i; j++ ) { StringBuf_Printf(&buf, "(%d,%d,%d,%d,%d)", sd->vender_id, j, sd->cart.u.items_cart[sd->vending[j].index].id, sd->vending[j].amount, sd->vending[j].value); if( j < i - 1 ) StringBuf_AppendStr(&buf, ","); } if( SQL_ERROR == Sql_QueryStr(mmysql_handle, StringBuf_Value(&buf)) ) Sql_ShowDebug(mmysql_handle); StringBuf_Destroy(&buf); clif_openvending(sd, sd->bl.id, sd->vending); clif_showvendingboard(&sd->bl, message, 0); idb_put(vending_db, sd->status.char_id, sd); return 0; }