mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 18:51:29 +00:00
Implemented per-client character creation limits
This commit is contained in:
parent
e4be4d6895
commit
766641cd15
@ -49,7 +49,6 @@ public:
|
|||||||
// database
|
// database
|
||||||
static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client
|
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;
|
static const size_t CHARACTER_CREATION_LIMIT = RoF2::consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
// inventory
|
// inventory
|
||||||
|
|||||||
@ -158,32 +158,46 @@ struct CharSelectEquip
|
|||||||
Color_Struct Color;
|
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
|
struct CharacterSelect_Struct
|
||||||
{
|
{
|
||||||
uint32 Race[10]; // Characters Race
|
uint32 CharCount; //number of chars in this packet
|
||||||
uint8 BeardColor[10]; // Characters beard Color
|
uint32 TotalChars; //total number of chars allowed?
|
||||||
uint8 HairStyle[10]; // Characters hair style
|
CharacterSelectEntry_Struct Entries[0];
|
||||||
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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -2897,85 +2897,99 @@ namespace RoF
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
|
||||||
int char_count;
|
FINISH_ENCODE();
|
||||||
int namelen = 0;
|
return;
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
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);
|
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];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
//eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->CharCount = char_count;
|
//if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
//eq->total_chars = 10;
|
// eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->Entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
|
|
||||||
|
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]);
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
{ //post-name section...
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->Class_ = emu->Class_[r];
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->Race = emu->Race[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->Level = emu->Level[r];
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
eq2->Class_2 = emu->Class_[r];
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
eq2->Race2 = emu->Race[r];
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
eq2->Zone = emu->Zone[r];
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
eq2->Instance = 0;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->Gender = emu->Gender[r];
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->Face = emu->Face[r];
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
int k;
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->Enabled = emu_cse->Enabled;
|
||||||
eq2->Equip[k].Material = emu->Equip[r][k].Material;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
|
eq_cse->Unknown1 = emu_cse->Unknown1;
|
||||||
eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel;
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->Equip[k].Material2 = emu->Equip[r][k].Material2;
|
eq_cse->LastLogin = emu_cse->LastLogin;
|
||||||
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
|
eq_cse->Unknown2 = emu_cse->Unknown2;
|
||||||
}
|
|
||||||
eq2->Unknown15 = 0xFF;
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->Uknown19 = 0xFF;
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
|
|||||||
@ -2981,85 +2981,99 @@ namespace RoF2
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
if (emu->CharCount == 0) {
|
||||||
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
||||||
|
eq->CharCount = emu->CharCount;
|
||||||
|
|
||||||
int char_count;
|
FINISH_ENCODE();
|
||||||
int namelen = 0;
|
return;
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
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);
|
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];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
//eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->CharCount = char_count;
|
//if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
//eq->total_chars = 10;
|
// eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->Entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
|
|
||||||
|
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]);
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
{ //post-name section...
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->Class_ = emu->Class_[r];
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->Race = emu->Race[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->Level = emu->Level[r];
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
eq2->Class_2 = emu->Class_[r];
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
eq2->Race2 = emu->Race[r];
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
eq2->Zone = emu->Zone[r];
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
eq2->Instance = 0;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->Gender = emu->Gender[r];
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->Face = emu->Face[r];
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
int k;
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->Enabled = emu_cse->Enabled;
|
||||||
eq2->Equip[k].Material = emu->Equip[r][k].Material;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
|
eq_cse->Unknown1 = emu_cse->Unknown1;
|
||||||
eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel;
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->Equip[k].Material2 = emu->Equip[r][k].Material2;
|
eq_cse->LastLogin = emu_cse->LastLogin;
|
||||||
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
|
eq_cse->Unknown2 = emu_cse->Unknown2;
|
||||||
}
|
|
||||||
eq2->Unknown15 = 0xFF;
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->Unknown19 = 0xFF;
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
|
|||||||
@ -103,7 +103,7 @@ namespace RoF2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
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_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
|
|||||||
@ -166,11 +166,11 @@ struct CharSelectEquip
|
|||||||
struct CharacterSelectEntry_Struct
|
struct CharacterSelectEntry_Struct
|
||||||
{
|
{
|
||||||
/*0000*/ char Name[1]; // Name null terminated
|
/*0000*/ char Name[1]; // Name null terminated
|
||||||
/*0000*/ uint8 Class_;
|
/*0000*/ uint8 Class;
|
||||||
/*0000*/ uint32 Race;
|
/*0000*/ uint32 Race;
|
||||||
/*0000*/ uint8 Level;
|
/*0000*/ uint8 Level;
|
||||||
/*0000*/ uint8 Class_2;
|
/*0000*/ uint8 ShroudClass;
|
||||||
/*0000*/ uint32 Race2;
|
/*0000*/ uint32 ShroudRace;
|
||||||
/*0000*/ uint16 Zone;
|
/*0000*/ uint16 Zone;
|
||||||
/*0000*/ uint16 Instance;
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 Gender;
|
/*0000*/ uint8 Gender;
|
||||||
@ -181,15 +181,15 @@ struct CharacterSelectEntry_Struct
|
|||||||
/*0000*/ uint32 DrakkinTattoo;
|
/*0000*/ uint32 DrakkinTattoo;
|
||||||
/*0000*/ uint32 DrakkinDetails;
|
/*0000*/ uint32 DrakkinDetails;
|
||||||
/*0000*/ uint32 Deity;
|
/*0000*/ uint32 Deity;
|
||||||
/*0000*/ uint32 Primary;
|
/*0000*/ uint32 PrimaryIDFile;
|
||||||
/*0000*/ uint32 Secondary;
|
/*0000*/ uint32 SecondaryIDFile;
|
||||||
/*0000*/ uint8 HairColor;
|
/*0000*/ uint8 HairColor;
|
||||||
/*0000*/ uint8 BeardColor;
|
/*0000*/ uint8 BeardColor;
|
||||||
/*0000*/ uint8 EyeColor1;
|
/*0000*/ uint8 EyeColor1;
|
||||||
/*0000*/ uint8 EyeColor2;
|
/*0000*/ uint8 EyeColor2;
|
||||||
/*0000*/ uint8 HairStyle;
|
/*0000*/ uint8 HairStyle;
|
||||||
/*0000*/ uint8 Beard;
|
/*0000*/ uint8 Beard;
|
||||||
/*0000*/ uint8 CharEnabled;
|
/*0000*/ uint8 Enabled;
|
||||||
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
||||||
/*0000*/ uint32 DrakkinHeritage;
|
/*0000*/ uint32 DrakkinHeritage;
|
||||||
/*0000*/ uint8 Unknown1; // Seen 0
|
/*0000*/ uint8 Unknown1; // Seen 0
|
||||||
|
|||||||
@ -102,7 +102,7 @@ namespace RoF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
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_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
|
|||||||
@ -165,37 +165,37 @@ struct CharSelectEquip
|
|||||||
|
|
||||||
struct CharacterSelectEntry_Struct
|
struct CharacterSelectEntry_Struct
|
||||||
{
|
{
|
||||||
/*0000*/ char Name[1]; // Name null terminated
|
/*0000*/ char Name[1]; // Name null terminated
|
||||||
/*0000*/ uint8 Class_;
|
/*0000*/ uint8 Class;
|
||||||
/*0000*/ uint32 Race;
|
/*0000*/ uint32 Race;
|
||||||
/*0000*/ uint8 Level;
|
/*0000*/ uint8 Level;
|
||||||
/*0000*/ uint8 Class_2;
|
/*0000*/ uint8 ShroudClass;
|
||||||
/*0000*/ uint32 Race2;
|
/*0000*/ uint32 ShroudRace;
|
||||||
/*0000*/ uint16 Zone;
|
/*0000*/ uint16 Zone;
|
||||||
/*0000*/ uint16 Instance;
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 Gender;
|
/*0000*/ uint8 Gender;
|
||||||
/*0000*/ uint8 Face;
|
/*0000*/ uint8 Face;
|
||||||
/*0000*/ CharSelectEquip Equip[9];
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint8 Unknown15; // Seen FF
|
/*0000*/ uint8 Unknown15; // Seen FF
|
||||||
/*0000*/ uint8 Uknown19; // Seen FF
|
/*0000*/ uint8 Unknown19; // Seen FF
|
||||||
/*0000*/ uint32 DrakkinTattoo;
|
/*0000*/ uint32 DrakkinTattoo;
|
||||||
/*0000*/ uint32 DrakkinDetails;
|
/*0000*/ uint32 DrakkinDetails;
|
||||||
/*0000*/ uint32 Deity;
|
/*0000*/ uint32 Deity;
|
||||||
/*0000*/ uint32 Primary;
|
/*0000*/ uint32 PrimaryIDFile;
|
||||||
/*0000*/ uint32 Secondary;
|
/*0000*/ uint32 SecondaryIDFile;
|
||||||
/*0000*/ uint8 HairColor;
|
/*0000*/ uint8 HairColor;
|
||||||
/*0000*/ uint8 BeardColor;
|
/*0000*/ uint8 BeardColor;
|
||||||
/*0000*/ uint8 EyeColor1;
|
/*0000*/ uint8 EyeColor1;
|
||||||
/*0000*/ uint8 EyeColor2;
|
/*0000*/ uint8 EyeColor2;
|
||||||
/*0000*/ uint8 HairStyle;
|
/*0000*/ uint8 HairStyle;
|
||||||
/*0000*/ uint8 Beard;
|
/*0000*/ uint8 Beard;
|
||||||
/*0000*/ uint8 CharEnabled;
|
/*0000*/ uint8 Enabled;
|
||||||
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing
|
||||||
/*0000*/ uint32 DrakkinHeritage;
|
/*0000*/ uint32 DrakkinHeritage;
|
||||||
/*0000*/ uint8 Unknown1; // Seen 0
|
/*0000*/ uint8 Unknown1; // Seen 0
|
||||||
/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing
|
/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing
|
||||||
/*0000*/ uint32 LastLogin;
|
/*0000*/ uint32 LastLogin;
|
||||||
/*0000*/ uint8 Unknown2; // Seen 0
|
/*0000*/ uint8 Unknown2; // Seen 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -1911,76 +1911,95 @@ namespace SoD
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
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;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
int namelen = 0;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->Name[char_count][0] == '\0')
|
FINISH_ENCODE();
|
||||||
break;
|
return;
|
||||||
if (strcmp(emu->Name[char_count], "<none>") == 0)
|
|
||||||
break;
|
|
||||||
namelen += strlen(emu->Name[char_count]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
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);
|
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];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->CharCount = char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
eq->TotalChars = 10;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->Entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
eq2->Level = emu->Level[r];
|
|
||||||
eq2->HairStyle = emu->HairStyle[r];
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
eq2->Gender = emu->Gender[r];
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
|
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]);
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
{ //post-name section...
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->Beard = emu->Beard[r];
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
eq2->HairColor = emu->HairColor[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->Face = emu->Face[r];
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
int k;
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->Race = emu_cse->Race;
|
||||||
eq2->Equip[k].Material = emu->Equip[r][k].Material;
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
|
eq_cse->Class = emu_cse->Class;
|
||||||
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
}
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->Primary = emu->Primary[r];
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->Secondary = emu->Secondary[r];
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->Tutorial = emu->Tutorial[r]; // was u15
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->Unknown15 = 0xFF;
|
|
||||||
eq2->Deity = emu->Deity[r];
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->Zone = emu->Zone[r];
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
|
|||||||
@ -101,7 +101,7 @@ namespace SoD {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
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_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
|
|||||||
@ -132,8 +132,8 @@ struct CharacterSelectEntry_Struct
|
|||||||
/*0001*/ uint8 HairColor; //
|
/*0001*/ uint8 HairColor; //
|
||||||
/*0000*/ uint8 Face; //
|
/*0000*/ uint8 Face; //
|
||||||
/*0000*/ CharSelectEquip Equip[9];
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint32 Primary; //
|
/*0000*/ uint32 PrimaryIDFile; //
|
||||||
/*0000*/ uint32 Secondary; //
|
/*0000*/ uint32 SecondaryIDFile; //
|
||||||
/*0000*/ uint8 Unknown15; // 0xff
|
/*0000*/ uint8 Unknown15; // 0xff
|
||||||
/*0000*/ uint32 Deity; //
|
/*0000*/ uint32 Deity; //
|
||||||
/*0000*/ uint16 Zone; //
|
/*0000*/ uint16 Zone; //
|
||||||
@ -142,7 +142,7 @@ struct CharacterSelectEntry_Struct
|
|||||||
/*0000*/ uint8 Unknown19; // 0xff
|
/*0000*/ uint8 Unknown19; // 0xff
|
||||||
/*0000*/ uint32 Race; //
|
/*0000*/ uint32 Race; //
|
||||||
/*0000*/ uint8 Tutorial; //
|
/*0000*/ uint8 Tutorial; //
|
||||||
/*0000*/ uint8 Class_; //
|
/*0000*/ uint8 Class; //
|
||||||
/*0000*/ uint8 EyeColor1; //
|
/*0000*/ uint8 EyeColor1; //
|
||||||
/*0000*/ uint8 BeardColor; //
|
/*0000*/ uint8 BeardColor; //
|
||||||
/*0000*/ uint8 EyeColor2; //
|
/*0000*/ uint8 EyeColor2; //
|
||||||
|
|||||||
@ -1570,76 +1570,95 @@ namespace SoF
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
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;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
int namelen = 0;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->Name[char_count][0] == '\0')
|
FINISH_ENCODE();
|
||||||
break;
|
return;
|
||||||
if (strcmp(emu->Name[char_count], "<none>") == 0)
|
|
||||||
break;
|
|
||||||
namelen += strlen(emu->Name[char_count]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int total_length = sizeof(structs::CharacterSelect_Struct)
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
+ namelen;
|
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);
|
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];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->CharCount = char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
eq->TotalChars = 10;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->Entries;
|
emu_ptr = __emu_buffer;
|
||||||
int r;
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
for (r = 0; r < char_count; r++) {
|
|
||||||
{ //pre-name section...
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
eq2->Level = emu->Level[r];
|
|
||||||
eq2->HairStyle = emu->HairStyle[r];
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
eq2->Gender = emu->Gender[r];
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
|
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]);
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
||||||
{ //post-name section...
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
||||||
eq2->Beard = emu->Beard[r];
|
eq_cse->Unknown15 = emu_cse->Unknown15;
|
||||||
eq2->HairColor = emu->HairColor[r];
|
eq_cse->Deity = emu_cse->Deity;
|
||||||
eq2->Face = emu->Face[r];
|
eq_cse->Zone = emu_cse->Zone;
|
||||||
int k;
|
eq_cse->Unknown19 = emu_cse->Unknown19;
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
eq_cse->Race = emu_cse->Race;
|
||||||
eq2->Equip[k].Material = emu->Equip[r][k].Material;
|
eq_cse->GoHome = emu_cse->GoHome;
|
||||||
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
|
eq_cse->Class = emu_cse->Class;
|
||||||
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
||||||
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
||||||
}
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
||||||
eq2->Primary = emu->Primary[r];
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
||||||
eq2->Secondary = emu->Secondary[r];
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
||||||
eq2->Tutorial = emu->Tutorial[r]; // was u15
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
||||||
eq2->Unknown15 = 0xff;
|
|
||||||
eq2->Deity = emu->Deity[r];
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
eq2->Zone = emu->Zone[r];
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
|
|||||||
@ -101,7 +101,7 @@ namespace SoF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
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_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
|
|||||||
@ -132,17 +132,17 @@ struct CharacterSelectEntry_Struct
|
|||||||
/*0001*/ uint8 HairColor; //
|
/*0001*/ uint8 HairColor; //
|
||||||
/*0000*/ uint8 Face; //
|
/*0000*/ uint8 Face; //
|
||||||
/*0000*/ CharSelectEquip Equip[9];
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint32 Primary; //
|
/*0000*/ uint32 PrimaryIDFile; //
|
||||||
/*0000*/ uint32 Secondary; //
|
/*0000*/ uint32 SecondaryIDFile; //
|
||||||
/*0000*/ uint8 Unknown15; // 0xff
|
/*0000*/ uint8 Unknown15; // 0xff
|
||||||
/*0000*/ uint32 Deity; //
|
/*0000*/ uint32 Deity; //
|
||||||
/*0000*/ uint16 Zone; //
|
/*0000*/ uint16 Zone; //
|
||||||
/*0000*/ uint16 Instance;
|
/*0000*/ uint16 Instance;
|
||||||
/*0000*/ uint8 GoHome; //
|
/*0000*/ uint8 GoHome; //
|
||||||
/*0000*/ uint8 Unknown19; // 0xff
|
/*0000*/ uint8 Unknown19; // 0xff
|
||||||
/*0000*/ uint32 Race; //
|
/*0000*/ uint32 Race; //
|
||||||
/*0000*/ uint8 Tutorial; //
|
/*0000*/ uint8 Tutorial; //
|
||||||
/*0000*/ uint8 Class_; //
|
/*0000*/ uint8 Class; //
|
||||||
/*0000*/ uint8 EyeColor1; //
|
/*0000*/ uint8 EyeColor1; //
|
||||||
/*0000*/ uint8 BeardColor; //
|
/*0000*/ uint8 BeardColor; //
|
||||||
/*0000*/ uint8 EyeColor2; //
|
/*0000*/ uint8 EyeColor2; //
|
||||||
|
|||||||
@ -1155,39 +1155,96 @@ namespace Titanium
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct);
|
SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct);
|
||||||
|
|
||||||
int r;
|
unsigned char *emu_ptr = __emu_buffer;
|
||||||
for (r = 0; r < 10; r++) {
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
OUT(Zone[r]);
|
CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr;
|
||||||
OUT(EyeColor1[r]);
|
|
||||||
OUT(EyeColor2[r]);
|
for (size_t index = 0; index < 10; ++index) {
|
||||||
OUT(HairStyle[r]);
|
memset(eq->Name[index], 0, 64);
|
||||||
OUT(Primary[r]);
|
}
|
||||||
if (emu->Race[r] > 473)
|
|
||||||
eq->Race[r] = 1;
|
// Non character-indexed packet fields
|
||||||
else
|
eq->Unknown830[0] = 0;
|
||||||
eq->Race[r] = emu->Race[r];
|
eq->Unknown830[1] = 0;
|
||||||
OUT(Class_[r]);
|
eq->Unknown0962[0] = 0;
|
||||||
OUT_str(Name[r]);
|
eq->Unknown0962[1] = 0;
|
||||||
OUT(Gender[r]);
|
|
||||||
OUT(Level[r]);
|
size_t char_index = 0;
|
||||||
OUT(Secondary[r]);
|
for (; char_index < emu->CharCount && char_index < 8; ++char_index) {
|
||||||
OUT(Face[r]);
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
OUT(Beard[r]);
|
|
||||||
int k;
|
eq->Race[char_index] = emu_cse->Race;
|
||||||
for (k = 0; k < 9; k++) {
|
if (eq->Race[char_index] > 473)
|
||||||
eq->Equip[r][k] = emu->Equip[r][k].Material;
|
eq->Race[char_index] = 1;
|
||||||
eq->CS_Colors[r][k].Color = emu->Equip[r][k].Color.Color;
|
|
||||||
|
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]);
|
eq->BeardColor[char_index] = emu_cse->BeardColor;
|
||||||
OUT(Tutorial[r]);
|
eq->HairStyle[char_index] = emu_cse->HairStyle;
|
||||||
OUT(Deity[r]);
|
|
||||||
OUT(BeardColor[r]);
|
for (int index = 0; index < _MaterialCount; ++index) {
|
||||||
eq->Unknown820[r] = 0xFF;
|
eq->Equip[char_index][index] = emu_cse->Equip[index].Material;
|
||||||
eq->Unknown902[r] = 0xFF;
|
}
|
||||||
|
|
||||||
|
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();
|
FINISH_ENCODE();
|
||||||
|
|||||||
@ -100,7 +100,7 @@ namespace Titanium {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
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_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 16;
|
static const uint16 MAP_BANK_SIZE = 16;
|
||||||
|
|||||||
@ -122,7 +122,7 @@ struct CharacterSelect_Struct
|
|||||||
/*0400*/ uint8 BeardColor[10]; // Characters beard Color
|
/*0400*/ uint8 BeardColor[10]; // Characters beard Color
|
||||||
/*0410*/ uint8 HairStyle[10]; // Characters hair style
|
/*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)
|
/*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
|
/*0820*/ uint8 Unknown820[10]; // 10x ff
|
||||||
/*0830*/ uint8 Unknown830[2]; // 2x 00
|
/*0830*/ uint8 Unknown830[2]; // 2x 00
|
||||||
/*0832*/ uint32 Deity[10]; // Characters Deity
|
/*0832*/ uint32 Deity[10]; // Characters Deity
|
||||||
@ -130,11 +130,11 @@ struct CharacterSelect_Struct
|
|||||||
/*0882*/ uint8 Tutorial[10]; // 1=Tutorial available, 0=not
|
/*0882*/ uint8 Tutorial[10]; // 1=Tutorial available, 0=not
|
||||||
/*0892*/ uint8 Beard[10]; // Characters Beard Type
|
/*0892*/ uint8 Beard[10]; // Characters Beard Type
|
||||||
/*0902*/ uint8 Unknown902[10]; // 10x ff
|
/*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
|
/*0952*/ uint8 HairColor[10]; // Characters Hair Color
|
||||||
/*0962*/ uint8 Unknown0962[2]; // 2x 00
|
/*0962*/ uint8 Unknown0962[2]; // 2x 00
|
||||||
/*0964*/ uint32 Zone[10]; // Characters Current Zone
|
/*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
|
/*1014*/ uint8 Face[10]; // Characters Face Type
|
||||||
/*1024*/ char Name[10][64]; // Characters Names
|
/*1024*/ char Name[10][64]; // Characters Names
|
||||||
/*1664*/ uint8 Gender[10]; // Characters Gender
|
/*1664*/ uint8 Gender[10]; // Characters Gender
|
||||||
|
|||||||
@ -2194,77 +2194,103 @@ namespace UF
|
|||||||
|
|
||||||
ENCODE(OP_SendCharInfo)
|
ENCODE(OP_SendCharInfo)
|
||||||
{
|
{
|
||||||
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
||||||
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
||||||
|
|
||||||
//EQApplicationPacket *packet = *p;
|
// Zero-character count shunt
|
||||||
//const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer;
|
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;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
int namelen = 0;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
for (char_count = 0; char_count < 10; char_count++) {
|
|
||||||
if (emu->Name[char_count][0] == '\0')
|
// Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars'
|
||||||
break;
|
uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field
|
||||||
if (strcmp(emu->Name[char_count], "<none>") == 0)
|
eq->TotalChars = adjusted_total;
|
||||||
break;
|
|
||||||
namelen += strlen(emu->Name[char_count]);
|
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)
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
||||||
+ char_count * sizeof(structs::CharacterSelectEntry_Struct)
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
||||||
+ namelen;
|
+ names_length;
|
||||||
|
|
||||||
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_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];
|
eq->CharCount = character_count;
|
||||||
//structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer;
|
eq->TotalChars = emu->TotalChars;
|
||||||
|
|
||||||
eq->CharCount = char_count;
|
if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT)
|
||||||
eq->TotalChars = 10;
|
eq->TotalChars = consts::CHARACTER_CREATION_LIMIT;
|
||||||
|
|
||||||
unsigned char *bufptr = (unsigned char *)eq->Entries;
|
// Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' in this client
|
||||||
int r;
|
uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field
|
||||||
for (r = 0; r < char_count; r++) {
|
eq->TotalChars = adjusted_total;
|
||||||
{ //pre-name section...
|
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
emu_ptr = __emu_buffer;
|
||||||
eq2->Level = emu->Level[r];
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
||||||
eq2->HairStyle = emu->HairStyle[r];
|
|
||||||
eq2->Gender = emu->Gender[r];
|
unsigned char *eq_ptr = __packet->pBuffer;
|
||||||
memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1);
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
||||||
}
|
|
||||||
//adjust for name.
|
for (int counter = 0; counter < character_count; ++counter) {
|
||||||
bufptr += strlen(emu->Name[r]);
|
emu_cse = (CharacterSelectEntry_Struct *)emu_ptr;
|
||||||
{ //post-name section...
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr;
|
|
||||||
eq2->Beard = emu->Beard[r];
|
eq_cse->Level = emu_cse->Level;
|
||||||
eq2->HairColor = emu->HairColor[r];
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
||||||
eq2->Face = emu->Face[r];
|
eq_cse->Gender = emu_cse->Gender;
|
||||||
int k;
|
|
||||||
for (k = 0; k < _MaterialCount; k++) {
|
strcpy(eq_cse->Name, emu_cse->Name);
|
||||||
eq2->Equip[k].Material = emu->Equip[r][k].Material;
|
eq_ptr += strlen(eq_cse->Name);
|
||||||
eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1;
|
eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr;
|
||||||
eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial;
|
|
||||||
eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color;
|
eq_cse->Beard = emu_cse->Beard;
|
||||||
}
|
eq_cse->HairColor = emu_cse->HairColor;
|
||||||
eq2->Primary = emu->Primary[r];
|
eq_cse->Face = emu_cse->Face;
|
||||||
eq2->Secondary = emu->Secondary[r];
|
|
||||||
eq2->Tutorial = emu->Tutorial[r]; // was u15
|
for (int equip_index = 0; equip_index < _MaterialCount; equip_index++) {
|
||||||
eq2->Unknown15 = 0xFF;
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
||||||
eq2->Deity = emu->Deity[r];
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
||||||
eq2->Zone = emu->Zone[r];
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteMaterial;
|
||||||
eq2->Unknown19 = 0xFF;
|
eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color;
|
||||||
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();
|
FINISH_ENCODE();
|
||||||
|
|||||||
@ -101,7 +101,7 @@ namespace UF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace consts {
|
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_POSSESSIONS_SIZE = slots::_MainCount;
|
||||||
static const uint16 MAP_BANK_SIZE = 24;
|
static const uint16 MAP_BANK_SIZE = 24;
|
||||||
|
|||||||
@ -132,8 +132,8 @@ struct CharacterSelectEntry_Struct
|
|||||||
/*0001*/ uint8 HairColor; //
|
/*0001*/ uint8 HairColor; //
|
||||||
/*0000*/ uint8 Face; //
|
/*0000*/ uint8 Face; //
|
||||||
/*0000*/ CharSelectEquip Equip[9];
|
/*0000*/ CharSelectEquip Equip[9];
|
||||||
/*0000*/ uint32 Primary; //
|
/*0000*/ uint32 PrimaryIDFile; //
|
||||||
/*0000*/ uint32 Secondary; //
|
/*0000*/ uint32 SecondaryIDFile; //
|
||||||
/*0000*/ uint8 Unknown15; // 0xff
|
/*0000*/ uint8 Unknown15; // 0xff
|
||||||
/*0000*/ uint32 Deity; //
|
/*0000*/ uint32 Deity; //
|
||||||
/*0000*/ uint16 Zone; //
|
/*0000*/ uint16 Zone; //
|
||||||
@ -142,7 +142,7 @@ struct CharacterSelectEntry_Struct
|
|||||||
/*0000*/ uint8 Unknown19; // 0xff
|
/*0000*/ uint8 Unknown19; // 0xff
|
||||||
/*0000*/ uint32 Race; //
|
/*0000*/ uint32 Race; //
|
||||||
/*0000*/ uint8 Tutorial; //
|
/*0000*/ uint8 Tutorial; //
|
||||||
/*0000*/ uint8 Class_; //
|
/*0000*/ uint8 Class; //
|
||||||
/*0000*/ uint8 EyeColor1; //
|
/*0000*/ uint8 EyeColor1; //
|
||||||
/*0000*/ uint8 BeardColor; //
|
/*0000*/ uint8 BeardColor; //
|
||||||
/*0000*/ uint8 EyeColor2; //
|
/*0000*/ uint8 EyeColor2; //
|
||||||
|
|||||||
138
world/client.cpp
138
world/client.cpp
@ -16,6 +16,7 @@
|
|||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
#include "../common/clientversions.h"
|
#include "../common/clientversions.h"
|
||||||
#include "../common/random.h"
|
#include "../common/random.h"
|
||||||
|
#include "../common/shareddb.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "worlddb.h"
|
#include "worlddb.h"
|
||||||
@ -161,32 +162,34 @@ void Client::SendCharInfo() {
|
|||||||
cle->SetOnline(CLE_Status_CharSelect);
|
cle->SetOnline(CLE_Status_CharSelect);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_ClientVersionBit & BIT_RoFAndLater)
|
if (m_ClientVersionBit & BIT_RoFAndLater) {
|
||||||
{
|
SendMaxCharCreate();
|
||||||
// Can make max char per account into a rule - New to VoA
|
|
||||||
SendMaxCharCreate(10);
|
|
||||||
SendMembership();
|
SendMembership();
|
||||||
SendMembershipSettings();
|
SendMembershipSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
seencharsel = true;
|
seencharsel = true;
|
||||||
|
|
||||||
|
|
||||||
// Send OP_SendCharInfo
|
// Send OP_SendCharInfo
|
||||||
auto outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
EQApplicationPacket *outapp = nullptr;
|
||||||
CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer;
|
database.GetCharSelectInfo(GetAccountID(), &outapp, m_ClientVersionBit);
|
||||||
|
|
||||||
database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit);
|
if (outapp) {
|
||||||
|
QueuePacket(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);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendMaxCharCreate(int max_chars) {
|
void Client::SendMaxCharCreate() {
|
||||||
auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct));
|
auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct));
|
||||||
MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer;
|
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);
|
QueuePacket(outapp);
|
||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
@ -716,66 +719,71 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pZoning && ew->return_home && !ew->tutorial) {
|
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
|
||||||
auto cs = new CharacterSelect_Struct;
|
if (!pZoning) {
|
||||||
memset(cs, 0, sizeof(CharacterSelect_Struct));
|
size_t character_limit = EQLimits::CharacterCreationLimit(eqs->GetClientVersion());
|
||||||
database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit);
|
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) { character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; }
|
||||||
bool home_enabled = false;
|
if (eqs->GetClientVersion() == ClientVersion::Titanium) { character_limit = 8; }
|
||||||
|
|
||||||
for(int x = 0; x < 10; ++x)
|
std::string tgh_query = StringFormat(
|
||||||
{
|
"SELECT "
|
||||||
if(strcasecmp(cs->Name[x], char_name) == 0)
|
"`id`, "
|
||||||
{
|
"name, "
|
||||||
if(cs->GoHome[x] == 1)
|
"`level`, "
|
||||||
{
|
"last_login, "
|
||||||
home_enabled = true;
|
"FROM "
|
||||||
break;
|
"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) {
|
if (home_enabled) {
|
||||||
zoneID = database.MoveCharacterToBind(charid,4);
|
zoneID = database.MoveCharacterToBind(charid, 4);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go home before they're able...",char_name);
|
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.");
|
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||||
eqs->Close();
|
eqs->Close();
|
||||||
return true;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
safe_delete(cs);
|
|
||||||
|
|
||||||
if(tutorial_enabled)
|
/* Check Tutorial*/
|
||||||
{
|
if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) {
|
||||||
zoneID = RuleI(World, TutorialZoneID);
|
bool tutorial_enabled = false;
|
||||||
database.MoveCharacterToZone(charid, database.GetZoneName(zoneID));
|
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||||
}
|
if (strcasecmp(row[1], char_name) == 0) {
|
||||||
else
|
if (RuleB(World, EnableReturnHomeButton)) {
|
||||||
{
|
int now = time(nullptr);
|
||||||
Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go to tutorial but are not allowed...",char_name);
|
if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) {
|
||||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
tutorial_enabled = true;
|
||||||
eqs->Close();
|
break;
|
||||||
return true;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ public:
|
|||||||
bool Process();
|
bool Process();
|
||||||
void ReceiveData(uchar* buf, int len);
|
void ReceiveData(uchar* buf, int len);
|
||||||
void SendCharInfo();
|
void SendCharInfo();
|
||||||
void SendMaxCharCreate(int max_chars);
|
void SendMaxCharCreate();
|
||||||
void SendMembership();
|
void SendMembership();
|
||||||
void SendMembershipSettings();
|
void SendMembershipSettings();
|
||||||
void EnterWorld(bool TryBootup = true);
|
void EnterWorld(bool TryBootup = true);
|
||||||
|
|||||||
@ -33,21 +33,20 @@ extern std::vector<RaceClassCombos> character_create_race_class_combos;
|
|||||||
|
|
||||||
|
|
||||||
// the current stuff is at the bottom of this function
|
// 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;
|
/* Set Character Creation Limit */
|
||||||
uint8 has_home = 0;
|
ClientVersion client_version = ClientVersionFromBit(clientVersionBit);
|
||||||
uint8 has_bind = 0;
|
size_t character_limit = EQLimits::CharacterCreationLimit(client_version);
|
||||||
|
|
||||||
/* Initialize Variables */
|
// Validate against absolute server max
|
||||||
for (int i=0; i<10; i++) {
|
if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT)
|
||||||
strcpy(cs->Name[i], "<none>");
|
character_limit = EmuConstants::CHARACTER_CREATION_LIMIT;
|
||||||
cs->Zone[i] = 0;
|
|
||||||
cs->Level[i] = 0;
|
|
||||||
cs->Tutorial[i] = 0;
|
|
||||||
cs->GoHome[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Force Titanium clients to use '8'
|
||||||
|
if (client_version == ClientVersion::Titanium)
|
||||||
|
character_limit = 8;
|
||||||
|
|
||||||
/* Get Character Info */
|
/* Get Character Info */
|
||||||
std::string cquery = StringFormat(
|
std::string cquery = StringFormat(
|
||||||
"SELECT "
|
"SELECT "
|
||||||
@ -73,52 +72,93 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*
|
|||||||
"zone_id " // 19
|
"zone_id " // 19
|
||||||
"FROM "
|
"FROM "
|
||||||
"character_data "
|
"character_data "
|
||||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT 10 ", account_id);
|
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", accountID, character_limit);
|
||||||
auto results = database.QueryDatabase(cquery); int char_num = 0;
|
auto results = database.QueryDatabase(cquery);
|
||||||
for (auto row = results.begin(); row != results.end() && char_num < 10; ++row, ++char_num) {
|
|
||||||
|
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;
|
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));
|
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]);
|
if (RuleB(World, EnableTutorialButton) && (cse->Level <= RuleI(World, MaxLevelForTutorial))) {
|
||||||
strcpy(cs->Name[char_num], row[1]);
|
cse->Tutorial = 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, EnableReturnHomeButton)) {
|
if (RuleB(World, EnableReturnHomeButton)) {
|
||||||
int now = time(nullptr);
|
int now = time(nullptr);
|
||||||
if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome))
|
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 */
|
/* 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);
|
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) {
|
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]) == 1){ has_home = 1; }
|
||||||
if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 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",
|
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);
|
auto results_bind = database.QueryDatabase(cquery);
|
||||||
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
|
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
|
||||||
/* If a bind_id is specified, make them start there */
|
/* 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]);
|
float z = atof(row_d[4]);
|
||||||
if (x == 0 && y == 0 && z == 0){ GetSafePoints(pp.binds[4].zoneId, 0, &x, &y, &z); }
|
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[4].x = x; pp.binds[4].y = y; pp.binds[4].z = z;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pp.binds[0] = pp.binds[4];
|
pp.binds[0] = pp.binds[4];
|
||||||
/* If no home bind set, set it */
|
/* 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)"
|
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)",
|
" 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);
|
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 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)"
|
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)",
|
" 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);
|
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 */
|
/* 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 */
|
/* 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);
|
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;
|
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]);
|
slot = atoi(row_b[0]);
|
||||||
pp.item_tint[slot].RGB.Red = atoi(row_b[1]);
|
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.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]);
|
pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load Inventory */
|
buff_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) {
|
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "../common/shareddb.h"
|
#include "../common/shareddb.h"
|
||||||
#include "../common/zone_numbers.h"
|
#include "../common/zone_numbers.h"
|
||||||
|
#include "../common/eq_packet.h"
|
||||||
|
|
||||||
struct PlayerProfile_Struct;
|
struct PlayerProfile_Struct;
|
||||||
struct CharCreate_Struct;
|
struct CharCreate_Struct;
|
||||||
@ -29,7 +30,7 @@ struct CharacterSelect_Struct;
|
|||||||
class WorldDatabase : public SharedDatabase {
|
class WorldDatabase : public SharedDatabase {
|
||||||
public:
|
public:
|
||||||
bool GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc, bool isTitanium);
|
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);
|
int MoveCharacterToBind(int CharID, uint8 bindnum = 0);
|
||||||
|
|
||||||
void GetLauncherList(std::vector<std::string> &result);
|
void GetLauncherList(std::vector<std::string> &result);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user