From 72351d986315e826c7c32d0de62932067fd98bb8 Mon Sep 17 00:00:00 2001 From: Inkfish Date: Sun, 11 Oct 2009 03:07:52 +0000 Subject: Added character rename function.(topic:225576)(written by pakpil and fixed by me) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@14084 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char_sql/char.c | 187 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 162 insertions(+), 25 deletions(-) (limited to 'src/char_sql/char.c') diff --git a/src/char_sql/char.c b/src/char_sql/char.c index d57168903..e402c4f7a 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -100,6 +100,7 @@ char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the request #define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] char char_name_letters[1024] = ""; // list of letters/symbols used to authorise or not a name of a character. by [Yor] bool char_rename = true; +int char_max_rename = 1; int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius] int char_del_level = 0; //From which level u can delete character [Lupus] @@ -130,6 +131,7 @@ struct char_session_data { int gmlevel; uint32 version; uint8 clienttype; + char new_name[NAME_LENGTH]; }; int char_num, char_max; @@ -477,7 +479,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," - "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d'" + "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'" " WHERE `account_id`='%d' AND `char_id` = '%d'", char_db, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, @@ -486,7 +488,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, - mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, + mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, p->account_id, p->char_id) ) { Sql_ShowDebug(sql_handle); @@ -835,7 +837,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," - "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`" + "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`rename`" " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) || SQL_ERROR == SqlStmt_Execute(stmt) || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) @@ -870,6 +872,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p.rename, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -884,6 +887,8 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) for( ; i < MAX_CHARS; i++ ) sd->found_char[i] = -1; + memset(sd->new_name,0,sizeof(sd->new_name)); + SqlStmt_Free(stmt); return j; } @@ -925,7 +930,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`hair`," "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," - "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`" + "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`" " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SqlStmt_Execute(stmt) @@ -976,7 +981,9 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->father, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->mother, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->child, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->fame, 0, NULL, NULL) ) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->fame, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_SHORT, &p->rename, 0, NULL, NULL) + ) { SqlStmt_ShowDebug(stmt); SqlStmt_Free(stmt); @@ -1173,18 +1180,73 @@ int mmo_char_sql_init(void) } //----------------------------------- -// Function to create a new character +// Function to change chararcter's names //----------------------------------- -int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) +int rename_char_sql(struct char_session_data *sd, int char_id) { - char name[NAME_LENGTH]; + StringBuf buf; + struct mmo_charstatus char_dat; char esc_name[NAME_LENGTH*2+1]; - unsigned int i; - int char_id; - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( sd->new_name[0] == 0 ) // Not ready for rename + return 2; + + if( !mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. + return 2; + + if( char_dat.rename >= char_max_rename && char_max_rename != 0 ) + return 1; + + Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); + + // check if the char exist + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s'", char_db, esc_name) ) { + Sql_ShowDebug(sql_handle); + return 4; + } + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `name` = '%s'", char_db, esc_name); + + if( char_max_rename ) + { + char_dat.rename++; + StringBuf_Printf(&buf, ", `rename` = '%d'", char_dat.rename); + } + + StringBuf_Printf(&buf, " WHERE `char_id` = '%d'", char_id); + + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + return 3; + } + + StringBuf_Destroy(&buf); + + // Change character's name into guild_db. + if( char_dat.guild_id ) + inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); + + safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); + memset(sd->new_name,0,sizeof(sd->new_name)); + + // log change + if( log_char ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", + charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) + Sql_ShowDebug(sql_handle); + } + + return 0; +} + +int check_char_name(char * name, char * esc_name) +{ + int i; // check length of character name if( name[0] == '\0' ) @@ -1197,27 +1259,49 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag // check for reserved names if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) return -1; // nick reserved for internal server messages - + // Check Authorised letters/symbols in the name of the character - if( char_name_option == 1 ) { // only letters/symbols in char_name_letters are authorised + if( char_name_option == 1 ) + { // only letters/symbols in char_name_letters are authorised for( i = 0; i < NAME_LENGTH && name[i]; i++ ) if( strchr(char_name_letters, name[i]) == NULL ) return -2; - } else - if( char_name_option == 2 ) { // letters/symbols in char_name_letters are forbidden + } + else if( char_name_option == 2 ) + { // letters/symbols in char_name_letters are forbidden for( i = 0; i < NAME_LENGTH && name[i]; i++ ) if( strchr(char_name_letters, name[i]) != NULL ) return -2; - } // else, all letters/symbols are authorised (except control char removed before) + } - // check name (already in use?) - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + { // check name (already in use?) Sql_ShowDebug(sql_handle); return -2; } if( Sql_NumRows(sql_handle) > 0 ) return -1; // name already exists + return 0; +} + +//----------------------------------- +// Function to create a new character +//----------------------------------- +int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) +{ + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + int char_id, flag; + + safestrncpy(name, name_, NAME_LENGTH); + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + + flag = check_char_name(name,esc_name); + if( flag < 0 ) + return flag; + //check other inputs if((slot >= MAX_CHARS) // slots || (hair_style >= 24) // hair style @@ -1512,7 +1596,7 @@ int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p) WBUFB(buf,103) = min(p->luk, UCHAR_MAX); WBUFW(buf,104) = p->slot; if (char_rename) { - WBUFW(buf,106) = 1;// Rename bit (0=rename,1=no rename) + WBUFW(buf,106) = (p->rename >= char_max_rename && char_max_rename != 0) ? 1 : 0;// Rename bit (0=rename,1=no rename) return 108; } else { return 106; @@ -3142,7 +3226,7 @@ int parse_char(int fd) // add new entry to the chars list ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // the char_id of the new char + sd->found_char[ch] = i; // the char_id of the new char } RFIFOSKIP(fd,37); @@ -3220,9 +3304,60 @@ int parse_char(int fd) // R 028d .l .l .24B case 0x28d: FIFOSD_CHECK(34); - //not implemented - RFIFOSKIP(fd,34); - break; + { + int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); + RFIFOSKIP(fd,34); + + if( aid != sd->account_id ) + break; + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + break; + + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( !check_char_name(name,esc_name) ) + { + i = 1; + safestrncpy(sd->new_name, name, NAME_LENGTH); + } + else + i = 0; + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x28e; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; + //Confirm change name. + // 0x28f .L + case 0x28f: + // 0: Sucessfull + // 1: This character's name has already been changed. You cannot change a character's name more than once. + // 2: User information is not correct. + // 3: You have failed to change this character's name. + // 4: Another user is using this character name, so please select another one. + FIFOSD_CHECK(6); + { + int i; + int cid = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + break; + i = rename_char_sql(sd, cid); + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x290; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); + } + break; // log in as map-server case 0x2af8: @@ -3772,6 +3907,8 @@ int char_config_read(const char* cfgName) strcpy(char_name_letters, w2); } else if (strcmpi(w1, "char_rename") == 0) { char_rename = config_switch(w2); + } else if (strcmpi(w1, "char_max_rename") == 0) { + char_max_rename = atoi(w2); } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] char_per_account = atoi(w2); } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] -- cgit v1.2.3-60-g2f50