mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-31 09:06:46 +00:00
Merge from master, fixed conflicts
This commit is contained in:
+85
-77
@@ -16,6 +16,7 @@
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/clientversions.h"
|
||||
#include "../common/random.h"
|
||||
#include "../common/shareddb.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "worlddb.h"
|
||||
@@ -86,11 +87,11 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
charid = 0;
|
||||
pwaitingforbootup = 0;
|
||||
StartInTutorial = false;
|
||||
ClientVersionBit = 0;
|
||||
numclients++;
|
||||
|
||||
if (eqs->GetClientVersion() != ClientVersion::Unknown)
|
||||
ClientVersionBit = 1 << (static_cast<unsigned int>(eqs->GetClientVersion()) - 1);
|
||||
m_ClientVersion = eqs->GetClientVersion();
|
||||
m_ClientVersionBit = ClientBitFromVersion(m_ClientVersion);
|
||||
|
||||
numclients++;
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
@@ -161,32 +162,34 @@ void Client::SendCharInfo() {
|
||||
cle->SetOnline(CLE_Status_CharSelect);
|
||||
}
|
||||
|
||||
if (ClientVersionBit & BIT_RoFAndLater)
|
||||
{
|
||||
// Can make max char per account into a rule - New to VoA
|
||||
SendMaxCharCreate(10);
|
||||
if (m_ClientVersionBit & BIT_RoFAndLater) {
|
||||
SendMaxCharCreate();
|
||||
SendMembership();
|
||||
SendMembershipSettings();
|
||||
}
|
||||
|
||||
seencharsel = true;
|
||||
|
||||
|
||||
// Send OP_SendCharInfo
|
||||
auto outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
||||
CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;
|
||||
EQApplicationPacket *outapp = nullptr;
|
||||
database.GetCharSelectInfo(GetAccountID(), &outapp, m_ClientVersionBit);
|
||||
|
||||
database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit);
|
||||
|
||||
QueuePacket(outapp);
|
||||
if (outapp) {
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::General, Logs::World_Server, "[Error] Database did not return an OP_SendCharInfo packet for account %u", GetAccountID());
|
||||
}
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SendMaxCharCreate(int max_chars) {
|
||||
void Client::SendMaxCharCreate() {
|
||||
auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct));
|
||||
MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer;
|
||||
|
||||
mc->max_chars = max_chars;
|
||||
mc->max_chars = EQLimits::CharacterCreationLimit(m_ClientVersion);
|
||||
if (mc->max_chars > EmuConstants::CHARACTER_CREATION_LIMIT)
|
||||
mc->max_chars = EmuConstants::CHARACTER_CREATION_LIMIT;
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
@@ -671,7 +674,7 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||
if (m_ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||
StartInTutorial = true;
|
||||
SendCharInfo();
|
||||
}
|
||||
@@ -716,66 +719,71 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!pZoning && ew->return_home && !ew->tutorial) {
|
||||
auto cs = new CharacterSelect_Struct;
|
||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
||||
database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit);
|
||||
bool home_enabled = false;
|
||||
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
|
||||
if (!pZoning) {
|
||||
size_t character_limit = EQLimits::CharacterCreationLimit(eqs->GetClientVersion());
|
||||
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) { character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; }
|
||||
if (eqs->GetClientVersion() == ClientVersion::Titanium) { character_limit = 8; }
|
||||
|
||||
for(int x = 0; x < 10; ++x)
|
||||
{
|
||||
if(strcasecmp(cs->name[x], char_name) == 0)
|
||||
{
|
||||
if(cs->gohome[x] == 1)
|
||||
{
|
||||
home_enabled = true;
|
||||
break;
|
||||
std::string tgh_query = StringFormat(
|
||||
"SELECT "
|
||||
"`id`, "
|
||||
"name, "
|
||||
"`level`, "
|
||||
"last_login "
|
||||
"FROM "
|
||||
"character_data "
|
||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit);
|
||||
auto tgh_results = database.QueryDatabase(tgh_query);
|
||||
|
||||
/* Check GoHome */
|
||||
if (ew->return_home && !ew->tutorial) {
|
||||
bool home_enabled = false;
|
||||
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||
if (strcasecmp(row[1], char_name) == 0) {
|
||||
if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) {
|
||||
home_enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
safe_delete(cs);
|
||||
|
||||
if(home_enabled) {
|
||||
zoneID = database.MoveCharacterToBind(charid,4);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go home before they're able...",char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) {
|
||||
auto cs = new CharacterSelect_Struct;
|
||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
||||
database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit);
|
||||
bool tutorial_enabled = false;
|
||||
|
||||
for(int x = 0; x < 10; ++x)
|
||||
{
|
||||
if(strcasecmp(cs->name[x], char_name) == 0)
|
||||
{
|
||||
if(cs->tutorial[x] == 1)
|
||||
{
|
||||
tutorial_enabled = true;
|
||||
break;
|
||||
}
|
||||
if (home_enabled) {
|
||||
zoneID = database.MoveCharacterToBind(charid, 4);
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go home before they're able...", char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
safe_delete(cs);
|
||||
|
||||
if(tutorial_enabled)
|
||||
{
|
||||
zoneID = RuleI(World, TutorialZoneID);
|
||||
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go to tutorial but are not allowed...",char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
/* Check Tutorial*/
|
||||
if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) {
|
||||
bool tutorial_enabled = false;
|
||||
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||
if (strcasecmp(row[1], char_name) == 0) {
|
||||
if (RuleB(World, EnableReturnHomeButton)) {
|
||||
int now = time(nullptr);
|
||||
if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) {
|
||||
tutorial_enabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tutorial_enabled) {
|
||||
zoneID = RuleI(World, TutorialZoneID);
|
||||
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
||||
}
|
||||
else {
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go to tutorial but are not allowed...", char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,9 +854,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
|
||||
char ConnectionType;
|
||||
|
||||
if(ClientVersionBit & BIT_UFAndLater)
|
||||
if (m_ClientVersionBit & BIT_UFAndLater)
|
||||
ConnectionType = 'U';
|
||||
else if(ClientVersionBit & BIT_SoFAndLater)
|
||||
else if (m_ClientVersionBit & BIT_SoFAndLater)
|
||||
ConnectionType = 'S';
|
||||
else
|
||||
ConnectionType = 'C';
|
||||
@@ -872,7 +880,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
|
||||
outapp2 = new EQApplicationPacket(OP_SetChatServer2);
|
||||
|
||||
if(ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||
if (m_ClientVersionBit & BIT_TitaniumAndEarlier)
|
||||
ConnectionType = 'M';
|
||||
|
||||
sprintf(buffer,"%s,%i,%s.%s,%c%08X",
|
||||
@@ -906,7 +914,7 @@ bool Client::HandleDeleteCharacterPacket(const EQApplicationPacket *app) {
|
||||
|
||||
bool Client::HandleZoneChangePacket(const EQApplicationPacket *app) {
|
||||
// HoT sends this to world while zoning and wants it echoed back.
|
||||
if(ClientVersionBit & BIT_RoFAndLater)
|
||||
if (m_ClientVersionBit & BIT_RoFAndLater)
|
||||
{
|
||||
QueuePacket(app);
|
||||
}
|
||||
@@ -1370,7 +1378,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
Log.Out(Logs::Detail, Logs::World_Server, "Beard: %d Beardcolor: %d", cc->beard, cc->beardcolor);
|
||||
|
||||
/* Validate the char creation struct */
|
||||
if (ClientVersionBit & BIT_SoFAndLater) {
|
||||
if (m_ClientVersionBit & BIT_SoFAndLater) {
|
||||
if (!CheckCharCreateInfoSoF(cc)) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
||||
return false;
|
||||
@@ -1438,7 +1446,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
|
||||
|
||||
/* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
|
||||
if (ClientVersionBit & BIT_SoFAndLater) {
|
||||
if (m_ClientVersionBit & BIT_SoFAndLater) {
|
||||
Log.Out(Logs::Detail, Logs::World_Server,"Found 'SoFStartZoneID' rule setting: %i", RuleI(World, SoFStartZoneID));
|
||||
if (RuleI(World, SoFStartZoneID) > 0) {
|
||||
pp.zone_id = RuleI(World, SoFStartZoneID);
|
||||
@@ -1454,7 +1462,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
}
|
||||
}
|
||||
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
|
||||
bool ValidStartZone = database.GetStartZone(&pp, cc, ClientVersionBit & BIT_TitaniumAndEarlier);
|
||||
bool ValidStartZone = database.GetStartZone(&pp, cc, m_ClientVersionBit & BIT_TitaniumAndEarlier);
|
||||
|
||||
if (!ValidStartZone){
|
||||
return false;
|
||||
|
||||
+3
-2
@@ -41,7 +41,7 @@ public:
|
||||
bool Process();
|
||||
void ReceiveData(uchar* buf, int len);
|
||||
void SendCharInfo();
|
||||
void SendMaxCharCreate(int max_chars);
|
||||
void SendMaxCharCreate();
|
||||
void SendMembership();
|
||||
void SendMembershipSettings();
|
||||
void EnterWorld(bool TryBootup = true);
|
||||
@@ -84,7 +84,8 @@ private:
|
||||
uint32 pwaitingforbootup;
|
||||
|
||||
bool StartInTutorial;
|
||||
uint32 ClientVersionBit;
|
||||
ClientVersion m_ClientVersion;
|
||||
uint32 m_ClientVersionBit;
|
||||
bool OPCharCreate(char *name, CharCreate_Struct *cc);
|
||||
|
||||
void SetClassStartingSkills( PlayerProfile_Struct *pp );
|
||||
|
||||
+124
-104
@@ -33,20 +33,20 @@ extern std::vector<RaceClassCombos> character_create_race_class_combos;
|
||||
|
||||
|
||||
// the current stuff is at the bottom of this function
|
||||
void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs, uint32 ClientVersion) {
|
||||
InventoryOld *inv;
|
||||
uint8 has_home = 0;
|
||||
uint8 has_bind = 0;
|
||||
|
||||
/* Initialize Variables */
|
||||
for (int i=0; i<10; i++) {
|
||||
strcpy(cs->name[i], "<none>");
|
||||
cs->zone[i] = 0;
|
||||
cs->level[i] = 0;
|
||||
cs->tutorial[i] = 0;
|
||||
cs->gohome[i] = 0;
|
||||
}
|
||||
void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit)
|
||||
{
|
||||
/* Set Character Creation Limit */
|
||||
ClientVersion client_version = ClientVersionFromBit(clientVersionBit);
|
||||
size_t character_limit = EQLimits::CharacterCreationLimit(client_version);
|
||||
|
||||
// Validate against absolute server max
|
||||
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT)
|
||||
character_limit = EmuConstants::CHARACTER_CREATION_LIMIT;
|
||||
|
||||
// Force Titanium clients to use '8'
|
||||
if (client_version == ClientVersion::Titanium)
|
||||
character_limit = 8;
|
||||
|
||||
/* Get Character Info */
|
||||
std::string cquery = StringFormat(
|
||||
"SELECT "
|
||||
@@ -72,52 +72,93 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
|
||||
"zone_id " // 19
|
||||
"FROM "
|
||||
"character_data "
|
||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT 10 ", account_id);
|
||||
auto results = database.QueryDatabase(cquery); int char_num = 0;
|
||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", accountID, character_limit);
|
||||
auto results = database.QueryDatabase(cquery);
|
||||
|
||||
size_t character_count = results.RowCount();
|
||||
if (character_count == 0) {
|
||||
*outApp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
||||
CharacterSelect_Struct *cs = (CharacterSelect_Struct *)(*outApp)->pBuffer;
|
||||
cs->CharCount = 0;
|
||||
cs->TotalChars = character_limit;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t packet_size = sizeof(CharacterSelect_Struct) + (sizeof(CharacterSelectEntry_Struct) * character_count);
|
||||
*outApp = new EQApplicationPacket(OP_SendCharInfo, packet_size);
|
||||
|
||||
unsigned char *buff_ptr = (*outApp)->pBuffer;
|
||||
CharacterSelect_Struct *cs = (CharacterSelect_Struct *)buff_ptr;
|
||||
|
||||
cs->CharCount = character_count;
|
||||
cs->TotalChars = character_limit;
|
||||
|
||||
buff_ptr += sizeof(CharacterSelect_Struct);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
CharacterSelectEntry_Struct *cse = (CharacterSelectEntry_Struct *)buff_ptr;
|
||||
PlayerProfile_Struct pp;
|
||||
InventoryOld inv;
|
||||
uint32 character_id = (uint32)atoi(row[0]);
|
||||
uint8 has_home = 0;
|
||||
uint8 has_bind = 0;
|
||||
|
||||
memset(&pp, 0, sizeof(PlayerProfile_Struct));
|
||||
|
||||
/* Fill CharacterSelectEntry_Struct */
|
||||
strcpy(cse->Name, row[1]);
|
||||
cse->Class = (uint8)atoi(row[4]);
|
||||
cse->Race = (uint32)atoi(row[3]);
|
||||
cse->Level = (uint8)atoi(row[5]);
|
||||
cse->ShroudClass = cse->Class;
|
||||
cse->ShroudRace = cse->Race;
|
||||
cse->Zone = (uint16)atoi(row[19]);
|
||||
cse->Instance = 0;
|
||||
cse->Gender = (uint8)atoi(row[2]);
|
||||
cse->Face = (uint8)atoi(row[15]);
|
||||
cse->Equip[0] = { 0 }; // Processed below
|
||||
cse->Unknown15 = 0xFF;
|
||||
cse->Unknown19 = 0xFF;
|
||||
cse->DrakkinTattoo = (uint32)atoi(row[17]);
|
||||
cse->DrakkinDetails = (uint32)atoi(row[18]);
|
||||
cse->Deity = (uint32)atoi(row[6]);
|
||||
cse->PrimaryIDFile = 0; // Processed Below
|
||||
cse->SecondaryIDFile = 0; // Processed Below
|
||||
cse->HairColor = (uint8)atoi(row[9]);
|
||||
cse->BeardColor = (uint8)atoi(row[10]);
|
||||
cse->EyeColor1 = (uint8)atoi(row[11]);
|
||||
cse->EyeColor2 = (uint8)atoi(row[12]);
|
||||
cse->HairStyle = (uint8)atoi(row[13]);
|
||||
cse->Beard = (uint8)atoi(row[14]);
|
||||
cse->Enabled = 1;
|
||||
cse->Tutorial = 0; // Processed Below
|
||||
cse->DrakkinHeritage = (uint32)atoi(row[16]);
|
||||
cse->Unknown1 = 0;
|
||||
cse->GoHome = 0; // Processed Below
|
||||
cse->LastLogin = (uint32)atoi(row[7]); // RoF2 value: 1212696584
|
||||
cse->Unknown2 = 0;
|
||||
/* Fill End */
|
||||
|
||||
uint32 character_id = atoi(row[0]);
|
||||
strcpy(cs->name[char_num], row[1]);
|
||||
uint8 lvl = atoi(row[5]);
|
||||
cs->level[char_num] = lvl;
|
||||
cs->class_[char_num] = atoi(row[4]);
|
||||
cs->race[char_num] = atoi(row[3]);
|
||||
cs->gender[char_num] = atoi(row[2]);
|
||||
cs->deity[char_num] = atoi(row[6]);
|
||||
cs->zone[char_num] = atoi(row[19]);
|
||||
cs->face[char_num] = atoi(row[15]);
|
||||
cs->haircolor[char_num] = atoi(row[9]);
|
||||
cs->beardcolor[char_num] = atoi(row[10]);
|
||||
cs->eyecolor2[char_num] = atoi(row[12]);
|
||||
cs->eyecolor1[char_num] = atoi(row[11]);
|
||||
cs->hairstyle[char_num] = atoi(row[13]);
|
||||
cs->beard[char_num] = atoi(row[14]);
|
||||
cs->drakkin_heritage[char_num] = atoi(row[16]);
|
||||
cs->drakkin_tattoo[char_num] = atoi(row[17]);
|
||||
cs->drakkin_details[char_num] = atoi(row[18]);
|
||||
|
||||
if (RuleB(World, EnableTutorialButton) && (lvl <= RuleI(World, MaxLevelForTutorial)))
|
||||
cs->tutorial[char_num] = 1;
|
||||
if (RuleB(World, EnableTutorialButton) && (cse->Level <= RuleI(World, MaxLevelForTutorial))) {
|
||||
cse->Tutorial = 1;
|
||||
}
|
||||
|
||||
if (RuleB(World, EnableReturnHomeButton)) {
|
||||
int now = time(nullptr);
|
||||
if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome))
|
||||
cs->gohome[char_num] = 1;
|
||||
cse->GoHome = 1;
|
||||
}
|
||||
|
||||
/* Set Bind Point Data for any character that may possibly be missing it for any reason */
|
||||
cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %i LIMIT 2", character_id);
|
||||
auto results_bind = database.QueryDatabase(cquery); has_home = 0; has_bind = 0;
|
||||
auto results_bind = database.QueryDatabase(cquery);
|
||||
for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) {
|
||||
if (row_b[6] && atoi(row_b[6]) == 1){ has_home = 1; }
|
||||
if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 1; }
|
||||
}
|
||||
|
||||
if (has_home == 0 || has_bind == 0){
|
||||
if (has_home == 0 || has_bind == 0) {
|
||||
cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i",
|
||||
cs->class_[char_num], cs->deity[char_num], cs->race[char_num]);
|
||||
cse->Class, cse->Deity, cse->Race);
|
||||
auto results_bind = database.QueryDatabase(cquery);
|
||||
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
|
||||
/* If a bind_id is specified, make them start there */
|
||||
@@ -133,118 +174,97 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
|
||||
float z = atof(row_d[4]);
|
||||
if (x == 0 && y == 0 && z == 0){ GetSafePoints(pp.binds[4].zoneId, 0, &x, &y, &z); }
|
||||
pp.binds[4].x = x; pp.binds[4].y = y; pp.binds[4].z = z;
|
||||
|
||||
}
|
||||
}
|
||||
pp.binds[0] = pp.binds[4];
|
||||
/* If no home bind set, set it */
|
||||
if (has_home == 0){
|
||||
if (has_home == 0) {
|
||||
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||
character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 1);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
}
|
||||
/* If no regular bind set, set it */
|
||||
if (has_bind == 0){
|
||||
if (has_bind == 0) {
|
||||
std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||
character_id, pp.binds[0].zoneId, 0, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z, pp.binds[0].heading, 0);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
/* Bind End */
|
||||
|
||||
/* Load Character Material Data for Char Select */
|
||||
cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id);
|
||||
auto results_b = database.QueryDatabase(cquery); uint8 slot = 0;
|
||||
for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b)
|
||||
{
|
||||
slot = atoi(row_b[0]);
|
||||
pp.item_tint[slot].rgb.red = atoi(row_b[1]);
|
||||
pp.item_tint[slot].rgb.green = atoi(row_b[2]);
|
||||
pp.item_tint[slot].rgb.blue = atoi(row_b[3]);
|
||||
pp.item_tint[slot].rgb.use_tint = atoi(row_b[4]);
|
||||
}
|
||||
|
||||
/* Load Inventory */
|
||||
inv = new InventoryOld;
|
||||
if (GetInventory(account_id, cs->name[char_num], inv))
|
||||
{
|
||||
// If we ensure that the material data is updated appropriately, we can do away with inventory loads
|
||||
if (GetInventory(accountID, cse->Name, &inv)) {
|
||||
const ItemData* item = nullptr;
|
||||
const ItemInst* inst = nullptr;
|
||||
int16 invslot = 0;
|
||||
|
||||
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++)
|
||||
{
|
||||
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) {
|
||||
invslot = InventoryOld::CalcSlotFromMaterial(matslot);
|
||||
|
||||
if (invslot == INVALID_INDEX) { continue; }
|
||||
|
||||
inst = inv->GetItem(invslot);
|
||||
inst = inv.GetItem(invslot);
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
item = inst->GetItem();
|
||||
if (item == nullptr) { continue; }
|
||||
|
||||
if (matslot > 6)
|
||||
{
|
||||
if (matslot > 6) {
|
||||
uint32 idfile = 0;
|
||||
// Weapon Models
|
||||
if (inst->GetOrnamentationIDFile() != 0)
|
||||
{
|
||||
if (inst->GetOrnamentationIDFile() != 0) {
|
||||
idfile = inst->GetOrnamentationIDFile();
|
||||
cs->equip[char_num][matslot].material = idfile;
|
||||
cse->Equip[matslot].Material = idfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(item->IDFile) > 2)
|
||||
{
|
||||
else {
|
||||
if (strlen(item->IDFile) > 2) {
|
||||
idfile = atoi(&item->IDFile[2]);
|
||||
cs->equip[char_num][matslot].material = idfile;
|
||||
cse->Equip[matslot].Material = idfile;
|
||||
}
|
||||
}
|
||||
if (matslot == MaterialPrimary)
|
||||
{
|
||||
cs->primary[char_num] = idfile;
|
||||
if (matslot == MaterialPrimary) {
|
||||
cse->PrimaryIDFile = idfile;
|
||||
}
|
||||
else
|
||||
{
|
||||
cs->secondary[char_num] = idfile;
|
||||
else {
|
||||
cse->SecondaryIDFile = idfile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
uint32 color = 0;
|
||||
if (pp.item_tint[matslot].rgb.use_tint)
|
||||
{
|
||||
color = pp.item_tint[matslot].color;
|
||||
if (pp.item_tint[matslot].RGB.UseTint) {
|
||||
color = pp.item_tint[matslot].Color;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
color = inst->GetColor();
|
||||
}
|
||||
|
||||
// Armor Materials/Models
|
||||
cs->equip[char_num][matslot].material = item->Material;
|
||||
cs->equip[char_num][matslot].elitematerial = item->EliteMaterial;
|
||||
cs->equip[char_num][matslot].heroforgemodel = inst->GetOrnamentHeroModel(matslot);
|
||||
cs->equip[char_num][matslot].color.color = color;
|
||||
cse->Equip[matslot].Material = item->Material;
|
||||
cse->Equip[matslot].EliteMaterial = item->EliteMaterial;
|
||||
cse->Equip[matslot].HeroForgeModel = inst->GetOrnamentHeroModel(matslot);
|
||||
cse->Equip[matslot].Color.Color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error loading inventory for %s\n", cs->name[char_num]);
|
||||
else {
|
||||
printf("Error loading inventory for %s\n", cse->Name);
|
||||
}
|
||||
/* Load Inventory End */
|
||||
|
||||
/* Load Character Material Data for Char Select */
|
||||
cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id);
|
||||
auto results_b = database.QueryDatabase(cquery); uint8 slot = 0;
|
||||
for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) {
|
||||
slot = atoi(row_b[0]);
|
||||
pp.item_tint[slot].RGB.Red = atoi(row_b[1]);
|
||||
pp.item_tint[slot].RGB.Green = atoi(row_b[2]);
|
||||
pp.item_tint[slot].RGB.Blue = atoi(row_b[3]);
|
||||
pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]);
|
||||
}
|
||||
|
||||
safe_delete(inv);
|
||||
|
||||
if (++char_num > 10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
buff_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) {
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "../common/shareddb.h"
|
||||
#include "../common/zone_numbers.h"
|
||||
#include "../common/eq_packet.h"
|
||||
|
||||
struct PlayerProfile_Struct;
|
||||
struct CharCreate_Struct;
|
||||
@@ -29,7 +30,7 @@ struct CharacterSelect_Struct;
|
||||
class WorldDatabase : public SharedDatabase {
|
||||
public:
|
||||
bool GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc, bool isTitanium);
|
||||
void GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*, uint32 ClientVersion);
|
||||
void GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit);
|
||||
int MoveCharacterToBind(int CharID, uint8 bindnum = 0);
|
||||
|
||||
void GetLauncherList(std::vector<std::string> &result);
|
||||
|
||||
Reference in New Issue
Block a user