[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:
Alex
2021-04-22 23:49:44 -04:00
committed by GitHub
parent 5893730704
commit 00fb9bc9f9
41 changed files with 697 additions and 481 deletions
+7 -7
View File
@@ -1569,25 +1569,25 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
}
/* Set Home Binds -- yep, all of them */
pp.binds[1].zoneId = pp.zone_id;
pp.binds[1].zone_id = pp.zone_id;
pp.binds[1].x = pp.x;
pp.binds[1].y = pp.y;
pp.binds[1].z = pp.z;
pp.binds[1].heading = pp.heading;
pp.binds[2].zoneId = pp.zone_id;
pp.binds[2].zone_id = pp.zone_id;
pp.binds[2].x = pp.x;
pp.binds[2].y = pp.y;
pp.binds[2].z = pp.z;
pp.binds[2].heading = pp.heading;
pp.binds[3].zoneId = pp.zone_id;
pp.binds[3].zone_id = pp.zone_id;
pp.binds[3].x = pp.x;
pp.binds[3].y = pp.y;
pp.binds[3].z = pp.z;
pp.binds[3].heading = pp.heading;
pp.binds[4].zoneId = pp.zone_id;
pp.binds[4].zone_id = pp.zone_id;
pp.binds[4].x = pp.x;
pp.binds[4].y = pp.y;
pp.binds[4].z = pp.z;
@@ -1601,7 +1601,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
/* Will either be the same as home or tutorial if enabled. */
if(RuleB(World, StartZoneSameAsBindOnCreation)) {
pp.binds[0].zoneId = pp.zone_id;
pp.binds[0].zone_id = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
@@ -1611,9 +1611,9 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
Log(Logs::Detail, Logs::WorldServer, "Current location: %s (%d) %0.2f, %0.2f, %0.2f, %0.2f",
ZoneName(pp.zone_id), pp.zone_id, pp.x, pp.y, pp.z, pp.heading);
Log(Logs::Detail, Logs::WorldServer, "Bind location: %s (%d) %0.2f, %0.2f, %0.2f",
ZoneName(pp.binds[0].zoneId), pp.binds[0].zoneId, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z);
ZoneName(pp.binds[0].zone_id), pp.binds[0].zone_id, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z);
Log(Logs::Detail, Logs::WorldServer, "Home location: %s (%d) %0.2f, %0.2f, %0.2f",
ZoneName(pp.binds[4].zoneId), pp.binds[4].zoneId, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z);
ZoneName(pp.binds[4].zone_id), pp.binds[4].zone_id, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z);
/* Starting Items inventory */
content_db.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());
+269 -188
View File
@@ -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;
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ class WorldDatabase : public SharedDatabase {
public:
bool GetStartZone(PlayerProfile_Struct* p_player_profile_struct, CharCreate_Struct* p_char_create_struct, bool is_titanium);
void GetCharSelectInfo(uint32 account_id, EQApplicationPacket **out_app, uint32 client_version_bit);
int MoveCharacterToBind(int CharID, uint8 bindnum = 0);
int MoveCharacterToBind(int character_id, uint8 bind_number = 0);
void GetLauncherList(std::vector<std::string> &result);
bool GetCharacterLevel(const char *name, int &level);