mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
[Bug Fix] Zone Heading for Binds, Summons, Teleports, and Zoning. (#1328)
* For as long as I can remember people have had issues with zoning in, facing the wrong way, and walking through a zone line. With this we will be able to set zone's safe heading as well as preserve heading on summon (NPC or GM) and teleports between zones. This affects several pre-existing quest methods and extends their parameters to allow for the addition of heading. The following functions have had heading added. Lua - client:SetBindPoint() - client:SetStartZone() Perl - $client->SetBindPoint() - $client->SetStartZone() - quest::rebind() SetStartZone parameter list was fixed also. This converts some pre-existing methods from glm::vec3() to glm::vec4() and has an overload where necessary to use a glm::vec3() method versus glm::vec4() method. This shouldn't affect any pre-existing servers and will allow PEQ and others to document safe headings for zones properly. * Removed possible memory leaks. * Fix SQL. * Fix client message. * Fix debug log. * Fix log message. * Fix call in rebind overload. * Fix floats. * Add default to column.
This commit is contained in:
+269
-188
@@ -54,42 +54,48 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
character_limit = 8;
|
||||
}
|
||||
|
||||
std::string character_list_query = StringFormat(
|
||||
"SELECT "
|
||||
"`id`, " // 0
|
||||
"name, " // 1
|
||||
"gender, " // 2
|
||||
"race, " // 3
|
||||
"class, " // 4
|
||||
"`level`, " // 5
|
||||
"deity, " // 6
|
||||
"last_login, " // 7
|
||||
"time_played, " // 8
|
||||
"hair_color, " // 9
|
||||
"beard_color, " // 10
|
||||
"eye_color_1, " // 11
|
||||
"eye_color_2, " // 12
|
||||
"hair_style, " // 13
|
||||
"beard, " // 14
|
||||
"face, " // 15
|
||||
"drakkin_heritage, " // 16
|
||||
"drakkin_tattoo, " // 17
|
||||
"drakkin_details, " // 18
|
||||
"zone_id " // 19
|
||||
"FROM "
|
||||
"character_data "
|
||||
"WHERE `account_id` = %i AND deleted_at IS NULL ORDER BY `name` LIMIT %u",
|
||||
std::string character_list_query = fmt::format(
|
||||
SQL(
|
||||
SELECT
|
||||
`id`,
|
||||
`name`,
|
||||
`gender`,
|
||||
`race`,
|
||||
`class`,
|
||||
`level`,
|
||||
`deity`,
|
||||
`last_login`,
|
||||
`time_played`,
|
||||
`hair_color`,
|
||||
`beard_color`,
|
||||
`eye_color_1`,
|
||||
`eye_color_2`,
|
||||
`hair_style`,
|
||||
`beard`,
|
||||
`face`,
|
||||
`drakkin_heritage`,
|
||||
`drakkin_tattoo`,
|
||||
`drakkin_details`,
|
||||
`zone_id`
|
||||
FROM
|
||||
`character_data`
|
||||
WHERE
|
||||
`account_id` = {}
|
||||
AND
|
||||
`deleted_at` IS NULL
|
||||
ORDER BY `name`
|
||||
LIMIT {}
|
||||
),
|
||||
account_id,
|
||||
character_limit
|
||||
);
|
||||
|
||||
auto results = database.QueryDatabase(character_list_query);
|
||||
|
||||
size_t character_count = results.RowCount();
|
||||
if (character_count == 0) {
|
||||
*out_app = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
||||
*out_app = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct));
|
||||
CharacterSelect_Struct *cs = (CharacterSelect_Struct *) (*out_app)->pBuffer;
|
||||
cs->CharCount = 0;
|
||||
cs->CharCount = 0;
|
||||
cs->TotalChars = character_limit;
|
||||
return;
|
||||
}
|
||||
@@ -97,155 +103,181 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
size_t packet_size = sizeof(CharacterSelect_Struct) + (sizeof(CharacterSelectEntry_Struct) * character_count);
|
||||
*out_app = new EQApplicationPacket(OP_SendCharInfo, packet_size);
|
||||
|
||||
unsigned char *buff_ptr = (*out_app)->pBuffer;
|
||||
CharacterSelect_Struct *cs = (CharacterSelect_Struct *) buff_ptr;
|
||||
unsigned char *buff_ptr = (*out_app)->pBuffer;
|
||||
CharacterSelect_Struct *cs = (CharacterSelect_Struct *) buff_ptr;
|
||||
|
||||
cs->CharCount = character_count;
|
||||
cs->CharCount = character_count;
|
||||
cs->TotalChars = character_limit;
|
||||
|
||||
buff_ptr += sizeof(CharacterSelect_Struct);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
CharacterSelectEntry_Struct *p_character_select_entry_struct = (CharacterSelectEntry_Struct *) buff_ptr;
|
||||
PlayerProfile_Struct player_profile_struct;
|
||||
EQ::InventoryProfile inventory_profile;
|
||||
PlayerProfile_Struct player_profile_struct;
|
||||
EQ::InventoryProfile inventory_profile;
|
||||
|
||||
player_profile_struct.SetPlayerProfileVersion(EQ::versions::ConvertClientVersionToMobVersion(client_version));
|
||||
inventory_profile.SetInventoryVersion(client_version);
|
||||
inventory_profile.SetGMInventory(true); // charsel can not interact with items..but, no harm in setting to full expansion support
|
||||
|
||||
uint32 character_id = (uint32) atoi(row[0]);
|
||||
uint8 has_home = 0;
|
||||
uint8 has_bind = 0;
|
||||
uint8 has_home = 0;
|
||||
uint8 has_bind = 0;
|
||||
|
||||
memset(&player_profile_struct, 0, sizeof(PlayerProfile_Struct));
|
||||
|
||||
memset(p_character_select_entry_struct->Name, 0, sizeof(p_character_select_entry_struct->Name));
|
||||
strcpy(p_character_select_entry_struct->Name, row[1]);
|
||||
p_character_select_entry_struct->Class = (uint8) atoi(row[4]);
|
||||
p_character_select_entry_struct->Race = (uint32) atoi(row[3]);
|
||||
p_character_select_entry_struct->Level = (uint8) atoi(row[5]);
|
||||
p_character_select_entry_struct->Class = (uint8) atoi(row[4]);
|
||||
p_character_select_entry_struct->Race = (uint32) atoi(row[3]);
|
||||
p_character_select_entry_struct->Level = (uint8) atoi(row[5]);
|
||||
p_character_select_entry_struct->ShroudClass = p_character_select_entry_struct->Class;
|
||||
p_character_select_entry_struct->ShroudRace = p_character_select_entry_struct->Race;
|
||||
p_character_select_entry_struct->Zone = (uint16) atoi(row[19]);
|
||||
p_character_select_entry_struct->Instance = 0;
|
||||
p_character_select_entry_struct->Gender = (uint8) atoi(row[2]);
|
||||
p_character_select_entry_struct->Face = (uint8) atoi(row[15]);
|
||||
p_character_select_entry_struct->ShroudRace = p_character_select_entry_struct->Race;
|
||||
p_character_select_entry_struct->Zone = (uint16) atoi(row[19]);
|
||||
p_character_select_entry_struct->Instance = 0;
|
||||
p_character_select_entry_struct->Gender = (uint8) atoi(row[2]);
|
||||
p_character_select_entry_struct->Face = (uint8) atoi(row[15]);
|
||||
|
||||
for (uint32 material_slot = 0; material_slot < EQ::textures::materialCount; material_slot++) {
|
||||
p_character_select_entry_struct->Equip[material_slot].Material = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Unknown1 = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].EliteModel = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Material = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Unknown1 = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].EliteModel = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].HerosForgeModel = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Unknown2 = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Color = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Unknown2 = 0;
|
||||
p_character_select_entry_struct->Equip[material_slot].Color = 0;
|
||||
}
|
||||
|
||||
p_character_select_entry_struct->Unknown15 = 0xFF;
|
||||
p_character_select_entry_struct->Unknown19 = 0xFF;
|
||||
p_character_select_entry_struct->DrakkinTattoo = (uint32) atoi(row[17]);
|
||||
p_character_select_entry_struct->DrakkinDetails = (uint32) atoi(row[18]);
|
||||
p_character_select_entry_struct->Deity = (uint32) atoi(row[6]);
|
||||
p_character_select_entry_struct->PrimaryIDFile = 0; // Processed Below
|
||||
p_character_select_entry_struct->Unknown15 = 0xFF;
|
||||
p_character_select_entry_struct->Unknown19 = 0xFF;
|
||||
p_character_select_entry_struct->DrakkinTattoo = (uint32) atoi(row[17]);
|
||||
p_character_select_entry_struct->DrakkinDetails = (uint32) atoi(row[18]);
|
||||
p_character_select_entry_struct->Deity = (uint32) atoi(row[6]);
|
||||
p_character_select_entry_struct->PrimaryIDFile = 0; // Processed Below
|
||||
p_character_select_entry_struct->SecondaryIDFile = 0; // Processed Below
|
||||
p_character_select_entry_struct->HairColor = (uint8) atoi(row[9]);
|
||||
p_character_select_entry_struct->BeardColor = (uint8) atoi(row[10]);
|
||||
p_character_select_entry_struct->EyeColor1 = (uint8) atoi(row[11]);
|
||||
p_character_select_entry_struct->EyeColor2 = (uint8) atoi(row[12]);
|
||||
p_character_select_entry_struct->HairStyle = (uint8) atoi(row[13]);
|
||||
p_character_select_entry_struct->Beard = (uint8) atoi(row[14]);
|
||||
p_character_select_entry_struct->GoHome = 0; // Processed Below
|
||||
p_character_select_entry_struct->Tutorial = 0; // Processed Below
|
||||
p_character_select_entry_struct->HairColor = (uint8) atoi(row[9]);
|
||||
p_character_select_entry_struct->BeardColor = (uint8) atoi(row[10]);
|
||||
p_character_select_entry_struct->EyeColor1 = (uint8) atoi(row[11]);
|
||||
p_character_select_entry_struct->EyeColor2 = (uint8) atoi(row[12]);
|
||||
p_character_select_entry_struct->HairStyle = (uint8) atoi(row[13]);
|
||||
p_character_select_entry_struct->Beard = (uint8) atoi(row[14]);
|
||||
p_character_select_entry_struct->GoHome = 0; // Processed Below
|
||||
p_character_select_entry_struct->Tutorial = 0; // Processed Below
|
||||
p_character_select_entry_struct->DrakkinHeritage = (uint32) atoi(row[16]);
|
||||
p_character_select_entry_struct->Unknown1 = 0;
|
||||
p_character_select_entry_struct->Enabled = 1;
|
||||
p_character_select_entry_struct->LastLogin = (uint32) atoi(row[7]); // RoF2 value: 1212696584
|
||||
p_character_select_entry_struct->Unknown2 = 0;
|
||||
p_character_select_entry_struct->Unknown1 = 0;
|
||||
p_character_select_entry_struct->Enabled = 1;
|
||||
p_character_select_entry_struct->LastLogin = (uint32) atoi(row[7]); // RoF2 value: 1212696584
|
||||
p_character_select_entry_struct->Unknown2 = 0;
|
||||
|
||||
if (RuleB(World, EnableReturnHomeButton)) {
|
||||
int now = time(nullptr);
|
||||
if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome)) {
|
||||
if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome))
|
||||
p_character_select_entry_struct->GoHome = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(World, EnableTutorialButton) && (p_character_select_entry_struct->Level <= RuleI(World, MaxLevelForTutorial))) {
|
||||
if (RuleB(World, EnableTutorialButton) && (p_character_select_entry_struct->Level <= RuleI(World, MaxLevelForTutorial)))
|
||||
p_character_select_entry_struct->Tutorial = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind
|
||||
*/
|
||||
character_list_query = StringFormat(
|
||||
"SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot` FROM `character_bind` WHERE `id` = %i LIMIT 5",
|
||||
character_list_query = fmt::format(
|
||||
SQL(
|
||||
SELECT
|
||||
`zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot`
|
||||
FROM
|
||||
`character_bind`
|
||||
WHERE
|
||||
`id` = {}
|
||||
LIMIT 5
|
||||
),
|
||||
character_id
|
||||
);
|
||||
auto results_bind = database.QueryDatabase(character_list_query);
|
||||
auto bind_count = results_bind.RowCount();
|
||||
for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) {
|
||||
auto results_bind = database.QueryDatabase(character_list_query);
|
||||
auto bind_count = results_bind.RowCount();
|
||||
for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) {
|
||||
if (row_b[6] && atoi(row_b[6]) == 4) {
|
||||
has_home = 1;
|
||||
// If our bind count is less than 5, we need to actually make use of this data so lets parse it
|
||||
if (bind_count < 5) {
|
||||
player_profile_struct.binds[4].zoneId = atoi(row_b[0]);
|
||||
player_profile_struct.binds[4].zone_id = atoi(row_b[0]);
|
||||
player_profile_struct.binds[4].instance_id = atoi(row_b[1]);
|
||||
player_profile_struct.binds[4].x = atof(row_b[2]);
|
||||
player_profile_struct.binds[4].y = atof(row_b[3]);
|
||||
player_profile_struct.binds[4].z = atof(row_b[4]);
|
||||
player_profile_struct.binds[4].heading = atof(row_b[5]);
|
||||
player_profile_struct.binds[4].x = atof(row_b[2]);
|
||||
player_profile_struct.binds[4].y = atof(row_b[3]);
|
||||
player_profile_struct.binds[4].z = atof(row_b[4]);
|
||||
player_profile_struct.binds[4].heading = atof(row_b[5]);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
character_list_query = StringFormat(
|
||||
"SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i %s",
|
||||
std::string character_list_query = fmt::format(
|
||||
SQL(
|
||||
SELECT
|
||||
`zone_id`, `bind_id`, `x`, `y`, `z`, `heading`
|
||||
FROM
|
||||
`start_zones`
|
||||
WHERE
|
||||
`player_class` = {}
|
||||
AND
|
||||
`player_deity` = {}
|
||||
AND
|
||||
`player_race` = {} {}
|
||||
),
|
||||
p_character_select_entry_struct->Class,
|
||||
p_character_select_entry_struct->Deity,
|
||||
p_character_select_entry_struct->Race,
|
||||
ContentFilterCriteria::apply().c_str()
|
||||
);
|
||||
auto results_bind = content_db.QueryDatabase(character_list_query);
|
||||
for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) {
|
||||
auto results_bind = content_db.QueryDatabase(character_list_query);
|
||||
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 (atoi(row_d[1]) != 0) {
|
||||
player_profile_struct.binds[4].zoneId = (uint32) atoi(row_d[1]);
|
||||
player_profile_struct.binds[4].zone_id = (uint32) atoi(row_d[1]);
|
||||
content_db.GetSafePoints(
|
||||
ZoneName(player_profile_struct.binds[4].zoneId),
|
||||
ZoneName(player_profile_struct.binds[4].zone_id),
|
||||
0,
|
||||
&player_profile_struct.binds[4].x,
|
||||
&player_profile_struct.binds[4].y,
|
||||
&player_profile_struct.binds[4].z
|
||||
&player_profile_struct.binds[4].z,
|
||||
&player_profile_struct.binds[4].heading
|
||||
);
|
||||
}
|
||||
/* Otherwise, use the zone and coordinates given */
|
||||
else {
|
||||
player_profile_struct.binds[4].zoneId = (uint32) atoi(row_d[0]);
|
||||
player_profile_struct.binds[4].zone_id = (uint32) atoi(row_d[0]);
|
||||
float x = atof(row_d[2]);
|
||||
float y = atof(row_d[3]);
|
||||
float z = atof(row_d[4]);
|
||||
if (x == 0 && y == 0 && z == 0) {
|
||||
float heading = atof(row_d[5]);
|
||||
if (x == 0 && y == 0 && z == 0 && heading == 0) {
|
||||
content_db.GetSafePoints(
|
||||
ZoneName(player_profile_struct.binds[4].zoneId),
|
||||
ZoneName(player_profile_struct.binds[4].zone_id),
|
||||
0,
|
||||
&x,
|
||||
&y,
|
||||
&z
|
||||
&z,
|
||||
&heading
|
||||
);
|
||||
}
|
||||
player_profile_struct.binds[4].x = x;
|
||||
player_profile_struct.binds[4].y = y;
|
||||
player_profile_struct.binds[4].z = z;
|
||||
player_profile_struct.binds[4].heading = heading;
|
||||
}
|
||||
}
|
||||
player_profile_struct.binds[0] = player_profile_struct.binds[4];
|
||||
/* If no home bind set, set it */
|
||||
if (has_home == 0) {
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
REPLACE INTO
|
||||
`character_bind`
|
||||
(`id`, `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot`)
|
||||
VALUES ({}, {}, {}, {}, {}, {}, {}, {})
|
||||
),
|
||||
character_id,
|
||||
player_profile_struct.binds[4].zoneId,
|
||||
player_profile_struct.binds[4].zone_id,
|
||||
0,
|
||||
player_profile_struct.binds[4].x,
|
||||
player_profile_struct.binds[4].y,
|
||||
@@ -253,15 +285,19 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
player_profile_struct.binds[4].heading,
|
||||
4
|
||||
);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
}
|
||||
/* If no regular bind set, set it */
|
||||
if (has_bind == 0) {
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
REPLACE INTO
|
||||
`character_bind`
|
||||
(`id`, `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot`)
|
||||
VALUES ({}, {}, {}, {}, {}, {}, {}, {})
|
||||
),
|
||||
character_id,
|
||||
player_profile_struct.binds[0].zoneId,
|
||||
player_profile_struct.binds[0].zone_id,
|
||||
0,
|
||||
player_profile_struct.binds[0].x,
|
||||
player_profile_struct.binds[0].y,
|
||||
@@ -269,7 +305,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
player_profile_struct.binds[0].heading,
|
||||
0
|
||||
);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
/* If our bind count is less than 5, then we have null data that needs to be filled in. */
|
||||
@@ -277,15 +313,18 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
// we know that home and main bind must be valid here, so we don't check those
|
||||
// we also use home to fill in the null data like live does.
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (player_profile_struct.binds[i].zoneId != 0) { // we assume 0 is the only invalid one ...
|
||||
if (player_profile_struct.binds[i].zone_id != 0) // we assume 0 is the only invalid one ...
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, slot)"
|
||||
" VALUES (%u, %u, %u, %f, %f, %f, %f, %i)",
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
REPLACE INTO
|
||||
`character_bind`
|
||||
(`id`, `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `slot`)
|
||||
VALUES ({}, {}, {}, {}, {}, {}, {}, {})
|
||||
),
|
||||
character_id,
|
||||
player_profile_struct.binds[4].zoneId,
|
||||
player_profile_struct.binds[4].zone_id,
|
||||
0,
|
||||
player_profile_struct.binds[4].x,
|
||||
player_profile_struct.binds[4].y,
|
||||
@@ -293,40 +332,45 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
player_profile_struct.binds[4].heading,
|
||||
i
|
||||
);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
auto results_bset = QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
character_list_query = StringFormat(
|
||||
"SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u",
|
||||
character_list_query = fmt::format(
|
||||
SQL(
|
||||
SELECT
|
||||
`slot`, `red`, `green`, `blue`, `use_tint`, `color`
|
||||
FROM
|
||||
`character_material`
|
||||
WHERE
|
||||
`id` = {}
|
||||
),
|
||||
character_id
|
||||
);
|
||||
auto results_b = database.QueryDatabase(character_list_query);
|
||||
uint8 slot = 0;
|
||||
for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) {
|
||||
auto results_b = database.QueryDatabase(character_list_query);
|
||||
uint8 slot = 0;
|
||||
for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) {
|
||||
slot = atoi(row_b[0]);
|
||||
player_profile_struct.item_tint.Slot[slot].Red = atoi(row_b[1]);
|
||||
player_profile_struct.item_tint.Slot[slot].Green = atoi(row_b[2]);
|
||||
player_profile_struct.item_tint.Slot[slot].Blue = atoi(row_b[3]);
|
||||
player_profile_struct.item_tint.Slot[slot].Red = atoi(row_b[1]);
|
||||
player_profile_struct.item_tint.Slot[slot].Green = atoi(row_b[2]);
|
||||
player_profile_struct.item_tint.Slot[slot].Blue = atoi(row_b[3]);
|
||||
player_profile_struct.item_tint.Slot[slot].UseTint = atoi(row_b[4]);
|
||||
}
|
||||
|
||||
if (GetCharSelInventory(account_id, p_character_select_entry_struct->Name, &inventory_profile)) {
|
||||
const EQ::ItemData *item = nullptr;
|
||||
const EQ::ItemInstance *inst = nullptr;
|
||||
const EQ::ItemData *item = nullptr;
|
||||
const EQ::ItemInstance *inst = nullptr;
|
||||
int16 inventory_slot = 0;
|
||||
|
||||
for (uint32 matslot = EQ::textures::textureBegin; matslot < EQ::textures::materialCount; matslot++) {
|
||||
inventory_slot = EQ::InventoryProfile::CalcSlotFromMaterial(matslot);
|
||||
if (inventory_slot == INVALID_INDEX) { continue; }
|
||||
inst = inventory_profile.GetItem(inventory_slot);
|
||||
if (inst == nullptr) {
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
}
|
||||
|
||||
item = inst->GetItem();
|
||||
if (item == nullptr) {
|
||||
if (item == nullptr)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (matslot > 6) {
|
||||
uint32 item_id_file = 0;
|
||||
@@ -334,54 +378,59 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, EQApplicationPacket **o
|
||||
if (inst->GetOrnamentationIDFile() != 0) {
|
||||
item_id_file = inst->GetOrnamentationIDFile();
|
||||
p_character_select_entry_struct->Equip[matslot].Material = item_id_file;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (strlen(item->IDFile) > 2) {
|
||||
item_id_file = atoi(&item->IDFile[2]);
|
||||
p_character_select_entry_struct->Equip[matslot].Material = item_id_file;
|
||||
}
|
||||
}
|
||||
|
||||
if (matslot == EQ::textures::weaponPrimary) {
|
||||
p_character_select_entry_struct->PrimaryIDFile = item_id_file;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
p_character_select_entry_struct->SecondaryIDFile = item_id_file;
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint32 color = 0;
|
||||
if (player_profile_struct.item_tint.Slot[matslot].UseTint) {
|
||||
color = player_profile_struct.item_tint.Slot[matslot].Color;
|
||||
}
|
||||
else {
|
||||
color = inst->GetColor();
|
||||
}
|
||||
|
||||
} else {
|
||||
// Armor Materials/Models
|
||||
p_character_select_entry_struct->Equip[matslot].Material = item->Material;
|
||||
p_character_select_entry_struct->Equip[matslot].EliteModel = item->EliteMaterial;
|
||||
uint32 color = (
|
||||
player_profile_struct.item_tint.Slot[matslot].UseTint ?
|
||||
player_profile_struct.item_tint.Slot[matslot].Color :
|
||||
inst->GetColor()
|
||||
);
|
||||
p_character_select_entry_struct->Equip[matslot].Material = item->Material;
|
||||
p_character_select_entry_struct->Equip[matslot].EliteModel = item->EliteMaterial;
|
||||
p_character_select_entry_struct->Equip[matslot].HerosForgeModel = inst->GetOrnamentHeroModel(matslot);
|
||||
p_character_select_entry_struct->Equip[matslot].Color = color;
|
||||
p_character_select_entry_struct->Equip[matslot].Color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
printf("Error loading inventory for %s\n", p_character_select_entry_struct->Name);
|
||||
}
|
||||
|
||||
buff_ptr += sizeof(CharacterSelectEntry_Struct);
|
||||
}
|
||||
}
|
||||
|
||||
int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum)
|
||||
int WorldDatabase::MoveCharacterToBind(int character_id, uint8 bind_number)
|
||||
{
|
||||
/* if an invalid bind point is specified, use the primary bind */
|
||||
if (bindnum > 4)
|
||||
{
|
||||
bindnum = 0;
|
||||
}
|
||||
if (bind_number > 4)
|
||||
bind_number = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT zone_id, instance_id, x, y, z FROM character_bind WHERE id = %u AND slot = %u LIMIT 1", CharID, bindnum);
|
||||
std::string query = fmt::format(
|
||||
SQL(
|
||||
SELECT
|
||||
zone_id, instance_id, x, y, z, heading
|
||||
FROM
|
||||
character_bind
|
||||
WHERE
|
||||
id = {}
|
||||
AND
|
||||
slot = {}
|
||||
LIMIT 1
|
||||
),
|
||||
character_id,
|
||||
bind_number
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success() || results.RowCount() == 0) {
|
||||
return 0;
|
||||
@@ -398,8 +447,27 @@ int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum)
|
||||
heading = atof(row[5]);
|
||||
}
|
||||
|
||||
query = StringFormat("UPDATE character_data SET zone_id = '%d', zone_instance = '%d', x = '%f', y = '%f', z = '%f', heading = '%f' WHERE id = %u",
|
||||
zone_id, instance_id, x, y, z, heading, CharID);
|
||||
query = fmt::format(
|
||||
SQL(
|
||||
UPDATE
|
||||
`character_data`
|
||||
SET
|
||||
`zone_id` = {},
|
||||
`zone_instance` = {},
|
||||
`x` = {},
|
||||
`y` = {},
|
||||
`z` = {},
|
||||
`heading` = {}
|
||||
WHERE `id` = {}
|
||||
),
|
||||
zone_id,
|
||||
instance_id,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
heading,
|
||||
character_id
|
||||
);
|
||||
|
||||
results = database.QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
@@ -434,7 +502,7 @@ bool WorldDatabase::GetStartZone(
|
||||
p_player_profile_struct->binds[0].x = 0;
|
||||
p_player_profile_struct->binds[0].y = 0;
|
||||
p_player_profile_struct->binds[0].z = 0;
|
||||
p_player_profile_struct->binds[0].zoneId = 0;
|
||||
p_player_profile_struct->binds[0].zone_id = 0;
|
||||
p_player_profile_struct->binds[0].instance_id = 0;
|
||||
|
||||
// see if we have an entry for start_zone. We can support both titanium & SOF+ by having two entries per class/race/deity combo with different zone_ids
|
||||
@@ -480,35 +548,47 @@ bool WorldDatabase::GetStartZone(
|
||||
else {
|
||||
LogInfo("Found starting location in start_zones");
|
||||
auto row = results.begin();
|
||||
p_player_profile_struct->x = atof(row[0]);
|
||||
p_player_profile_struct->y = atof(row[1]);
|
||||
p_player_profile_struct->z = atof(row[2]);
|
||||
p_player_profile_struct->heading = atof(row[3]);
|
||||
p_player_profile_struct->zone_id = atoi(row[4]);
|
||||
p_player_profile_struct->binds[0].zoneId = atoi(row[5]);
|
||||
p_player_profile_struct->binds[0].x = atof(row[6]);
|
||||
p_player_profile_struct->binds[0].y = atof(row[7]);
|
||||
p_player_profile_struct->binds[0].z = atof(row[8]);
|
||||
p_player_profile_struct->x = atof(row[0]);
|
||||
p_player_profile_struct->y = atof(row[1]);
|
||||
p_player_profile_struct->z = atof(row[2]);
|
||||
p_player_profile_struct->heading = atof(row[3]);
|
||||
p_player_profile_struct->zone_id = atoi(row[4]);
|
||||
p_player_profile_struct->binds[0].zone_id = atoi(row[5]);
|
||||
p_player_profile_struct->binds[0].x = atof(row[6]);
|
||||
p_player_profile_struct->binds[0].y = atof(row[7]);
|
||||
p_player_profile_struct->binds[0].z = atof(row[8]);
|
||||
p_player_profile_struct->binds[0].heading = atof(row[3]);
|
||||
}
|
||||
|
||||
if (p_player_profile_struct->x == 0 && p_player_profile_struct->y == 0 && p_player_profile_struct->z == 0) {
|
||||
if (
|
||||
p_player_profile_struct->x == 0 &&
|
||||
p_player_profile_struct->y == 0 &&
|
||||
p_player_profile_struct->z == 0 &&
|
||||
p_player_profile_struct->heading == 0
|
||||
) {
|
||||
content_db.GetSafePoints(
|
||||
ZoneName(p_player_profile_struct->zone_id),
|
||||
0,
|
||||
&p_player_profile_struct->x,
|
||||
&p_player_profile_struct->y,
|
||||
&p_player_profile_struct->z
|
||||
&p_player_profile_struct->z,
|
||||
&p_player_profile_struct->heading
|
||||
);
|
||||
}
|
||||
|
||||
if (p_player_profile_struct->binds[0].x == 0 && p_player_profile_struct->binds[0].y == 0 &&
|
||||
p_player_profile_struct->binds[0].z == 0) {
|
||||
if (
|
||||
p_player_profile_struct->binds[0].x == 0 &&
|
||||
p_player_profile_struct->binds[0].y == 0 &&
|
||||
p_player_profile_struct->binds[0].z == 0 &&
|
||||
p_player_profile_struct->binds[0].heading == 0
|
||||
) {
|
||||
content_db.GetSafePoints(
|
||||
ZoneName(p_player_profile_struct->binds[0].zoneId),
|
||||
ZoneName(p_player_profile_struct->binds[0].zone_id),
|
||||
0,
|
||||
&p_player_profile_struct->binds[0].x,
|
||||
&p_player_profile_struct->binds[0].y,
|
||||
&p_player_profile_struct->binds[0].z
|
||||
&p_player_profile_struct->binds[0].z,
|
||||
&p_player_profile_struct->binds[0].heading
|
||||
);
|
||||
}
|
||||
|
||||
@@ -520,10 +600,11 @@ void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCrea
|
||||
in_pp->zone_id = in_cc->start_zone;
|
||||
}
|
||||
else {
|
||||
in_pp->x = in_pp->binds[0].x = -51;
|
||||
in_pp->y = in_pp->binds[0].y = -20;
|
||||
in_pp->z = in_pp->binds[0].z = 0.79;
|
||||
in_pp->zone_id = in_pp->binds[0].zoneId = 394; // Crescent Reach.
|
||||
in_pp->x = in_pp->binds[0].x = -51.0f;
|
||||
in_pp->y = in_pp->binds[0].y = -20.0f;
|
||||
in_pp->z = in_pp->binds[0].z = 0.79f;
|
||||
in_pp->heading = in_pp->binds[0].heading = 0.0f;
|
||||
in_pp->zone_id = in_pp->binds[0].zone_id = 394; // Crescent Reach.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,91 +617,91 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha
|
||||
if (in_cc->deity == 203) // Cazic-Thule Erudites go to Paineel
|
||||
{
|
||||
in_pp->zone_id = 75; // paineel
|
||||
in_pp->binds[0].zoneId = 75;
|
||||
in_pp->binds[0].zone_id = 75;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_pp->zone_id = 24; // erudnext
|
||||
in_pp->binds[0].zoneId = 38; // tox
|
||||
in_pp->binds[0].zone_id = 38; // tox
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
in_pp->zone_id = 2; // qeynos2
|
||||
in_pp->binds[0].zoneId = 2; // qeynos2
|
||||
in_pp->binds[0].zone_id = 2; // qeynos2
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
in_pp->zone_id = 29; // halas
|
||||
in_pp->binds[0].zoneId = 30; // everfrost
|
||||
in_pp->binds[0].zone_id = 30; // everfrost
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
in_pp->zone_id = 19; // rivervale
|
||||
in_pp->binds[0].zoneId = 20; // kithicor
|
||||
in_pp->binds[0].zone_id = 20; // kithicor
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
in_pp->zone_id = 9; // freportw
|
||||
in_pp->binds[0].zoneId = 9; // freportw
|
||||
in_pp->binds[0].zone_id = 9; // freportw
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
in_pp->zone_id = 40; // neriaka
|
||||
in_pp->binds[0].zoneId = 25; // nektulos
|
||||
in_pp->binds[0].zone_id = 25; // nektulos
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
in_pp->zone_id = 52; // gukta
|
||||
in_pp->binds[0].zoneId = 46; // innothule
|
||||
in_pp->binds[0].zone_id = 46; // innothule
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
in_pp->zone_id = 49; // oggok
|
||||
in_pp->binds[0].zoneId = 47; // feerrott
|
||||
in_pp->binds[0].zone_id = 47; // feerrott
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
in_pp->zone_id = 60; // kaladima
|
||||
in_pp->binds[0].zoneId = 68; // butcher
|
||||
in_pp->binds[0].zone_id = 68; // butcher
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
in_pp->zone_id = 54; // gfaydark
|
||||
in_pp->binds[0].zoneId = 54; // gfaydark
|
||||
in_pp->binds[0].zone_id = 54; // gfaydark
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
in_pp->zone_id = 61; // felwithea
|
||||
in_pp->binds[0].zoneId = 54; // gfaydark
|
||||
in_pp->binds[0].zone_id = 54; // gfaydark
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
{
|
||||
in_pp->zone_id = 55; // akanon
|
||||
in_pp->binds[0].zoneId = 56; // steamfont
|
||||
in_pp->binds[0].zone_id = 56; // steamfont
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
{
|
||||
in_pp->zone_id = 82; // cabwest
|
||||
in_pp->binds[0].zoneId = 78; // fieldofbone
|
||||
in_pp->binds[0].zone_id = 78; // fieldofbone
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
{
|
||||
in_pp->zone_id = 155; // sharvahl
|
||||
in_pp->binds[0].zoneId = 155; // sharvahl
|
||||
in_pp->binds[0].zone_id = 155; // sharvahl
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user