diff --git a/conf/battle/feature.conf b/conf/battle/feature.conf index ac1c9b6993..30633c949a 100644 --- a/conf/battle/feature.conf +++ b/conf/battle/feature.conf @@ -43,3 +43,6 @@ feature.autotrade_direction: 4 // Do you want your autotraders to sit? (Note 1) feature.autotrade_sit: yes + +// Delay in miliseconds to open vending/buyingsotre after player logged in. +feature.autotrade_open_delay: 5000 diff --git a/src/char/char_mapif.c b/src/char/char_mapif.c index 0458e4d36e..82e9a0341f 100644 --- a/src/char/char_mapif.c +++ b/src/char/char_mapif.c @@ -348,7 +348,7 @@ int chmapif_parse_regmapuser(int fd, int id){ */ int chmapif_parse_reqsavechar(int fd, int id){ if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; + return 0; { int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); struct online_char_data* character; @@ -449,7 +449,7 @@ int chmapif_parse_authok(int fd){ //Request to save skill cooldown data int chmapif_parse_req_saveskillcooldown(int fd){ if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) - return 0; + return 0; else { int count, aid, cid; aid = RFIFOL(fd,4); diff --git a/src/common/utils.h b/src/common/utils.h index 329c9f67b7..10f515612a 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -14,9 +14,15 @@ void ShowDump(const void* buffer, size_t length); void findfile(const char *p, const char *pat, void (func)(const char*)); bool exists(const char* filename); -//Caps values to min/max +/// Caps values to min/max #define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a) +/// Apply rate for val, divided by 100) +#define apply_rate(val, rate) (((rate) == 100) ? (val) : ((val) > 100000) ? (val) / 100 * (rate) : (val) * (rate) / 100) + +/// Apply rate for val, divided by per +#define apply_rate2(val, rate, per) (((rate) == (per)) ? (val) : ((val) > 100000) ? (val) / (per) * (rate) : (val) * (rate) / (per)) + /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B); diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 35f216bec7..e5dc8e4da1 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -5752,6 +5752,7 @@ ACMD_FUNC(autotrade) { } sd->state.autotrade = 1; + sd->state.monster_ignore = 1; if( sd->state.vending ){ if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ){ diff --git a/src/map/battle.c b/src/map/battle.c index a6b5437288..e972575528 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7754,6 +7754,7 @@ static const struct _battle_data { { "feature.autotrade", &battle_config.feature_autotrade, 1, 0, 1, }, { "feature.autotrade_direction", &battle_config.feature_autotrade_direction, 4, 0, 7, }, { "feature.autotrade_sit", &battle_config.feature_autotrade_sit, 1, 0, 1, }, + { "feature.autotrade_open_delay", &battle_config.feature_autotrade_open_delay, 5000, 1000, INT_MAX, }, { "disp_serverbank_msg", &battle_config.disp_serverbank_msg, 0, 0, 1, }, { "warg_can_falcon", &battle_config.warg_can_falcon, 0, 0, 1, }, { "path_blown_halt", &battle_config.path_blown_halt, 1, 0, 1, }, diff --git a/src/map/battle.h b/src/map/battle.h index 2b7f37cd90..8188d72cbb 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -537,6 +537,7 @@ extern struct Battle_Config int feature_autotrade; int feature_autotrade_direction; int feature_autotrade_sit; + int feature_autotrade_open_delay; // Fame points int fame_taekwon_mission; diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c index 4d47a91710..ea41f15051 100644 --- a/src/map/buyingstore.c +++ b/src/map/buyingstore.c @@ -73,27 +73,32 @@ static unsigned int buyingstore_getuid(void) return ++buyingstore_nextid; } - -bool buyingstore_setup(struct map_session_data* sd, unsigned char slots){ +/** +* Attempt to setup buying store fast check before create new one +* @param sd +* @param slots Number of item on the list +* @return 0 If success, 1 - Cannot open, 2 - Manner penalty, 3 - Mapflag restiction, 4 - Cell restriction +*/ +char buyingstore_setup(struct map_session_data* sd, unsigned char slots){ if (!battle_config.feature_buying_store || sd->state.vending || sd->state.buyingstore || sd->state.trading || slots == 0) { - return false; + return 1; } if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) ) {// custom: mute limitation - return false; + 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 false; + 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 false; + return 4; } if( slots > MAX_BUYINGSTORE_SLOTS ) @@ -105,25 +110,34 @@ bool buyingstore_setup(struct map_session_data* sd, unsigned char slots){ sd->buyingstore.slots = slots; clif_buyingstore_open(sd); - return true; + return 0; } - -bool buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count) +/** +* Attempt to create new buying store +* @param sd +* @param zenylimit +* @param result +* @param storename +* @param *itemlist { .W, .W, .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]; if( !result || count == 0 ) {// canceled, or no items - return false; + 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 false; + return 1; } if( !pc_can_give_items(sd) ) @@ -131,24 +145,24 @@ bool buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha sd->buyingstore.slots = 0; clif_displaymessage(sd->fd, msg_txt(sd,246)); clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); - return false; + return 6; } if( sd->sc.data[SC_NOCHAT] && (sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM) ) {// custom: mute limitation - return false; + 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 false; + 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 false; + return 4; } weight = sd->weight; @@ -204,14 +218,14 @@ bool buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha {// invalid item/amount/price sd->buyingstore.slots = 0; clif_buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0); - return false; + 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 false; + return 7; } // success @@ -236,10 +250,13 @@ bool buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha clif_buyingstore_myitemlist(sd); clif_buyingstore_entry(sd); - return true; + return 0; } - +/** +* Close buying store +* @param sd +*/ void buyingstore_close(struct map_session_data* sd) { if( sd->state.buyingstore ) @@ -262,7 +279,11 @@ void buyingstore_close(struct map_session_data* sd) } } - +/** +* Open buying store from buyer +* @param sd Player +* @param account_id Buyer account ID +*/ void buyingstore_open(struct map_session_data* sd, int account_id) { struct map_session_data* pl_sd; @@ -292,7 +313,13 @@ void buyingstore_open(struct map_session_data* sd, int account_id) clif_buyingstore_itemlist(sd, pl_sd); } - +/** +* Start transaction +* @param sd Player/Seller +* @param account_id Buyer account ID +* @param *itemlist List of sold items { .W, .W, .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; @@ -544,14 +571,15 @@ bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_st return true; } -/** Open buyingstore for Autotrader +/** +* Open buyingstore for Autotrader * @param sd Player as autotrader */ void buyingstore_reopen( struct map_session_data* sd ){ // Ready to open buyingstore for this char if ( sd && autotrader_count > 0 && autotraders){ uint16 i; - uint8 *data, *p; + uint8 *data, *p, fail = 0; uint16 j, count; ARR_FIND(0,autotrader_count,i,autotraders[i] && autotraders[i]->char_id == sd->status.char_id); @@ -576,11 +604,11 @@ void buyingstore_reopen( struct map_session_data* sd ){ } // Open the buyingstore again - if( buyingstore_setup( sd, (unsigned char)autotraders[i]->count ) && - buyingstore_create( sd, autotraders[i]->limit, 1, autotraders[i]->title, data, autotraders[i]->count ) ) + if( (fail = buyingstore_setup( sd, (unsigned char)autotraders[i]->count ) == 0) && + (fail = buyingstore_create( sd, autotraders[i]->limit, 1, autotraders[i]->title, data, autotraders[i]->count ) == 0) ) { - ShowInfo("Loaded autotrade buyingstore data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", - sd->status.name,count,mapindex_id2name(sd->mapindex),sd->bl.x,sd->bl.y); + ShowInfo("Loaded buyingstore for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", + sd->status.name, count, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y); // Set him to autotrade if (Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", @@ -594,9 +622,12 @@ void buyingstore_reopen( struct map_session_data* sd ){ if( battle_config.feature_autotrade_sit ) pc_setsit(sd); + + // Immediate save + chrif_save(sd, 3); }else{ // Failed to open the buyingstore, set him offline - ShowWarning("Failed to load autotrade buyingstore data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items\n", sd->status.name, count ); + ShowError("Failed (%d) to load autotrade buyingstore data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items\n", fail, sd->status.name, count ); map_quit( sd ); } diff --git a/src/map/buyingstore.h b/src/map/buyingstore.h index 40ca85d7f6..ee4673d8c3 100644 --- a/src/map/buyingstore.h +++ b/src/map/buyingstore.h @@ -22,8 +22,8 @@ struct s_buyingstore unsigned char slots; }; -bool buyingstore_setup(struct map_session_data* sd, unsigned char slots); -bool buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count); +char buyingstore_setup(struct map_session_data* sd, unsigned char slots); +char buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count); void buyingstore_close(struct map_session_data* sd); void buyingstore_open(struct map_session_data* sd, int account_id); void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count); diff --git a/src/map/chrif.c b/src/map/chrif.c index 0ae053b309..4977a934a6 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -287,12 +287,12 @@ int chrif_save(struct map_session_data *sd, int flag) { if (flag && sd->state.active) { //Store player data which is quitting //FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex] - if (chrif_isconnected()) { - chrif_save_scdata(sd); - chrif_skillcooldown_save(sd); - chrif_save_bsdata(sd); - chrif_req_login_operation(sd->status.account_id, sd->status.name, 7, 0, 2, sd->status.bank_vault); //save Bank data - } + if (chrif_isconnected()) { + chrif_save_scdata(sd); + chrif_skillcooldown_save(sd); + chrif_save_bsdata(sd); + chrif_req_login_operation(sd->status.account_id, sd->status.name, 7, 0, 2, sd->status.bank_vault); //save Bank data + } if ( flag != 3 && !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) ShowError("chrif_save: Failed to set up player %d:%d for proper quitting!\n", sd->status.account_id, sd->status.char_id); } @@ -1378,17 +1378,6 @@ int chrif_load_scdata(int fd) { pc_scdata_received(sd); #endif - - if( sd->state.autotrade ) { - buyingstore_reopen( sd ); - vending_reopen( sd ); - - if (!sd->vender_id && !sd->buyer_id) { - sd->state.autotrade = 0; - map_quit(sd); - } - } - return 0; } diff --git a/src/map/clif.c b/src/map/clif.c index 7cb7772088..5ad23e5e6f 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9703,8 +9703,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) // Set the initial idle time sd->idletime = last_tick; - //Login Event - npc_script_event(sd, NPCE_LOGIN); + if (!sd->state.autotrade) { // Don't trigger NPC event or opening vending/buyingstore will be failed + //Login Event + npc_script_event(sd, NPCE_LOGIN); + } } else { //For some reason the client "loses" these on warp/map-change. clif_updatestatus(sd,SP_STR); @@ -9803,7 +9805,8 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif_showvendingboard(&sd->bl,sd->message,0); } - if(map[sd->bl.m].flag.loadevent) // Lance + // Don't trigger NPC event or opening vending/buyingstore will be failed + if(!sd->state.autotrade && map[sd->bl.m].flag.loadevent) // Lance npc_script_event(sd, NPCE_LOADMAP); if (pc_checkskill(sd, SG_DEVIL) && !pc_nextjobexp(sd)) diff --git a/src/map/map.c b/src/map/map.c index 6b590659a5..af61cd6847 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1652,6 +1652,9 @@ int map_quit(struct map_session_data *sd) { if (sd->npc_timer_id != INVALID_TIMER) //Cancel the event timer. npc_timerevent_quit(sd); + if (sd->autotrade_tid != INVALID_TIMER) + delete_timer(sd->autotrade_tid, pc_autotrade_timer); + if (sd->npc_id) npc_event_dequeue(sd); diff --git a/src/map/mob.c b/src/map/mob.c index bf1e73720b..4ee20715db 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -2266,13 +2266,21 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if (map[m].flag.nobaseexp || !md->db->base_exp) base_exp = 0; - else - base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].adjust.bexp/100., 1, UINT_MAX); + else { + double exp = apply_rate2(md->db->base_exp, per, 1); + exp = apply_rate(exp, bonus); + exp = apply_rate(exp, map[m].adjust.bexp); + base_exp = (unsigned int)cap_value(exp, 1, UINT_MAX); + } if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost. job_exp = 0; - else - job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].adjust.jexp/100., 1, UINT_MAX); + else { + double exp = apply_rate2(md->db->job_exp, per, 1); + exp = apply_rate(exp, bonus); + exp = apply_rate(exp, map[m].adjust.jexp); + job_exp = (unsigned int)cap_value(exp, 1, UINT_MAX); + } if ( ( temp = tmpsd[i]->status.party_id)>0 ) { int j; @@ -2310,8 +2318,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) { #ifdef RENEWAL_EXP int rate = pc_level_penalty_mod(tmpsd[i], md->level, md->status.class_, 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); + if (rate != 100) { + base_exp = (unsigned int)cap_value(apply_rate(base_exp, rate), 1, UINT_MAX); + job_exp = (unsigned int)cap_value(apply_rate(job_exp, rate), 1, UINT_MAX); + } #endif pc_gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false); } @@ -2395,7 +2405,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } #ifdef RENEWAL_DROP if( drop_modifier != 100 ) { - drop_rate = drop_rate * drop_modifier / 100; + drop_rate = apply_rate(drop_rate, drop_modifier); if( drop_rate < 1 ) drop_rate = 1; } diff --git a/src/map/pc.c b/src/map/pc.c index a2ef74b3a6..5d5becd2a8 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1136,6 +1136,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->npc_timer_id = INVALID_TIMER; sd->pvp_timer = INVALID_TIMER; sd->expiration_tid = INVALID_TIMER; + sd->autotrade_tid = INVALID_TIMER; #ifdef SECURE_NPCTIMEOUT // Initialize to defaults/expected @@ -1453,8 +1454,12 @@ void pc_reg_received(struct map_session_data *sd) clif_changeoption( &sd->bl ); } - if( sd->state.autotrade ) + pc_check_expiration(sd); + + if( sd->state.autotrade ) { clif_parse_LoadEndAck(sd->fd, sd); + sd->autotrade_tid = add_timer(gettick() + battle_config.feature_autotrade_open_delay, pc_autotrade_timer, sd->bl.id, 0); + } } static int pc_calc_skillpoint(struct map_session_data* sd) @@ -8228,7 +8233,7 @@ void pc_setoption(struct map_session_data *sd,int type) } else if( !( type&OPTION_CART ) && p_type&OPTION_CART ){ //Cart Off clif_clearcart(sd->fd); if(pc_checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Remove speed penalty. + status_calc_pc(sd,SCO_NONE); //Remove speed penalty. } #endif @@ -10757,9 +10762,17 @@ void pc_damage_log_clear(struct map_session_data *sd, int id) /* Status change data arrived from char-server */ void pc_scdata_received(struct map_session_data *sd) { + // Nothing todo yet + return; +} + +/** Check expiration time and rental items +* @param sd +*/ +void pc_check_expiration(struct map_session_data *sd) { pc_inventory_rentals(sd); - if( sd->expiration_time != 0 ) { //Don't display if it's unlimited or unknow value + if (sd->expiration_time != 0) { //Don't display if it's unlimited or unknow value time_t exp_time = sd->expiration_time; char tmpstr[1024]; @@ -10785,6 +10798,25 @@ int pc_expiration_timer(int tid, unsigned int tick, int id, intptr_t data) { return 0; } +int pc_autotrade_timer(int tid, unsigned int tick, int id, intptr_t data) { + struct map_session_data *sd = map_id2sd(id); + + if (!sd) + return 0; + + sd->autotrade_tid = INVALID_TIMER; + + buyingstore_reopen(sd); + vending_reopen(sd); + + if (sd && !sd->vender_id && !sd->buyer_id) { + sd->state.autotrade = 0; + map_quit(sd); + } + + return 0; +} + /* this timer exists only when a character with a expire timer > 24h is online */ /* it loops thru online players once an hour to check whether a new < 24h is available */ int pc_global_expiration_timer(int tid, unsigned int tick, int id, intptr_t data) { @@ -11157,6 +11189,7 @@ void do_init_pc(void) { add_timer_func_list(pc_talisman_timer, "pc_talisman_timer"); add_timer_func_list(pc_global_expiration_timer, "pc_global_expiration_timer"); add_timer_func_list(pc_expiration_timer, "pc_expiration_timer"); + add_timer_func_list(pc_autotrade_timer, "pc_autotrade_timer"); add_timer(gettick() + autosave_interval, pc_autosave, 0, 0); diff --git a/src/map/pc.h b/src/map/pc.h index d243fb1df8..32a223022b 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -610,6 +610,7 @@ struct map_session_data { time_t expiration_time; short last_addeditem_index; /// Index of latest item added + int autotrade_tid; }; struct eri *pc_sc_display_ers; /// Player's SC display table @@ -837,6 +838,7 @@ short pc_checkequip(struct map_session_data *sd,int pos); bool pc_checkequip2(struct map_session_data *sd, unsigned short nameid, int min, int max); void pc_scdata_received(struct map_session_data *sd); +void pc_check_expiration(struct map_session_data *sd); int pc_expiration_timer(int tid, unsigned int tick, int id, intptr_t data); int pc_global_expiration_timer(int tid, unsigned tick, int id, intptr_t data); void pc_expire_check(struct map_session_data *sd); @@ -1111,6 +1113,8 @@ bool pc_is_same_equip_index(enum equip_index eqi, int *equip_index, int8 index); /// Check if player is Taekwon Ranker and the level is >= 90 (battle_config.taekwon_ranker_min_lv) #define pc_is_taekwon_ranker(sd) (((sd)->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && (sd)->status.base_level >= battle_config.taekwon_ranker_min_lv && pc_famerank((sd)->status.char_id,MAPID_TAEKWON)) +int pc_autotrade_timer(int tid, unsigned int tick, int id, intptr_t data); + #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_class, int type); #endif diff --git a/src/map/skill.c b/src/map/skill.c index 0869652691..c0b2c87812 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -8320,7 +8320,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case ALL_BUYING_STORE: if( sd ) {// players only, skill allows 5 buying slots - clif_skill_nodamage(src, bl, skill_id, skill_lv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS)); + clif_skill_nodamage(src, bl, skill_id, skill_lv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS) ? 0 : 1); } break; case RK_ENCHANTBLADE: diff --git a/src/map/vending.c b/src/map/vending.c index a613df6f41..4c5f2268b2 100755 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -297,29 +297,30 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui * data := {.w .w .l}[count] * @param count : number of different items */ -bool vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) { +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 false; // can't open vendings lying dead || didn't use via the skill (wpe/hack) || can't have 2 shops at once + 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 false; + 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 false; + return 3; } if (save_settings&2) // Avoid invalid data from saving @@ -356,7 +357,7 @@ bool vending_openvending(struct map_session_data* sd, const char* message, const sprintf(msg, msg_txt(sd, 733), idb->jname); clif_displaymessage(sd->fd, msg); clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); - return false; + return 4; } i++; // item successfully added @@ -367,7 +368,7 @@ bool vending_openvending(struct map_session_data* sd, const char* message, const if( i == 0 ) { // no valid item found clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0); // custom reply packet - return false; + return 5; } sd->state.prevend = 0; sd->state.vending = true; @@ -392,7 +393,7 @@ bool vending_openvending(struct map_session_data* sd, const char* message, const idb_put(vending_db, sd->status.char_id, sd); - return true; + return 0; } /** @@ -475,14 +476,15 @@ bool vending_searchall(struct map_session_data* sd, const struct s_search_store_ return true; } -/** Open vending for Autotrader +/** +* Open vending for Autotrader * @param sd Player as autotrader */ void vending_reopen( struct map_session_data* sd ){ // Ready to open vending for this char if ( sd && autotrader_count > 0 && autotraders){ uint16 i; - uint8 *data, *p; + uint8 *data, *p, fail = 0; uint16 j, count; ARR_FIND(0,autotrader_count,i,autotraders[i] && autotraders[i]->char_id == sd->status.char_id); @@ -517,8 +519,12 @@ void vending_reopen( struct map_session_data* sd ){ // Set him into a hacked prevend state sd->state.prevend = 1; + // Make sure abort all NPCs + npc_event_dequeue(sd); + pc_cleareventtimer(sd); + // Open the vending again - if( vending_openvending(sd, autotraders[i]->title, data, count) ){ + if( (fail = vending_openvending(sd, autotraders[i]->title, data, count)) == 0 ){ // Set him to autotrade if (Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ) @@ -532,11 +538,14 @@ void vending_reopen( struct map_session_data* sd ){ if( battle_config.feature_autotrade_sit ) pc_setsit(sd); - ShowInfo("Loaded autotrade vending data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", - sd->status.name,count,mapindex_id2name(sd->mapindex),sd->bl.x,sd->bl.y); + // Immediate save + chrif_save(sd, 3); + + ShowInfo("Loaded vending for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", + sd->status.name, count, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y); }else{ // Failed to open the vending, set him offline - ShowWarning("Failed to load autotrade vending data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items\n", sd->status.name, count ); + ShowError("Failed (%d) to load autotrade vending data for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items\n", fail, sd->status.name, count ); map_quit( sd ); } @@ -600,6 +609,7 @@ void do_init_vending_autotrade( void ) { pc_setnewpc(autotraders[i]->sd, autotraders[i]->account_id, autotraders[i]->char_id, 0, gettick(), autotraders[i]->sex, 0); autotraders[i]->sd->state.autotrade = 1; + autotraders[i]->sd->state.monster_ignore = 1; chrif_authreq(autotraders[i]->sd, true); i++; } diff --git a/src/map/vending.h b/src/map/vending.h index 51fe634d5f..a449684a51 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -22,7 +22,7 @@ void do_init_vending_autotrade( void ); void vending_reopen( struct map_session_data* sd ); void vending_closevending(struct map_session_data* sd); -bool vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count); +char vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count); void vending_vendinglistreq(struct map_session_data* sd, int id); void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const uint8* data, int count); bool vending_search(struct map_session_data* sd, unsigned short nameid);