浏览代码

Adding banking support

lighta 11 年之前
父节点
当前提交
1290826be2

+ 5 - 1
conf/battle/feature.conf

@@ -17,4 +17,8 @@ feature.search_stores: on
 
 
 // Atcommand suggestions (Note 1)
 // Atcommand suggestions (Note 1)
 // If one type incomplete atcommand, it will suggest the complete ones.
 // If one type incomplete atcommand, it will suggest the complete ones.
-feature.atcommand_suggestions: off
+feature.atcommand_suggestions: off
+
+// Banking (Note 1)
+// Requires: 2013-07-24aRagexe or later
+feature.banking: on

+ 1 - 0
conf/inter_athena.conf

@@ -103,6 +103,7 @@ mercenary_db: mercenary
 mercenary_owner_db: mercenary_owner
 mercenary_owner_db: mercenary_owner
 elemental_db: elemental
 elemental_db: elemental
 ragsrvinfo_db: ragsrvinfo
 ragsrvinfo_db: ragsrvinfo
+skillcooldown_db: skillcooldown
 
 
 // Map Database Tables
 // Map Database Tables
 item_db_db: item_db
 item_db_db: item_db

+ 1 - 0
conf/log_athena.conf

@@ -28,6 +28,7 @@
 // 0x10000 - (X) Log all other transactions (rentals expiring/inserting cards/items removed by item_check/
 // 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)
 //           rings deleted by divorce/pet egg (un)hatching/pet armor (un)equipping/Weapon Refine skill/Remove Trap skill)
 // 0x20000 - ($) Log cash transactions
 // 0x20000 - ($) Log cash transactions
+// 0x40000 - (K) Log account bank transactions
 // Example: Log trades+vending+script items+created items: 1+2+32+1024 = 1059
 // 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.
 // Please note that moving items from inventory to cart and back is not logged by design.
 enable_logs: 0xFFFFF
 enable_logs: 0xFFFFF

+ 2 - 1
conf/map_athena.conf

@@ -101,11 +101,12 @@ minsave_time: 100
 // 16: After successfully sending a mail with attachment
 // 16: After successfully sending a mail with attachment
 // 32: After successfully submitting an item for auction
 // 32: After successfully submitting an item for auction
 // 64: After successfully get/delete/complete a quest
 // 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
 // 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 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
 // server rarely crashes, but experiences interserver lag, you may want to set
 // these off.
 // these off.
-save_settings: 127
+save_settings: 255
 
 
 // Message of the day file, when a character logs on, this message is displayed.
 // Message of the day file, when a character logs on, this message is displayed.
 motd_txt: conf/motd.txt
 motd_txt: conf/motd.txt

+ 4 - 0
conf/msg_conf/map_msg.conf

@@ -1493,5 +1493,9 @@
 1490: Item types on your autoloottype list:
 1490: Item types on your autoloottype list:
 1491: Your autoloottype list has been reset.
 1491: Your autoloottype list has been reset.
 
 
+//Banking
+1492: You can't withdraw that much money
+1493: Banking is disabled
+
 //Custom translations
 //Custom translations
 //import: conf/msg_conf/import/map_msg_eng_conf.txt
 //import: conf/msg_conf/import/map_msg_eng_conf.txt

+ 42 - 0
db/packet_db.txt

@@ -2190,3 +2190,45 @@ packet_ver: 44
 0x0863,26,friendslistadd,2
 0x0863,26,friendslistadd,2
 0x088A,5,hommenu,2:4
 0x088A,5,hommenu,2:4
 0x095B,36,storagepassword,2:4:20
 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

+ 1 - 0
sql-files/main.sql

@@ -459,6 +459,7 @@ CREATE TABLE IF NOT EXISTS `login` (
   `character_slots` tinyint(3) unsigned NOT NULL default '0',
   `character_slots` tinyint(3) unsigned NOT NULL default '0',
   `pincode` varchar(4) NOT NULL DEFAULT '',
   `pincode` varchar(4) NOT NULL DEFAULT '',
   `pincode_change` int(11) unsigned NOT NULL DEFAULT '0',
   `pincode_change` int(11) unsigned NOT NULL DEFAULT '0',
+  `bank_vault` BIGINT(64) NOT NULL DEFAULT '0',
   PRIMARY KEY  (`account_id`),
   PRIMARY KEY  (`account_id`),
   KEY `name` (`userid`)
   KEY `name` (`userid`)
 ) ENGINE=MyISAM AUTO_INCREMENT=2000000; 
 ) ENGINE=MyISAM AUTO_INCREMENT=2000000; 

+ 1 - 0
sql-files/upgrades/upgrade_svn17600.sql

@@ -0,0 +1 @@
+ALTER TABLE `login` ADD `bank_vault` BIGINT( 64 ) NOT NULL DEFAULT '0';

+ 93 - 4
src/char/char.c

@@ -143,6 +143,7 @@ struct char_session_data {
 	time_t pincode_change;
 	time_t pincode_change;
 	uint16 pincode_try;
 	uint16 pincode_try;
 	// Addon system
 	// Addon system
+	int bank_vault;
 	unsigned int char_moves[MAX_CHARS]; // character moves left
 	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 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 );
 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]
 //Custom limits for the fame lists. [Skotlex]
 int fame_list_size_chemist = MAX_FAME_LIST;
 int fame_list_size_chemist = MAX_FAME_LIST;
 int fame_list_size_smith = 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
 		} else
 			strcat(save_status, " status");
 			strcat(save_status, " status");
 	}
 	}
-
+	
 	//Values that will seldom change (to speed up saving)
 	//Values that will seldom change (to speed up saving)
 	if (
 	if (
 		(p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) ||
 		(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
 		else
 			errors++;
 			errors++;
 	}
 	}
-
+	
 	//memo points
 	//memo points
 	if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) )
 	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);
 int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
 void mapif_server_reset(int id);
 void mapif_server_reset(int id);
 
 
+/*
+ * HA 0x2740<aid>L <type>B <data>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 0x2741<aid>L <bank_vault>L <not_fw>B
+ * HZ 0x2b29 <aid>L <bank_vault>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 <aid>L <bank_vault>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 <aid>L <money>L
+ * HA 0x2740<aid>L <type>B <money>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 <aid>L
+ * HA 0x2740<aid>L <type>B <money>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.
 /// Resets all the data.
 void loginif_reset(void)
 void loginif_reset(void)
@@ -2230,6 +2314,7 @@ int parse_fromlogin(int fd) {
 
 
 		switch( command )
 		switch( command )
 		{
 		{
+		case 0x2741: loginif_parse_BankingAck(fd); break;
 
 
 		// acknowledgement of connect-to-loginserver request
 		// acknowledgement of connect-to-loginserver request
 		case 0x2711:
 		case 0x2711:
@@ -2289,7 +2374,7 @@ int parse_fromlogin(int fd) {
 		break;
 		break;
 
 
 		case 0x2717: // account data
 		case 0x2717: // account data
-			if (RFIFOREST(fd) < 72)
+			if (RFIFOREST(fd) < 76)
 				return 0;
 				return 0;
 
 
 			// find the authenticated session with this account id
 			// 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->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
 				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
 				safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
 				sd->pincode_change = (time_t)RFIFOL(fd,68);
 				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] );
 				ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
 				// continued from char_auth_ok...
 				// continued from char_auth_ok...
 				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
 				if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
@@ -2355,7 +2441,7 @@ int parse_fromlogin(int fd) {
 #endif
 #endif
 				}
 				}
 			}
 			}
-			RFIFOSKIP(fd,72);
+			RFIFOSKIP(fd,76);
 		break;
 		break;
 
 
 		// login-server alive packet
 		// login-server alive packet
@@ -3579,6 +3665,9 @@ int parse_frommap(int fd)
 				RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
 				RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
 		}
 		}
 		break;
 		break;
+		
+		case 0x2b28: mapif_parse_UpdBankInfo(fd); break;
+		case 0x2b2a: mapif_parse_ReqBankInfo(fd); break; 
 
 
 		default:
 		default:
 		{
 		{

+ 3 - 1
src/common/mmo.h

@@ -47,7 +47,7 @@
 // 20120307 - 2012-03-07aRagexeRE+ - 0x970
 // 20120307 - 2012-03-07aRagexeRE+ - 0x970
 
 
 #ifndef PACKETVER
 #ifndef PACKETVER
-	#define PACKETVER 20120410
+	#define PACKETVER 20130724
 	//#define PACKETVER 20130320
 	//#define PACKETVER 20130320
 	//#define PACKETVER 20111116
 	//#define PACKETVER 20111116
 #endif
 #endif
@@ -79,6 +79,7 @@
 //Max amount of a single stacked item
 //Max amount of a single stacked item
 #define MAX_AMOUNT 30000
 #define MAX_AMOUNT 30000
 #define MAX_ZENY 1000000000
 #define MAX_ZENY 1000000000
+#define MAX_BANK_ZENY SINT32_MAX
 #define MAX_FAME 1000000000
 #define MAX_FAME 1000000000
 #define MAX_CART 100
 #define MAX_CART 100
 #define MAX_SKILL 5020
 #define MAX_SKILL 5020
@@ -351,6 +352,7 @@ struct mmo_charstatus {
 
 
 	unsigned int base_exp,job_exp;
 	unsigned int base_exp,job_exp;
 	int zeny;
 	int zeny;
+	int bank_vault;
 
 
 	short class_;
 	short class_;
 	unsigned int status_point,skill_point;
 	unsigned int status_point,skill_point;

+ 1 - 0
src/login/account.h

@@ -53,6 +53,7 @@ struct mmo_account
 	char pincode[PINCODE_LENGTH+1];		// pincode system
 	char pincode[PINCODE_LENGTH+1];		// pincode system
 	time_t pincode_change;	// (timestamp): last time of pincode change
 	time_t pincode_change;	// (timestamp): last time of pincode change
 	int account_reg2_num;
 	int account_reg2_num;
+	int bank_vault;
 	struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server)
 	struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server)
 };
 };
 
 

+ 37 - 34
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
 	// retrieve login entry for the specified account
 	if( SQL_ERROR == Sql_Query(sql_handle,
 	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 )
 		db->account_db, account_id )
 	) {
 	) {
 		Sql_ShowDebug(sql_handle);
 		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, 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, 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, 15, &data, NULL); acc->pincode_change = atol(data);
+	Sql_GetData(sql_handle, 16, &data, NULL); acc->bank_vault = atoi(data);
 
 
 	Sql_FreeResult(sql_handle);
 	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 )
 	if( is_new )
 	{// insert into account table
 	{// insert into account table
 		if( SQL_SUCCESS != SqlStmt_Prepare(stmt,
 		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)
 			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)
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
 		) {
 		) {
 			SqlStmt_ShowDebug(stmt);
 			SqlStmt_ShowDebug(stmt);
@@ -625,22 +627,23 @@ static bool mmo_auth_tosql(AccountDB_SQL* db, const struct mmo_account* acc, boo
 	}
 	}
 	else
 	else
 	{// update account table
 	{// 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)
 		||  SQL_SUCCESS != SqlStmt_Execute(stmt)
 		) {
 		) {
 			SqlStmt_ShowDebug(stmt);
 			SqlStmt_ShowDebug(stmt);

+ 35 - 4
src/login/login.c

@@ -567,6 +567,7 @@ int parse_fromchar(int fd){
 				char birthdate[10+1] = "";
 				char birthdate[10+1] = "";
 				char pincode[PINCODE_LENGTH+1];
 				char pincode[PINCODE_LENGTH+1];
 				int account_id = RFIFOL(fd,2);
 				int account_id = RFIFOL(fd,2);
+				int bank_vault = 0;
 
 
 				memset(pincode,0,PINCODE_LENGTH+1);
 				memset(pincode,0,PINCODE_LENGTH+1);
 
 
@@ -581,9 +582,10 @@ int parse_fromchar(int fd){
 					char_slots = acc.char_slots;
 					char_slots = acc.char_slots;
 					safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
 					safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
 					safestrncpy(pincode, acc.pincode, sizeof(pincode));
 					safestrncpy(pincode, acc.pincode, sizeof(pincode));
+					bank_vault = acc.bank_vault;
 				}
 				}
 
 
-				WFIFOHEAD(fd,72);
+				WFIFOHEAD(fd,76);
 				WFIFOW(fd,0) = 0x2717;
 				WFIFOW(fd,0) = 0x2717;
 				WFIFOL(fd,2) = account_id;
 				WFIFOL(fd,2) = account_id;
 				safestrncpy((char*)WFIFOP(fd,6), email, 40);
 				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,52), birthdate, 10+1);
 				safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
 				safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
 				WFIFOL(fd,68) = (uint32)acc.pincode_change;
 				WFIFOL(fd,68) = (uint32)acc.pincode_change;
-				WFIFOSET(fd,72);
+				WFIFOL(fd,72) = bank_vault;
+				WFIFOSET(fd,76);
 			}
 			}
 		break;
 		break;
 
 
@@ -907,13 +910,11 @@ int parse_fromchar(int fd){
 				return 0;
 				return 0;
 			else{
 			else{
 				struct mmo_account acc;
 				struct mmo_account acc;
-
 				if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
 				if( accounts->load_num(accounts, &acc, RFIFOL(fd,2) ) ){
 					strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
 					strncpy( acc.pincode, (char*)RFIFOP(fd,6), 5 );
 					acc.pincode_change = time( NULL );
 					acc.pincode_change = time( NULL );
 					accounts->save(accounts, &acc);
 					accounts->save(accounts, &acc);
 				}
 				}
-
 				RFIFOSKIP(fd,11);
 				RFIFOSKIP(fd,11);
 			}
 			}
 		break;
 		break;
@@ -941,6 +942,35 @@ int parse_fromchar(int fd){
 			}
 			}
 		break;
 		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:
 		default:
 			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
 			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
 			set_eof(fd);
 			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.pincode_change = 0;
 
 
 	acc.char_slots = 0;
 	acc.char_slots = 0;
+	acc.bank_vault = 0;
 
 
 	if( !accounts->create(accounts, &acc) )
 	if( !accounts->create(accounts, &acc) )
 		return 0;
 		return 0;

+ 8 - 0
src/map/battle.c

@@ -7138,6 +7138,7 @@ static const struct _battle_data {
 	{ "item_flooritem_check",               &battle_config.item_onfloor,                    1,      0,      1,              },
 	{ "item_flooritem_check",               &battle_config.item_onfloor,                    1,      0,      1,              },
 	{ "bowling_bash_area",                  &battle_config.bowling_bash_area,               0,      0,      20,             },
 	{ "bowling_bash_area",                  &battle_config.bowling_bash_area,               0,      0,      20,             },
 	{ "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
 	{ "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
+	{ "feature.banking",                    &battle_config.feature_banking,                 1,      0,      1,              },
 };
 };
 #ifndef STATS_OPT_OUT
 #ifndef STATS_OPT_OUT
 /**
 /**
@@ -7352,6 +7353,13 @@ void battle_adjust_conf()
 	}
 	}
 #endif
 #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
 #ifndef CELL_NOSTACK
 	if (battle_config.cell_stack_limit != 1)
 	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");
 		ShowWarning("Battle setting 'cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");

+ 1 - 0
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 item_onfloor; // Whether to drop an undroppable item on the map or destroy it if inventory is full.
 	int bowling_bash_area;
 	int bowling_bash_area;
 	int drop_rateincrease;
 	int drop_rateincrease;
+	int feature_banking;
 
 
 } battle_config;
 } battle_config;
 
 

+ 1 - 0
src/map/channel.c

@@ -101,6 +101,7 @@ int channel_delete(struct Channel *channel) {
 	}
 	}
 	default:
 	default:
 		strdb_remove(channel_db, channel->name);
 		strdb_remove(channel_db, channel->name);
+                aFree(channel);
 		break;
 		break;
 	}
 	}
 	return 0;
 	return 0;

+ 88 - 42
src/map/chrif.c

@@ -34,6 +34,7 @@
 #include <time.h>
 #include <time.h>
 
 
 static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_t data);
 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 struct eri *auth_db_ers; //For reutilizing player login structures.
 static DBMap* auth_db; // int id -> struct auth_node*
 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
 	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
 	 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
 	-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:
 //Used Packets:
 //2af8: Outgoing, chrif_connect -> 'connect to charserver / auth @ charserver'
 //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'
 //2b07: Outgoing, chrif_removefriend -> 'Tell charserver to remove friend_id from char_id friend list'
 //2b08: Outgoing, chrif_searchcharid -> '...'
 //2b08: Outgoing, chrif_searchcharid -> '...'
 //2b09: Incoming, map_addchariddb -> 'Adds a name to the nick db'
 //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 ...'
 //2b0c: Outgoing, chrif_changeemail -> 'change mail address ...'
 //2b0d: Incoming, chrif_changedsex -> 'Change sex of acc XY'
 //2b0d: Incoming, chrif_changedsex -> 'Change sex of acc XY'
 //2b0e: Outgoing, chrif_char_ask_name -> 'Do some operations (change sex, ban / unban etc)'
 //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
 //2b12: Incoming, chrif_divorceack -> 'divorce chars
 //2b13: FREE
 //2b13: FREE
 //2b14: Incoming, chrif_accountban -> 'not sure: kick the player with message XY'
 //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 ....'
 //2b16: Outgoing, chrif_ragsrvinfo -> 'sends base / job / drop rates ....'
 //2b17: Outgoing, chrif_char_offline -> 'tell the charserver that the char is now offline'
 //2b17: Outgoing, chrif_char_offline -> 'tell the charserver that the char is now offline'
 //2b18: Outgoing, chrif_char_reset_offline -> 'set all players OFF!'
 //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'
 //2b25: Incoming, chrif_deadopt -> 'Removes baby from Father ID and Mother ID'
 //2b26: Outgoing, chrif_authreq -> 'client authentication request'
 //2b26: Outgoing, chrif_authreq -> 'client authentication request'
 //2b27: Incoming, chrif_authfail -> 'client authentication failed'
 //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 chrif_connected = 0;
 int char_fd = -1;
 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
 	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]
 		//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) )
 		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);
 			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;
 	WFIFOL(char_fd,6) = char_id;
 	WFIFOSET(char_fd,10);
 	WFIFOSET(char_fd,10);
 #endif
 #endif
-    return 0;
+	return 0;
 }
 }
 
 
 /*==========================================
 /*==========================================
  * Request skillcooldown from charserver
  * Request skillcooldown from charserver
  *------------------------------------------*/
  *------------------------------------------*/
 int chrif_skillcooldown_request(int account_id, int char_id) {
 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;
 	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]
 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
 #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
 	WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size
 	WFIFOSET(char_fd,WFIFOW(char_fd,2));
 	WFIFOSET(char_fd,WFIFOW(char_fd,2));
 #endif
 #endif
-    return 0;
+	return 0;
 }
 }
 
 
 int chrif_skillcooldown_save(struct map_session_data *sd) {
 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);
 		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
 #endif
-    return 0;
+	return 0;
 }
 }
 
 
 //Retrieve and load skillcooldown for a player
 //Retrieve and load skillcooldown for a player
 
 
 int chrif_skillcooldown_load(int fd) {
 int chrif_skillcooldown_load(int fd) {
-    struct map_session_data *sd;
-    struct skill_cooldown_data *data;
-    int aid, cid, i, count;
-
-    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;
+	struct map_session_data *sd;
+	struct skill_cooldown_data *data;
+	int aid, cid, i, count;
+
+	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;
 }
 }
 
 
 /*==========================================
 /*==========================================
@@ -1522,7 +1567,7 @@ int chrif_parse(int fd) {
 			case 0x2b04: chrif_recvmap(fd); break;
 			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 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 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 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 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;
 			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 0x2b24: chrif_keepalive_ack(fd); break;
 			case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
 			case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
 			case 0x2b27: chrif_authfail(fd); break;
 			case 0x2b27: chrif_authfail(fd); break;
+			case 0x2b29: chrif_load_bankdata(fd); break;
 			default:
 			default:
 				ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);
 				ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);
 				set_eof(fd);
 				set_eof(fd);

+ 3 - 0
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_request(int account_id, int char_id);
 int chrif_skillcooldown_save(struct map_session_data *sd);
 int chrif_skillcooldown_save(struct map_session_data *sd);
 int chrif_skillcooldown_load(int fd);
 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_save(struct map_session_data* sd, int flag);
 int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip);
 int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip);
 int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port);
 int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port);

+ 238 - 9
src/map/clif.c

@@ -55,8 +55,8 @@
 /* for clif_clearunit_delayed */
 /* for clif_clearunit_delayed */
 static struct eri *delay_clearunit_ers;
 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 {
 struct Clif_Config {
 	int packet_db_ver;	//Preferred packet version.
 	int packet_db_ver;	//Preferred packet version.
@@ -64,6 +64,7 @@ struct Clif_Config {
 } clif_config;
 } clif_config;
 
 
 struct s_packet_db packet_db[MAX_PACKET_VER + 1][MAX_PACKET_DB + 1];
 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.
 //Converts item type in case of pet eggs.
 static inline int itemtype(int type) {
 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
 #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 <result>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;
 	int fd;
 	unsigned char *buf;
 	unsigned char *buf;
@@ -6126,10 +6133,208 @@ void clif_cart_additem_ack(struct map_session_data *sd, int flag)
 	fd = sd->fd;
 	fd = sd->fd;
 	buf = WFIFOP(fd,0);
 	buf = WFIFOP(fd,0);
 	WBUFW(buf,0) = 0x12c;
 	WBUFW(buf,0) = 0x12c;
-	WBUFL(buf,2) = flag;
+	WBUFB(buf,2) = flag;
 	clif_send(buf,packet_len(0x12c),&sd->bl,SELF);
 	clif_send(buf,packet_len(0x12c),&sd->bl,SELF);
 }
 }
 
 
+// 09B7 <unknow data> (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 <aid>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 <unknow data> (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 <aid>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 <Bank_Vault>Q <Reason>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 <aid>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 <Reason>W <Money>Q <balance>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 <AID>L <Money>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 <Reason>W <Money>Q <balance>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 <AID>L <Money>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).
 /// Deletes an item from character's cart (ZC_DELETE_ITEM_FROM_CART).
 /// 0125 <index>.W <amount>.L
 /// 0125 <index>.W <amount>.L
 void clif_cart_delitem(struct map_session_data *sd,int n,int amount)
 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,
 		0,  0,  0,  0,  0,  0,  0, 14,  6, 50,  0,  0,  0,  0,  0,  0,
 	//#0x0980
 	//#0x0980
 		0,  0,  0, 29,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 		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 {
 	struct {
@@ -17261,6 +17466,12 @@ void packetdb_readdb(void)
 		{clif_parse_PartyBookingUpdateReq,"bookingupdatereq"},
 		{clif_parse_PartyBookingUpdateReq,"bookingupdatereq"},
 		{clif_parse_PartyBookingDeleteReq,"bookingdelreq"},
 		{clif_parse_PartyBookingDeleteReq,"bookingdelreq"},
 #endif
 #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_PVPInfo,"pvpinfo"},
 		{clif_parse_LessEffect,"lesseffect"},
 		{clif_parse_LessEffect,"lesseffect"},
 		// Buying Store
 		// Buying Store
@@ -17288,6 +17499,15 @@ void packetdb_readdb(void)
 		{ clif_parse_ranklist, "ranklist"},
 		{ clif_parse_ranklist, "ranklist"},
 		{NULL,NULL}
 		{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
 	// initialize packet_db[SERVER] from hardcoded packet_len_table[] values
 	memset(packet_db,0,sizeof(packet_db));
 	memset(packet_db,0,sizeof(packet_db));
@@ -17344,6 +17564,7 @@ void packetdb_readdb(void)
 				// copy from previous version into new version and continue
 				// copy from previous version into new version and continue
 				// - indicating all following packets should be read into the newer version
 				// - 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[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;
 				continue;
 			} else if(strcmpi(w1,"packet_db_ver")==0) {
 			} else if(strcmpi(w1,"packet_db_ver")==0) {
 				if(strcmpi(w2,"default")==0) //This is the preferred version.
 				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 );
 		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) )
 		if( j < ARRAYLENGTH(clif_parse_func) )
 			packet_db[packet_ver][cmd].func = clif_parse_func[j].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
 		// set the identifying cmd for the packet_db version
 		if (strcmp(str[2],"wanttoconnection")==0)
 		if (strcmp(str[2],"wanttoconnection")==0)
 			clif_config.connect_cmd[packet_ver] = cmd;
 			clif_config.connect_cmd[packet_ver] = cmd;

+ 34 - 3
src/map/clif.h

@@ -35,20 +35,42 @@ struct party_booking_ad_info;
 enum
 enum
 {// packet DB
 {// packet DB
 	MAX_PACKET_DB  = 0xf00,
 	MAX_PACKET_DB  = 0xf00,
-	MAX_PACKET_VER = 44,
+	MAX_PACKET_VER = 45,
 	MAX_PACKET_POS = 20,
 	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 {
 struct s_packet_db {
 	short len;
 	short len;
 	void (*func)(int, struct map_session_data *);
 	void (*func)(int, struct map_session_data *);
 	short pos[MAX_PACKET_POS];
 	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
 // packet_db[SERVER] is reserved for server use
 #define SERVER 0
 #define SERVER 0
 #define packet_len(cmd) packet_db[SERVER][cmd].len
 #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 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
 // local define
 typedef enum send_target {
 typedef enum send_target {
@@ -58,7 +80,7 @@ typedef enum send_target {
 	AREA_WOS,			// area, without self
 	AREA_WOS,			// area, without self
 	AREA_WOC,			// area, without chatrooms
 	AREA_WOC,			// area, without chatrooms
 	AREA_WOSC,			// area, without own chatroom
 	AREA_WOSC,			// area, without own chatroom
-	AREA_CHAT_WOC,		// hearable area, without chatrooms
+	AREA_CHAT_WOC,			// hearable area, without chatrooms
 	CHAT,				// current chatroom
 	CHAT,				// current chatroom
 	CHAT_WOS,			// current chatroom, without self
 	CHAT_WOS,			// current chatroom, without self
 	PARTY,
 	PARTY,
@@ -488,7 +510,7 @@ void clif_inventorylist(struct map_session_data *sd);
 void clif_equiplist(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(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_cart_delitem(struct map_session_data *sd,int n,int amount);
 void clif_cartlist(struct map_session_data *sd);
 void clif_cartlist(struct map_session_data *sd);
 void clif_clearcart(int fd);
 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_PartyBookingDeleteNotify(struct map_session_data* sd, int index);
 void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad);
 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);
 void clif_showdigit(struct map_session_data* sd, unsigned char type, int value);
 
 
 /// Buying Store System
 /// Buying Store System

+ 1 - 0
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_AUCTION:          return 'I';  // Auct(I)on
 		case LOG_TYPE_BUYING_STORE:     return 'B';  // (B)uying Store
 		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_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_OTHER:			return 'X';  // Other
 		case LOG_TYPE_CASH:				return '$';  // Cash
 		case LOG_TYPE_CASH:				return '$';  // Cash
 	}
 	}

+ 1 - 0
src/map/log.h

@@ -45,6 +45,7 @@ typedef enum e_log_pick_type
 	LOG_TYPE_BUYING_STORE     = 0x08000,
 	LOG_TYPE_BUYING_STORE     = 0x08000,
 	LOG_TYPE_OTHER            = 0x10000,
 	LOG_TYPE_OTHER            = 0x10000,
 	LOG_TYPE_CASH             = 0x20000,
 	LOG_TYPE_CASH             = 0x20000,
+	LOG_TYPE_BANK             = 0x40000,
 	// combinations
 	// combinations
 	LOG_TYPE_LOOT             = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
 	LOG_TYPE_LOOT             = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
 	// all
 	// all

+ 42 - 0
src/map/pc.c

@@ -1292,6 +1292,7 @@ int pc_reg_received(struct map_session_data *sd)
 	status_calc_pc(sd,1);
 	status_calc_pc(sd,1);
 	chrif_scdata_request(sd->status.account_id, sd->status.char_id);
 	chrif_scdata_request(sd->status.account_id, sd->status.char_id);
 	chrif_skillcooldown_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_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
 	intif_request_questlog(sd);
 	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_TRICKDEAD] ||
 		sd->sc.data[SC_HIDING] ||
 		sd->sc.data[SC_HIDING] ||
 		sd->sc.data[SC__SHADOWFORM] ||
 		sd->sc.data[SC__SHADOWFORM] ||
+		sd->sc.data[SC__INVISIBILITY] ||
 		sd->sc.data[SC__MANHOLE] ||
 		sd->sc.data[SC__MANHOLE] ||
 		sd->sc.data[SC_KAGEHUMI] ||
 		sd->sc.data[SC_KAGEHUMI] ||
 		(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
 		(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
  * pc Init/Terminate
  *------------------------------------------*/
  *------------------------------------------*/

+ 4 - 0
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 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 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 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;
 	} state;
 	struct {
 	struct {
 		unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;
 		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_add(struct map_session_data *sd, int id);
 void pc_damage_log_clear(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)
 #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);
 int pc_level_penalty_mod(struct map_session_data *sd, int mob_level, uint32 mob_race, uint32 mob_mode, int type);
 #endif
 #endif

+ 0 - 1
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_CLOAKING, INVALID_TIMER);
 			status_change_end(target, SC_CHASEWALK, INVALID_TIMER);
 			status_change_end(target, SC_CHASEWALK, INVALID_TIMER);
 			status_change_end(target, SC_CAMOUFLAGE, 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);
 			status_change_end(target, SC_DEEPSLEEP, INVALID_TIMER);
 			if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
 			if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
 				//Endure count is only reduced by non-players on non-gvg maps.
 				//Endure count is only reduced by non-players on non-gvg maps.