Bug Fixes:

- Failure when initializing autotrade persitance for PACKETVER < 20120201 or NEW_CARTS, ENABLE_SC_SAVING aren't defined
- Added 'feature.autotrade_open_delay' config at conf/battle/feature.conf to give delay to open vending/buyingstore by autotrade persistency (bugreport:9077)
- Add immediate save after vending/buyingstore opened to avoid missing sc_data (for SC_PUSH_CART) when server terminated before saving routine (bugreport:9077)
- Disable to trigger NPCE_LOGIN (and NPCE_LOADMAP?) for autotraders, avoid vending_reopen & buyingstore_reopen failure (bugreport:9077)
- Set player's state, 'monster_ignore' when autotrade
- EXP calculation overload (bugreport:9127)
- Added macro apply_rate(val,rate) & apply_rate2(val,rate,per)

Thank you all for reports & helps

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>
This commit is contained in:
Cydh Ramdh
2014-07-16 17:21:58 +07:00
parent 171de747e3
commit 171e2f2be9
17 changed files with 174 additions and 79 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 ){

View File

@@ -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, },

View File

@@ -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;

View File

@@ -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 { <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];
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 { <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;
@@ -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 );
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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))

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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:

View File

@@ -297,29 +297,30 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui
* data := {<index>.w <amount>.w <value>.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++;
}

View File

@@ -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);