Merge pull request #40 from Lemongrass3110/master
Added autotrade persistence support. - Players who are autotrading during a crash/shut down will be restored on start up. - Live vendor data is stored in SQL. - Credits to Ind and Lemongrass.
This commit is contained in:
commit
27cbc7ff24
@ -22,3 +22,15 @@ feature.atcommand_suggestions: off
|
||||
// Banking (Note 1)
|
||||
// Requires: 2013-07-24aRagexe or later
|
||||
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?
|
||||
// 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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
20
sql-files/upgrades/upgrade_20140114.sql
Normal file
20
sql-files/upgrades/upgrade_20140114.sql
Normal file
@ -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;
|
@ -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;
|
||||
@ -3779,7 +3777,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 +3789,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 +3806,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 &&
|
||||
|
@ -5653,6 +5653,13 @@ ACMD_FUNC(autotrade) {
|
||||
}
|
||||
|
||||
sd->state.autotrade = 1;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 +5667,8 @@ ACMD_FUNC(autotrade) {
|
||||
|
||||
channel_pcquit(sd,0xF); //leave all chan
|
||||
clif_authfail_fd(sd->fd, 15);
|
||||
|
||||
chrif_save(sd,3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7340,6 +7340,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
|
||||
/**
|
||||
|
@ -520,6 +520,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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@ -562,6 +563,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 +619,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 +627,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);
|
||||
}
|
||||
|
||||
@ -1117,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;
|
||||
@ -1286,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));
|
||||
@ -1364,6 +1371,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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -9441,7 +9441,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);
|
||||
}
|
||||
|
||||
|
||||
@ -17857,6 +17857,7 @@ void packetdb_readdb(void)
|
||||
packet_len(i) = packet_len_table[i];
|
||||
|
||||
for(f = 0; f<ARRAYLENGTH(filename); f++){
|
||||
entries = 0;
|
||||
sprintf(line, "%s/%s", db_path,filename[f]);
|
||||
if( (fp=fopen(line,"r"))==NULL ){
|
||||
if(f==0) {
|
||||
@ -18004,7 +18005,8 @@ void packetdb_readdb(void)
|
||||
|
||||
clif_config.packet_db_ver = j?j:MAX_PACKET_VER;
|
||||
}
|
||||
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, "packet_db.txt");
|
||||
sprintf(line, "%s/%s", db_path,filename[f]);
|
||||
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, line);
|
||||
}
|
||||
ShowStatus("Using default packet version: "CL_WHITE"%d"CL_RESET".\n", clif_config.packet_db_ver);
|
||||
}
|
||||
|
@ -2105,7 +2105,7 @@ void do_init_guild(void) {
|
||||
for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
|
||||
int n1 = strlen(db_path)+strlen(dbsubpath[i])+1;
|
||||
char* dbsubpath1 = aMalloc(n1+1);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s/%s",db_path,dbsubpath[i]);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);
|
||||
|
||||
sv_readdb(dbsubpath1, "castle_db.txt", ',', 4, 4, -1, &guild_read_castledb, i);
|
||||
sv_readdb(dbsubpath1, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, &guild_read_guildskill_tree_db, i); //guild skill tree [Komurka]
|
||||
|
@ -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)
|
||||
|
@ -910,6 +910,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);
|
||||
|
||||
|
@ -4558,9 +4558,9 @@ static void mob_load(void)
|
||||
int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
|
||||
char* dbsubpath1 = aMalloc(n1+1);
|
||||
char* dbsubpath2 = aMalloc(n2+1);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s/%s",db_path,dbsubpath[i]);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);
|
||||
if(i==0) safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s/%s",db_path,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s%s",db_path,dbsubpath[i]);
|
||||
|
||||
sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, i); // must be read before mobdb
|
||||
sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, MAX_MOB_CHAT, &mob_parse_row_chatdb, i);
|
||||
|
@ -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;
|
||||
}
|
||||
@ -10224,9 +10228,9 @@ int pc_readdb(void)
|
||||
int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
|
||||
char* dbsubpath1 = aMalloc(n1+1);
|
||||
char* dbsubpath2 = aMalloc(n2+1);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s/%s",db_path,dbsubpath[i]);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);
|
||||
if(i==0) safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s/%s",db_path,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s%s",db_path,dbsubpath[i]);
|
||||
|
||||
s = pc_read_statsdb(dbsubpath2,s,i);
|
||||
#ifdef RENEWAL_ASPD
|
||||
|
@ -19229,9 +19229,9 @@ static void skill_readdb(void) {
|
||||
int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
|
||||
char* dbsubpath1 = aMalloc(n1+1);
|
||||
char* dbsubpath2 = aMalloc(n2+1);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s/%s",db_path,dbsubpath[i]);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);
|
||||
if(i==0) safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s/%s",db_path,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s%s",db_path,dbsubpath[i]);
|
||||
|
||||
sv_readdb(dbsubpath2, "skill_db.txt" , ',', 18, 18, MAX_SKILL_DB, skill_parse_row_skilldb, i);
|
||||
sv_readdb(dbsubpath2, "skill_require_db.txt" , ',', 34, 34, MAX_SKILL_DB, skill_parse_row_requiredb, i);
|
||||
|
@ -12346,9 +12346,9 @@ int status_readdb(void)
|
||||
int n2 = strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1;
|
||||
char* dbsubpath1 = aMalloc(n1+1);
|
||||
char* dbsubpath2 = aMalloc(n2+1);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s/%s",db_path,dbsubpath[i]);
|
||||
safesnprintf(dbsubpath1,n1+1,"%s%s",db_path,dbsubpath[i]);
|
||||
if(i==0) safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s/%s",db_path,dbsubpath[i]);
|
||||
else safesnprintf(dbsubpath2,n2,"%s%s",db_path,dbsubpath[i]);
|
||||
|
||||
status_readdb_attrfix(dbsubpath2,i); // !TODO use sv_readdb ?
|
||||
sv_readdb(dbsubpath1, "size_fix.txt",',',MAX_WEAPON_TYPE,MAX_WEAPON_TYPE,ARRAYLENGTH(atkmods),&status_readdb_sizefix, i);
|
||||
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h> // atoi
|
||||
#include <string.h>
|
||||
|
||||
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,198 @@ 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 );
|
||||
aFree(vending->entries);
|
||||
aFree(vending);
|
||||
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 ){
|
||||
idb_remove( autotrade_db, sd->status.char_id );
|
||||
aFree(vending->entries);
|
||||
aFree(vending);
|
||||
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 "
|
||||
"ORDER BY `index` ASC;", 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
|
||||
idb_remove( autotrade_db, vending->char_id );
|
||||
map_quit(vending->sd);
|
||||
aFree(vending);
|
||||
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 +653,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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user