Fix persist pet name cross zone

This commit is contained in:
Emagi 2022-10-28 09:45:47 -04:00
parent 8b2549d178
commit c2068993ea
7 changed files with 100 additions and 33 deletions

View file

@ -8138,9 +8138,13 @@ void Commands::Command_Pet(Client* client, Seperator* sep)
*/
void Commands::Command_PetName(Client* client, Seperator* sep)
{
PrintSep(sep, "COMMAND_PETNAME");
LogWrite(MISC__TODO, 1, "Command", "TODO-Command: Pet Name Command");
client->Message(CHANNEL_COLOR_YELLOW, "Pets are not yet implemented.");
if (sep && sep->arg[0]) {
const char* pet_name = sep->argplus[0];
client->SetPetName(pet_name);
}
else {
client->GetPlayer()->GetInfoStruct()->set_pet_name("");
}
}
/*

View file

@ -5272,18 +5272,24 @@ int EQ2Emu_lua_SummonPet(lua_State* state) {
spawn->GetZone()->CallSpawnScript(spawn, SPAWN_SCRIPT_SPAWN);
}
// Get a random pet name
string random_pet_name;
int16 rand_index = MakeRandomInt(0, spawn->GetZone()->pet_names.size() - 1);
random_pet_name = spawn->GetZone()->pet_names.at(rand_index);
LogWrite(PET__DEBUG, 0, "Pets", "Randomize Pet Name: '%s' (rand: %i)", random_pet_name.c_str(), rand_index);
std::string petName = std::string("");
if(spawn->IsEntity()) {
petName = ((Entity*)spawn)->GetInfoStruct()->get_pet_name();
}
if(petName.size() < 1) {
int16 rand_index = MakeRandomInt(0, spawn->GetZone()->pet_names.size() - 1);
petName = spawn->GetZone()->pet_names.at(rand_index);
LogWrite(PET__DEBUG, 0, "Pets", "Randomize Pet Name: '%s' (rand: %i)", petName.c_str(), rand_index);
}
// If player set various values for the char sheet (pet window)
if (spawn->IsPlayer()) {
Player* player = (Player*)spawn;
player->GetInfoStruct()->set_pet_id(player->GetIDWithPlayerSpawn(pet));
player->GetInfoStruct()->set_pet_name(random_pet_name);
player->GetInfoStruct()->set_pet_name(petName);
player->GetInfoStruct()->set_pet_movement(2);
player->GetInfoStruct()->set_pet_behavior(3);
player->GetInfoStruct()->set_pet_health_pct(1.0f);
@ -5293,7 +5299,7 @@ int EQ2Emu_lua_SummonPet(lua_State* state) {
}
// Set the pets name
pet->SetName(random_pet_name.c_str());
pet->SetName(petName.c_str());
// Set the level of the pet to the owners level or max level(if set) if owners level is greater
if (max_level > 0)
pet->SetLevel(spawn->GetLevel() >= max_level ? max_level : spawn->GetLevel());
@ -7875,14 +7881,20 @@ int EQ2Emu_lua_SummonDumbFirePet(lua_State* state) {
spawn->GetZone()->CallSpawnScript(spawn, SPAWN_SCRIPT_SPAWN);
}
// Get a random pet name
string random_pet_name;
int16 rand_index = MakeRandomInt(0, spawn->GetZone()->pet_names.size() - 1);
random_pet_name = spawn->GetZone()->pet_names.at(rand_index);
LogWrite(PET__DEBUG, 0, "Pets", "Randomize Pet Name: '%s' (rand: %i)", random_pet_name.c_str(), rand_index);
std::string petName = std::string("");
if(spawn->IsEntity()) {
petName = ((Entity*)spawn)->GetInfoStruct()->get_pet_name();
}
if(petName.size() < 1) {
int16 rand_index = MakeRandomInt(0, spawn->GetZone()->pet_names.size() - 1);
petName = spawn->GetZone()->pet_names.at(rand_index);
LogWrite(PET__DEBUG, 0, "Pets", "Randomize Pet Name: '%s' (rand: %i)", petName.c_str(), rand_index);
}
// Set the pets name
pet->SetName(random_pet_name.c_str());
pet->SetName(petName.c_str());
// Set the level of the pet to the owners level
pet->SetLevel(spawn->GetLevel());
// Set the faction of the pet to the same faction as the owner

View file

@ -441,9 +441,15 @@ PacketStruct* PlayerInfo::serialize2(int16 version){
packet->setDataByName("coins_plat", info_struct->get_coin_plat());
packet->setDataByName("weight", info_struct->get_weight());
packet->setDataByName("max_weight", info_struct->get_max_weight());
char pet_name[32];
strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
packet->setDataByName("pet_name", pet_name);
if(info_struct->get_pet_id() != 0xFFFFFFFF) {
char pet_name[32];
strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
packet->setDataByName("pet_name", pet_name);
}
else {
packet->setDataByName("pet_name", "No Pet");
}
packet->setDataByName("status_points", info_struct->get_status_points());
if(bind_zone_id > 0){
string bind_name = database.GetZoneName(bind_zone_id);
@ -1220,10 +1226,16 @@ EQ2Packet* PlayerInfo::serializePet(int16 version) {
packet->setDataByName("spawn_id", info_struct->get_pet_id());
packet->setDataByName("spawn_id2", info_struct->get_pet_id());
char pet_name[32];
strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
packet->setDataByName("name", pet_name);
packet->setDataByName("no_pet", pet_name);
if(info_struct->get_pet_id() != 0xFFFFFFFF) {
char pet_name[32];
strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
packet->setDataByName("name", pet_name);
}
else {
packet->setDataByName("name", "No Pet");
packet->setDataByName("no_pet", "No Pet");
}
if (version >= 57000) {
packet->setDataByName("current_power3", pet->GetPower());
@ -5851,7 +5863,6 @@ void Player::RemoveAllPassives()
void Player::ResetPetInfo() {
GetInfoStruct()->set_pet_id(0xFFFFFFFF);
GetInfoStruct()->set_pet_name(std::string("No Pet"));
GetInfoStruct()->set_pet_movement(0);
GetInfoStruct()->set_pet_behavior(0);
GetInfoStruct()->set_pet_health_pct(0.0f);

View file

@ -24,6 +24,10 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
#include <iomanip>
#include <ios>
#include <assert.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include "WorldDatabase.h"
#include "../common/debug.h"
#include "../common/packet_dump.h"
@ -49,6 +53,7 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
#include "SpellProcess.h"
#include "races.h"
extern Classes classes;
extern Commands commands;
extern MasterTitlesList master_titles_list;
@ -1648,7 +1653,6 @@ bool WorldDatabase::LoadCharacterStats(int32 id, int32 account_id, Client* clien
info->set_coin_silver(result.GetInt32Str("coin_silver"));
info->set_coin_gold(result.GetInt32Str("coin_gold"));
info->set_coin_plat(result.GetInt32Str("coin_plat"));
info->set_pet_name(result.GetStringStr("pet_name") ? std::string(result.GetStringStr("pet_name")) : std::string(""));
const char* bio = result.GetStringStr("biography");
if(bio && strlen(bio) > 0)
info->set_biography(std::string(bio));
@ -1710,6 +1714,13 @@ bool WorldDatabase::LoadCharacterStats(int32 id, int32 account_id, Client* clien
client->GetPlayer()->SetTotalDissonanceBase(client->GetPlayer()->GetTotalDissonance());
client->GetPlayer()->SetCurrentLanguage(result.GetInt32Str("current_language"));
std::string petName = result.GetStringStr("pet_name");
boost::algorithm::to_lower(petName);
if(petName != "no pet") { // some reason we default to "no pet", the code handles an empty string as setting a random pet name when its summoned
client->GetPlayer()->GetInfoStruct()->set_pet_name(result.GetStringStr("pet_name"));
}
}
return true;
@ -2453,9 +2464,9 @@ int32 WorldDatabase::SaveCharacter(PacketStruct* create, int32 loginID){
return char_id;
}
int8 WorldDatabase::CheckNameFilter(const char* name) {
int8 WorldDatabase::CheckNameFilter(const char* name, int8 min_length, int8 max_length) {
// the minimum 4 is enforced by the client too
if(!name || strlen(name) < 4 || strlen(name) > 15) // Even 20 char length is long...
if(!name || strlen(name) < min_length || strlen(name) > max_length) // Even 20 char length is long...
return BADNAMELENGTH_REPLY;
uchar* checkname = (uchar*)name;
for (int32 i = 0; i < strlen(name); i++)
@ -4125,13 +4136,13 @@ void WorldDatabase::Save(Client* client){
if(client->GetCurrentZone())
zone_id = client->GetCurrentZone()->GetZoneID();
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update characters set current_zone_id=%u, x=%f, y=%f, z=%f, heading=%f, level=%i,instance_id=%i,last_saved=%i, `class`=%i, `tradeskill_level`=%i, `tradeskill_class`=%i, `group_id`=%u, deity = %u, alignment = %u where id = %u", zone_id, player->GetX(), player->GetY(), player->GetZ(), player->GetHeading(), player->GetLevel(), instance_id, client->GetLastSavedTimeStamp(), client->GetPlayer()->GetAdventureClass(), client->GetPlayer()->GetTSLevel(), client->GetPlayer()->GetTradeskillClass(), client->GetPlayer()->GetGroupMemberInfo() ? client->GetPlayer()->GetGroupMemberInfo()->group_id : client->GetRejoinGroupID(), client->GetPlayer()->GetDeity(), client->GetPlayer()->GetInfoStruct()->get_alignment(), client->GetCharacterID());
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update character_details set hp=%u, power=%u, str=%i, sta=%i, agi=%i, wis=%i, intel=%i, heat=%i, cold=%i, magic=%i, mental=%i, divine=%i, disease=%i, poison=%i, coin_copper=%u, coin_silver=%u, coin_gold=%u, coin_plat=%u, max_hp = %u, max_power=%u, xp = %u, xp_needed = %u, xp_debt = %f, xp_vitality = %f, tradeskill_xp = %u, tradeskill_xp_needed = %u, tradeskill_xp_vitality = %f, bank_copper = %u, bank_silver = %u, bank_gold = %u, bank_plat = %u, status_points = %u, bind_zone_id=%u, bind_x = %f, bind_y = %f, bind_z = %f, bind_heading = %f, house_zone_id=%u, combat_voice = %i, emote_voice = %i, biography='%s', flags=%u, flags2=%u, last_name='%s', assigned_aa = %i, unassigned_aa = %i, tradeskill_aa = %i, unassigned_tradeskill_aa = %i, prestige_aa = %i, unassigned_prestige_aa = %i, tradeskill_prestige_aa = %i, unassigned_tradeskill_prestige_aa = %i where char_id = %u",
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update character_details set hp=%u, power=%u, str=%i, sta=%i, agi=%i, wis=%i, intel=%i, heat=%i, cold=%i, magic=%i, mental=%i, divine=%i, disease=%i, poison=%i, coin_copper=%u, coin_silver=%u, coin_gold=%u, coin_plat=%u, max_hp = %u, max_power=%u, xp = %u, xp_needed = %u, xp_debt = %f, xp_vitality = %f, tradeskill_xp = %u, tradeskill_xp_needed = %u, tradeskill_xp_vitality = %f, bank_copper = %u, bank_silver = %u, bank_gold = %u, bank_plat = %u, status_points = %u, bind_zone_id=%u, bind_x = %f, bind_y = %f, bind_z = %f, bind_heading = %f, house_zone_id=%u, combat_voice = %i, emote_voice = %i, biography='%s', flags=%u, flags2=%u, last_name='%s', assigned_aa = %i, unassigned_aa = %i, tradeskill_aa = %i, unassigned_tradeskill_aa = %i, prestige_aa = %i, unassigned_prestige_aa = %i, tradeskill_prestige_aa = %i, unassigned_tradeskill_prestige_aa = %i, pet_name = '%s' where char_id = %u",
player->GetHP(), player->GetPower(), player->GetStrBase(), player->GetStaBase(), player->GetAgiBase(), player->GetWisBase(), player->GetIntBase(), player->GetHeatResistanceBase(), player->GetColdResistanceBase(), player->GetMagicResistanceBase(),
player->GetMentalResistanceBase(), player->GetDivineResistanceBase(), player->GetDiseaseResistanceBase(), player->GetPoisonResistanceBase(), player->GetCoinsCopper(), player->GetCoinsSilver(), player->GetCoinsGold(), player->GetCoinsPlat(), player->GetTotalHPBase(), player->GetTotalPowerBase(), player->GetXP(), player->GetNeededXP(), player->GetXPDebt(), player->GetXPVitality(), player->GetTSXP(), player->GetNeededTSXP(), player->GetTSXPVitality(), player->GetBankCoinsCopper(),
player->GetBankCoinsSilver(), player->GetBankCoinsGold(), player->GetBankCoinsPlat(), player->GetStatusPoints(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneID(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneX(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneY(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneZ(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneHeading(), client->GetPlayer()->GetPlayerInfo()->GetHouseZoneID(),
client->GetPlayer()->GetCombatVoice(), client->GetPlayer()->GetEmoteVoice(), getSafeEscapeString(client->GetPlayer()->GetBiography().c_str()).c_str(), player->GetFlags(), player->GetFlags2(), client->GetPlayer()->GetLastName(),
client->GetPlayer()->GetAssignedAA(), client->GetPlayer()->GetUnassignedAA(), client->GetPlayer()->GetTradeskillAA(), client->GetPlayer()->GetUnassignedTradeskillAA(), client->GetPlayer()->GetPrestigeAA(),
client->GetPlayer()->GetUnassignedPretigeAA(), client->GetPlayer()->GetTradeskillPrestigeAA(), client->GetPlayer()->GetUnassignedTradeskillPrestigeAA(), client->GetCharacterID());
client->GetPlayer()->GetUnassignedPretigeAA(), client->GetPlayer()->GetTradeskillPrestigeAA(), client->GetPlayer()->GetUnassignedTradeskillPrestigeAA(), client->GetPlayer()->GetInfoStruct()->get_pet_name().c_str(), client->GetCharacterID());
map<string, int8>::iterator itr;
map<string, int8>* friends = player->GetFriends();
if(friends && friends->size() > 0){

View file

@ -357,7 +357,7 @@ public:
int32 GetMaxHotBarID();
int8 CheckNameFilter(const char* name);
int8 CheckNameFilter(const char* name, int8 min_length = 4, int8 max_length = 15);
static int32 NextUniqueHotbarID(){
next_id++;
return next_id;

View file

@ -39,6 +39,7 @@ along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
#include "Chat/Chat.h"
#include "SpellProcess.h"
#include "Zone/ChestTrap.h"
#include "../../common/GlobalHeaders.h"
//#include "Quests.h"
@ -2039,9 +2040,8 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
packet->LoadPacketData(app->pBuffer, app->size);
string name = packet->getType_EQ2_16BitString_ByName("pet_name").data;
if (strlen(name.c_str()) != 0) {
if (strlen(name.c_str()) != 0 && SetPetName(name.c_str())) {
target->SetName(name.c_str());
player->GetInfoStruct()->set_pet_name(name);
GetCurrentZone()->SendUpdateTitles(target);
change = true;
}
@ -11448,3 +11448,31 @@ void Client::HandleDialogSelectMsg(int32 conversation_id, int32 response_index)
CloseDialog(conversation_id);
}
}
bool Client::SetPetName(const char* petName) {
int8 result = database.CheckNameFilter(petName,4,31);
if (result == BADNAMELENGTH_REPLY) {
SimpleMessage(CHANNEL_COLOR_YELLOW, "Name length is invalid, must be greater then 3 characters and less then 16.");
return false;
}
else if (result == NAMEINVALID_REPLY) {
SimpleMessage(CHANNEL_COLOR_YELLOW, "Name is invalid, can only contain letters.");
return false;
}
else if (result == NAMETAKEN_REPLY) {
SimpleMessage(CHANNEL_COLOR_YELLOW, "Name is already taken, please choose another.");
return false;
}
else if (result == NAMEFILTER_REPLY) {
SimpleMessage(CHANNEL_COLOR_YELLOW, "Name failed the filter check.");
return false;
}
else if (result == UNKNOWNERROR_REPLY) {
SimpleMessage(CHANNEL_COLOR_YELLOW, "Unknown error while checking the name.");
return false;
}
GetPlayer()->GetInfoStruct()->set_pet_name(petName);
return true;
}

View file

@ -575,6 +575,7 @@ public:
int32 GetPlayerPOVGhostSpawnID() { return pov_ghost_spawn_id; }
void HandleDialogSelectMsg(int32 conversation_id, int32 response_index);
bool SetPetName(const char* name);
private:
void SavePlayerImages();
void SkillChanged(Skill* skill, int16 previous_value, int16 new_value);