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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ){
|
||||
|
||||
@@ -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, },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
39
src/map/pc.c
39
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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user