Adding banking support

This commit is contained in:
lighta 2013-11-05 13:41:42 -05:00
parent cd3cb9fa95
commit 1290826be2
25 changed files with 644 additions and 97 deletions

View File

@ -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
feature.atcommand_suggestions: off
// Banking (Note 1)
// Requires: 2013-07-24aRagexe or later
feature.banking: on

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

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

View File

@ -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 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.
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:
{

View File

@ -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;

View File

@ -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)
};

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

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

View File

@ -34,6 +34,7 @@
#include <time.h>
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);

View File

@ -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);

View File

@ -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 <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;
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 <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).
/// 0125 <index>.W <amount>.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;

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
*------------------------------------------*/

View File

@ -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

View File

@ -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.