From 07b9fe761fd802c9e198786b30bef832589d8a29 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Tue, 14 Jan 2014 22:24:00 +0100 Subject: [PATCH 1/8] Autotrade persistency --- conf/battle/feature.conf | 11 ++ conf/inter_athena.conf | 2 + src/char/char.c | 26 ++++- src/map/atcommand.c | 7 ++ src/map/battle.c | 3 + src/map/battle.h | 5 + src/map/chrif.c | 15 ++- src/map/chrif.h | 2 +- src/map/clif.c | 2 +- src/map/map.c | 6 + src/map/map.h | 2 + src/map/pc.c | 4 + src/map/vending.c | 236 +++++++++++++++++++++++++++++++++++++++ src/map/vending.h | 4 +- 14 files changed, 316 insertions(+), 9 deletions(-) diff --git a/conf/battle/feature.conf b/conf/battle/feature.conf index fd9c65a12d..2a39698412 100644 --- a/conf/battle/feature.conf +++ b/conf/battle/feature.conf @@ -22,3 +22,14 @@ feature.atcommand_suggestions: off // Banking (Note 1) // Requires: 2013-07-24aRagexe or later feature.banking: on + +// Autotrade persistency (Note 1) +feature.autotrade: on + +// In which direction should respawned autotraders look? +// Possible values are from 0-7 +// Default: 4(South) +feature.autotrade_direction: 4 + +// Do you want your autotraders to sit? (Note 1) +feature.autotrade_sit: yes diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf index a2857c9f1f..d5d5eee092 100644 --- a/conf/inter_athena.conf +++ b/conf/inter_athena.conf @@ -122,6 +122,8 @@ mob_skill_db_re_db: mob_skill_db_re mob_skill_db2_db: mob_skill_db2 //mob_skill_db2_db: mob_skill_db2_re mapreg_db: mapreg +vending_db: vendings +vending_items_db: vending_items // Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no) use_sql_db: no diff --git a/src/char/char.c b/src/char/char.c index 54c7fb7af4..1f4ea72ba3 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3779,7 +3779,7 @@ int parse_frommap(int fd) break; case 0x2b26: // auth request from map-server - if (RFIFOREST(fd) < 19) + if (RFIFOREST(fd) < 20) return 0; { @@ -3791,13 +3791,15 @@ int parse_frommap(int fd) struct auth_node* node; struct mmo_charstatus* cd; struct mmo_charstatus char_dat; + bool autotrade = false; account_id = RFIFOL(fd,2); char_id = RFIFOL(fd,6); login_id1 = RFIFOL(fd,10); sex = RFIFOB(fd,14); ip = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); + autotrade = RFIFOB(fd,19); + RFIFOSKIP(fd,20); node = (struct auth_node*)idb_get(auth_db, account_id); cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); @@ -3806,7 +3808,25 @@ int parse_frommap(int fd) mmo_char_fromsql(char_id, &char_dat, true); cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); } - if( runflag == CHARSERVER_ST_RUNNING && + + if( runflag == CHARSERVER_ST_RUNNING && autotrade && cd ){ + uint32 mmo_charstatus_len = sizeof(struct mmo_charstatus) + 25; + cd->sex = sex; + + WFIFOHEAD(fd,mmo_charstatus_len); + WFIFOW(fd,0) = 0x2afd; + WFIFOW(fd,2) = mmo_charstatus_len; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = 0; + WFIFOL(fd,12) = 0; + WFIFOL(fd,16) = 0; + WFIFOL(fd,20) = 0; + WFIFOB(fd,24) = 0; + memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); + WFIFOSET(fd, WFIFOW(fd,2)); + + set_char_online(id, char_id, account_id); + }else if( runflag == CHARSERVER_ST_RUNNING && cd != NULL && node != NULL && node->account_id == account_id && diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 46eb8c554d..613855cbe0 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -5653,6 +5653,11 @@ ACMD_FUNC(autotrade) { } sd->state.autotrade = 1; + + if( battle_config.feature_autotrade && Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", "vendings", sd->vender_id ) != SQL_SUCCESS ){ + Sql_ShowDebug( mmysql_handle ); + } + if( battle_config.at_timeout ) { int timeout = atoi(message); status_change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0); @@ -5660,6 +5665,8 @@ ACMD_FUNC(autotrade) { channel_pcquit(sd,0xF); //leave all chan clif_authfail_fd(sd->fd, 15); + + chrif_save(sd,1); return 0; } diff --git a/src/map/battle.c b/src/map/battle.c index 8ba1a47630..e63e48cb92 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7339,6 +7339,9 @@ static const struct _battle_data { { "discount_item_point_shop", &battle_config.discount_item_point_shop, 0, 0, 3, }, { "update_enemy_position", &battle_config.update_enemy_position, 0, 0, 1, }, { "devotion_rdamage", &battle_config.devotion_rdamage, 0, 0, 100, }, + { "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, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index 217998dd74..2155086824 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -519,6 +519,11 @@ extern struct Battle_Config int discount_item_point_shop; int update_enemy_position; int devotion_rdamage; + + // autotrade persistency + int feature_autotrade; + int feature_autotrade_direction; + int feature_autotrade_sit; } battle_config; void do_init_battle(void); diff --git a/src/map/chrif.c b/src/map/chrif.c index f892bbec92..3909a7af0b 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -562,6 +562,9 @@ void chrif_on_ready(void) { //Re-save any guild castles that were modified in the disconnection time. guild_castle_reconnect(-1, 0, 0); + + // Charserver is ready for this now + do_init_vending_autotrade(); } @@ -615,7 +618,7 @@ int chrif_skillcooldown_request(int account_id, int char_id) { /*========================================== * Request auth confirmation *------------------------------------------*/ -void chrif_authreq(struct map_session_data *sd) { +void chrif_authreq(struct map_session_data *sd, bool autotrade) { struct auth_node *node= chrif_search(sd->bl.id); if( node != NULL || !chrif_isconnected() ) { @@ -623,14 +626,15 @@ void chrif_authreq(struct map_session_data *sd) { return; } - WFIFOHEAD(char_fd,19); + WFIFOHEAD(char_fd,20); WFIFOW(char_fd,0) = 0x2b26; WFIFOL(char_fd,2) = sd->status.account_id; WFIFOL(char_fd,6) = sd->status.char_id; WFIFOL(char_fd,10) = sd->login_id1; WFIFOB(char_fd,14) = sd->status.sex; WFIFOL(char_fd,15) = htonl(session[sd->fd]->client_addr); - WFIFOSET(char_fd,19); + WFIFOB(char_fd,19) = autotrade; + WFIFOSET(char_fd,20); chrif_sd_to_auth(sd, ST_LOGIN); } @@ -1364,6 +1368,11 @@ int chrif_load_scdata(int fd) { status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 1|2|4|8); } #endif + + if( sd->state.autotrade ){ + vending_reopen( sd ); + } + return 0; } diff --git a/src/map/chrif.h b/src/map/chrif.h index 7019389ef2..840e43ffc2 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -35,7 +35,7 @@ struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state st bool chrif_auth_delete(int account_id, int char_id, enum sd_state state); bool chrif_auth_finished(struct map_session_data* sd); -void chrif_authreq(struct map_session_data* sd); +void chrif_authreq(struct map_session_data* sd, bool autotrade); void chrif_authok(int fd); int chrif_scdata_request(int account_id, int char_id); int chrif_skillcooldown_request(int account_id, int char_id); diff --git a/src/map/clif.c b/src/map/clif.c index 2e0479dc58..4797c19f14 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -9436,7 +9436,7 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) WFIFOSET(fd,packet_len(0x283)); #endif - chrif_authreq(sd); + chrif_authreq(sd,false); } diff --git a/src/map/map.c b/src/map/map.c index be128ffbae..02b3a0fdfe 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -81,6 +81,8 @@ char mob_db2_db[32] = "mob_db2"; char mob_skill_db_db[32] = "mob_skill_db"; char mob_skill_db_re_db[32] = "mob_skill_db_re"; char mob_skill_db2_db[32] = "mob_skill_db2"; +char vendings_db[32] = "vendings"; +char vending_items_db[32] = "vending_items"; // log database char log_db_ip[32] = "127.0.0.1"; @@ -3555,6 +3557,10 @@ int inter_config_read(char *cfgName) strcpy( item_cash_db_db, w2 ); else if( strcmpi( w1, "item_cash_db2_db" ) == 0 ) strcpy( item_cash_db2_db, w2 ); + else if( strcmpi( w1, "vending_db" ) == 0 ) + strcpy( vendings_db, w2 ); + else if( strcmpi( w1, "vending_items_db" ) == 0 ) + strcpy( vending_items_db, w2 ); else //Map Server SQL DB if(strcmpi(w1,"map_server_ip")==0) diff --git a/src/map/map.h b/src/map/map.h index ea74e637e6..d6296b2bff 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -909,6 +909,8 @@ extern char mob_db2_db[32]; extern char mob_skill_db_db[32]; extern char mob_skill_db_re_db[32]; extern char mob_skill_db2_db[32]; +extern char vendings_db[32]; +extern char vending_items_db[32]; void do_shutdown(void); diff --git a/src/map/pc.c b/src/map/pc.c index c91081520b..5fd2a39243 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1328,6 +1328,10 @@ int pc_reg_received(struct map_session_data *sd) clif_changeoption( &sd->bl ); } + + if( sd->state.autotrade ){ + clif_parse_LoadEndAck(sd->fd, sd); + } return 1; } diff --git a/src/map/vending.c b/src/map/vending.c index dd52c73296..8aa1645f20 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -2,6 +2,8 @@ // For more information, see LICENCE in the main folder #include "../common/nullpo.h" +#include "../common/malloc.h" // aMalloc, aFree +#include "../common/showmsg.h" // ShowInfo #include "../common/strlib.h" #include "../common/utils.h" #include "clif.h" @@ -18,10 +20,33 @@ #include "log.h" #include +#include // atoi #include +struct vending_entry{ + int cartinventory_id; + int amount; + int price; + int index; +}; + +struct vending{ + int account_id; + int char_id; + int vendor_id; + int m; + int x; + int y; + unsigned char sex; + char title[MESSAGE_SIZE]; + uint32 count; + struct vending_entry* entries; + struct map_session_data *sd; +}; + static int vending_nextid = 0; ///Vending_id counter static DBMap *vending_db; ///Db holder the vender : charid -> map_session_data +static DBMap *autotrade_db; /** * Lookup to get the vending_db outside module @@ -48,6 +73,11 @@ void vending_closevending(struct map_session_data* sd) nullpo_retv(sd); if( sd->state.vending ) { + if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE vending_id = %d;", vending_items_db, sd->vender_id ) != SQL_SUCCESS || + Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `id` = %d;", vendings_db, sd->vender_id ) != SQL_SUCCESS ){ + Sql_ShowDebug(mmysql_handle); + } + sd->state.vending = false; clif_closevendingboard(&sd->bl, 0); idb_remove(vending_db, sd->status.char_id); @@ -198,6 +228,17 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui // vending item pc_additem(sd, &vsd->status.cart[idx], amount, LOG_TYPE_VENDING); vsd->vending[vend_list[i]].amount -= amount; + + if( vsd->vending[vend_list[i]].amount ){ + if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vending[vend_list[i]].amount, vsd->vender_id, vsd->status.cart[idx].id ) != SQL_SUCCESS ){ + Sql_ShowDebug( mmysql_handle ); + } + }else{ + if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vender_id, vsd->status.cart[idx].id ) != SQL_SUCCESS ){ + Sql_ShowDebug( mmysql_handle ); + } + } + pc_cart_delitem(vsd, idx, amount, 0, LOG_TYPE_VENDING); clif_vendingreport(vsd, idx, amount); @@ -253,12 +294,15 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui void 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_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); @@ -310,6 +354,18 @@ void vending_openvending(struct map_session_data* sd, const char* message, const 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`) VALUES( %d, %d, %d, '%c', '%s', %d, %d, '%s', %d );", vendings_db, sd->vender_id, sd->status.account_id, sd->status.char_id, sd->status.sex == 2 ? 'F' : 'M', map[sd->bl.m].name, sd->bl.x, sd->bl.y, message_sql, sd->state.autotrade ) != 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); @@ -397,12 +453,191 @@ bool vending_searchall(struct map_session_data* sd, const struct s_search_store_ return true; } +void vending_reopen( struct map_session_data* sd ){ + int i, count; + uint8 *data, *p; + uint16 *index, *amount; + uint32 *value; + struct vending *vending; + struct vending_entry *entry; + + vending = (struct vending*)idb_get( autotrade_db, sd->status.char_id ); + + if( !vending ){ + map_quit(sd); + return; + } + + if( vending->count <= 0 ){ + idb_remove( autotrade_db, sd->status.char_id ); + map_quit(sd); + return; + } + + data = (uint8*)aMalloc( vending->count * 8 ); + + for( i = 0, p = data, count = vending->count; i < vending->count; i++ ){ + entry = &vending->entries[i]; + + index = (uint16*)(p + 0); + amount = (uint16*)(p + 2); + value = (uint32*)(p + 4); + + ARR_FIND( 0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id ); + + if( entry->index == MAX_CART ){ + count--; + continue; + } + + *index = entry->index + 2; + *amount = entry->amount; + *value = entry->price; + + p += 8; + } + + if( !count ){ + map_quit(sd); + return; + } + + vending->count = count; + + // Set him into a hacked prevend state + sd->state.prevend = 1; + + // Open the shop again + vending_openvending( sd, vending->title, data, vending->count ); + + // Make him look perfect + unit_setdir(&sd->bl,battle_config.feature_autotrade_direction); + + if( battle_config.feature_autotrade_sit ){ + pc_setsit(sd); + } + + idb_remove( autotrade_db, sd->status.char_id ); + + aFree(data); + aFree(vending->entries); + aFree(vending); +} + +void do_init_vending_autotrade( void ){ + if( battle_config.feature_autotrade ){ + struct vending *autotraders; + struct vending *vending; + struct vending_entry *entry; + uint32 count; + int i, j; + + if( Sql_Query(mmysql_handle, + "SELECT `id`, `account_id`, `char_id`, `sex`, `map`, `x`, `y`, `title`" + "FROM `%s`" + "WHERE `autotrade` = 1;", vendings_db ) != SQL_SUCCESS ) { + Sql_ShowDebug(mmysql_handle); + return; + } + + count = (uint32)Sql_NumRows(mmysql_handle); + + if( count <= 0 ){ + return; + } + + autotraders = (struct vending*)aMalloc( sizeof( struct vending ) * count ); + i = 0; + + while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) { + size_t len; + char* data; + + vending = &autotraders[i]; + + Sql_GetData( mmysql_handle, 0, &data, NULL ); vending->vendor_id = atoi(data); + Sql_GetData( mmysql_handle, 1, &data, NULL ); vending->account_id = atoi(data); + Sql_GetData( mmysql_handle, 2, &data, NULL ); vending->char_id = atoi(data); + Sql_GetData( mmysql_handle, 3, &data, NULL ); vending->sex = data[0]; + Sql_GetData( mmysql_handle, 4, &data, NULL ); vending->m = map_mapname2mapid( data ); + Sql_GetData( mmysql_handle, 5, &data, NULL ); vending->x = atoi(data); + Sql_GetData( mmysql_handle, 6, &data, NULL ); vending->y = atoi(data); + Sql_GetData( mmysql_handle, 7, &data, &len ); safestrncpy( vending->title, data, min( len + 1, MESSAGE_SIZE ) ); + + vending->count = 0; + + idb_put( autotrade_db, vending->char_id, vending ); + + // initialize player + CREATE(vending->sd, TBL_PC, 1); + + pc_setnewpc( vending->sd, vending->account_id, vending->char_id, 0, gettick(), vending->sex, 0 ); + + vending->sd->state.autotrade = 1; + + chrif_authreq( vending->sd, true ); + + i++; + } + + Sql_FreeResult( mmysql_handle ); + + for( i = 0; i < count; i++ ){ + vending = &autotraders[i]; + + if( SQL_ERROR == Sql_Query(mmysql_handle, + "SELECT `cartinventory_id`, `amount`, `price`" + "FROM `%s`" + "WHERE `vending_id` = %d;", vending_items_db, vending->vendor_id ) ) { + Sql_ShowDebug(mmysql_handle); + return; + } + + vending->count = (uint32)Sql_NumRows(mmysql_handle); + + if( vending->count <= 0 ){ + // Player was not correctly deleted, must not be set online + vending->count = 0; + map_quit(vending->sd); + continue; + } + + vending->entries = (struct vending_entry*)aMalloc( sizeof( struct vending_entry ) * vending->count ); + j = 0; + + while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) { + char* data; + + entry = &vending->entries[j]; + + Sql_GetData( mmysql_handle, 0, &data, NULL ); entry->cartinventory_id = atoi(data); + Sql_GetData( mmysql_handle, 1, &data, NULL ); entry->amount = atoi(data); + Sql_GetData( mmysql_handle, 2, &data, NULL ); entry->price = atoi(data); + + j++; + } + + Sql_FreeResult( mmysql_handle ); + } + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' autotraders.\n",count); + } + + // Everything is loaded fine, their entries will be reinserted once they are loaded + if( Sql_Query( mmysql_handle, "TRUNCATE TABLE `%s`;", vendings_db ) != SQL_SUCCESS || + Sql_Query( mmysql_handle, "TRUNCATE TABLE `%s`;", vending_items_db ) != SQL_SUCCESS ){ + Sql_ShowDebug(mmysql_handle); + return; + } +} + /** * Initialise the vending module * called in map::do_init */ void do_final_vending(void) { db_destroy(vending_db); + db_destroy(autotrade_db); } /** @@ -411,5 +646,6 @@ void do_final_vending(void) { */ void do_init_vending(void) { vending_db = idb_alloc(DB_OPT_BASE); + autotrade_db = idb_alloc(DB_OPT_BASE); vending_nextid = 0; } diff --git a/src/map/vending.h b/src/map/vending.h index 8c429d9e96..9ed8092ed8 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -18,7 +18,9 @@ struct s_vending { DBMap * vending_getdb(); void do_final_vending(void); void do_init_vending(void); - +void do_init_vending_autotrade( void ); + +void vending_reopen( struct map_session_data* sd ); void vending_closevending(struct map_session_data* sd); void 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); From 21eac1da68f8746b469ded9e34b20c0b7a445e0b Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Tue, 14 Jan 2014 22:28:52 +0100 Subject: [PATCH 2/8] Forgot the SQL changes --- sql-files/main.sql | 21 +++++++++++++++++++++ sql-files/upgrades/upgrade_20140114.sql | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 sql-files/upgrades/upgrade_20140114.sql diff --git a/sql-files/main.sql b/sql-files/main.sql index 088d66772c..6e14ae872e 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -712,3 +712,24 @@ CREATE TABLE IF NOT EXISTS `bonus_script` ( `type` char(1) NOT NULL DEFAULT '0', `icon` varchar(3) NOT NULL DEFAULT '-1' ) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `vending_items` ( + `vending_id` int(10) unsigned NOT NULL, + `index` smallint(5) unsigned NOT NULL, + `cartinventory_id` int(10) unsigned NOT NULL, + `amount` smallint(5) unsigned NOT NULL, + `price` int(10) unsigned NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `vendings` ( + `id` int(10) unsigned NOT NULL, + `account_id` int(11) unsigned NOT NULL, + `char_id` int(10) unsigned NOT NULL, + `sex` enum('F','M') NOT NULL DEFAULT 'M', + `map` varchar(20) NOT NULL, + `x` smallint(5) unsigned NOT NULL, + `y` smallint(5) unsigned NOT NULL, + `title` varchar(80) NOT NULL, + `autotrade` tinyint(4) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; diff --git a/sql-files/upgrades/upgrade_20140114.sql b/sql-files/upgrades/upgrade_20140114.sql new file mode 100644 index 0000000000..594be5e4f9 --- /dev/null +++ b/sql-files/upgrades/upgrade_20140114.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS `vending_items` ( + `vending_id` int(10) unsigned NOT NULL, + `index` smallint(5) unsigned NOT NULL, + `cartinventory_id` int(10) unsigned NOT NULL, + `amount` smallint(5) unsigned NOT NULL, + `price` int(10) unsigned NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `vendings` ( + `id` int(10) unsigned NOT NULL, + `account_id` int(11) unsigned NOT NULL, + `char_id` int(10) unsigned NOT NULL, + `sex` enum('F','M') NOT NULL DEFAULT 'M', + `map` varchar(20) NOT NULL, + `x` smallint(5) unsigned NOT NULL, + `y` smallint(5) unsigned NOT NULL, + `title` varchar(80) NOT NULL, + `autotrade` tinyint(4) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; \ No newline at end of file From 92403205019d91ea10ec7caafb5bb41c08c3f9dc Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Tue, 14 Jan 2014 22:44:43 +0100 Subject: [PATCH 3/8] Possible leak fix --- src/map/vending.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/map/vending.c b/src/map/vending.c index 8aa1645f20..fbff410c80 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -470,6 +470,8 @@ void vending_reopen( struct map_session_data* sd ){ if( vending->count <= 0 ){ idb_remove( autotrade_db, sd->status.char_id ); + aFree(vending->entries); + aFree(vending); map_quit(sd); return; } @@ -498,6 +500,9 @@ void vending_reopen( struct map_session_data* sd ){ } if( !count ){ + idb_remove( autotrade_db, sd->status.char_id ); + aFree(vending->entries); + aFree(vending); map_quit(sd); return; } @@ -597,8 +602,9 @@ void do_init_vending_autotrade( void ){ if( vending->count <= 0 ){ // Player was not correctly deleted, must not be set online - vending->count = 0; + idb_remove( autotrade_db, vending->char_id ); map_quit(vending->sd); + aFree(vending); continue; } From b7fd4dd274ac806b19da100ff3426c81760fb44f Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Tue, 14 Jan 2014 23:38:12 +0100 Subject: [PATCH 4/8] Unneeded semicolons removed Removed duplicate slashes --- npc/quests/quests_13_1.txt | 2 +- npc/quests/quests_13_2.txt | 2 +- npc/quests/quests_louyang.txt | 6 +++--- npc/quests/quests_morocc.txt | 4 ++-- src/map/clif.c | 4 +++- src/map/guild.c | 2 +- src/map/mob.c | 4 ++-- src/map/pc.c | 4 ++-- src/map/skill.c | 4 ++-- src/map/status.c | 4 ++-- 10 files changed, 19 insertions(+), 17 deletions(-) diff --git a/npc/quests/quests_13_1.txt b/npc/quests/quests_13_1.txt index a2438e0a1e..d2d650e7b7 100644 --- a/npc/quests/quests_13_1.txt +++ b/npc/quests/quests_13_1.txt @@ -12014,7 +12014,7 @@ OnTouch: que_job01,6,94,0 warp morocc#01 2,2,morocc,45,103 que_job01,17,48,0 warp que_job01#02 2,2,que_job01,68,92 -que_job01,68,96,0 warp que_job01#03 2,2,que_job01,17,53; +que_job01,68,96,0 warp que_job01#03 2,2,que_job01,17,53 que_job01,82,95,3 script Bar Master#moc2_01 46,{ if (checkweight(1201,1) == 0) { diff --git a/npc/quests/quests_13_2.txt b/npc/quests/quests_13_2.txt index b95e5a2ed3..965a9b5df5 100644 --- a/npc/quests/quests_13_2.txt +++ b/npc/quests/quests_13_2.txt @@ -2548,7 +2548,7 @@ OnTouch: } } -spl_in02,236,86,0 warp terrashome_out 1,1,splendide,285,139; +spl_in02,236,86,0 warp terrashome_out 1,1,splendide,285,139 spl_fild01,357,44,0 script ???#ep13mdf01 844,{ if (checkweight(1201,2) == 0) { diff --git a/npc/quests/quests_louyang.txt b/npc/quests/quests_louyang.txt index b39e086f18..d15d347969 100644 --- a/npc/quests/quests_louyang.txt +++ b/npc/quests/quests_louyang.txt @@ -2409,9 +2409,9 @@ lou_in02,192,170,0 script Supply Stack#2 111,{ close; } -louyang,129,121,0 warp Storage Warp#1 1,1,lou_in02,203,161; -louyang,125,121,0 warp Storage Warp#2 1,1,lou_in02,198,161; -lou_in02,198,159,0 warp Storage Warp#3 1,1,louyang,124,118; +louyang,129,121,0 warp Storage Warp#1 1,1,lou_in02,203,161 +louyang,125,121,0 warp Storage Warp#2 1,1,lou_in02,198,161 +lou_in02,198,159,0 warp Storage Warp#3 1,1,louyang,124,118 lou_in02,203,159,0 warp Storage Warp#4 1,1,louyang,129,118 // Poison King Quest :: poison_king diff --git a/npc/quests/quests_morocc.txt b/npc/quests/quests_morocc.txt index b5b8bbbd6b..7e650af292 100644 --- a/npc/quests/quests_morocc.txt +++ b/npc/quests/quests_morocc.txt @@ -3646,8 +3646,8 @@ que_ba,181,14,7 script Researcher#bpast_2_2 865,{ close; } -que_ba,183,25,0 warp #bpast_2to3_1 1,1,que_ba,72,25; -que_ba,183,52,0 warp #bpast_2to3_2 1,1,que_ba,72,51; +que_ba,183,25,0 warp #bpast_2to3_1 1,1,que_ba,72,25 +que_ba,183,52,0 warp #bpast_2to3_2 1,1,que_ba,72,51 que_ba,102,56,0 script #3room_barmunt -1,3,3,{ //OnTouch2: diff --git a/src/map/clif.c b/src/map/clif.c index 4797c19f14..35023385eb 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -17852,6 +17852,7 @@ void packetdb_readdb(void) packet_len(i) = packet_len_table[i]; for(f = 0; f Date: Wed, 15 Jan 2014 09:05:15 +0100 Subject: [PATCH 5/8] Added a comment for @euphyy Vendings are now deleted after you relogin with that account Should fix player freezing? --- conf/battle/feature.conf | 1 + src/map/atcommand.c | 6 ++++-- src/map/chrif.c | 10 ++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/conf/battle/feature.conf b/conf/battle/feature.conf index 2a39698412..39b3e3d03f 100644 --- a/conf/battle/feature.conf +++ b/conf/battle/feature.conf @@ -24,6 +24,7 @@ feature.atcommand_suggestions: off feature.banking: on // Autotrade persistency (Note 1) +// Should vendors that used @autotrade be restored after a restart? feature.autotrade: on // In which direction should respawned autotraders look? diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 613855cbe0..38bfa7bb74 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -5654,7 +5654,9 @@ ACMD_FUNC(autotrade) { sd->state.autotrade = 1; - if( battle_config.feature_autotrade && Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", "vendings", sd->vender_id ) != SQL_SUCCESS ){ + if( battle_config.feature_autotrade && + sd->state.vending && + Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;", "vendings", sd->vender_id ) != SQL_SUCCESS ){ Sql_ShowDebug( mmysql_handle ); } @@ -5666,7 +5668,7 @@ ACMD_FUNC(autotrade) { channel_pcquit(sd,0xF); //leave all chan clif_authfail_fd(sd->fd, 15); - chrif_save(sd,1); + chrif_save(sd,3); return 0; } diff --git a/src/map/chrif.c b/src/map/chrif.c index 3909a7af0b..dd2960a9dd 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -277,6 +277,7 @@ int chrif_isconnected(void) { * Saves character data. * Flag = 1: Character is quitting * Flag = 2: Character is changing map-servers + * Flag = 3: Character used @autotrade *------------------------------------------*/ int chrif_save(struct map_session_data *sd, int flag) { uint32 mmo_charstatus_len = 0; @@ -292,7 +293,7 @@ int chrif_save(struct map_session_data *sd, int flag) { 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_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) + 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); } @@ -1121,8 +1122,13 @@ int chrif_disconnectplayer(int fd) { } if (!sd->fd) { //No connection - if (sd->state.autotrade) + if (sd->state.autotrade){ + if( sd->state.vending ){ + vending_closevending(sd); + } + map_quit(sd); //Remove it. + } //Else we don't remove it because the char should have a timer to remove the player because it force-quit before, //and we don't want them kicking their previous instance before the 10 secs penalty time passes. [Skotlex] return 0; From 8183c380f7793aebb4e05a6ca9706b2ede405b1e Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Wed, 15 Jan 2014 21:21:57 +0100 Subject: [PATCH 6/8] Shop order Order will now be the same everytime --- src/map/vending.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/map/vending.c b/src/map/vending.c index fbff410c80..255a95d964 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -593,7 +593,8 @@ void do_init_vending_autotrade( void ){ if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `cartinventory_id`, `amount`, `price`" "FROM `%s`" - "WHERE `vending_id` = %d;", vending_items_db, vending->vendor_id ) ) { + "WHERE `vending_id` = %d" + "ORDER BY `index` ASC;", vending_items_db, vending->vendor_id ) ) { Sql_ShowDebug(mmysql_handle); return; } From ef0515873e98d9c997b646deafe773c72663b7ec Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Fri, 17 Jan 2014 20:47:54 +0100 Subject: [PATCH 7/8] Channels & Typo Autotraders dont join any channels nomore Fixed a small typo for vending entry loading --- src/map/channel.c | 2 ++ src/map/vending.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/map/channel.c b/src/map/channel.c index 55892eb9f2..1342a86f1e 100644 --- a/src/map/channel.c +++ b/src/map/channel.c @@ -119,6 +119,8 @@ int channel_delete(struct Channel *channel) { int channel_join(struct Channel *channel, struct map_session_data *sd) { if(!channel || !sd) return -1; + if(sd->state.autotrade) + return 0; // fake success if(channel_haspc(channel,sd)==1) return -2; diff --git a/src/map/vending.c b/src/map/vending.c index 255a95d964..8cb11498f6 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -593,7 +593,7 @@ void do_init_vending_autotrade( void ){ if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `cartinventory_id`, `amount`, `price`" "FROM `%s`" - "WHERE `vending_id` = %d" + "WHERE `vending_id` = %d " "ORDER BY `index` ASC;", vending_items_db, vending->vendor_id ) ) { Sql_ShowDebug(mmysql_handle); return; From 3f1242edfd882eae59e87d944e7d14e40055a4c1 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Wed, 22 Jan 2014 21:32:00 +0100 Subject: [PATCH 8/8] Status Saving Fixed status saving in general, now cart will always be loaded. --- src/char/char.c | 10 ++++------ src/map/chrif.c | 3 --- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index 1f4ea72ba3..c8f7cd792d 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3308,10 +3308,6 @@ int parse_frommap(int fd) WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); WFIFOW(fd,12) = count; WFIFOSET(fd,WFIFOW(fd,2)); - - //Clear the data once loaded. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) ) - Sql_ShowDebug(sql_handle); } } Sql_FreeResult(sql_handle); @@ -3715,8 +3711,10 @@ int parse_frommap(int fd) cid = RFIFOL(fd, 8); count = RFIFOW(fd, 12); - if( count > 0 ) - { + // Whatever comes from the mapserver, now is the time to drop previous entries + if( Sql_Query( sql_handle, "DELETE FROM `%s` where `account_id` = %d and `char_id` = %d;", scdata_db, aid, cid ) != SQL_SUCCESS ){ + Sql_ShowDebug( sql_handle ); + }else if( count > 0 ){ struct status_change_data data; StringBuf buf; int i; diff --git a/src/map/chrif.c b/src/map/chrif.c index dd2960a9dd..34b89d221f 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1296,9 +1296,6 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the count++; } - if (count == 0) - return 0; //Nothing to save. - WFIFOW(char_fd,12) = count; WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size WFIFOSET(char_fd,WFIFOW(char_fd,2));