diff --git a/conf/char_athena.conf b/conf/char_athena.conf index 89460b92c4..ff792b6383 100644 --- a/conf/char_athena.conf +++ b/conf/char_athena.conf @@ -238,6 +238,15 @@ char_movetoused: yes // Allow users to move characters as often as they like? char_moves_unlimited: no +// Character renaming +// Allow users to rename a character while being in a party? +// Default: no +char_rename_party: no + +// Allow users to rename a character while being in a guild? +// Default: no +char_rename_guild: no + // Should we check if sql-tables are correct on server startup ? char_checkdb: yes diff --git a/src/char/char.c b/src/char/char.c index 72d20eebc8..dd29eb162c 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -1247,16 +1247,31 @@ int char_rename_char_sql(struct char_session_data *sd, uint32 char_id) if( !char_mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. return 2; + // If the new name is exactly the same as the old one + if( !strcmp( sd->new_name, char_dat.name ) ) + return 0; + if( char_dat.rename == 0 ) return 1; + if( !charserv_config.char_config.char_rename_party && char_dat.party_id ){ + return 6; + } + + if( !charserv_config.char_config.char_rename_guild && char_dat.guild_id ){ + return 5; + } + 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' LIMIT 1", schema_config.char_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return 4; + switch( char_check_char_name( sd->new_name, esc_name ) ){ + case 0: + break; + case -1: + // character already exists + return 4; + default: + return 8; } if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", schema_config.char_db, esc_name, --char_dat.rename, char_id) ) @@ -2879,6 +2894,10 @@ bool char_config_read(const char* cfgName, bool normal){ charserv_config.char_config.char_del_option = atoi(w2); } else if (strcmpi(w1, "char_del_restriction") == 0) { charserv_config.char_config.char_del_restriction = atoi(w2); + } else if (strcmpi(w1, "char_rename_party") == 0) { + charserv_config.char_config.char_rename_party = (bool)config_switch(w2); + } else if (strcmpi(w1, "char_rename_guild") == 0) { + charserv_config.char_config.char_rename_guild = (bool)config_switch(w2); } else if(strcmpi(w1,"db_path")==0) { safestrncpy(schema_config.db_path, w2, sizeof(schema_config.db_path)); } else if (strcmpi(w1, "fame_list_alchemist") == 0) { diff --git a/src/char/char.h b/src/char/char.h index 7ed84ede95..07e240581d 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -119,6 +119,8 @@ struct Char_Config { int char_name_option; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] int char_del_option; // Character deletion type, email = 1, birthdate = 2 (default) int char_del_restriction; // Character deletion restriction (0: none, 1: if the character is in a party, 2: if the character is in a guild, 3: if the character is in a party or a guild) + bool char_rename_party; // Character renaming in a party + bool char_rename_guild; // Character renaming in a guild }; #define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] diff --git a/src/char/char_clif.c b/src/char/char_clif.c index 1e5e320772..7edfefb82d 100644 --- a/src/char/char_clif.c +++ b/src/char/char_clif.c @@ -1055,29 +1055,33 @@ int chclif_parse_keepalive(int fd){ return 1; } -// R 08fc .l .24B -// R 028d .l .l .24B -int chclif_parse_reqrename(int fd, struct char_session_data* sd, int cmd){ - int i, cid = 0; +// Tells the client if the name was accepted or not +// 028e .W (HC_ACK_IS_VALID_CHARNAME) +// result: +// 0 = name is not OK +// 1 = name is OK +void chclif_reqrename_response( int fd, struct char_session_data* sd, bool name_valid ){ + WFIFOHEAD(fd, 4); + WFIFOW(fd, 0) = 0x28e; + WFIFOW(fd, 2) = name_valid; + WFIFOSET(fd, 4); +} + +// Request for checking the new name on character renaming +// 028d .l .l .24B (CH_REQ_IS_VALID_CHARNAME) +int chclif_parse_reqrename( int fd, struct char_session_data* sd ){ + int i, cid, aid; char name[NAME_LENGTH]; char esc_name[NAME_LENGTH*2+1]; - if(cmd == 0x8fc){ - FIFOSD_CHECK(30) - cid =RFIFOL(fd,2); - safestrncpy(name, RFIFOCP(fd,6), NAME_LENGTH); - RFIFOSKIP(fd,30); - } - else if(cmd == 0x28d) { - int aid; - FIFOSD_CHECK(34); - aid = RFIFOL(fd,2); - cid =RFIFOL(fd,6); - safestrncpy(name, RFIFOCP(fd,10), NAME_LENGTH); - RFIFOSKIP(fd,34); - if( aid != sd->account_id ) - return 1; - } + FIFOSD_CHECK(34); + aid = RFIFOL(fd,2); + cid = RFIFOL(fd,6); + safestrncpy(name, RFIFOCP(fd,10), NAME_LENGTH); + RFIFOSKIP(fd,34); + + if( aid != sd->account_id ) + return 1; ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); if( i == MAX_CHARS ) @@ -1090,12 +1094,10 @@ int chclif_parse_reqrename(int fd, struct char_session_data* sd, int cmd){ safestrncpy(sd->new_name, name, NAME_LENGTH); } else - i = 0; + i = 0; + + chclif_reqrename_response(fd, sd, i > 0); - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x28e; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); return 1; } @@ -1158,13 +1160,70 @@ void chclif_block_character( int fd, struct char_session_data* sd){ } } -// 0x28f .L +// Sends the response to a rename request to the client. +// 0290 .W (HC_ACK_CHANGE_CHARNAME) +// 08fd .L (HC_ACK_CHANGE_CHARACTERNAME) +// result: +// 0: Successful +// 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. +// 5: In order to change the character name, you must leave the guild. +// 6: In order to change the character name, you must leave the party. +// 7: Length exceeds the maximum size of the character name you want to change. +// 8: Name contains invalid characters. Character name change failed. +// 9: The name change is prohibited. Character name change failed. +// 10: Character name change failed, due an unknown error. +void chclif_rename_response(int fd, struct char_session_data* sd, int16 response) { +#if PACKETVER >= 20111101 + WFIFOHEAD(fd, 6); + WFIFOW(fd, 0) = 0x8fd; + WFIFOL(fd, 2) = response; + WFIFOSET(fd, 6); +#else + WFIFOHEAD(fd, 4); + WFIFOW(fd, 0) = 0x290; + WFIFOW(fd, 2) = response; + WFIFOSET(fd, 4); +#endif +} + +// Request to change a character name +// 028f .L (CH_REQ_CHANGE_CHARNAME) +// 08fc .L .24B (CH_REQ_CHANGE_CHARACTERNAME) int chclif_parse_ackrename(int fd, struct char_session_data* sd){ - // 0: Successful - // 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. +#if PACKETVER >= 20111101 + FIFOSD_CHECK(30) + { + int i, cid; + char name[NAME_LENGTH], esc_name[NAME_LENGTH * 2 + 1]; + + cid = RFIFOL(fd, 2); + safestrncpy(name, RFIFOCP(fd, 6), NAME_LENGTH); + RFIFOSKIP(fd, 30); + + ARR_FIND(0, MAX_CHARS, i, sd->found_char[i] == cid); + if (i == MAX_CHARS) + return 1; + + normalize_name(name, TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + + safestrncpy(sd->new_name, name, NAME_LENGTH); + + // Start the renaming process + i = char_rename_char_sql(sd, cid); + + chclif_rename_response(fd, sd, i); + + // If the renaming was successful, we need to resend the characters + if( i == 0 ) + chclif_mmo_char_send(fd, sd); + + return 1; + } +#else FIFOSD_CHECK(6) { int i; @@ -1176,12 +1235,10 @@ int chclif_parse_ackrename(int fd, struct char_session_data* sd){ return 1; i = char_rename_char_sql(sd, cid); - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x290; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); + chclif_rename_response(fd, sd, i); } return 1; +#endif } int chclif_ack_captcha(int fd){ @@ -1262,9 +1319,9 @@ int chclif_parse(int fd) { // client keep-alive packet (every 12 seconds) case 0x187: next=chclif_parse_keepalive(fd); break; // char rename - case 0x8fc: next=chclif_parse_reqrename(fd,sd,cmd); break; //request - case 0x28d: next=chclif_parse_reqrename(fd,sd,cmd); break; //request + case 0x28d: next=chclif_parse_reqrename(fd,sd); break; //Check new desired name case 0x28f: next=chclif_parse_ackrename(fd,sd); break; //Confirm change name. + case 0x8fc: next=chclif_parse_ackrename(fd,sd); break; //Rename request without confirmation // captcha case 0x7e5: next=chclif_parse_reqcaptcha(fd); break; // captcha code request (not implemented) case 0x7e7: next=chclif_parse_chkcaptcha(fd); break; // captcha code check (not implemented) diff --git a/src/char/char_clif.h b/src/char/char_clif.h index fe9c04c849..a377ce342b 100644 --- a/src/char/char_clif.h +++ b/src/char/char_clif.h @@ -48,7 +48,7 @@ int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl); int chclif_parse_createnewchar(int fd, struct char_session_data* sd,int cmd); int chclif_parse_delchar(int fd,struct char_session_data* sd, int cmd); int chclif_parse_keepalive(int fd); -int chclif_parse_reqrename(int fd, struct char_session_data* sd, int cmd); +int chclif_parse_reqrename(int fd, struct char_session_data* sd); int chclif_parse_ackrename(int fd, struct char_session_data* sd); int chclif_ack_captcha(int fd); int chclif_parse_reqcaptcha(int fd);