From 1290826be233d3a67a8ead585db1d46b3bf5053f Mon Sep 17 00:00:00 2001 From: lighta Date: Tue, 5 Nov 2013 13:41:42 -0500 Subject: [PATCH] Adding banking support --- conf/battle/feature.conf | 6 +- conf/inter_athena.conf | 1 + conf/log_athena.conf | 1 + conf/map_athena.conf | 3 +- conf/msg_conf/map_msg.conf | 4 + db/packet_db.txt | 42 ++++ sql-files/main.sql | 1 + sql-files/upgrades/upgrade_svn17600.sql | 1 + src/char/char.c | 97 +++++++++- src/common/mmo.h | 4 +- src/login/account.h | 1 + src/login/account_sql.c | 71 +++---- src/login/login.c | 39 +++- src/map/battle.c | 8 + src/map/battle.h | 1 + src/map/channel.c | 1 + src/map/chrif.c | 124 ++++++++---- src/map/chrif.h | 3 + src/map/clif.c | 247 +++++++++++++++++++++++- src/map/clif.h | 37 +++- src/map/log.c | 1 + src/map/log.h | 1 + src/map/pc.c | 42 ++++ src/map/pc.h | 4 + src/map/status.c | 1 - 25 files changed, 644 insertions(+), 97 deletions(-) create mode 100644 sql-files/upgrades/upgrade_svn17600.sql diff --git a/conf/battle/feature.conf b/conf/battle/feature.conf index fa05efd8b4..a6854812c5 100644 --- a/conf/battle/feature.conf +++ b/conf/battle/feature.conf @@ -17,4 +17,8 @@ feature.search_stores: on // Atcommand suggestions (Note 1) // If one type incomplete atcommand, it will suggest the complete ones. -feature.atcommand_suggestions: off \ No newline at end of file +feature.atcommand_suggestions: off + +// Banking (Note 1) +// Requires: 2013-07-24aRagexe or later +feature.banking: on \ No newline at end of file diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf index da770e73e6..fcc0d36bb3 100644 --- a/conf/inter_athena.conf +++ b/conf/inter_athena.conf @@ -103,6 +103,7 @@ mercenary_db: mercenary mercenary_owner_db: mercenary_owner elemental_db: elemental ragsrvinfo_db: ragsrvinfo +skillcooldown_db: skillcooldown // Map Database Tables item_db_db: item_db diff --git a/conf/log_athena.conf b/conf/log_athena.conf index 2e6cf79469..6136188a70 100644 --- a/conf/log_athena.conf +++ b/conf/log_athena.conf @@ -28,6 +28,7 @@ // 0x10000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/ // rings deleted by divorce/pet egg (un)hatching/pet armor (un)equipping/Weapon Refine skill/Remove Trap skill) // 0x20000 - ($) Log cash transactions +// 0x40000 - (K) Log account bank transactions // Example: Log trades+vending+script items+created items: 1+2+32+1024 = 1059 // Please note that moving items from inventory to cart and back is not logged by design. enable_logs: 0xFFFFF diff --git a/conf/map_athena.conf b/conf/map_athena.conf index 40869408af..45ed4cf289 100644 --- a/conf/map_athena.conf +++ b/conf/map_athena.conf @@ -101,11 +101,12 @@ minsave_time: 100 // 16: After successfully sending a mail with attachment // 32: After successfully submitting an item for auction // 64: After successfully get/delete/complete a quest +// 128: After every bank transaction (deposit/withdraw) // NOTE: These settings decrease the chance of dupes/lost items when there's a // server crash at the expense of increasing the map/char server lag. If your // server rarely crashes, but experiences interserver lag, you may want to set // these off. -save_settings: 127 +save_settings: 255 // Message of the day file, when a character logs on, this message is displayed. motd_txt: conf/motd.txt diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index b3efc1334e..2f60341950 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -1493,5 +1493,9 @@ 1490: Item types on your autoloottype list: 1491: Your autoloottype list has been reset. +//Banking +1492: You can't withdraw that much money +1493: Banking is disabled + //Custom translations //import: conf/msg_conf/import/map_msg_eng_conf.txt diff --git a/db/packet_db.txt b/db/packet_db.txt index 1306491420..0fa074c82d 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -2190,3 +2190,45 @@ packet_ver: 44 0x0863,26,friendslistadd,2 0x088A,5,hommenu,2:4 0x095B,36,storagepassword,2:4:20 +0x09A6,12,ZC_BANKING_CHECK,2:10 +0x09A7,10,bankdeposit,2:6 +0x09A8,16,ZC_ACK_BANKING_DEPOSIT,2:4:12 +0x09A9,10,bankwithdrawal,2:6 +0x09AA,16,ZC_ACK_BANKING_WITHDRAW,2:4:12 +0x09AB,6,bankcheck,2 +0x09B6,6,bankopen,2 +0x09B7,4,ZC_ACK_OPEN_BANKING,2 +0x09B8,6,bankclose,2 +0x09B9,4,ZC_ACK_CLOSE_BANKING,2 + +//2013-08-07Ragexe (Shakto) +packet_ver: 45 +0x0369,7,actionrequest,2:6 +0x083C,10,useskilltoid,2:4:6 +0x0437,5,walktoxy,2 +0x035F,6,ticksend,2 +0x0202,5,changedir,2:4 +0x07E4,6,takeitem,2 +0x0362,6,dropitem,2:4 +0x07EC,8,movetokafra,2:4 +0x0364,8,movefromkafra,2:4 +0x0438,10,useskilltopos,2:4:6:8 +0x0366,90,useskilltoposinfo,2:4:6:8:10 +0x096A,6,getcharnamerequest,2 +0x0368,6,solvecharname,2 +0x0838,12,searchstoreinfolistitemclick,2:6:10 +0x0835,2,searchstoreinfonextpage,0 +0x0819,-1,searchstoreinfo,2:4:5:9:13:14:15 +0x0811,-1,reqtradebuyingstore,2:4:8:12 +0x0360,6,reqclickbuyingstore,2 +0x0817,2,reqclosebuyingstore,0 +0x0815,-1,reqopenbuyingstore,2:4:8:9:89 +0x0365,18,bookingregreq,2:4:6 +// 0x363,8 CZ_JOIN_BATTLE_FIELD +0x0281,-1,itemlistwindowselected,2:4:8:12 +0x022D,19,wanttoconnection,2:6:10:14:18 +0x0802,26,partyinvite2,2 +// 0x436,4 CZ_GANGSI_RANK +0x023B,26,friendslistadd,2 +0x0361,5,hommenu,2:4 +0x0887,36,storagepassword,2:4:20 diff --git a/sql-files/main.sql b/sql-files/main.sql index 34f872b147..ebade202f7 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -459,6 +459,7 @@ CREATE TABLE IF NOT EXISTS `login` ( `character_slots` tinyint(3) unsigned NOT NULL default '0', `pincode` varchar(4) NOT NULL DEFAULT '', `pincode_change` int(11) unsigned NOT NULL DEFAULT '0', + `bank_vault` BIGINT(64) NOT NULL DEFAULT '0', PRIMARY KEY (`account_id`), KEY `name` (`userid`) ) ENGINE=MyISAM AUTO_INCREMENT=2000000; diff --git a/sql-files/upgrades/upgrade_svn17600.sql b/sql-files/upgrades/upgrade_svn17600.sql new file mode 100644 index 0000000000..de44d7d647 --- /dev/null +++ b/sql-files/upgrades/upgrade_svn17600.sql @@ -0,0 +1 @@ +ALTER TABLE `login` ADD `bank_vault` BIGINT( 64 ) NOT NULL DEFAULT '0'; diff --git a/src/char/char.c b/src/char/char.c index 8215acce7a..7d6af5c275 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -143,6 +143,7 @@ struct char_session_data { time_t pincode_change; uint16 pincode_try; // Addon system + int bank_vault; unsigned int char_moves[MAX_CHARS]; // character moves left }; @@ -189,6 +190,12 @@ bool char_moves_unlimited = false; void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ); void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ); +int loginif_BankingReq(int32 account_id, int8 type, int32 data); +int loginif_parse_BankingAck(int fd); +int mapif_BankingAck(int32 account_id, int32 bank_vault); +int mapif_parse_UpdBankInfo(int fd); +int mapif_parse_ReqBankInfo(int fd); + //Custom limits for the fame lists. [Skotlex] int fame_list_size_chemist = MAX_FAME_LIST; int fame_list_size_smith = MAX_FAME_LIST; @@ -552,7 +559,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) } else strcat(save_status, " status"); } - + //Values that will seldom change (to speed up saving) if ( (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || @@ -591,7 +598,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) else errors++; } - + //memo points if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) ) { @@ -2146,6 +2153,83 @@ static void char_auth_ok(int fd, struct char_session_data *sd) int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); void mapif_server_reset(int id); +/* + * HA 0x2740L B L + * type: + * 0 = select + * 1 = update + */ +int loginif_BankingReq(int32 account_id, int8 type, int32 data){ + if (login_fd > 0 && session[login_fd] && !session[login_fd]->flag.eof){ + WFIFOHEAD(login_fd,11); + WFIFOW(login_fd,0) = 0x2740; + WFIFOL(login_fd,2) = account_id; + WFIFOB(login_fd,6) = type; + WFIFOL(login_fd,7) = data; + WFIFOSET(login_fd,11); + return 1; + } + return 0; +} + +/* + * Received the banking data from login and transmit it to all map-serv + * AH 0x2741L L B + * HZ 0x2b29 L L + */ +int loginif_parse_BankingAck(int fd){ + if (RFIFOREST(fd) < 11) + return 0; + uint32 aid = RFIFOL(fd,2); + int32 bank_vault = RFIFOL(fd,6); + char not_fw = RFIFOB(fd,10); + RFIFOSKIP(fd,11); + + if(!not_fw) mapif_BankingAck(aid, bank_vault); + return 1; +} + +//HZ 0x2b29 L L +int mapif_BankingAck(int32 account_id, int32 bank_vault){ + unsigned char buf[14]; + WBUFW(buf,0) = 0x2b29; + WBUFL(buf,2) = account_id; + WBUFL(buf,6) = bank_vault; + mapif_sendall(buf, 10); //inform all maps-attached + return 1; +} + +/* + * Receive a map request to save banking + * Fowarding it to login-serv + * ZH 0x2b28 L L + * HA 0x2740L B L + */ +int mapif_parse_UpdBankInfo(int fd){ + if( RFIFOREST(fd) < 10 ) + return 0; + uint32 aid = RFIFOL(fd,2); + int money = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + loginif_BankingReq(aid, 2, money); + return 1; +} + +/* + * Receive a map request to get banking info + * Fowarding it to login-serv + * ZH 0x2b2a L + * HA 0x2740L B L + */ +int mapif_parse_ReqBankInfo(int fd){ + if( RFIFOREST(fd) < 6 ) + return 0; + uint32 aid = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + loginif_BankingReq(aid, 1, 0); + return 1; +} + /// Resets all the data. void loginif_reset(void) @@ -2230,6 +2314,7 @@ int parse_fromlogin(int fd) { switch( command ) { + case 0x2741: loginif_parse_BankingAck(fd); break; // acknowledgement of connect-to-loginserver request case 0x2711: @@ -2289,7 +2374,7 @@ int parse_fromlogin(int fd) { break; case 0x2717: // account data - if (RFIFOREST(fd) < 72) + if (RFIFOREST(fd) < 76) return 0; // find the authenticated session with this account id @@ -2309,6 +2394,7 @@ int parse_fromlogin(int fd) { safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate)); safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode)); sd->pincode_change = (time_t)RFIFOL(fd,68); + sd->bank_vault = RFIFOL(fd,72); ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); // continued from char_auth_ok... if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 @@ -2355,7 +2441,7 @@ int parse_fromlogin(int fd) { #endif } } - RFIFOSKIP(fd,72); + RFIFOSKIP(fd,76); break; // login-server alive packet @@ -3579,6 +3665,9 @@ int parse_frommap(int fd) RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */ } break; + + case 0x2b28: mapif_parse_UpdBankInfo(fd); break; + case 0x2b2a: mapif_parse_ReqBankInfo(fd); break; default: { diff --git a/src/common/mmo.h b/src/common/mmo.h index db707ba92a..f56c0525f5 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -47,7 +47,7 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER - #define PACKETVER 20120410 + #define PACKETVER 20130724 //#define PACKETVER 20130320 //#define PACKETVER 20111116 #endif @@ -79,6 +79,7 @@ //Max amount of a single stacked item #define MAX_AMOUNT 30000 #define MAX_ZENY 1000000000 +#define MAX_BANK_ZENY SINT32_MAX #define MAX_FAME 1000000000 #define MAX_CART 100 #define MAX_SKILL 5020 @@ -351,6 +352,7 @@ struct mmo_charstatus { unsigned int base_exp,job_exp; int zeny; + int bank_vault; short class_; unsigned int status_point,skill_point; diff --git a/src/login/account.h b/src/login/account.h index 57b841da54..3d7acefb7e 100644 --- a/src/login/account.h +++ b/src/login/account.h @@ -53,6 +53,7 @@ struct mmo_account char pincode[PINCODE_LENGTH+1]; // pincode system time_t pincode_change; // (timestamp): last time of pincode change int account_reg2_num; + int bank_vault; struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) }; diff --git a/src/login/account_sql.c b/src/login/account_sql.c index 66bd9c1f08..3478870e55 100644 --- a/src/login/account_sql.c +++ b/src/login/account_sql.c @@ -522,7 +522,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc // retrieve login entry for the specified account if( SQL_ERROR == Sql_Query(sql_handle, - "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change` FROM `%s` WHERE `account_id` = %d", + "SELECT `account_id`,`userid`,`user_pass`,`sex`,`email`,`group_id`,`state`,`unban_time`,`expiration_time`,`logincount`,`lastlogin`,`last_ip`,`birthdate`,`character_slots`,`pincode`, `pincode_change`, `bank_vault` FROM `%s` WHERE `account_id` = %d", db->account_db, account_id ) ) { Sql_ShowDebug(sql_handle); @@ -551,6 +551,7 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, int acc Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = atoi(data); Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode)); Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data); + Sql_GetData(sql_handle, 16, &data, NULL); acc->bank_vault = atoi(data); Sql_FreeResult(sql_handle); @@ -599,24 +600,25 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo if( is_new ) {// insert into account table if( SQL_SUCCESS != SqlStmt_Prepare(stmt, - "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + "INSERT INTO `%s` (`account_id`, `userid`, `user_pass`, `sex`, `email`, `group_id`, `state`, `unban_time`, `expiration_time`, `logincount`, `lastlogin`, `last_ip`, `birthdate`, `character_slots`, `pincode`, `pincode_change`, `bank_vault`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", db->account_db) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_INT, (void*)&acc->account_id, sizeof(acc->account_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_STRING, (void*)&acc->email, strlen(acc->email)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_INT, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 16, SQLDT_INT, (void*)&acc->bank_vault, sizeof(acc->bank_vault)) || SQL_SUCCESS != SqlStmt_Execute(stmt) ) { SqlStmt_ShowDebug(stmt); @@ -625,22 +627,23 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo } else {// update account table - if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change)) + if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "UPDATE `%s` SET `userid`=?,`user_pass`=?,`sex`=?,`email`=?,`group_id`=?,`state`=?,`unban_time`=?,`expiration_time`=?,`logincount`=?,`lastlogin`=?,`last_ip`=?,`birthdate`=?,`character_slots`=?,`pincode`=?, `pincode_change`=?, `bank_vault`=? WHERE `account_id` = '%d'", db->account_db, acc->account_id) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (void*)acc->userid, strlen(acc->userid)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (void*)acc->pass, strlen(acc->pass)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_ENUM, (void*)&acc->sex, sizeof(acc->sex)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, (void*)acc->email, strlen(acc->email)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 4, SQLDT_INT, (void*)&acc->group_id, sizeof(acc->group_id)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 5, SQLDT_UINT, (void*)&acc->state, sizeof(acc->state)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 6, SQLDT_LONG, (void*)&acc->unban_time, sizeof(acc->unban_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 7, SQLDT_LONG, (void*)&acc->expiration_time, sizeof(acc->expiration_time)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 8, SQLDT_UINT, (void*)&acc->logincount, sizeof(acc->logincount)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 9, SQLDT_STRING, (void*)&acc->lastlogin, strlen(acc->lastlogin)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 10, SQLDT_STRING, (void*)&acc->last_ip, strlen(acc->last_ip)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 11, SQLDT_STRING, (void*)&acc->birthdate, strlen(acc->birthdate)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 12, SQLDT_UCHAR, (void*)&acc->char_slots, sizeof(acc->char_slots)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 13, SQLDT_STRING, (void*)&acc->pincode, strlen(acc->pincode)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 14, SQLDT_LONG, (void*)&acc->pincode_change, sizeof(acc->pincode_change)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 15, SQLDT_INT, (void*)&acc->bank_vault, sizeof(acc->bank_vault)) || SQL_SUCCESS != SqlStmt_Execute(stmt) ) { SqlStmt_ShowDebug(stmt); diff --git a/src/login/login.c b/src/login/login.c index e41b7865e1..9bc540295e 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -567,6 +567,7 @@ int parse_fromchar(int fd){ char birthdate[10+1] = ""; char pincode[PINCODE_LENGTH+1]; int account_id = RFIFOL(fd,2); + int bank_vault = 0; memset(pincode,0,PINCODE_LENGTH+1); @@ -581,9 +582,10 @@ int parse_fromchar(int fd){ char_slots = acc.char_slots; safestrncpy(birthdate, acc.birthdate, sizeof(birthdate)); safestrncpy(pincode, acc.pincode, sizeof(pincode)); + bank_vault = acc.bank_vault; } - WFIFOHEAD(fd,72); + WFIFOHEAD(fd,76); WFIFOW(fd,0) = 0x2717; WFIFOL(fd,2) = account_id; safestrncpy((char*)WFIFOP(fd,6), email, 40); @@ -593,7 +595,8 @@ int parse_fromchar(int fd){ safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1); safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 ); WFIFOL(fd,68) = (uint32)acc.pincode_change; - WFIFOSET(fd,72); + WFIFOL(fd,72) = bank_vault; + WFIFOSET(fd,76); } break; @@ -907,13 +910,11 @@ int parse_fromchar(int fd){ return 0; else{ struct mmo_account acc; - if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){ strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 ); acc.pincode_change = time( NULL ); accounts->save(accounts, &acc); } - RFIFOSKIP(fd,11); } break; @@ -941,6 +942,35 @@ int parse_fromchar(int fd){ } break; + case 0x2740: // req upd bank_vault + if( RFIFOREST(fd) < 11 ) + return 0; + else{ + struct mmo_account acc; + + int account_id = RFIFOL(fd,2); + char type = RFIFOB(fd,6); + int32 data = RFIFOL(fd,7); + RFIFOSKIP(fd,11); + + if( !accounts->load_num(accounts, &acc, account_id) ) + ShowNotice("Char-server '%s': Error on banking (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else{ + unsigned char buf[11]; + if(type==2){ // upd and Save + acc.bank_vault = data; + accounts->save(accounts, &acc); + WBUFB(buf,10) = 1; + } + // announce to other servers + WBUFW(buf,0) = 0x2741; + WBUFL(buf,2) = account_id; + WBUFL(buf,6) = acc.bank_vault; + charif_sendallwos(-1, buf, 11); + } + } + break; + default: ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); set_eof(fd); @@ -996,6 +1026,7 @@ int mmo_auth_new(const char* userid, const char* pass, const char sex, const cha acc.pincode_change = 0; acc.char_slots = 0; + acc.bank_vault = 0; if( !accounts->create(accounts, &acc) ) return 0; diff --git a/src/map/battle.c b/src/map/battle.c index 4b2a9f5e76..9184c151fa 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7138,6 +7138,7 @@ static const struct _battle_data { { "item_flooritem_check", &battle_config.item_onfloor, 1, 0, 1, }, { "bowling_bash_area", &battle_config.bowling_bash_area, 0, 0, 20, }, { "drop_rateincrease", &battle_config.drop_rateincrease, 0, 0, 1, }, + { "feature.banking", &battle_config.feature_banking, 1, 0, 1, }, }; #ifndef STATS_OPT_OUT /** @@ -7352,6 +7353,13 @@ void battle_adjust_conf() } #endif +#if PACKETVER < 20130724 + if( battle_config.feature_banking ) { + ShowWarning("conf/battle/feature.conf banking is enabled but it requires PACKETVER 2013-07-24 or newer, disabling...\n"); + battle_config.feature_banking = 0; + } +#endif + #ifndef CELL_NOSTACK if (battle_config.cell_stack_limit != 1) ShowWarning("Battle setting 'cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n"); diff --git a/src/map/battle.h b/src/map/battle.h index 06d632b26e..6ffa6e1e50 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -494,6 +494,7 @@ extern struct Battle_Config int item_onfloor; // Whether to drop an undroppable item on the map or destroy it if inventory is full. int bowling_bash_area; int drop_rateincrease; + int feature_banking; } battle_config; diff --git a/src/map/channel.c b/src/map/channel.c index 637e1b905a..8e6c02dbfa 100644 --- a/src/map/channel.c +++ b/src/map/channel.c @@ -101,6 +101,7 @@ int channel_delete(struct Channel *channel) { } default: strdb_remove(channel_db, channel->name); + aFree(channel); break; } return 0; diff --git a/src/map/chrif.c b/src/map/chrif.c index 9b685c382f..209ed97c3e 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -34,6 +34,7 @@ #include static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_t data); +int chrif_save_bankdata(struct map_session_data *sd); static struct eri *auth_db_ers; //For reutilizing player login structures. static DBMap* auth_db; // int id -> struct auth_node* @@ -45,7 +46,8 @@ static const int packet_len_table[0x3d] = { // U - used, F - free 11,10,10, 0,11, -1,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17 2,10, 2,-1,-1,-1, 2, 7, // 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f -1,10, 8, 2, 2,14,19,19, // 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27 -}; + 10,10, 6, 0, 0, 0, 0, 0, // 2b28-2b2f: U->2b28, U->2b29, U->2b2a, F->2b2b, F->2b2c, F->2b2d, F->2b2e, F->2b2f + }; //Used Packets: //2af8: Outgoing, chrif_connect -> 'connect to charserver / auth @ charserver' @@ -66,8 +68,8 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2b07: Outgoing, chrif_removefriend -> 'Tell charserver to remove friend_id from char_id friend list' //2b08: Outgoing, chrif_searchcharid -> '...' //2b09: Incoming, map_addchariddb -> 'Adds a name to the nick db' -//2b0a: FREE -//2b0b: FREE +//2b0a: Outgoing, chrif_skillcooldown_request -> requesting the list of skillcooldown for char +//2b0b: Incoming, chrif_skillcooldown_load -> received the list of cooldown for char //2b0c: Outgoing, chrif_changeemail -> 'change mail address ...' //2b0d: Incoming, chrif_changedsex -> 'Change sex of acc XY' //2b0e: Outgoing, chrif_char_ask_name -> 'Do some operations (change sex, ban / unban etc)' @@ -77,7 +79,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2b12: Incoming, chrif_divorceack -> 'divorce chars //2b13: FREE //2b14: Incoming, chrif_accountban -> 'not sure: kick the player with message XY' -//2b15: FREE +//2b15: Outgoing, chrif_skillcooldown_save -> request to save skillcooldown //2b16: Outgoing, chrif_ragsrvinfo -> 'sends base / job / drop rates ....' //2b17: Outgoing, chrif_char_offline -> 'tell the charserver that the char is now offline' //2b18: Outgoing, chrif_char_reset_offline -> 'set all players OFF!' @@ -96,6 +98,9 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2b25: Incoming, chrif_deadopt -> 'Removes baby from Father ID and Mother ID' //2b26: Outgoing, chrif_authreq -> 'client authentication request' //2b27: Incoming, chrif_authfail -> 'client authentication failed' +//2b28: Outgoing, chrif_save_bankdata -> 'send bank data to be saved' +//2b29: Incoming, chrif_load_bankdata -> 'received bank data for playeer to be loaded' +//2b2a: Outgoing, chrif_bankdata_request -> 'request bank data for charid' int chrif_connected = 0; int char_fd = -1; @@ -275,10 +280,11 @@ 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); - } + if (chrif_isconnected()) { + chrif_save_scdata(sd); + chrif_skillcooldown_save(sd); + chrif_save_bankdata(sd); + } if ( !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); } @@ -577,20 +583,20 @@ int chrif_scdata_request(int account_id, int char_id) { WFIFOL(char_fd,6) = char_id; WFIFOSET(char_fd,10); #endif - return 0; + return 0; } /*========================================== * Request skillcooldown from charserver *------------------------------------------*/ int chrif_skillcooldown_request(int account_id, int char_id) { - chrif_check(-1); - WFIFOHEAD(char_fd, 10); - WFIFOW(char_fd, 0) = 0x2b0a; - WFIFOL(char_fd, 2) = account_id; - WFIFOL(char_fd, 6) = char_id; - WFIFOSET(char_fd, 10); - return 0; + chrif_check(-1); + WFIFOHEAD(char_fd, 10); + WFIFOW(char_fd, 0) = 0x2b0a; + WFIFOL(char_fd, 2) = account_id; + WFIFOL(char_fd, 6) = char_id; + WFIFOSET(char_fd, 10); + return 0; } /*========================================== @@ -1184,6 +1190,45 @@ int chrif_updatefamelist_ack(int fd) { return 1; } +int chrif_bankdata_request(int account_id, int char_id) { + + chrif_check(-1); + + WFIFOHEAD(char_fd,6); + WFIFOW(char_fd,0) = 0x2b2a; + WFIFOL(char_fd,2) = account_id; + WFIFOSET(char_fd,6); + return 0; +} + +int chrif_load_bankdata(int fd){ + struct map_session_data *sd; + int aid, bank_vault; + + aid = RFIFOL(fd,2); //Player Account ID + bank_vault = RFIFOL(fd,6); //Player money in bank + + sd = map_id2sd(aid); + + if ( !sd ) { + ShowError("chrif_load_bankdata: Player of AID %d not found!\n", aid); + return -1; + } + sd->status.bank_vault = bank_vault; + return 1; +} + +int chrif_save_bankdata(struct map_session_data *sd){ + if( CheckForCharServer() ) + return 0; + WFIFOHEAD(char_fd,10); + WFIFOW(char_fd,0) = 0x2b28; + WFIFOL(char_fd,2) = sd->status.account_id; + WFIFOL(char_fd,6) = sd->status.bank_vault; + WFIFOSET(char_fd,10); + return 1; +} + int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the player and sends it to the char-server for saving. [Skotlex] #ifdef ENABLE_SC_SAVING @@ -1228,7 +1273,7 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size WFIFOSET(char_fd,WFIFOW(char_fd,2)); #endif - return 0; + return 0; } int chrif_skillcooldown_save(struct map_session_data *sd) { @@ -1300,35 +1345,35 @@ 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 - return 0; + return 0; } //Retrieve and load skillcooldown for a player int chrif_skillcooldown_load(int fd) { - struct map_session_data *sd; - struct skill_cooldown_data *data; - int aid, cid, i, count; + struct map_session_data *sd; + struct skill_cooldown_data *data; + int aid, cid, i, count; - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); + aid = RFIFOL(fd, 4); + cid = RFIFOL(fd, 8); - sd = map_id2sd(aid); - if (!sd) { - ShowError("chrif_skillcooldown_load: Player of AID %d not found!\n", aid); - return -1; - } - if (sd->status.char_id != cid) { - ShowError("chrif_skillcooldown_load: Receiving data for account %d, char id does not matches (%d != %d)!\n", aid, sd->status.char_id, cid); - return -1; - } - count = RFIFOW(fd, 12); //sc_count - for (i = 0; i < count; i++) { - data = (struct skill_cooldown_data*) RFIFOP(fd, 14 + i * sizeof (struct skill_cooldown_data)); - skill_blockpc_start(sd, data->skill_id, data->tick); - } - return 0; + sd = map_id2sd(aid); + if (!sd) { + ShowError("chrif_skillcooldown_load: Player of AID %d not found!\n", aid); + return -1; + } + if (sd->status.char_id != cid) { + ShowError("chrif_skillcooldown_load: Receiving data for account %d, char id does not matches (%d != %d)!\n", aid, sd->status.char_id, cid); + return -1; + } + count = RFIFOW(fd, 12); //sc_count + for (i = 0; i < count; i++) { + data = (struct skill_cooldown_data*) RFIFOP(fd, 14 + i * sizeof (struct skill_cooldown_data)); + skill_blockpc_start(sd, data->skill_id, data->tick); + } + return 0; } /*========================================== @@ -1522,7 +1567,7 @@ int chrif_parse(int fd) { case 0x2b04: chrif_recvmap(fd); break; case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; - case 0x2b0b: chrif_skillcooldown_load(fd); break; + case 0x2b0b: chrif_skillcooldown_load(fd); break; case 0x2b0d: chrif_changedsex(fd); break; case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break; @@ -1537,6 +1582,7 @@ int chrif_parse(int fd) { case 0x2b24: chrif_keepalive_ack(fd); break; case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; case 0x2b27: chrif_authfail(fd); break; + case 0x2b29: chrif_load_bankdata(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); diff --git a/src/map/chrif.h b/src/map/chrif.h index e16e56a52a..fe0bb0b81a 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -41,6 +41,9 @@ int chrif_scdata_request(int account_id, int char_id); int chrif_skillcooldown_request(int account_id, int char_id); int chrif_skillcooldown_save(struct map_session_data *sd); int chrif_skillcooldown_load(int fd); +int chrif_bankdata_request(int account_id, int char_id); +int chrif_load_bankdata(int fd); +int chrif_save_bankdata(struct map_session_data *sd); int chrif_save(struct map_session_data* sd, int flag); int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip); int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port); diff --git a/src/map/clif.c b/src/map/clif.c index 958913c562..2fa69ef344 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -55,8 +55,8 @@ /* for clif_clearunit_delayed */ static struct eri *delay_clearunit_ers; -//#define DUMP_UNKNOWN_PACKET -//#define DUMP_INVALID_PACKET +#define DUMP_UNKNOWN_PACKET +#define DUMP_INVALID_PACKET struct Clif_Config { int packet_db_ver; //Preferred packet version. @@ -64,6 +64,7 @@ struct Clif_Config { } clif_config; struct s_packet_db packet_db[MAX_PACKET_VER + 1][MAX_PACKET_DB + 1]; +int packet_db_ack[MAX_PACKET_VER + 1][MAX_ACK_FUNC + 1]; //Converts item type in case of pet eggs. static inline int itemtype(int type) { @@ -6116,8 +6117,14 @@ void clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail) #endif } -// [Ind/Hercules] - Data Thanks to Yommy -void clif_cart_additem_ack(struct map_session_data *sd, int flag) +// [Ind/Hercules] - Data Thanks to Yommy (ZC_ACK_ADDITEM_TO_CART) +/* Acknowledge an item have been added to cart + * 012c B + * result : + * 0 = ADDITEM_TO_CART_FAIL_WEIGHT + * 1 = ADDITEM_TO_CART_FAIL_COUNT + */ +void clif_cart_additem_ack(struct map_session_data *sd, uint8 flag) { int fd; unsigned char *buf; @@ -6126,10 +6133,208 @@ void clif_cart_additem_ack(struct map_session_data *sd, int flag) fd = sd->fd; buf = WFIFOP(fd,0); WBUFW(buf,0) = 0x12c; - WBUFL(buf,2) = flag; + WBUFB(buf,2) = flag; clif_send(buf,packet_len(0x12c),&sd->bl,SELF); } +// 09B7 (ZC_ACK_OPEN_BANKING) +void clif_bank_open(struct map_session_data *sd){ + int fd = sd->fd; + + WFIFOHEAD(fd,4); + WFIFOW(fd,0) = 0x09b7; + WFIFOW(fd,2) = 0; + WFIFOSET(fd,4); + return; //TODO found out what going on here +} + +/* + * Request to Open the banking system + * 09B6 L ??? (dunno just wild guess checkme) + */ +void clif_parse_BankOpen(int fd, struct map_session_data* sd) { + //TODO check if preventing trade or stuff like that + //also mark something in case char ain't available for saving, should we check now ? + if( !battle_config.feature_banking ) { + clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1483)); + return; + } + else { + struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)]; + int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ? + sd->state.banking = 1; + } + //request save ? +// chrif_bankdata_request(sd->status.account_id, sd->status.char_id); + //on succes open bank ? + clif_bank_open(sd); + return; +} + +// 09B9 (ZC_ACK_CLOSE_BANKING) + +void clif_bank_close(struct map_session_data *sd){ + int fd = sd->fd; + + WFIFOHEAD(fd,4); + WFIFOW(fd,0) = 0x09B9; + WFIFOW(fd,2) = 0; + WFIFOSET(fd,4); + return; //TODO found out what going on here +} + +/* + * Request to close the banking system + * 09B8 L ??? (dunno just wild guess checkme) + */ +void clif_parse_BankClose(int fd, struct map_session_data* sd) { + struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)]; + int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ? + if( !battle_config.feature_banking ) { + clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1483)); + //still allow to go trough to not stuck player if we have disable it while they was in + } + sd->state.banking = 0; + clif_bank_close(sd); + return; +} + +/* + * Display how much we got in bank (I suppose) + 09A6 Q W (PACKET_ZC_BANKING_CHECK) + */ +void clif_Bank_Check(struct map_session_data* sd) { + unsigned char buf[13]; + struct s_packet_db* info; + int16 len; + int cmd = 0; + + nullpo_retv(sd); + + cmd = packet_db_ack[sd->packet_ver][ZC_BANKING_CHECK]; + if(!cmd) cmd = 0x09A6; //default + info = &packet_db[sd->packet_ver][cmd]; + len = info->len; +// sd->state.banking = 1; //mark opening and closing + + WBUFW(buf,0) = cmd; + WBUFQ(buf,info->pos[0]) = sd->status.bank_vault; //testig value + WBUFW(buf,info->pos[1]) = 0; //reason + clif_send(buf,len,&sd->bl,SELF); +} + +/* + * Requesting the data in bank + * 09AB L (PACKET_CZ_REQ_BANKING_CHECK) + */ +void clif_parse_BankCheck(int fd, struct map_session_data* sd) { + nullpo_retv(sd); + + if( !battle_config.feature_banking ) { + clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1483)); + return; + } + else { + struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)]; + int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ? + if(sd->status.account_id == aid) //since we have it let check it for extra security + clif_Bank_Check(sd); + } +} + +/* + * Acknowledge of deposit some money in bank + 09A8 W Q L (PACKET_ZC_ACK_BANKING_DEPOSIT) + */ +void clif_bank_deposit(struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK reason) { + unsigned char buf[17]; + struct s_packet_db* info; + int16 len; + int cmd =0; + + nullpo_retv(sd); + + cmd = packet_db_ack[sd->packet_ver][ZC_ACK_BANKING_DEPOSIT]; + if(!cmd) cmd = 0x09A8; + info = &packet_db[sd->packet_ver][cmd]; + len = info->len; + + WBUFW(buf,0) = cmd; + WBUFW(buf,info->pos[0]) = (short)reason; + WBUFQ(buf,info->pos[1]) = sd->status.bank_vault;/* money in the bank */ + WBUFL(buf,info->pos[2]) = sd->status.zeny;/* how much zeny char has after operation */ + clif_send(buf,len,&sd->bl,SELF); +} + +/* + * Request saving some money in bank + * @author : original [Yommy/Hercules] + * 09A7 L L (PACKET_CZ_REQ_BANKING_DEPOSIT) + */ +void clif_parse_BankDeposit(int fd, struct map_session_data* sd) { + if( !battle_config.feature_banking ) { + clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1483)); + return; + } + else { + struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)]; + int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ? + int money = RFIFOL(fd,info->pos[1]); + + if(sd->status.account_id == aid){ + money = max(0,money); + enum e_BANKING_DEPOSIT_ACK reason = pc_bank_deposit(sd,money); + clif_bank_deposit(sd,reason); + } + } +} + +/* + * Acknowledge of withdrawing some money from bank + 09AA W Q L (PACKET_ZC_ACK_BANKING_WITHDRAW) + */ +void clif_bank_withdraw(struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK reason) { + unsigned char buf[17]; + struct s_packet_db* info; + int16 len; + int cmd; + + nullpo_retv(sd); + + cmd = packet_db_ack[sd->packet_ver][ZC_ACK_BANKING_WITHDRAW]; + if(!cmd) cmd = 0x09AA; + info = &packet_db[sd->packet_ver][cmd]; + len = info->len; + + WBUFW(buf,0) = cmd; + WBUFW(buf,info->pos[0]) = (short)reason; + WBUFQ(buf,info->pos[1]) = sd->status.bank_vault;/* money in the bank */ + WBUFL(buf,info->pos[2]) = sd->status.zeny;/* how much zeny char has after operation */ + + clif_send(buf,len,&sd->bl,SELF); +} + +/* + * Request Withdrawing some money from bank + * 09A9 L L (PACKET_CZ_REQ_BANKING_WITHDRAW) + */ +void clif_parse_BankWithdraw(int fd, struct map_session_data* sd) { + if( !battle_config.feature_banking ) { + clif_colormes(sd,color_table[COLOR_RED],msg_txt(sd,1483)); + return; + } + else { + struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)]; + int aid = RFIFOL(fd,info->pos[0]); //unused should we check vs fd ? + int money = RFIFOL(fd,info->pos[1]); + if(sd->status.account_id == aid){ + money = max(0,money); + enum e_BANKING_WITHDRAW_ACK reason = pc_bank_withdraw(sd,money); + clif_bank_withdraw(sd,reason); + } + } +} + /// Deletes an item from character's cart (ZC_DELETE_ITEM_FROM_CART). /// 0125 .W .L void clif_cart_delitem(struct map_session_data *sd,int n,int amount) @@ -17069,9 +17274,9 @@ void packetdb_readdb(void) 0, 0, 0, 0, 0, 0, 0, 14, 6, 50, 0, 0, 0, 0, 0, 0, //#0x0980 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 31, 0, 0, 0, 0, 0, 0, -1, 8, 11, 9, 8, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, + 31, 0, 0, 0, 0, 0, 0, -1, 8, 11, 9, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 10, 14, 10, 14, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 4, 6, 4, 0, 0, 0, 0, 0, 0, }; struct { @@ -17261,6 +17466,12 @@ void packetdb_readdb(void) {clif_parse_PartyBookingUpdateReq,"bookingupdatereq"}, {clif_parse_PartyBookingDeleteReq,"bookingdelreq"}, #endif + {clif_parse_BankCheck,"bankcheck"}, + {clif_parse_BankDeposit,"bankdeposit"}, + {clif_parse_BankWithdraw,"bankwithdrawal"}, + {clif_parse_BankOpen,"bankopen"}, + {clif_parse_BankClose,"bankclose"}, + {clif_parse_PVPInfo,"pvpinfo"}, {clif_parse_LessEffect,"lesseffect"}, // Buying Store @@ -17288,6 +17499,15 @@ void packetdb_readdb(void) { clif_parse_ranklist, "ranklist"}, {NULL,NULL} }; + struct { + char *name; //function name + int funcidx; // + } clif_ack_func[]={ //hash + { "ZC_ACK_OPEN_BANKING", ZC_ACK_OPEN_BANKING}, + { "ZC_ACK_BANKING_DEPOSIT", ZC_ACK_BANKING_DEPOSIT}, + { "ZC_ACK_BANKING_WITHDRAW", ZC_ACK_BANKING_WITHDRAW}, + { "ZC_BANKING_CHECK", ZC_BANKING_CHECK}, + }; // initialize packet_db[SERVER] from hardcoded packet_len_table[] values memset(packet_db,0,sizeof(packet_db)); @@ -17344,6 +17564,7 @@ void packetdb_readdb(void) // copy from previous version into new version and continue // - indicating all following packets should be read into the newer version memcpy(&packet_db[packet_ver], &packet_db[prev_ver], sizeof(packet_db[0])); + memcpy(&packet_db_ack[packet_ver], &packet_db_ack[prev_ver], sizeof(packet_db_ack[0])); continue; } else if(strcmpi(w1,"packet_db_ver")==0) { if(strcmpi(w2,"default")==0) //This is the preferred version. @@ -17390,7 +17611,15 @@ void packetdb_readdb(void) ARR_FIND( 0, ARRAYLENGTH(clif_parse_func), j, clif_parse_func[j].name != NULL && strcmp(str[2],clif_parse_func[j].name)==0 ); if( j < ARRAYLENGTH(clif_parse_func) ) packet_db[packet_ver][cmd].func = clif_parse_func[j].func; - + else { //search if it's a mapped ack func + ARR_FIND( 0, ARRAYLENGTH(clif_ack_func), j, clif_ack_func[j].name != NULL && strcmp(str[2],clif_ack_func[j].name)==0 ); + if( j < ARRAYLENGTH(clif_ack_func)) { + int fidx = clif_ack_func[j].funcidx; + packet_db_ack[packet_ver][fidx] = cmd; + ShowInfo("Added %s, <=> %X i=%d for v=%d\n",clif_ack_func[j].name,cmd,fidx,packet_ver); + } + } + // set the identifying cmd for the packet_db version if (strcmp(str[2],"wanttoconnection")==0) clif_config.connect_cmd[packet_ver] = cmd; diff --git a/src/map/clif.h b/src/map/clif.h index 4cf641205b..340f1234dc 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -35,20 +35,42 @@ struct party_booking_ad_info; enum {// packet DB MAX_PACKET_DB = 0xf00, - MAX_PACKET_VER = 44, + MAX_PACKET_VER = 45, MAX_PACKET_POS = 20, }; +enum e_packet_ack { + ZC_ACK_OPEN_BANKING = 0, + ZC_ACK_BANKING_DEPOSIT, + ZC_ACK_BANKING_WITHDRAW, + ZC_BANKING_CHECK, + MAX_ACK_FUNC //auto upd len +}; + struct s_packet_db { short len; void (*func)(int, struct map_session_data *); short pos[MAX_PACKET_POS]; }; +enum e_BANKING_DEPOSIT_ACK { + BDA_SUCCESS = 0x0, + BDA_ERROR = 0x1, + BDA_NO_MONEY = 0x2, + BDA_OVERFLOW = 0x3, +}; + +enum e_BANKING_WITHDRAW_ACK { + BWA_SUCCESS = 0x0, + BWA_NO_MONEY = 0x1, + BWA_UNKNOWN_ERROR = 0x2, +}; + // packet_db[SERVER] is reserved for server use #define SERVER 0 #define packet_len(cmd) packet_db[SERVER][cmd].len extern struct s_packet_db packet_db[MAX_PACKET_VER+1][MAX_PACKET_DB+1]; +extern int packet_db_ack[MAX_PACKET_VER + 1][MAX_ACK_FUNC + 1]; // local define typedef enum send_target { @@ -58,7 +80,7 @@ typedef enum send_target { AREA_WOS, // area, without self AREA_WOC, // area, without chatrooms AREA_WOSC, // area, without own chatroom - AREA_CHAT_WOC, // hearable area, without chatrooms + AREA_CHAT_WOC, // hearable area, without chatrooms CHAT, // current chatroom CHAT_WOS, // current chatroom, without self PARTY, @@ -488,7 +510,7 @@ void clif_inventorylist(struct map_session_data *sd); void clif_equiplist(struct map_session_data *sd); void clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail); -void clif_cart_additem_ack(struct map_session_data *sd, int flag); +void clif_cart_additem_ack(struct map_session_data *sd, uint8 flag); void clif_cart_delitem(struct map_session_data *sd,int n,int amount); void clif_cartlist(struct map_session_data *sd); void clif_clearcart(int fd); @@ -715,6 +737,15 @@ void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_boo void clif_PartyBookingDeleteNotify(struct map_session_data* sd, int index); void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad); +/* Bank System [Yommy/Hercules] */ +void clif_bank_deposit (struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK reason); +void clif_bank_withdraw (struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK reason); +void clif_parse_BankDeposit (int fd, struct map_session_data *sd); +void clif_parse_BankWithdraw (int fd, struct map_session_data *sd); +void clif_parse_BankCheck (int fd, struct map_session_data *sd); +void clif_parse_BankOpen (int fd, struct map_session_data *sd); +void clif_parse_BankClose (int fd, struct map_session_data *sd); + void clif_showdigit(struct map_session_data* sd, unsigned char type, int value); /// Buying Store System diff --git a/src/map/log.c b/src/map/log.c index 54be3e96c5..2b41f0c8b8 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -73,6 +73,7 @@ static char log_picktype2char(e_log_pick_type type) case LOG_TYPE_AUCTION: return 'I'; // Auct(I)on case LOG_TYPE_BUYING_STORE: return 'B'; // (B)uying Store case LOG_TYPE_LOOT: return 'L'; // (L)oot (consumed monster pick/drop) + case LOG_TYPE_BANK: return 'K'; // Ban(K) Transactions case LOG_TYPE_OTHER: return 'X'; // Other case LOG_TYPE_CASH: return '$'; // Cash } diff --git a/src/map/log.h b/src/map/log.h index 8341dee453..35bc4ad0ce 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -45,6 +45,7 @@ typedef enum e_log_pick_type LOG_TYPE_BUYING_STORE = 0x08000, LOG_TYPE_OTHER = 0x10000, LOG_TYPE_CASH = 0x20000, + LOG_TYPE_BANK = 0x40000, // combinations LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME, // all diff --git a/src/map/pc.c b/src/map/pc.c index 2b6d1e7108..5e68854049 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1292,6 +1292,7 @@ int pc_reg_received(struct map_session_data *sd) status_calc_pc(sd,1); chrif_scdata_request(sd->status.account_id, sd->status.char_id); chrif_skillcooldown_request(sd->status.account_id, sd->status.char_id); + chrif_bankdata_request(sd->status.account_id, sd->status.char_id); intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox intif_request_questlog(sd); @@ -4343,6 +4344,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_HIDING] || sd->sc.data[SC__SHADOWFORM] || + sd->sc.data[SC__INVISIBILITY] || sd->sc.data[SC__MANHOLE] || sd->sc.data[SC_KAGEHUMI] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) @@ -10248,6 +10250,46 @@ void pc_damage_log_clear(struct map_session_data *sd, int id) } } +enum e_BANKING_DEPOSIT_ACK pc_bank_deposit(struct map_session_data *sd, int money) { + unsigned int limit_check = money+sd->status.bank_vault; + + if( money <= 0 || limit_check > MAX_BANK_ZENY ) { + return BDA_OVERFLOW; + } else if ( money > sd->status.zeny ) { + return BDA_NO_MONEY; + } + + if( pc_payzeny(sd,money, LOG_TYPE_BANK, NULL) ) + return BDA_NO_MONEY; + + sd->status.bank_vault += money; + if( save_settings&256 ) + chrif_save(sd,0); + return BDA_SUCCESS; +} + +enum e_BANKING_WITHDRAW_ACK pc_bank_withdraw(struct map_session_data *sd, int money) { + unsigned int limit_check = money+sd->status.zeny; + + if( money <= 0 ) { + return BWA_UNKNOWN_ERROR; + } else if ( money > sd->status.bank_vault ) { + return BWA_NO_MONEY; + } else if ( limit_check > MAX_ZENY ) { + /* no official response for this scenario exists. */ + clif_colormes(sd,COLOR_RED,msg_txt(sd,1482)); + return BWA_UNKNOWN_ERROR; + } + + if( pc_getzeny(sd,money, LOG_TYPE_BANK, NULL) ) + return BWA_NO_MONEY; + + sd->status.bank_vault -= money; + if( save_settings&256 ) + chrif_save(sd,0); + return BWA_SUCCESS; +} + /*========================================== * pc Init/Terminate *------------------------------------------*/ diff --git a/src/map/pc.h b/src/map/pc.h index 087619f5c5..8cf9b9b3f1 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -192,6 +192,7 @@ struct map_session_data { unsigned int prevend : 1;//used to flag wheather you've spent 40sp to open the vending or not. unsigned int warping : 1;//states whether you're in the middle of a warp processing unsigned int permanent_speed : 1; // When 1, speed cannot be changed through status_calc_pc(). + unsigned int banking : 1; //1 when we using the banking system 0 when closed } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -1010,6 +1011,9 @@ void pc_baselevelchanged(struct map_session_data *sd); void pc_damage_log_add(struct map_session_data *sd, int id); void pc_damage_log_clear(struct map_session_data *sd, int id); +enum e_BANKING_DEPOSIT_ACK pc_bank_deposit(struct map_session_data *sd, int money); +enum e_BANKING_WITHDRAW_ACK pc_bank_withdraw(struct map_session_data *sd, int money); + #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_race, uint32 mob_mode, int type); #endif diff --git a/src/map/status.c b/src/map/status.c index c23175ab3f..d5c2839605 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1212,7 +1212,6 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp, in status_change_end(target, SC_CLOAKING, INVALID_TIMER); status_change_end(target, SC_CHASEWALK, INVALID_TIMER); status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(target, SC__INVISIBILITY, INVALID_TIMER); status_change_end(target, SC_DEEPSLEEP, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4) { //Endure count is only reduced by non-players on non-gvg maps.