Implemented per-client character creation limits

This commit is contained in:
Uleat 2015-02-17 13:56:58 -05:00
parent e4be4d6895
commit 766641cd15
24 changed files with 790 additions and 597 deletions

View File

@ -49,7 +49,6 @@ public:
// database
static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client
// This value should be at least 8 or Titanium will have issues (tested at 6)
static const size_t CHARACTER_CREATION_LIMIT = RoF2::consts::CHARACTER_CREATION_LIMIT;
// inventory

View File

@ -158,32 +158,46 @@ struct CharSelectEquip
Color_Struct Color;
};
struct CharacterSelectEntry_Struct
{
char Name[64];
uint8 Class;
uint32 Race;
uint8 Level;
uint8 ShroudClass;
uint32 ShroudRace;
uint16 Zone;
uint16 Instance;
uint8 Gender;
uint8 Face;
CharSelectEquip Equip[9];
uint8 Unknown15; // Seen FF
uint8 Unknown19; // Seen FF
uint32 DrakkinTattoo;
uint32 DrakkinDetails;
uint32 Deity;
uint32 PrimaryIDFile;
uint32 SecondaryIDFile;
uint8 HairColor;
uint8 BeardColor;
uint8 EyeColor1;
uint8 EyeColor2;
uint8 HairStyle;
uint8 Beard;
uint8 Enabled;
uint8 Tutorial; // Seen 1 for new char or 0 for existing
uint32 DrakkinHeritage;
uint8 Unknown1; // Seen 0
uint8 GoHome; // Seen 0 for new char and 1 for existing
uint32 LastLogin;
uint8 Unknown2; // Seen 0
};
struct CharacterSelect_Struct
{
uint32 Race[10]; // Characters Race
uint8 BeardColor[10]; // Characters beard Color
uint8 HairStyle[10]; // Characters hair style
CharSelectEquip Equip[10][9];
uint32 Secondary[10]; // Characters secondary IDFile number
uint32 DrakkinHeritage[10]; // added for SoF
uint32 DrakkinTattoo[10]; // added for SoF
uint32 DrakkinDetails[10]; // added for SoF
uint32 Deity[10]; // Characters Deity
uint8 GoHome[10]; // 1=Go Home available, 0=not
uint8 Tutorial[10]; // 1=Tutorial available, 0=not
uint8 Beard[10]; // Characters Beard Type
uint8 Unknown902[10]; // 10x ff
uint32 Primary[10]; // Characters primary IDFile number
uint8 HairColor[10]; // Characters Hair Color
uint8 Unknown0962[2]; // 2x 00
uint32 Zone[10]; // Characters Current Zone
uint8 Class_[10]; // Characters Classes
uint8 Face[10]; // Characters Face Type
char Name[10][64]; // Characters Names
uint8 Gender[10]; // Characters Gender
uint8 EyeColor1[10]; // Characters Eye Color
uint8 EyeColor2[10]; // Characters Eye 2 Color
uint8 Level[10]; // Characters Levels
uint32 CharCount; //number of chars in this packet
uint32 TotalChars; //total number of chars allowed?
CharacterSelectEntry_Struct Entries[0];
};
/*

View File

@ -2897,85 +2897,99 @@ namespace RoF
ENCODE(OP_SendCharInfo)
{
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
SETUP_VAR_ENCODE(CharacterSelect_Struct);
//EQApplicationPacket *packet = *p;
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
// Zero-character count shunt
if (emu->CharCount == 0) {
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
eq->CharCount = emu->CharCount;
int char_count;
int namelen = 0;
for (char_count = 0; char_count < 10; char_count++) {
if (emu->Name[char_count][0] == '\0')
break;
if (strcmp(emu->Name[char_count], "<none>") == 0)
break;
namelen += strlen(emu->Name[char_count]);
FINISH_ENCODE();
return;
}
int total_length = sizeof(structs::CharacterSelect_Struct)
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
+ namelen;
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
size_t names_length = 0;
size_t character_count = 0;
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
names_length += strlen(emu_cse->Name);
emu_ptr += sizeof(CharacterSelectEntry_Struct);
}
size_t total_length = sizeof(structs::CharacterSelect_Struct)
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
+ names_length;
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
//unsigned char *eq_buffer = new unsigned char[total_length];
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
eq->CharCount = character_count;
//eq->TotalChars = emu->TotalChars;
eq->CharCount = char_count;
//eq->total_chars = 10;
//if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
// eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
unsigned char *bufptr = (unsigned char *)eq->Entries;
int r;
for (r = 0; r < char_count; r++) {
{ //pre-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
unsigned char *eq_ptr = __packet->pBuffer;
eq_ptr += sizeof(structs::CharacterSelect_Struct);
for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Class = emu_cse->Class;
eq_cse->Race = emu_cse->Race;
eq_cse->Level = emu_cse->Level;
eq_cse->ShroudClass = emu_cse->ShroudClass;
eq_cse->ShroudRace = emu_cse->ShroudRace;
eq_cse->Zone = emu_cse->Zone;
eq_cse->Instance = emu_cse->Instance;
eq_cse->Gender = emu_cse->Gender;
eq_cse->Face = emu_cse->Face;
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel;
eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2;
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
}
//adjust for name.
bufptr += strlen(emu->Name[r]);
{ //post-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Class_ = emu->Class_[r];
eq2->Race = emu->Race[r];
eq2->Level = emu->Level[r];
eq2->Class_2 = emu->Class_[r];
eq2->Race2 = emu->Race[r];
eq2->Zone = emu->Zone[r];
eq2->Instance = 0;
eq2->Gender = emu->Gender[r];
eq2->Face = emu->Face[r];
int k;
for (k = 0; k < _MaterialCount; k++) {
eq2->Equip[k].Material = emu->Equip[r][k].Material;
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel;
eq2->Equip[k].Material2 = emu->Equip[r][k].Material2;
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
}
eq2->Unknown15 = 0xFF;
eq2->Uknown19 = 0xFF;
eq2->DrakkinTattoo = emu->DrakkinTattoo[r];
eq2->DrakkinDetails = emu->DrakkinDetails[r];
eq2->Deity = emu->Deity[r];
eq2->Primary = emu->Primary[r];
eq2->Secondary = emu->Secondary[r];
eq2->HairColor = emu->HairColor[r];
eq2->BeardColor = emu->BeardColor[r];
eq2->EyeColor1 = emu->EyeColor1[r];
eq2->EyeColor2 = emu->EyeColor2[r];
eq2->HairStyle = emu->HairStyle[r];
eq2->Beard = emu->Beard[r];
eq2->CharEnabled = 1;
eq2->Tutorial = emu->Tutorial[r];
eq2->DrakkinHeritage = emu->DrakkinHeritage[r];
eq2->Unknown1 = 0;
eq2->GoHome = emu->GoHome[r];
eq2->LastLogin = 1212696584;
eq2->Unknown2 = 0;
}
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
eq_cse->Unknown15 = emu_cse->Unknown15;
eq_cse->Unknown19 = emu_cse->Unknown19;
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
eq_cse->Deity = emu_cse->Deity;
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
eq_cse->HairColor = emu_cse->HairColor;
eq_cse->BeardColor = emu_cse->BeardColor;
eq_cse->EyeColor1 = emu_cse->EyeColor1;
eq_cse->EyeColor2 = emu_cse->EyeColor2;
eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Beard = emu_cse->Beard;
eq_cse->Enabled = emu_cse->Enabled;
eq_cse->Tutorial = emu_cse->Tutorial;
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
eq_cse->Unknown1 = emu_cse->Unknown1;
eq_cse->GoHome = emu_cse->GoHome;
eq_cse->LastLogin = emu_cse->LastLogin;
eq_cse->Unknown2 = emu_cse->Unknown2;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
}
FINISH_ENCODE();

View File

@ -2981,85 +2981,99 @@ namespace RoF2
ENCODE(OP_SendCharInfo)
{
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
SETUP_VAR_ENCODE(CharacterSelect_Struct);
//EQApplicationPacket *packet = *p;
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
// Zero-character count shunt
if (emu->CharCount == 0) {
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
eq->CharCount = emu->CharCount;
int char_count;
int namelen = 0;
for (char_count = 0; char_count < 10; char_count++) {
if (emu->Name[char_count][0] == '\0')
break;
if (strcmp(emu->Name[char_count], "<none>") == 0)
break;
namelen += strlen(emu->Name[char_count]);
FINISH_ENCODE();
return;
}
int total_length = sizeof(structs::CharacterSelect_Struct)
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
+ namelen;
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
size_t names_length = 0;
size_t character_count = 0;
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
names_length += strlen(emu_cse->Name);
emu_ptr += sizeof(CharacterSelectEntry_Struct);
}
size_t total_length = sizeof(structs::CharacterSelect_Struct)
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
+ names_length;
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
//unsigned char *eq_buffer = new unsigned char[total_length];
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
eq->CharCount = character_count;
//eq->TotalChars = emu->TotalChars;
eq->CharCount = char_count;
//eq->total_chars = 10;
//if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
// eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
unsigned char *bufptr = (unsigned char *)eq->Entries;
int r;
for (r = 0; r < char_count; r++) {
{ //pre-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
unsigned char *eq_ptr = __packet->pBuffer;
eq_ptr += sizeof(structs::CharacterSelect_Struct);
for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Class = emu_cse->Class;
eq_cse->Race = emu_cse->Race;
eq_cse->Level = emu_cse->Level;
eq_cse->ShroudClass = emu_cse->ShroudClass;
eq_cse->ShroudRace = emu_cse->ShroudRace;
eq_cse->Zone = emu_cse->Zone;
eq_cse->Instance = emu_cse->Instance;
eq_cse->Gender = emu_cse->Gender;
eq_cse->Face = emu_cse->Face;
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel;
eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2;
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
}
//adjust for name.
bufptr += strlen(emu->Name[r]);
{ //post-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Class_ = emu->Class_[r];
eq2->Race = emu->Race[r];
eq2->Level = emu->Level[r];
eq2->Class_2 = emu->Class_[r];
eq2->Race2 = emu->Race[r];
eq2->Zone = emu->Zone[r];
eq2->Instance = 0;
eq2->Gender = emu->Gender[r];
eq2->Face = emu->Face[r];
int k;
for (k = 0; k < _MaterialCount; k++) {
eq2->Equip[k].Material = emu->Equip[r][k].Material;
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel;
eq2->Equip[k].Material2 = emu->Equip[r][k].Material2;
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
}
eq2->Unknown15 = 0xFF;
eq2->Unknown19 = 0xFF;
eq2->DrakkinTattoo = emu->DrakkinTattoo[r];
eq2->DrakkinDetails = emu->DrakkinDetails[r];
eq2->Deity = emu->Deity[r];
eq2->Primary = emu->Primary[r];
eq2->Secondary = emu->Secondary[r];
eq2->HairColor = emu->HairColor[r];
eq2->BeardColor = emu->BeardColor[r];
eq2->EyeColor1 = emu->EyeColor1[r];
eq2->EyeColor2 = emu->EyeColor2[r];
eq2->HairStyle = emu->HairStyle[r];
eq2->Beard = emu->Beard[r];
eq2->CharEnabled = 1;
eq2->Tutorial = emu->Tutorial[r];
eq2->DrakkinHeritage = emu->DrakkinHeritage[r];
eq2->Unknown1 = 0;
eq2->GoHome = emu->GoHome[r];
eq2->LastLogin = 1212696584;
eq2->Unknown2 = 0;
}
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
eq_cse->Unknown15 = emu_cse->Unknown15;
eq_cse->Unknown19 = emu_cse->Unknown19;
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
eq_cse->Deity = emu_cse->Deity;
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
eq_cse->HairColor = emu_cse->HairColor;
eq_cse->BeardColor = emu_cse->BeardColor;
eq_cse->EyeColor1 = emu_cse->EyeColor1;
eq_cse->EyeColor2 = emu_cse->EyeColor2;
eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Beard = emu_cse->Beard;
eq_cse->Enabled = emu_cse->Enabled;
eq_cse->Tutorial = emu_cse->Tutorial;
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
eq_cse->Unknown1 = emu_cse->Unknown1;
eq_cse->GoHome = emu_cse->GoHome;
eq_cse->LastLogin = emu_cse->LastLogin;
eq_cse->Unknown2 = emu_cse->Unknown2;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
}
FINISH_ENCODE();

View File

@ -103,7 +103,7 @@ namespace RoF2 {
}
namespace consts {
static const size_t CHARACTER_CREATION_LIMIT = 10;
static const size_t CHARACTER_CREATION_LIMIT = 12;
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
static const uint16 MAP_BANK_SIZE = 24;

View File

@ -166,11 +166,11 @@ struct CharSelectEquip
struct CharacterSelectEntry_Struct
{
/*0000*/ char Name[1]; // Name null terminated
/*0000*/ uint8 Class_;
/*0000*/ uint8 Class;
/*0000*/ uint32 Race;
/*0000*/ uint8 Level;
/*0000*/ uint8 Class_2;
/*0000*/ uint32 Race2;
/*0000*/ uint8 ShroudClass;
/*0000*/ uint32 ShroudRace;
/*0000*/ uint16 Zone;
/*0000*/ uint16 Instance;
/*0000*/ uint8 Gender;
@ -181,15 +181,15 @@ struct CharacterSelectEntry_Struct
/*0000*/ uint32 DrakkinTattoo;
/*0000*/ uint32 DrakkinDetails;
/*0000*/ uint32 Deity;
/*0000*/ uint32 Primary;
/*0000*/ uint32 Secondary;
/*0000*/ uint32 PrimaryIDFile;
/*0000*/ uint32 SecondaryIDFile;
/*0000*/ uint8 HairColor;
/*0000*/ uint8 BeardColor;
/*0000*/ uint8 EyeColor1;
/*0000*/ uint8 EyeColor2;
/*0000*/ uint8 HairStyle;
/*0000*/ uint8 Beard;
/*0000*/ uint8 CharEnabled;
/*0000*/ uint8 Enabled;
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
/*0000*/ uint32 DrakkinHeritage;
/*0000*/ uint8 Unknown1; // Seen 0

View File

@ -102,7 +102,7 @@ namespace RoF {
}
namespace consts {
static const size_t CHARACTER_CREATION_LIMIT = 10;
static const size_t CHARACTER_CREATION_LIMIT = 12;
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
static const uint16 MAP_BANK_SIZE = 24;

View File

@ -165,37 +165,37 @@ struct CharSelectEquip
struct CharacterSelectEntry_Struct
{
/*0000*/ char Name[1]; // Name null terminated
/*0000*/ uint8 Class_;
/*0000*/ char Name[1]; // Name null terminated
/*0000*/ uint8 Class;
/*0000*/ uint32 Race;
/*0000*/ uint8 Level;
/*0000*/ uint8 Class_2;
/*0000*/ uint32 Race2;
/*0000*/ uint8 ShroudClass;
/*0000*/ uint32 ShroudRace;
/*0000*/ uint16 Zone;
/*0000*/ uint16 Instance;
/*0000*/ uint8 Gender;
/*0000*/ uint8 Face;
/*0000*/ CharSelectEquip Equip[9];
/*0000*/ uint8 Unknown15; // Seen FF
/*0000*/ uint8 Uknown19; // Seen FF
/*0000*/ uint8 Unknown15; // Seen FF
/*0000*/ uint8 Unknown19; // Seen FF
/*0000*/ uint32 DrakkinTattoo;
/*0000*/ uint32 DrakkinDetails;
/*0000*/ uint32 Deity;
/*0000*/ uint32 Primary;
/*0000*/ uint32 Secondary;
/*0000*/ uint32 PrimaryIDFile;
/*0000*/ uint32 SecondaryIDFile;
/*0000*/ uint8 HairColor;
/*0000*/ uint8 BeardColor;
/*0000*/ uint8 EyeColor1;
/*0000*/ uint8 EyeColor2;
/*0000*/ uint8 HairStyle;
/*0000*/ uint8 Beard;
/*0000*/ uint8 CharEnabled;
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
/*0000*/ uint8 Enabled;
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
/*0000*/ uint32 DrakkinHeritage;
/*0000*/ uint8 Unknown1; // Seen 0
/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing
/*0000*/ uint8 Unknown1; // Seen 0
/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing
/*0000*/ uint32 LastLogin;
/*0000*/ uint8 Unknown2; // Seen 0
/*0000*/ uint8 Unknown2; // Seen 0
};
/*

View File

@ -1911,76 +1911,95 @@ namespace SoD
ENCODE(OP_SendCharInfo)
{
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
SETUP_VAR_ENCODE(CharacterSelect_Struct);
//EQApplicationPacket *packet = *p;
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
// Zero-character count shunt
if (emu->CharCount == 0) {
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
eq->CharCount = emu->CharCount;
eq->TotalChars = eq->TotalChars;
int char_count;
int namelen = 0;
for (char_count = 0; char_count < 10; char_count++) {
if (emu->Name[char_count][0] == '\0')
break;
if (strcmp(emu->Name[char_count], "<none>") == 0)
break;
namelen += strlen(emu->Name[char_count]);
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
FINISH_ENCODE();
return;
}
int total_length = sizeof(structs::CharacterSelect_Struct)
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
+ namelen;
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
size_t names_length = 0;
size_t character_count = 0;
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
names_length += strlen(emu_cse->Name);
emu_ptr += sizeof(CharacterSelectEntry_Struct);
}
size_t total_length = sizeof(structs::CharacterSelect_Struct)
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
+ names_length;
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
//unsigned char *eq_buffer = new unsigned char[total_length];
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
eq->CharCount = character_count;
eq->TotalChars = emu->TotalChars;
eq->CharCount = char_count;
eq->TotalChars = 10;
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
unsigned char *bufptr = (unsigned char *)eq->Entries;
int r;
for (r = 0; r < char_count; r++) {
{ //pre-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Level = emu->Level[r];
eq2->HairStyle = emu->HairStyle[r];
eq2->Gender = emu->Gender[r];
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
unsigned char *eq_ptr = __packet->pBuffer;
eq_ptr += sizeof(structs::CharacterSelect_Struct);
for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Level = emu_cse->Level;
eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Beard = emu_cse->Beard;
eq_cse->HairColor = emu_cse->HairColor;
eq_cse->Face = emu_cse->Face;
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
}
//adjust for name.
bufptr += strlen(emu->Name[r]);
{ //post-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Beard = emu->Beard[r];
eq2->HairColor = emu->HairColor[r];
eq2->Face = emu->Face[r];
int k;
for (k = 0; k < _MaterialCount; k++) {
eq2->Equip[k].Material = emu->Equip[r][k].Material;
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
}
eq2->Primary = emu->Primary[r];
eq2->Secondary = emu->Secondary[r];
eq2->Tutorial = emu->Tutorial[r]; // was u15
eq2->Unknown15 = 0xFF;
eq2->Deity = emu->Deity[r];
eq2->Zone = emu->Zone[r];
eq2->Unknown19 = 0xFF;
eq2->Race = emu->Race[r];
eq2->GoHome = emu->GoHome[r];
eq2->Class_ = emu->Class_[r];
eq2->EyeColor1 = emu->EyeColor1[r];
eq2->BeardColor = emu->BeardColor[r];
eq2->EyeColor2 = emu->EyeColor2[r];
eq2->DrakkinHeritage = emu->DrakkinHeritage[r];
eq2->DrakkinTattoo = emu->DrakkinTattoo[r];
eq2->DrakkinDetails = emu->DrakkinDetails[r];
}
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
eq_cse->Tutorial = emu_cse->Tutorial;
eq_cse->Unknown15 = emu_cse->Unknown15;
eq_cse->Deity = emu_cse->Deity;
eq_cse->Zone = emu_cse->Zone;
eq_cse->Unknown19 = emu_cse->Unknown19;
eq_cse->Race = emu_cse->Race;
eq_cse->GoHome = emu_cse->GoHome;
eq_cse->Class = emu_cse->Class;
eq_cse->EyeColor1 = emu_cse->EyeColor1;
eq_cse->BeardColor = emu_cse->BeardColor;
eq_cse->EyeColor2 = emu_cse->EyeColor2;
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
}
FINISH_ENCODE();

View File

@ -101,7 +101,7 @@ namespace SoD {
}
namespace consts {
static const size_t CHARACTER_CREATION_LIMIT = 10;
static const size_t CHARACTER_CREATION_LIMIT = 12;
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
static const uint16 MAP_BANK_SIZE = 24;

View File

@ -132,8 +132,8 @@ struct CharacterSelectEntry_Struct
/*0001*/ uint8 HairColor; //
/*0000*/ uint8 Face; //
/*0000*/ CharSelectEquip Equip[9];
/*0000*/ uint32 Primary; //
/*0000*/ uint32 Secondary; //
/*0000*/ uint32 PrimaryIDFile; //
/*0000*/ uint32 SecondaryIDFile; //
/*0000*/ uint8 Unknown15; // 0xff
/*0000*/ uint32 Deity; //
/*0000*/ uint16 Zone; //
@ -142,7 +142,7 @@ struct CharacterSelectEntry_Struct
/*0000*/ uint8 Unknown19; // 0xff
/*0000*/ uint32 Race; //
/*0000*/ uint8 Tutorial; //
/*0000*/ uint8 Class_; //
/*0000*/ uint8 Class; //
/*0000*/ uint8 EyeColor1; //
/*0000*/ uint8 BeardColor; //
/*0000*/ uint8 EyeColor2; //

View File

@ -1570,76 +1570,95 @@ namespace SoF
ENCODE(OP_SendCharInfo)
{
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
SETUP_VAR_ENCODE(CharacterSelect_Struct);
//EQApplicationPacket *packet = *p;
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
// Zero-character count shunt
if (emu->CharCount == 0) {
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
eq->CharCount = emu->CharCount;
eq->TotalChars = eq->TotalChars;
int char_count;
int namelen = 0;
for (char_count = 0; char_count < 10; char_count++) {
if (emu->Name[char_count][0] == '\0')
break;
if (strcmp(emu->Name[char_count], "<none>") == 0)
break;
namelen += strlen(emu->Name[char_count]);
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
FINISH_ENCODE();
return;
}
int total_length = sizeof(structs::CharacterSelect_Struct)
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
+ namelen;
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
size_t names_length = 0;
size_t character_count = 0;
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
names_length += strlen(emu_cse->Name);
emu_ptr += sizeof(CharacterSelectEntry_Struct);
}
size_t total_length = sizeof(structs::CharacterSelect_Struct)
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
+ names_length;
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
//unsigned char *eq_buffer = new unsigned char[total_length];
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
eq->CharCount = character_count;
eq->TotalChars = emu->TotalChars;
eq->CharCount = char_count;
eq->TotalChars = 10;
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
unsigned char *bufptr = (unsigned char *)eq->Entries;
int r;
for (r = 0; r < char_count; r++) {
{ //pre-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Level = emu->Level[r];
eq2->HairStyle = emu->HairStyle[r];
eq2->Gender = emu->Gender[r];
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
unsigned char *eq_ptr = __packet->pBuffer;
eq_ptr += sizeof(structs::CharacterSelect_Struct);
for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Level = emu_cse->Level;
eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Beard = emu_cse->Beard;
eq_cse->HairColor = emu_cse->HairColor;
eq_cse->Face = emu_cse->Face;
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
}
//adjust for name.
bufptr += strlen(emu->Name[r]);
{ //post-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Beard = emu->Beard[r];
eq2->HairColor = emu->HairColor[r];
eq2->Face = emu->Face[r];
int k;
for (k = 0; k < _MaterialCount; k++) {
eq2->Equip[k].Material = emu->Equip[r][k].Material;
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
}
eq2->Primary = emu->Primary[r];
eq2->Secondary = emu->Secondary[r];
eq2->Tutorial = emu->Tutorial[r]; // was u15
eq2->Unknown15 = 0xff;
eq2->Deity = emu->Deity[r];
eq2->Zone = emu->Zone[r];
eq2->Unknown19 = 0xFF;
eq2->Race = emu->Race[r];
eq2->GoHome = emu->GoHome[r];
eq2->Class_ = emu->Class_[r];
eq2->EyeColor1 = emu->EyeColor1[r];
eq2->BeardColor = emu->BeardColor[r];
eq2->EyeColor2 = emu->EyeColor2[r];
eq2->DrakkinHeritage = emu->DrakkinHeritage[r];
eq2->DrakkinTattoo = emu->DrakkinTattoo[r];
eq2->DrakkinDetails = emu->DrakkinDetails[r];
}
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
eq_cse->Tutorial = emu_cse->Tutorial;
eq_cse->Unknown15 = emu_cse->Unknown15;
eq_cse->Deity = emu_cse->Deity;
eq_cse->Zone = emu_cse->Zone;
eq_cse->Unknown19 = emu_cse->Unknown19;
eq_cse->Race = emu_cse->Race;
eq_cse->GoHome = emu_cse->GoHome;
eq_cse->Class = emu_cse->Class;
eq_cse->EyeColor1 = emu_cse->EyeColor1;
eq_cse->BeardColor = emu_cse->BeardColor;
eq_cse->EyeColor2 = emu_cse->EyeColor2;
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
}
FINISH_ENCODE();

View File

@ -101,7 +101,7 @@ namespace SoF {
}
namespace consts {
static const size_t CHARACTER_CREATION_LIMIT = 10;
static const size_t CHARACTER_CREATION_LIMIT = 12;
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
static const uint16 MAP_BANK_SIZE = 24;

View File

@ -132,17 +132,17 @@ struct CharacterSelectEntry_Struct
/*0001*/ uint8 HairColor; //
/*0000*/ uint8 Face; //
/*0000*/ CharSelectEquip Equip[9];
/*0000*/ uint32 Primary; //
/*0000*/ uint32 Secondary; //
/*0000*/ uint8 Unknown15; // 0xff
/*0000*/ uint32 PrimaryIDFile; //
/*0000*/ uint32 SecondaryIDFile; //
/*0000*/ uint8 Unknown15; // 0xff
/*0000*/ uint32 Deity; //
/*0000*/ uint16 Zone; //
/*0000*/ uint16 Instance;
/*0000*/ uint8 GoHome; //
/*0000*/ uint8 Unknown19; // 0xff
/*0000*/ uint8 Unknown19; // 0xff
/*0000*/ uint32 Race; //
/*0000*/ uint8 Tutorial; //
/*0000*/ uint8 Class_; //
/*0000*/ uint8 Class; //
/*0000*/ uint8 EyeColor1; //
/*0000*/ uint8 BeardColor; //
/*0000*/ uint8 EyeColor2; //

View File

@ -1155,39 +1155,96 @@ namespace Titanium
ENCODE(OP_SendCharInfo)
{
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct);
int r;
for (r = 0; r < 10; r++) {
OUT(Zone[r]);
OUT(EyeColor1[r]);
OUT(EyeColor2[r]);
OUT(HairStyle[r]);
OUT(Primary[r]);
if (emu->Race[r] > 473)
eq->Race[r] = 1;
else
eq->Race[r] = emu->Race[r];
OUT(Class_[r]);
OUT_str(Name[r]);
OUT(Gender[r]);
OUT(Level[r]);
OUT(Secondary[r]);
OUT(Face[r]);
OUT(Beard[r]);
int k;
for (k = 0; k < 9; k++) {
eq->Equip[r][k] = emu->Equip[r][k].Material;
eq->CS_Colors[r][k].Color = emu->Equip[r][k].Color.Color;
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
for (size_t index = 0; index < 10; ++index) {
memset(eq->Name[index], 0, 64);
}
// Non character-indexed packet fields
eq->Unknown830[0] = 0;
eq->Unknown830[1] = 0;
eq->Unknown0962[0] = 0;
eq->Unknown0962[1] = 0;
size_t char_index = 0;
for (; char_index < emu->CharCount && char_index < 8; ++char_index) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq->Race[char_index] = emu_cse->Race;
if (eq->Race[char_index] > 473)
eq->Race[char_index] = 1;
for (int index = 0; index < _MaterialCount; ++index) {
eq->CS_Colors[char_index][index].Color = emu_cse->Equip[index].Color.Color;
}
OUT(HairColor[r]);
OUT(GoHome[r]);
OUT(Tutorial[r]);
OUT(Deity[r]);
OUT(BeardColor[r]);
eq->Unknown820[r] = 0xFF;
eq->Unknown902[r] = 0xFF;
eq->BeardColor[char_index] = emu_cse->BeardColor;
eq->HairStyle[char_index] = emu_cse->HairStyle;
for (int index = 0; index < _MaterialCount; ++index) {
eq->Equip[char_index][index] = emu_cse->Equip[index].Material;
}
eq->SecondaryIDFile[char_index] = emu_cse->SecondaryIDFile;
eq->Unknown820[char_index] = 0xFF;
eq->Deity[char_index] = emu_cse->Deity;
eq->GoHome[char_index] = emu_cse->GoHome;
eq->Tutorial[char_index] = emu_cse->Tutorial;
eq->Beard[char_index] = emu_cse->Beard;
eq->Unknown902[char_index] = 0xFF;
eq->PrimaryIDFile[char_index] = emu_cse->PrimaryIDFile;
eq->HairColor[char_index] = emu_cse->HairColor;
eq->Zone[char_index] = emu_cse->Zone;
eq->Class[char_index] = emu_cse->Class;
eq->Face[char_index] = emu_cse->Face;
memcpy(eq->Name[char_index], emu_cse->Name, 64);
eq->Gender[char_index] = emu_cse->Gender;
eq->EyeColor1[char_index] = emu_cse->EyeColor1;
eq->EyeColor2[char_index] = emu_cse->EyeColor2;
eq->Level[char_index] = emu_cse->Level;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
}
for (; char_index < 10; ++char_index) {
eq->Race[char_index] = 0;
for (int index = 0; index < _MaterialCount; ++index) {
eq->CS_Colors[char_index][index].Color = 0;
}
eq->BeardColor[char_index] = 0;
eq->HairStyle[char_index] = 0;
for (int index = 0; index < _MaterialCount; ++index) {
eq->Equip[char_index][index] = 0;
}
eq->SecondaryIDFile[char_index] = 0;
eq->Unknown820[char_index] = 0xFF;
eq->Deity[char_index] = 0;
eq->GoHome[char_index] = 0;
eq->Tutorial[char_index] = 0;
eq->Beard[char_index] = 0;
eq->Unknown902[char_index] = 0xFF;
eq->PrimaryIDFile[char_index] = 0;
eq->HairColor[char_index] = 0;
eq->Zone[char_index] = 0;
eq->Class[char_index] = 0;
eq->Face[char_index] = 0;
//eq->Name[char_index][0] = '\0'; // Cleared above
eq->Gender[char_index] = 0;
eq->EyeColor1[char_index] = 0;
eq->EyeColor2[char_index] = 0;
eq->Level[char_index] = 0;
}
FINISH_ENCODE();

View File

@ -100,7 +100,7 @@ namespace Titanium {
}
namespace consts {
static const size_t CHARACTER_CREATION_LIMIT = 8;
static const size_t CHARACTER_CREATION_LIMIT = 8; // Hard-coded in client - DO NOT ALTER
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
static const uint16 MAP_BANK_SIZE = 16;

View File

@ -122,7 +122,7 @@ struct CharacterSelect_Struct
/*0400*/ uint8 BeardColor[10]; // Characters beard Color
/*0410*/ uint8 HairStyle[10]; // Characters hair style
/*0420*/ uint32 Equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be)
/*0780*/ uint32 Secondary[10]; // Characters secondary IDFile number
/*0780*/ uint32 SecondaryIDFile[10]; // Characters secondary IDFile number
/*0820*/ uint8 Unknown820[10]; // 10x ff
/*0830*/ uint8 Unknown830[2]; // 2x 00
/*0832*/ uint32 Deity[10]; // Characters Deity
@ -130,11 +130,11 @@ struct CharacterSelect_Struct
/*0882*/ uint8 Tutorial[10]; // 1=Tutorial available, 0=not
/*0892*/ uint8 Beard[10]; // Characters Beard Type
/*0902*/ uint8 Unknown902[10]; // 10x ff
/*0912*/ uint32 Primary[10]; // Characters primary IDFile number
/*0912*/ uint32 PrimaryIDFile[10]; // Characters primary IDFile number
/*0952*/ uint8 HairColor[10]; // Characters Hair Color
/*0962*/ uint8 Unknown0962[2]; // 2x 00
/*0964*/ uint32 Zone[10]; // Characters Current Zone
/*1004*/ uint8 Class_[10]; // Characters Classes
/*1004*/ uint8 Class[10]; // Characters Classes
/*1014*/ uint8 Face[10]; // Characters Face Type
/*1024*/ char Name[10][64]; // Characters Names
/*1664*/ uint8 Gender[10]; // Characters Gender

View File

@ -2194,77 +2194,103 @@ namespace UF
ENCODE(OP_SendCharInfo)
{
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
SETUP_VAR_ENCODE(CharacterSelect_Struct);
//EQApplicationPacket *packet = *p;
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
// Zero-character count shunt
if (emu->CharCount == 0) {
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
eq->CharCount = emu->CharCount;
eq->TotalChars = eq->TotalChars;
int char_count;
int namelen = 0;
for (char_count = 0; char_count < 10; char_count++) {
if (emu->Name[char_count][0] == '\0')
break;
if (strcmp(emu->Name[char_count], "<none>") == 0)
break;
namelen += strlen(emu->Name[char_count]);
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
// Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars'
uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field
eq->TotalChars = adjusted_total;
FINISH_ENCODE();
return;
}
unsigned char *emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
size_t names_length = 0;
size_t character_count = 0;
for (; character_count < emu->CharCount && character_count < consts::CHARACTER_CREATION_LIMIT; ++character_count) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
names_length += strlen(emu_cse->Name);
emu_ptr += sizeof(CharacterSelectEntry_Struct);
}
int total_length = sizeof(structs::CharacterSelect_Struct)
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
+ namelen;
size_t total_length = sizeof(structs::CharacterSelect_Struct)
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
+ names_length;
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
structs::CharacterSelectEntry_Struct *eq_cse = (structs::CharacterSelectEntry_Struct *)nullptr;
//unsigned char *eq_buffer = new unsigned char[total_length];
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
eq->CharCount = character_count;
eq->TotalChars = emu->TotalChars;
eq->CharCount = char_count;
eq->TotalChars = 10;
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
unsigned char *bufptr = (unsigned char *)eq->Entries;
int r;
for (r = 0; r < char_count; r++) {
{ //pre-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Level = emu->Level[r];
eq2->HairStyle = emu->HairStyle[r];
eq2->Gender = emu->Gender[r];
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
}
//adjust for name.
bufptr += strlen(emu->Name[r]);
{ //post-name section...
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
eq2->Beard = emu->Beard[r];
eq2->HairColor = emu->HairColor[r];
eq2->Face = emu->Face[r];
int k;
for (k = 0; k < _MaterialCount; k++) {
eq2->Equip[k].Material = emu->Equip[r][k].Material;
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
}
eq2->Primary = emu->Primary[r];
eq2->Secondary = emu->Secondary[r];
eq2->Tutorial = emu->Tutorial[r]; // was u15
eq2->Unknown15 = 0xFF;
eq2->Deity = emu->Deity[r];
eq2->Zone = emu->Zone[r];
eq2->Unknown19 = 0xFF;
eq2->Race = emu->Race[r];
eq2->GoHome = emu->GoHome[r];
eq2->Class_ = emu->Class_[r];
eq2->EyeColor1 = emu->EyeColor1[r];
eq2->BeardColor = emu->BeardColor[r];
eq2->EyeColor2 = emu->EyeColor2[r];
eq2->DrakkinHeritage = emu->DrakkinHeritage[r];
eq2->DrakkinTattoo = emu->DrakkinTattoo[r];
eq2->DrakkinDetails = emu->DrakkinDetails[r];
// Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' in this client
uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field
eq->TotalChars = adjusted_total;
emu_ptr = __emu_buffer;
emu_ptr += sizeof(CharacterSelect_Struct);
unsigned char *eq_ptr = __packet->pBuffer;
eq_ptr += sizeof(structs::CharacterSelect_Struct);
for (int counter = 0; counter < character_count; ++counter) {
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Level = emu_cse->Level;
eq_cse->HairStyle = emu_cse->HairStyle;
eq_cse->Gender = emu_cse->Gender;
strcpy(eq_cse->Name, emu_cse->Name);
eq_ptr += strlen(eq_cse->Name);
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
eq_cse->Beard = emu_cse->Beard;
eq_cse->HairColor = emu_cse->HairColor;
eq_cse->Face = emu_cse->Face;
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
}
bufptr += sizeof(structs::CharacterSelectEntry_Struct);
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
eq_cse->Tutorial = emu_cse->Tutorial;
eq_cse->Unknown15 = emu_cse->Unknown15;
eq_cse->Deity = emu_cse->Deity;
eq_cse->Zone = emu_cse->Zone;
eq_cse->Unknown19 = emu_cse->Unknown19;
eq_cse->Race = emu_cse->Race;
eq_cse->GoHome = emu_cse->GoHome;
eq_cse->Class = emu_cse->Class;
eq_cse->EyeColor1 = emu_cse->EyeColor1;
eq_cse->BeardColor = emu_cse->BeardColor;
eq_cse->EyeColor2 = emu_cse->EyeColor2;
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
emu_ptr += sizeof(CharacterSelectEntry_Struct);
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
}
FINISH_ENCODE();

View File

@ -101,7 +101,7 @@ namespace UF {
}
namespace consts {
static const size_t CHARACTER_CREATION_LIMIT = 10;
static const size_t CHARACTER_CREATION_LIMIT = 12;
static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount;
static const uint16 MAP_BANK_SIZE = 24;

View File

@ -132,8 +132,8 @@ struct CharacterSelectEntry_Struct
/*0001*/ uint8 HairColor; //
/*0000*/ uint8 Face; //
/*0000*/ CharSelectEquip Equip[9];
/*0000*/ uint32 Primary; //
/*0000*/ uint32 Secondary; //
/*0000*/ uint32 PrimaryIDFile; //
/*0000*/ uint32 SecondaryIDFile; //
/*0000*/ uint8 Unknown15; // 0xff
/*0000*/ uint32 Deity; //
/*0000*/ uint16 Zone; //
@ -142,7 +142,7 @@ struct CharacterSelectEntry_Struct
/*0000*/ uint8 Unknown19; // 0xff
/*0000*/ uint32 Race; //
/*0000*/ uint8 Tutorial; //
/*0000*/ uint8 Class_; //
/*0000*/ uint8 Class; //
/*0000*/ uint8 EyeColor1; //
/*0000*/ uint8 BeardColor; //
/*0000*/ uint8 EyeColor2; //

View File

@ -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"
@ -161,32 +162,34 @@ void Client::SendCharInfo() {
cle->SetOnline(CLE_Status_CharSelect);
}
if (m_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, m_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);
@ -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, m_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, m_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;
}
}
}

View File

@ -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);

View File

@ -33,21 +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)
void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit)
{
Inventory *inv = nullptr;
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;
}
/* 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 "
@ -73,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;
for (auto row = results.begin(); row != results.end() && char_num < 10; ++row, ++char_num) {
"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;
Inventory 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->DrakkinHeritage[char_num] = atoi(row[16]);
cs->DrakkinTattoo[char_num] = atoi(row[17]);
cs->DrakkinDetails[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 */
@ -134,32 +174,87 @@ 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 Inventory */
// If we ensure that the material data is updated appropriately, we can do away with inventory loads
if (GetInventory(accountID, cse->Name, &inv)) {
const Item_Struct* item = nullptr;
const ItemInst* inst = nullptr;
int16 invslot = 0;
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) {
invslot = Inventory::CalcSlotFromMaterial(matslot);
if (invslot == INVALID_INDEX) { continue; }
inst = inv.GetItem(invslot);
if (inst == nullptr) { continue; }
item = inst->GetItem();
if (item == nullptr) { continue; }
if (matslot > 6) {
uint32 idfile = 0;
// Weapon Models
if (inst->GetOrnamentationIDFile() != 0) {
idfile = inst->GetOrnamentationIDFile();
cse->Equip[matslot].Material = idfile;
}
else {
if (strlen(item->IDFile) > 2) {
idfile = atoi(&item->IDFile[2]);
cse->Equip[matslot].Material = idfile;
}
}
if (matslot == MaterialPrimary) {
cse->PrimaryIDFile = idfile;
}
else {
cse->SecondaryIDFile = idfile;
}
}
else {
uint32 color = 0;
if (pp.item_tint[matslot].RGB.UseTint) {
color = pp.item_tint[matslot].Color;
}
else {
color = inst->GetColor();
}
// Armor Materials/Models
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", 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)
{
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]);
@ -167,81 +262,8 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]);
}
/* Load Inventory */
// If we ensure that the material data is updated appropriately, we can do away with inventory loads
inv = new Inventory;
if (GetInventory(account_id, cs->Name[char_num], inv))
{
const Item_Struct* item = nullptr;
const ItemInst* inst = nullptr;
int16 invslot = 0;
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++)
{
invslot = Inventory::CalcSlotFromMaterial(matslot);
if (invslot == INVALID_INDEX) { continue; }
inst = inv->GetItem(invslot);
if (inst == nullptr) { continue; }
item = inst->GetItem();
if (item == nullptr) { continue; }
if (matslot > 6)
{
uint32 idfile = 0;
// Weapon Models
if (inst->GetOrnamentationIDFile() != 0)
{
idfile = inst->GetOrnamentationIDFile();
cs->Equip[char_num][matslot].Material = idfile;
}
else
{
if (strlen(item->IDFile) > 2)
{
idfile = atoi(&item->IDFile[2]);
cs->Equip[char_num][matslot].Material = idfile;
}
}
if (matslot == MaterialPrimary)
{
cs->Primary[char_num] = idfile;
}
else
{
cs->Secondary[char_num] = idfile;
}
}
else
{
uint32 color = 0;
if (pp.item_tint[matslot].RGB.UseTint)
{
color = pp.item_tint[matslot].Color;
}
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;
}
}
}
else
{
printf("Error loading inventory for %s\n", cs->Name[char_num]);
}
safe_delete(inv);
buff_ptr += sizeof(CharacterSelectEntry_Struct);
}
return;
}
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) {

View File

@ -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);