[Feature] Implement /changename & related script bindings. Clean up #set name (#4770)

* initial work, need to clean up gm commands still

* cleaned up command, works without kicking char select now

* remove thj-specific methods

* add script hooks

* actually clear flag

* rework questmgr::rename

* remove unnecessary logging

* revert

* added missing binding to perl api and updated some text

* don't return a value

* Fix some bad argument types.

* adjust case

* alpha order

* refactor some old string stuff

* don't quote integers, bob

---------

Co-authored-by: Zimp <zimp@zenryo.xyz>
Co-authored-by: Chris Miles <akkadius1@gmail.com>
This commit is contained in:
catapultam-habeo 2025-03-19 19:00:45 -07:00 committed by GitHub
parent be6a5d5f50
commit 213fe6a9e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 223 additions and 39 deletions

View File

@ -955,6 +955,29 @@ bool Database::UpdateName(const std::string& old_name, const std::string& new_na
return CharacterDataRepository::UpdateOne(*this, e); return CharacterDataRepository::UpdateOne(*this, e);
} }
bool Database::UpdateNameByID(const int character_id, const std::string& new_name)
{
LogInfo("Renaming [{}] to [{}]", character_id, new_name);
auto l = CharacterDataRepository::GetWhere(
*this,
fmt::format(
"`id` = {}",
character_id
)
);
if (l.empty()) {
return false;
}
auto& e = l.front();
e.name = new_name;
return CharacterDataRepository::UpdateOne(*this, e);
}
bool Database::IsNameUsed(const std::string& name) bool Database::IsNameUsed(const std::string& name)
{ {
if (RuleB(Bots, Enabled)) { if (RuleB(Bots, Enabled)) {
@ -982,6 +1005,20 @@ bool Database::IsNameUsed(const std::string& name)
return !character_data.empty(); return !character_data.empty();
} }
// Players cannot have the same name as a pet vanity name, or memory corruption occurs.
bool Database::IsPetNameUsed(const std::string& name)
{
const auto& pet_name_data = CharacterPetNameRepository::GetWhere(
*this,
fmt::format(
"`name` = '{}'",
Strings::Escape(name)
)
);
return !pet_name_data.empty();
}
uint32 Database::GetServerType() uint32 Database::GetServerType()
{ {
const auto& l = VariablesRepository::GetWhere(*this, "`varname` = 'ServerType' LIMIT 1"); const auto& l = VariablesRepository::GetWhere(*this, "`varname` = 'ServerType' LIMIT 1");

View File

@ -103,6 +103,7 @@ public:
bool ReserveName(uint32 account_id, const std::string& name); bool ReserveName(uint32 account_id, const std::string& name);
bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp); bool SaveCharacterCreate(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool UpdateName(const std::string& old_name, const std::string& new_name); bool UpdateName(const std::string& old_name, const std::string& new_name);
bool UpdateNameByID(const int character_id, const std::string& new_name);
bool CopyCharacter( bool CopyCharacter(
const std::string& source_character_name, const std::string& source_character_name,
const std::string& destination_character_name, const std::string& destination_character_name,
@ -116,6 +117,7 @@ public:
bool CheckGMIPs(const std::string& login_ip, uint32 account_id); bool CheckGMIPs(const std::string& login_ip, uint32 account_id);
bool CheckNameFilter(const std::string& name, bool surname = false); bool CheckNameFilter(const std::string& name, bool surname = false);
bool IsNameUsed(const std::string& name); bool IsNameUsed(const std::string& name);
bool IsPetNameUsed(const std::string& name);
uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0); uint32 GetAccountIDByChar(const std::string& name, uint32* character_id = 0);
uint32 GetAccountIDByChar(uint32 character_id); uint32 GetAccountIDByChar(uint32 character_id);

View File

@ -287,6 +287,8 @@ N(OP_InstillDoubt),
N(OP_InterruptCast), N(OP_InterruptCast),
N(OP_InvokeChangePetName), N(OP_InvokeChangePetName),
N(OP_InvokeChangePetNameImmediate), N(OP_InvokeChangePetNameImmediate),
N(OP_InvokeNameChangeImmediate),
N(OP_InvokeNameChangeLazy),
N(OP_ItemLinkClick), N(OP_ItemLinkClick),
N(OP_ItemLinkResponse), N(OP_ItemLinkResponse),
N(OP_ItemLinkText), N(OP_ItemLinkText),

View File

@ -5832,21 +5832,28 @@ struct ChangeSize_Struct
/*16*/ /*16*/
}; };
enum ChangeNameResponse : int {
Denied = 0, // 5167: "You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name."
Accepted = 1, // 5976: "Your request for a name change was successful."
Timeout = -1, // 5977: "Your request for a name change has timed out. Please try again later."
ServerError = -2, // 5978: "The server had an error while processing your name request. Please try again later."
RateLimited = -3, // 5979: "You must wait longer before submitting another name request. Please try again in a few minutes."
Ineligible = -4, // 5980: "Your character is not eligible for a name change."
Pending = -5 // 5193: "You already have a name change pending. Please wait until it is fully processed before attempting another name change."
};
struct AltChangeName_Struct {
/*00*/ char new_name[64];
/*40*/ char old_name[64];
/*80*/ int response_code;
};
struct ChangePetName_Struct { struct ChangePetName_Struct {
/*00*/ char new_pet_name[64]; /*00*/ char new_pet_name[64];
/*40*/ char pet_owner_name[64]; /*40*/ char pet_owner_name[64];
/*80*/ int response_code; /*80*/ int response_code;
}; };
enum ChangePetNameResponse : int {
Denied = 0, // 5167 You have requested an invalid name or a Customer Service Representative has denied your name request. Please try another name.
Accepted = 1, // 5976 Your request for a name change was successful.
Timeout = -3, // 5979 You must wait longer before submitting another name request. Please try again in a few minutes.
NotEligible = -4, // 5980 Your character is not eligible for a name change.
Pending = -5, // 5193 You already have a name change pending. Please wait until it is fully processed before attempting another name change.
Unhandled = -1
};
// New OpCode/Struct for SoD+ // New OpCode/Struct for SoD+
struct GroupMakeLeader_Struct struct GroupMakeLeader_Struct
{ {

View File

@ -231,6 +231,7 @@ RULE_INT(Character, MendAlwaysSucceedValue, 199, "Value at which mend will alway
RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false") RULE_BOOL(Character, SneakAlwaysSucceedOver100, false, "When sneak skill is over 100, always succeed sneak/hide. Default: false")
RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0") RULE_INT(Character, BandolierSwapDelay, 0, "Bandolier swap delay in milliseconds, default is 0")
RULE_BOOL(Character, EnableHackedFastCampForGM, false, "Enables hacked fast camp for GM clients, if the GM doesn't have a hacked client they'll camp like normal") RULE_BOOL(Character, EnableHackedFastCampForGM, false, "Enables hacked fast camp for GM clients, if the GM doesn't have a hacked client they'll camp like normal")
RULE_BOOL(Character, AlwaysAllowNameChange, false, "Enable this option to allow /changename to work without enabling a name change via scripts.")
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY(Mercs) RULE_CATEGORY(Mercs)

View File

@ -746,3 +746,6 @@ OP_TradeSkillRecipeInspect=0x4f7e
OP_InvokeChangePetNameImmediate=0x046d OP_InvokeChangePetNameImmediate=0x046d
OP_InvokeChangePetName=0x4506 OP_InvokeChangePetName=0x4506
OP_ChangePetName=0x5dab OP_ChangePetName=0x5dab
OP_InvokeNameChangeImmediate=0x4fe2
OP_InvokeNameChangeLazy=0x2f2e

View File

@ -2549,40 +2549,59 @@ void Client::ChangeLastName(std::string last_name) {
safe_delete(outapp); safe_delete(outapp);
} }
bool Client::ChangeFirstName(const char* in_firstname, const char* gmname) // Deprecated, this packet does not actually work in ROF2
bool Client::ChangeFirstName(const std::string in_firstname, const std::string gmname)
{ {
// check duplicate name if (!ChangeFirstName(in_firstname)) {
bool used_name = database.IsNameUsed((const char*) in_firstname);
if (used_name) {
return false; return false;
} }
// update character_
if(!database.UpdateName(GetName(), in_firstname))
return false;
// update pp
memset(m_pp.name, 0, sizeof(m_pp.name));
snprintf(m_pp.name, sizeof(m_pp.name), "%s", in_firstname);
strcpy(name, m_pp.name);
Save();
// send name update packet // send name update packet
auto outapp = new EQApplicationPacket(OP_GMNameChange, sizeof(GMName_Struct)); auto outapp = new EQApplicationPacket(OP_GMNameChange, sizeof(GMName_Struct));
GMName_Struct* gmn=(GMName_Struct*)outapp->pBuffer; GMName_Struct* gmn=(GMName_Struct*)outapp->pBuffer;
strn0cpy(gmn->gmname,gmname,64); strn0cpy(gmn->gmname,gmname.c_str(),64);
strn0cpy(gmn->oldname,GetName(),64); strn0cpy(gmn->oldname,GetName(),64);
strn0cpy(gmn->newname,in_firstname,64); strn0cpy(gmn->newname,in_firstname.c_str(),64);
gmn->unknown[0] = 1; gmn->unknown[0] = 1;
gmn->unknown[1] = 1; gmn->unknown[1] = 1;
gmn->unknown[2] = 1; gmn->unknown[2] = 1;
entity_list.QueueClients(this, outapp, false); entity_list.QueueClients(this, outapp, false);
safe_delete(outapp); safe_delete(outapp);
// success
return true;
}
bool Client::ChangeFirstName(const std::string in_firstname)
{
// check duplicate name
bool used_name = database.IsNameUsed(in_firstname) || database.IsPetNameUsed(in_firstname);
if (used_name || !database.CheckNameFilter(in_firstname, false)) {
return false;
}
// update character_
if(!database.UpdateNameByID(CharacterID(), in_firstname))
return false;
// Send Name Update to Clients
SendRename(this, GetName(), in_firstname.c_str());
SetName(in_firstname.c_str());
// update pp
memset(m_pp.name, 0, sizeof(m_pp.name));
snprintf(m_pp.name, sizeof(m_pp.name), "%s", in_firstname.c_str());
strcpy(name, m_pp.name);
Save();
// Update the active char in account table
database.UpdateLiveChar(in_firstname, AccountID());
// finally, update the /who list // finally, update the /who list
UpdateWho(); UpdateWho();
// success // success
ClearNameChange();
return true; return true;
} }
@ -4737,6 +4756,57 @@ bool Client::KeyRingRemove(uint32 item_id)
); );
} }
bool Client::IsNameChangeAllowed() {
if (RuleB(Character, AlwaysAllowNameChange)) {
return true;
}
auto k = GetScopedBucketKeys();
k.key = "name_change_allowed";
auto b = DataBucket::GetData(k);
if (!b.value.empty()) {
return true;
}
return false;
}
bool Client::ClearNameChange() {
if (!IsNameChangeAllowed()) {
return false;
}
auto k = GetScopedBucketKeys();
k.key = "name_change_allowed";
DataBucket::DeleteData(k);
return true;
}
void Client::InvokeChangeNameWindow(bool immediate) {
if (!IsNameChangeAllowed()) {
return;
}
auto packet_op = immediate ? OP_InvokeNameChangeImmediate : OP_InvokeNameChangeLazy;
auto outapp = new EQApplicationPacket(packet_op, 0);
QueuePacket(outapp);
safe_delete(outapp);
}
void Client::GrantNameChange() {
auto k = GetScopedBucketKeys();
k.key = "name_change_allowed";
k.value = "allowed"; // potentially put a timestamp here
DataBucket::SetData(k);
InvokeChangeNameWindow(true);
}
bool Client::IsPetNameChangeAllowed() { bool Client::IsPetNameChangeAllowed() {
if (RuleB(Pets, AlwaysAllowPetRename)) { if (RuleB(Pets, AlwaysAllowPetRename)) {
return true; return true;

View File

@ -332,6 +332,10 @@ public:
bool KeyRingClear(); bool KeyRingClear();
bool KeyRingRemove(uint32 item_id); bool KeyRingRemove(uint32 item_id);
void KeyRingList(); void KeyRingList();
bool IsNameChangeAllowed();
void InvokeChangeNameWindow(bool immediate = true);
bool ClearNameChange();
void GrantNameChange();
bool IsPetNameChangeAllowed(); bool IsPetNameChangeAllowed();
void GrantPetNameChange(); void GrantPetNameChange();
void ClearPetNameChange(); void ClearPetNameChange();
@ -511,7 +515,8 @@ public:
bool AutoAttackEnabled() const { return auto_attack; } bool AutoAttackEnabled() const { return auto_attack; }
bool AutoFireEnabled() const { return auto_fire; } bool AutoFireEnabled() const { return auto_fire; }
bool ChangeFirstName(const char* in_firstname,const char* gmname); bool ChangeFirstName(const std::string in_firstname,const std::string gmname);
bool ChangeFirstName(const std::string in_firstname);
void Duck(); void Duck();
void Stand(); void Stand();

View File

@ -826,6 +826,10 @@ void Client::CompleteConnect()
if (IsPetNameChangeAllowed() && !RuleB(Pets, AlwaysAllowPetRename)) { if (IsPetNameChangeAllowed() && !RuleB(Pets, AlwaysAllowPetRename)) {
InvokeChangePetName(false); InvokeChangePetName(false);
} }
if (IsNameChangeAllowed() && !RuleB(Character, AlwaysAllowNameChange)) {
InvokeChangeNameWindow(false);
}
} }
if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) { if(ClientVersion() == EQ::versions::ClientVersion::RoF2 && RuleB(Parcel, EnableParcelMerchants)) {
@ -4256,7 +4260,7 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app)
else { else {
OnDisconnect(true); OnDisconnect(true);
} }
return; return;
} }
@ -4548,14 +4552,14 @@ void Client::Handle_OP_ChangePetName(const EQApplicationPacket *app) {
auto p = (ChangePetName_Struct *) app->pBuffer; auto p = (ChangePetName_Struct *) app->pBuffer;
if (!IsPetNameChangeAllowed()) { if (!IsPetNameChangeAllowed()) {
p->response_code = ChangePetNameResponse::NotEligible; p->response_code = ChangeNameResponse::Ineligible;
QueuePacket(app); QueuePacket(app);
return; return;
} }
p->response_code = ChangePetNameResponse::Denied; p->response_code = ChangeNameResponse::Denied;
if (ChangePetName(p->new_pet_name)) { if (ChangePetName(p->new_pet_name)) {
p->response_code = ChangePetNameResponse::Accepted; p->response_code = ChangeNameResponse::Accepted;
} }
QueuePacket(app); QueuePacket(app);
@ -6776,6 +6780,21 @@ void Client::Handle_OP_GMLastName(const EQApplicationPacket *app)
void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app) void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
{ {
if (app->size == sizeof(AltChangeName_Struct)) {
auto p = (AltChangeName_Struct *) app->pBuffer;
if (!IsNameChangeAllowed()) {
p->response_code = ChangeNameResponse::Ineligible;
QueuePacket(app);
return;
}
p->response_code = ChangeFirstName(p->new_name) ? ChangeNameResponse::Accepted : ChangeNameResponse::Denied;
QueuePacket(app);
return;
}
if (app->size != sizeof(GMName_Struct)) { if (app->size != sizeof(GMName_Struct)) {
LogError("Wrong size: OP_GMNameChange, size=[{}], expected [{}]", app->size, sizeof(GMName_Struct)); LogError("Wrong size: OP_GMNameChange, size=[{}], expected [{}]", app->size, sizeof(GMName_Struct));
return; return;

View File

@ -14,7 +14,7 @@ void SetName(Client *c, const Seperator *sep)
std::string new_name = sep->arg[2]; std::string new_name = sep->arg[2];
std::string old_name = t->GetCleanName(); std::string old_name = t->GetCleanName();
if (t->ChangeFirstName(new_name.c_str(), c->GetCleanName())) { if (t->ChangeFirstName(new_name, c->GetCleanName())) {
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
@ -24,17 +24,13 @@ void SetName(Client *c, const Seperator *sep)
).c_str() ).c_str()
); );
c->Message(Chat::White, "Sending player to char select.");
t->Kick("Name was changed");
return; return;
} }
c->Message( c->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
"Unable to rename {}. Check that the new name '{}' isn't already taken.", "Unable to rename {}. Check that the new name '{}' isn't already taken (Including Pet Names), or isn't invalid",
old_name, old_name,
new_name new_name
).c_str() ).c_str()

View File

@ -3496,6 +3496,24 @@ std::string Lua_Client::GetAccountBucketRemaining(std::string bucket_name)
return self->GetAccountBucketRemaining(bucket_name); return self->GetAccountBucketRemaining(bucket_name);
} }
void Lua_Client::GrantNameChange()
{
Lua_Safe_Call_Void();
self->GrantNameChange();
}
bool Lua_Client::IsNameChangeAllowed()
{
Lua_Safe_Call_Bool();
return self->IsNameChangeAllowed();
}
bool Lua_Client::ClearNameChange()
{
Lua_Safe_Call_Bool();
return self->ClearNameChange();
}
std::string Lua_Client::GetBandolierName(uint8 bandolier_slot) std::string Lua_Client::GetBandolierName(uint8 bandolier_slot)
{ {
Lua_Safe_Call_String(); Lua_Safe_Call_String();
@ -3635,6 +3653,7 @@ luabind::scope lua_register_client() {
.def("CashReward", &Lua_Client::CashReward) .def("CashReward", &Lua_Client::CashReward)
.def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName) .def("ChangeLastName", (void(Lua_Client::*)(std::string))&Lua_Client::ChangeLastName)
.def("GrantPetNameChange", &Lua_Client::GrantPetNameChange) .def("GrantPetNameChange", &Lua_Client::GrantPetNameChange)
.def("ClearNameChange", &Lua_Client::ClearNameChange)
.def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID) .def("CharacterID", (uint32(Lua_Client::*)(void))&Lua_Client::CharacterID)
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob))&Lua_Client::CheckIncreaseSkill) .def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob))&Lua_Client::CheckIncreaseSkill)
.def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob,int))&Lua_Client::CheckIncreaseSkill) .def("CheckIncreaseSkill", (void(Lua_Client::*)(int,Lua_Mob,int))&Lua_Client::CheckIncreaseSkill)
@ -3851,6 +3870,7 @@ luabind::scope lua_register_client() {
.def("GrantAllAAPoints", (void(Lua_Client::*)(uint8,bool))&Lua_Client::GrantAllAAPoints) .def("GrantAllAAPoints", (void(Lua_Client::*)(uint8,bool))&Lua_Client::GrantAllAAPoints)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility) .def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility) .def("GrantAlternateAdvancementAbility", (bool(Lua_Client::*)(int, int, bool))&Lua_Client::GrantAlternateAdvancementAbility)
.def("GrantNameChange", &Lua_Client::GrantNameChange)
.def("GuildID", (uint32(Lua_Client::*)(void))&Lua_Client::GuildID) .def("GuildID", (uint32(Lua_Client::*)(void))&Lua_Client::GuildID)
.def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank) .def("GuildRank", (int(Lua_Client::*)(void))&Lua_Client::GuildRank)
.def("HasAugmentEquippedByID", (bool(Lua_Client::*)(uint32))&Lua_Client::HasAugmentEquippedByID) .def("HasAugmentEquippedByID", (bool(Lua_Client::*)(uint32))&Lua_Client::HasAugmentEquippedByID)
@ -3881,6 +3901,7 @@ luabind::scope lua_register_client() {
.def("IsInAGuild", (bool(Lua_Client::*)(void))&Lua_Client::IsInAGuild) .def("IsInAGuild", (bool(Lua_Client::*)(void))&Lua_Client::IsInAGuild)
.def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD) .def("IsLD", (bool(Lua_Client::*)(void))&Lua_Client::IsLD)
.def("IsMedding", (bool(Lua_Client::*)(void))&Lua_Client::IsMedding) .def("IsMedding", (bool(Lua_Client::*)(void))&Lua_Client::IsMedding)
.def("IsNameChangeAllowed", &Lua_Client::IsNameChangeAllowed)
.def("IsRaidGrouped", (bool(Lua_Client::*)(void))&Lua_Client::IsRaidGrouped) .def("IsRaidGrouped", (bool(Lua_Client::*)(void))&Lua_Client::IsRaidGrouped)
.def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting) .def("IsSitting", (bool(Lua_Client::*)(void))&Lua_Client::IsSitting)
.def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding) .def("IsStanding", (bool(Lua_Client::*)(void))&Lua_Client::IsStanding)

View File

@ -609,6 +609,10 @@ public:
void ShowZoneShardMenu(); void ShowZoneShardMenu();
void GrantPetNameChange(); void GrantPetNameChange();
void GrantNameChange();
bool IsNameChangeAllowed();
bool ClearNameChange();
Lua_Expedition CreateExpedition(luabind::object expedition_info); Lua_Expedition CreateExpedition(luabind::object expedition_info);
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players); Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players);
Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages); Lua_Expedition CreateExpedition(std::string zone_name, uint32 version, uint32 duration, std::string expedition_name, uint32 min_players, uint32 max_players, bool disable_messages);

View File

@ -3261,6 +3261,21 @@ std::string Perl_Client_GetAccountBucketRemaining(Client* self, std::string buck
return self->GetAccountBucketRemaining(bucket_name); return self->GetAccountBucketRemaining(bucket_name);
} }
void Perl_Client_GrantNameChange(Client* self)
{
self->GrantNameChange();
}
bool Perl_Client_IsNameChangeAllowed(Client* self)
{
return self->IsNameChangeAllowed();
}
bool Perl_Client_ClearNameChange(Client* self)
{
return self->ClearNameChange();
}
std::string Perl_Client_GetBandolierName(Client* self, uint8 bandolier_slot) std::string Perl_Client_GetBandolierName(Client* self, uint8 bandolier_slot)
{ {
return self->GetBandolierName(bandolier_slot); return self->GetBandolierName(bandolier_slot);
@ -3393,6 +3408,7 @@ void perl_register_client()
package.add("CashReward", &Perl_Client_CashReward); package.add("CashReward", &Perl_Client_CashReward);
package.add("ChangeLastName", &Perl_Client_ChangeLastName); package.add("ChangeLastName", &Perl_Client_ChangeLastName);
package.add("GrantPetNameChange", &Perl_Client_GrantPetNameChange); package.add("GrantPetNameChange", &Perl_Client_GrantPetNameChange);
package.add("ClearNameChange", (bool(*)(Client*))&Perl_Client_ClearNameChange);
package.add("CharacterID", &Perl_Client_CharacterID); package.add("CharacterID", &Perl_Client_CharacterID);
package.add("CheckIncreaseSkill", (bool(*)(Client*, int))&Perl_Client_CheckIncreaseSkill); package.add("CheckIncreaseSkill", (bool(*)(Client*, int))&Perl_Client_CheckIncreaseSkill);
package.add("CheckIncreaseSkill", (bool(*)(Client*, int, int))&Perl_Client_CheckIncreaseSkill); package.add("CheckIncreaseSkill", (bool(*)(Client*, int, int))&Perl_Client_CheckIncreaseSkill);
@ -3607,6 +3623,7 @@ void perl_register_client()
package.add("GrantAllAAPoints", (void(*)(Client*, uint8, bool))&Perl_Client_GrantAllAAPoints); package.add("GrantAllAAPoints", (void(*)(Client*, uint8, bool))&Perl_Client_GrantAllAAPoints);
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int))&Perl_Client_GrantAlternateAdvancementAbility); package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int))&Perl_Client_GrantAlternateAdvancementAbility);
package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int, bool))&Perl_Client_GrantAlternateAdvancementAbility); package.add("GrantAlternateAdvancementAbility", (bool(*)(Client*, int, int, bool))&Perl_Client_GrantAlternateAdvancementAbility);
package.add("GrantNameChange", (void(*)(Client*))&Perl_Client_GrantNameChange);
package.add("GuildID", &Perl_Client_GuildID); package.add("GuildID", &Perl_Client_GuildID);
package.add("GuildRank", &Perl_Client_GuildRank); package.add("GuildRank", &Perl_Client_GuildRank);
package.add("HasAugmentEquippedByID", &Perl_Client_HasAugmentEquippedByID); package.add("HasAugmentEquippedByID", &Perl_Client_HasAugmentEquippedByID);
@ -3637,6 +3654,7 @@ void perl_register_client()
package.add("IsInAGuild", &Perl_Client_IsInAGuild); package.add("IsInAGuild", &Perl_Client_IsInAGuild);
package.add("IsLD", &Perl_Client_IsLD); package.add("IsLD", &Perl_Client_IsLD);
package.add("IsMedding", &Perl_Client_IsMedding); package.add("IsMedding", &Perl_Client_IsMedding);
package.add("IsNameChangeAllowed", (bool(*)(Client*))&Perl_Client_IsNameChangeAllowed);
package.add("IsRaidGrouped", &Perl_Client_IsRaidGrouped); package.add("IsRaidGrouped", &Perl_Client_IsRaidGrouped);
package.add("IsSitting", &Perl_Client_IsSitting); package.add("IsSitting", &Perl_Client_IsSitting);
package.add("IsStanding", &Perl_Client_IsStanding); package.add("IsStanding", &Perl_Client_IsStanding);

View File

@ -1310,15 +1310,14 @@ void QuestManager::rename(std::string name) {
QuestManagerCurrentQuestVars(); QuestManagerCurrentQuestVars();
if (initiator) { if (initiator) {
std::string current_name = initiator->GetName(); std::string current_name = initiator->GetName();
if (initiator->ChangeFirstName(name.c_str(), current_name.c_str())) { if (initiator->ChangeFirstName(name)) {
initiator->Message( initiator->Message(
Chat::White, Chat::White,
fmt::format( fmt::format(
"Successfully renamed to {}, kicking to character select.", "Successfully renamed to {}.",
name name
).c_str() ).c_str()
); );
initiator->Kick("Name was changed.");
} else { } else {
initiator->Message( initiator->Message(
Chat::Red, Chat::Red,