diff --git a/common/database.cpp b/common/database.cpp index 5a2d53940..5c1ec9a6f 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -703,11 +703,11 @@ bool Database::SaveCharacterCreate(uint32 character_id, uint32 account_id, Playe "(%u, %u, %u, %f, %f, %f, %f, %i), " "(%u, %u, %u, %f, %f, %f, %f, %i), " "(%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[1].zoneId, 0, pp->binds[1].x, pp->binds[1].y, pp->binds[1].z, pp->binds[1].heading, 1, - character_id, pp->binds[2].zoneId, 0, pp->binds[2].x, pp->binds[2].y, pp->binds[2].z, pp->binds[2].heading, 2, - character_id, pp->binds[3].zoneId, 0, pp->binds[3].x, pp->binds[3].y, pp->binds[3].z, pp->binds[3].heading, 3, - character_id, pp->binds[4].zoneId, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 4 + character_id, pp->binds[0].zone_id, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading, 0, + character_id, pp->binds[1].zone_id, 0, pp->binds[1].x, pp->binds[1].y, pp->binds[1].z, pp->binds[1].heading, 1, + character_id, pp->binds[2].zone_id, 0, pp->binds[2].x, pp->binds[2].y, pp->binds[2].z, pp->binds[2].heading, 2, + character_id, pp->binds[3].zone_id, 0, pp->binds[3].x, pp->binds[3].y, pp->binds[3].z, pp->binds[3].heading, 3, + character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading, 4 ); results = QueryDatabase(query); /* HoTT Ability */ @@ -971,10 +971,20 @@ bool Database::SetVariable(const std::string varname, const std::string &varvalu } // Get zone starting points from DB -bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe_x, float* safe_y, float* safe_z, int16* minstatus, uint8* minlevel, char *flag_needed) { - - std::string query = StringFormat("SELECT safe_x, safe_y, safe_z, min_status, min_level, flag_needed FROM zone " - " WHERE short_name='%s' AND (version=%i OR version=0) ORDER BY version DESC", short_name, version); +bool Database::GetSafePoints(const char* zone_short_name, uint32 instance_version, float* safe_x, float* safe_y, float* safe_z, float* safe_heading, int16* min_status, uint8* min_level, char *flag_needed) { + std::string query = fmt::format( + SQL( + SELECT + `safe_x`, `safe_y`, `safe_z`, `safe_heading`, `min_status`, `min_level`, `flag_needed` + FROM + zone + WHERE + `short_name` = '{}' + AND + (`version` = {} OR `version` = 0) + ORDER BY `version` DESC + ), zone_short_name, instance_version + ); auto results = QueryDatabase(query); if (!results.Success()) @@ -987,16 +997,24 @@ bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe if (safe_x != nullptr) *safe_x = atof(row[0]); + if (safe_y != nullptr) *safe_y = atof(row[1]); + if (safe_z != nullptr) *safe_z = atof(row[2]); - if (minstatus != nullptr) - *minstatus = atoi(row[3]); - if (minlevel != nullptr) - *minlevel = atoi(row[4]); + + if (safe_heading != nullptr) + *safe_heading = atof(row[3]); + + if (min_status != nullptr) + *min_status = atoi(row[4]); + + if (min_level != nullptr) + *min_level = atoi(row[5]); + if (flag_needed != nullptr) - strcpy(flag_needed, row[5]); + strcpy(flag_needed, row[6]); return true; } diff --git a/common/database.h b/common/database.h index db428b981..c15e200bc 100644 --- a/common/database.h +++ b/common/database.h @@ -242,7 +242,7 @@ public: /* General Queries */ - bool GetSafePoints(const char* short_name, uint32 version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int16* minstatus = 0, uint8* minlevel = 0, char *flag_needed = nullptr); + bool GetSafePoints(const char* zone_short_name, uint32 instance_version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, float* safe_heading = 0, int16* minstatus = 0, uint8* minlevel = 0, char *flag_needed = nullptr); bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0); bool GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, uint32* graveyard_id = 0, uint32* maxclients = 0); bool LoadPTimers(uint32 charid, PTimerList &into); diff --git a/common/database_conversions.cpp b/common/database_conversions.cpp index d49651f4d..561e1679b 100644 --- a/common/database_conversions.cpp +++ b/common/database_conversions.cpp @@ -48,7 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA namespace Convert { struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1320,18 +1320,18 @@ bool Database::CheckDatabaseConvertPPDeblob(){ if (rquery != ""){ results = QueryDatabase(rquery); } /* Run Bind Home Convert */ - if (pp->binds[4].zoneId < 999 && !_ISNAN_(pp->binds[4].x) && !_ISNAN_(pp->binds[4].y) && !_ISNAN_(pp->binds[4].z) && !_ISNAN_(pp->binds[4].heading)) { + if (pp->binds[4].zone_id < 999 && !_ISNAN_(pp->binds[4].x) && !_ISNAN_(pp->binds[4].y) && !_ISNAN_(pp->binds[4].z) && !_ISNAN_(pp->binds[4].heading)) { rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" " VALUES (%u, %u, %u, %f, %f, %f, %f, 1)", - character_id, pp->binds[4].zoneId, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading); + character_id, pp->binds[4].zone_id, 0, pp->binds[4].x, pp->binds[4].y, pp->binds[4].z, pp->binds[4].heading); if (rquery != ""){ results = QueryDatabase(rquery); } } /* Run Bind Convert */ - if (pp->binds[0].zoneId < 999 && !_ISNAN_(pp->binds[0].x) && !_ISNAN_(pp->binds[0].y) && !_ISNAN_(pp->binds[0].z) && !_ISNAN_(pp->binds[0].heading)) { + if (pp->binds[0].zone_id < 999 && !_ISNAN_(pp->binds[0].x) && !_ISNAN_(pp->binds[0].y) && !_ISNAN_(pp->binds[0].z) && !_ISNAN_(pp->binds[0].heading)) { rquery = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" " VALUES (%u, %u, %u, %f, %f, %f, %f, 0)", - character_id, pp->binds[0].zoneId, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading); + character_id, pp->binds[0].zone_id, 0, pp->binds[0].x, pp->binds[0].y, pp->binds[0].z, pp->binds[0].heading); if (rquery != ""){ results = QueryDatabase(rquery); } } /* Run Language Convert */ diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 401e62e59..808839b27 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -829,7 +829,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1772,7 +1772,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index cb5400f1f..b607502c4 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -1968,7 +1968,7 @@ namespace RoF for (int r = 0; r < 5; r++) { - outapp->WriteUInt32(emu->binds[r].zoneId); + outapp->WriteUInt32(emu->binds[r].zone_id); outapp->WriteFloat(emu->binds[r].x); outapp->WriteFloat(emu->binds[r].y); outapp->WriteFloat(emu->binds[r].z); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 4a902061d..a6426a279 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2025,7 +2025,7 @@ namespace RoF2 for (int r = 0; r < 5; r++) { - outapp->WriteUInt32(emu->binds[r].zoneId); + outapp->WriteUInt32(emu->binds[r].zone_id); outapp->WriteFloat(emu->binds[r].x); outapp->WriteFloat(emu->binds[r].y); outapp->WriteFloat(emu->binds[r].z); diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index c5111da6d..3041024c7 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -1053,7 +1053,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -2084,7 +2084,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index a67e7b972..1afc79334 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -998,7 +998,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -2062,7 +2062,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index d6eae5838..9f49f9651 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1475,7 +1475,7 @@ namespace SoD eq->level1 = emu->level; // OUT(unknown00022[2]); for (r = 0; r < 5; r++) { - OUT(binds[r].zoneId); + OUT(binds[r].zone_id); OUT(binds[r].x); OUT(binds[r].y); OUT(binds[r].z); diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 4e7735bf1..8070de172 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -803,7 +803,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1714,7 +1714,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index f24f265ff..4fb9642a8 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1140,7 +1140,7 @@ namespace SoF eq->level1 = emu->level; // OUT(unknown00022[2]); for (r = 0; r < 5; r++) { - OUT(binds[r].zoneId); + OUT(binds[r].zone_id); OUT(binds[r].x); OUT(binds[r].y); OUT(binds[r].z); diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index bf88bf5c2..96edbeb98 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -804,7 +804,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1742,7 +1742,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index f7d97b8d9..9bc1f161f 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1022,7 +1022,7 @@ namespace Titanium eq->level1 = emu->level; // OUT(unknown00022[2]); for (r = 0; r < 5; r++) { - OUT(binds[r].zoneId); + OUT(binds[r].zone_id); OUT(binds[r].x); OUT(binds[r].y); OUT(binds[r].z); diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index b2beae0cd..e3d0313a3 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -738,7 +738,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1509,7 +1509,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 47dafbbf3..2be12c733 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1705,7 +1705,7 @@ namespace UF eq->level1 = emu->level; // OUT(unknown00022[2]); for (r = 0; r < 5; r++) { - OUT(binds[r].zoneId); + OUT(binds[r].zone_id); OUT(binds[r].x); OUT(binds[r].y); OUT(binds[r].z); diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 4a4ac8a36..5ac8ac3c2 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -833,7 +833,7 @@ struct LeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1755,7 +1755,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ uint32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ int8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/common/version.h b/common/version.h index d66f8b060..0ad111e7c 100644 --- a/common/version.h +++ b/common/version.h @@ -34,7 +34,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9162 +#define CURRENT_BINARY_DATABASE_VERSION 9163 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9027 diff --git a/utils/deprecated/player_profile_set/player_profile_set/eq_player_structs.h b/utils/deprecated/player_profile_set/player_profile_set/eq_player_structs.h index e732757a4..3cfd276d6 100644 --- a/utils/deprecated/player_profile_set/player_profile_set/eq_player_structs.h +++ b/utils/deprecated/player_profile_set/player_profile_set/eq_player_structs.h @@ -720,7 +720,7 @@ struct RaidLeadershipAA_Struct { * Size: 20 Octets */ struct BindStruct { - /*000*/ uint32 zoneId; + /*000*/ uint32 zone_id; /*004*/ float x; /*008*/ float y; /*012*/ float z; @@ -1486,7 +1486,7 @@ struct GMZoneRequest_Struct { /*0068*/ float x; /*0072*/ float y; /*0076*/ float z; -/*0080*/ char unknown0080[4]; +/*0080*/ float heading; /*0084*/ int32 success; // 0 if command failed, 1 if succeeded? /*0088*/ // /*072*/ sint8 success; // =0 client->server, =1 server->client, -X=specific error diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 566058e3c..393dc23e8 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -416,6 +416,7 @@ 9160|2021_02_14_npc_exp_mod.sql|SHOW COLUMNS from `npc_types` LIKE 'exp_mod'|empty| 9161|2021_02_15_npc_spell_entries_unsigned.sql|SELECT * FROM db_version WHERE version >= 9161|empty| 9162|2021_02_17_server_scheduled_events.sql|SELECT * FROM db_version WHERE version >= 9162|empty| +9163|2021_04_17_zone_safe_heading_changes.sql|SHOW COLUMNS FROM `zone` LIKE 'safe_heading'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2021_04_17_zone_safe_heading_changes.sql b/utils/sql/git/required/2021_04_17_zone_safe_heading_changes.sql new file mode 100644 index 000000000..c10a5c6ff --- /dev/null +++ b/utils/sql/git/required/2021_04_17_zone_safe_heading_changes.sql @@ -0,0 +1 @@ +ALTER TABLE zone ADD COLUMN safe_heading float NOT NULL DEFAULT 0 AFTER safe_z; diff --git a/world/client.cpp b/world/client.cpp index 963369255..03c6195e8 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -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()); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 7bc5a801f..69d15c751 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -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; } } diff --git a/world/worlddb.h b/world/worlddb.h index 42fbf96b6..6431f175e 100644 --- a/world/worlddb.h +++ b/world/worlddb.h @@ -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 &result); bool GetCharacterLevel(const char *name, int &level); diff --git a/zone/attack.cpp b/zone/attack.cpp index 3f614598a..2f85dbaaf 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1655,7 +1655,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill d->spawn_id = GetID(); d->killer_id = killerMob ? killerMob->GetID() : 0; d->corpseid = GetID(); - d->bindzoneid = m_pp.binds[0].zoneId; + d->bindzoneid = m_pp.binds[0].zone_id; d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell; d->attack_skill = spell != SPELL_UNKNOWN ? 0xe7 : attack_skill; d->damage = damage; @@ -1892,7 +1892,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQ::skills::Skill r->MemberZoned(this); dead_timer.Start(5000, true); - m_pp.zone_id = m_pp.binds[0].zoneId; + m_pp.zone_id = m_pp.binds[0].zone_id; m_pp.zoneInstance = m_pp.binds[0].instance_id; database.MoveCharacterToZone(this->CharacterID(), m_pp.zone_id); Save(); diff --git a/zone/client.cpp b/zone/client.cpp index c34a314be..6ffda19a9 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -163,7 +163,7 @@ Client::Client(EQStreamInterface* ieqs) helm_toggle_timer(250), aggro_meter_timer(AGGRO_METER_UPDATE_MS), m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number - m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f), + m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f,-2.0f), m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f), m_AutoAttackTargetLocation(0.0f, 0.0f, 0.0f), last_region_type(RegionTypeUnsupported), @@ -441,7 +441,7 @@ Client::~Client() { if(IsHoveringForRespawn()) { - m_pp.zone_id = m_pp.binds[0].zoneId; + m_pp.zone_id = m_pp.binds[0].zone_id; m_pp.zoneInstance = m_pp.binds[0].instance_id; m_Position.x = m_pp.binds[0].x; m_Position.y = m_pp.binds[0].y; @@ -658,7 +658,7 @@ bool Client::Save(uint8 iCommitNow) { /* Save Current Bind Points */ for (int i = 0; i < 5; i++) - if (m_pp.binds[i].zoneId) + if (m_pp.binds[i].zone_id) database.SaveCharacterBindPoint(CharacterID(), m_pp.binds[i], i); /* Save Character Buffs */ @@ -3959,7 +3959,7 @@ void Client::Sacrifice(Client *caster) Death_Struct *d = (Death_Struct *)app.pBuffer; d->spawn_id = GetID(); d->killer_id = caster ? caster->GetID() : 0; - d->bindzoneid = GetPP().binds[0].zoneId; + d->bindzoneid = GetPP().binds[0].zone_id; d->spell_id = SPELL_UNKNOWN; d->attack_skill = 0xe7; d->damage = 0; @@ -4007,7 +4007,7 @@ void Client::SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID) { PendingTranslocateData.spell_id = ts->SpellID = SpellID; if((SpellID == 1422) || (SpellID == 1334) || (SpellID == 3243)) { - PendingTranslocateData.zone_id = ts->ZoneID = m_pp.binds[0].zoneId; + PendingTranslocateData.zone_id = ts->ZoneID = m_pp.binds[0].zone_id; PendingTranslocateData.instance_id = m_pp.binds[0].instance_id; PendingTranslocateData.x = ts->x = m_pp.binds[0].x; PendingTranslocateData.y = ts->y = m_pp.binds[0].y; @@ -4892,7 +4892,7 @@ void Client::SendRespawnBinds() BindStruct* b = &m_pp.binds[0]; RespawnOption opt; opt.name = "Bind Location"; - opt.zone_id = b->zoneId; + opt.zone_id = b->zone_id; opt.instance_id = b->instance_id; opt.x = b->x; opt.y = b->y; @@ -5289,11 +5289,11 @@ void Client::NotifyNewTitlesAvailable() } -void Client::SetStartZone(uint32 zoneid, float x, float y, float z) +void Client::SetStartZone(uint32 zoneid, float x, float y, float z, float heading) { // setting city to zero allows the player to use /setstartcity to set the city themselves if(zoneid == 0) { - m_pp.binds[4].zoneId = 0; + m_pp.binds[4].zone_id = 0; this->Message(Chat::Yellow,"Your starting city has been reset. Use /setstartcity to choose a new one"); return; } @@ -5303,24 +5303,32 @@ void Client::SetStartZone(uint32 zoneid, float x, float y, float z) if(target_zone_name == nullptr) return; - m_pp.binds[4].zoneId = zoneid; + m_pp.binds[4].zone_id = zoneid; if(zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) { m_pp.binds[4].instance_id = zone->GetInstanceID(); } if (x == 0 && y == 0 && z == 0) { - content_db.GetSafePoints(ZoneName(m_pp.binds[4].zoneId), 0, &m_pp.binds[4].x, &m_pp.binds[4].y, &m_pp.binds[4].z); + content_db.GetSafePoints( + ZoneName(m_pp.binds[4].zone_id), + 0, + &m_pp.binds[4].x, + &m_pp.binds[4].y, + &m_pp.binds[4].z, + &m_pp.binds[4].heading + ); } else { m_pp.binds[4].x = x; m_pp.binds[4].y = y; m_pp.binds[4].z = z; + m_pp.binds[4].heading = heading; } } uint32 Client::GetStartZone() { - return m_pp.binds[4].zoneId; + return m_pp.binds[4].zone_id; } void Client::ShowSkillsWindow() diff --git a/zone/client.h b/zone/client.h index d2abf3efb..741408d3f 100644 --- a/zone/client.h +++ b/zone/client.h @@ -426,7 +426,7 @@ public: inline const float GetBindY(uint32 index = 0) const { return m_pp.binds[index].y; } inline const float GetBindZ(uint32 index = 0) const { return m_pp.binds[index].z; } inline const float GetBindHeading(uint32 index = 0) const { return m_pp.binds[index].heading; } - inline uint32 GetBindZoneID(uint32 index = 0) const { return m_pp.binds[index].zoneId; } + inline uint32 GetBindZoneID(uint32 index = 0) const { return m_pp.binds[index].zone_id; } inline uint32 GetBindInstanceID(uint32 index = 0) const { return m_pp.binds[index].instance_id; } int32 CalcMaxMana(); int32 CalcBaseMana(); @@ -644,7 +644,8 @@ public: void GoToSafeCoords(uint16 zone_id, uint16 instance_id); void Gate(uint8 bindnum = 0); void SetBindPoint(int bind_num = 0, int to_zone = -1, int to_instance = 0, const glm::vec3& location = glm::vec3()); - void SetStartZone(uint32 zoneid, float x = 0.0f, float y =0.0f, float z = 0.0f); + void SetBindPoint2(int bind_num = 0, int to_zone = -1, int to_instance = 0, const glm::vec4& location = glm::vec4()); + void SetStartZone(uint32 zoneid, float x = 0.0f, float y =0.0f, float z = 0.0f, float heading = 0.0f); uint32 GetStartZone(void); void MovePC(const char* zonename, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); void MovePC(uint32 zoneID, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); @@ -1765,7 +1766,7 @@ private: void ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions, ZoneMode zm); void ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); - glm::vec3 m_ZoneSummonLocation; + glm::vec4 m_ZoneSummonLocation; uint16 zonesummon_id; uint8 zonesummon_ignorerestrictions; ZoneMode zone_mode; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index a48925e5e..3ffb2d785 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1332,10 +1332,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) strcpy(lastname, m_pp.last_name); /* If PP is set to weird coordinates */ if ((m_pp.x == -1 && m_pp.y == -1 && m_pp.z == -1) || (m_pp.x == -2 && m_pp.y == -2 && m_pp.z == -2)) { - auto safePoint = zone->GetSafePoint(); - m_pp.x = safePoint.x; - m_pp.y = safePoint.y; - m_pp.z = safePoint.z; + auto zone_safe_point = zone->GetSafePoint(); + m_pp.x = zone_safe_point.x; + m_pp.y = zone_safe_point.y; + m_pp.z = zone_safe_point.z; + m_pp.heading = zone_safe_point.w; } /* If too far below ground, then fix */ // float ground_z = GetGroundZ(m_pp.x, m_pp.y, m_pp.z); @@ -6594,34 +6595,45 @@ void Client::Handle_OP_GMZoneRequest(const EQApplicationPacket *app) } GMZoneRequest_Struct* gmzr = (GMZoneRequest_Struct*)app->pBuffer; - float tarx = -1, tary = -1, tarz = -1; + float target_x = -1, target_y = -1, target_z = -1, target_heading; - int16 minstatus = 0; - uint8 minlevel = 0; - char tarzone[32]; - uint16 zid = gmzr->zone_id; + int16 min_status = 0; + uint8 min_level = 0; + char target_zone[32]; + uint16 zone_id = gmzr->zone_id; if (gmzr->zone_id == 0) - zid = zonesummon_id; - const char * zname = ZoneName(zid); - if (zname == nullptr) - tarzone[0] = 0; + zone_id = zonesummon_id; + + const char* zone_short_name = ZoneName(zone_id); + if (zone_short_name == nullptr) + target_zone[0] = 0; else - strcpy(tarzone, zname); + strcpy(target_zone, zone_short_name); // this both loads the safe points and does a sanity check on zone name - if (!content_db.GetSafePoints(tarzone, 0, &tarx, &tary, &tarz, &minstatus, &minlevel)) { - tarzone[0] = 0; + if (!content_db.GetSafePoints( + target_zone, + 0, + &target_x, + &target_y, + &target_z, + &target_heading, + &min_status, + &min_level + )) { + target_zone[0] = 0; } auto outapp = new EQApplicationPacket(OP_GMZoneRequest, sizeof(GMZoneRequest_Struct)); GMZoneRequest_Struct* gmzr2 = (GMZoneRequest_Struct*)outapp->pBuffer; strcpy(gmzr2->charname, this->GetName()); gmzr2->zone_id = gmzr->zone_id; - gmzr2->x = tarx; - gmzr2->y = tary; - gmzr2->z = tarz; + gmzr2->x = target_x; + gmzr2->y = target_y; + gmzr2->z = target_z; + gmzr2->heading = target_heading; // Next line stolen from ZoneChange as well... - This gives us a nicer message than the normal "zone is down" message... - if (tarzone[0] != 0 && admin >= minstatus && GetLevel() >= minlevel) + if (target_zone[0] != 0 && admin >= min_status && GetLevel() >= min_level) gmzr2->success = 1; else { std::cout << "GetZoneSafeCoords failed. zoneid = " << gmzr->zone_id << "; czone = " << zone->GetZoneID() << std::endl; @@ -12663,8 +12675,8 @@ void Client::Handle_OP_SetServerFilter(const EQApplicationPacket *app) void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) { // if the character has a start city, don't let them use the command - if (m_pp.binds[4].zoneId != 0 && m_pp.binds[4].zoneId != 189) { - Message(Chat::Yellow, "Your home city has already been set.", m_pp.binds[4].zoneId, ZoneName(m_pp.binds[4].zoneId)); + if (m_pp.binds[4].zone_id != 0 && m_pp.binds[4].zone_id != 189) { + Message(Chat::Yellow, "Your home city has already been set.", m_pp.binds[4].zone_id, ZoneName(m_pp.binds[4].zone_id)); return; } @@ -12674,13 +12686,22 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) return; } - float x(0), y(0), z(0); - uint32 zoneid = 0; - uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); - - std::string 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", + float x = 0.0f, y = 0.0f, z = 0.0f, heading = 0.0f; + uint32 zone_id = 0; + uint32 start_city = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); + std::string 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 = {} {} + ), m_pp.class_, m_pp.deity, m_pp.race, @@ -12692,31 +12713,46 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) return; } - bool validCity = false; + bool valid_city = false; for (auto row = results.begin(); row != results.end(); ++row) { if (atoi(row[1]) != 0) - zoneid = atoi(row[1]); + zone_id = atoi(row[1]); else - zoneid = atoi(row[0]); + zone_id = atoi(row[0]); - if (zoneid != startCity) + if (zone_id != start_city) continue; - validCity = true; + valid_city = true; x = atof(row[2]); y = atof(row[3]); z = atof(row[4]); + heading = atof(row[5]); } - if (validCity) { + if (valid_city) { Message(Chat::Yellow, "Your home city has been set"); - SetStartZone(startCity, x, y, z); + SetStartZone(start_city, x, y, z, heading); return; } - query = StringFormat("SELECT zone_id, bind_id FROM start_zones " - "WHERE player_class=%i AND player_deity=%i AND player_race=%i", - m_pp.class_, m_pp.deity, m_pp.race); + query = fmt::format( + SQL( + SELECT + `zone_id`, `bind_id` + FROM + `start_zones` + WHERE + player_class = {} + AND + player_deity = {} + AND + player_race = {} + ), + m_pp.class_, + m_pp.deity, + m_pp.race + ); results = content_db.QueryDatabase(query); if (!results.Success()) return; @@ -12725,13 +12761,12 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) for (auto row = results.begin(); row != results.end(); ++row) { if (atoi(row[1]) != 0) - zoneid = atoi(row[1]); + zone_id = atoi(row[1]); else - zoneid = atoi(row[0]); + zone_id = atoi(row[0]); - char* name = nullptr; - content_db.GetZoneLongName(ZoneName(zoneid), &name); - Message(Chat::Yellow, "%d - %s", zoneid, name); + std::string zone_long_name = zone_store.GetZoneLongName(zone_id); + Message(Chat::Yellow, "%d - %s", zone_id, zone_long_name.c_str()); } } diff --git a/zone/client_process.cpp b/zone/client_process.cpp index bc8e2fd1e..384d3aab5 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -131,9 +131,9 @@ bool Client::Process() { CheckManaEndUpdate(); if (dead && dead_timer.Check()) { - database.MoveCharacterToZone(GetName(), m_pp.binds[0].zoneId); + database.MoveCharacterToZone(GetName(), m_pp.binds[0].zone_id); - m_pp.zone_id = m_pp.binds[0].zoneId; + m_pp.zone_id = m_pp.binds[0].zone_id; m_pp.zoneInstance = m_pp.binds[0].instance_id; m_pp.x = m_pp.binds[0].x; m_pp.y = m_pp.binds[0].y; @@ -1996,7 +1996,7 @@ void Client::HandleRespawnFromHover(uint32 Option) BindStruct* b = &m_pp.binds[0]; default_to_bind = new RespawnOption; default_to_bind->name = "Bind Location"; - default_to_bind->zone_id = b->zoneId; + default_to_bind->zone_id = b->zone_id; default_to_bind->instance_id = b->instance_id; default_to_bind->x = b->x; default_to_bind->y = b->y; diff --git a/zone/command.cpp b/zone/command.cpp index e49dea4d2..4991d25f6 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -5199,7 +5199,7 @@ void command_gmzone(Client *c, const Seperator *sep) } if (instance_id > 0) { - float target_x = -1, target_y = -1, target_z = -1; + float target_x = -1, target_y = -1, target_z = -1, target_heading = -1; int16 min_status = 0; uint8 min_level = 0; @@ -5209,6 +5209,7 @@ void command_gmzone(Client *c, const Seperator *sep) &target_x, &target_y, &target_z, + &target_heading, &min_status, &min_level )) { @@ -5218,7 +5219,7 @@ void command_gmzone(Client *c, const Seperator *sep) c->Message(Chat::Yellow, "Zoning to private GM instance (%s) (%u)", zone_short_name, instance_id); c->AssignToInstance(instance_id); - c->MovePC(zone_id, instance_id, target_x, target_y, target_z, 0, 1); + c->MovePC(zone_id, instance_id, target_x, target_y, target_z, target_heading, 1); } } diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index b662d5212..8a45470b7 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -1495,14 +1495,19 @@ XS(XS__ding) { XS(XS__rebind); XS(XS__rebind) { dXSARGS; - if (items != 4) - Perl_croak(aTHX_ "Usage: quest::rebind(int zone_id, float x, float y, float z)"); - - int zone_id = (int) SvIV(ST(0)); - auto location = glm::vec3((float) SvNV(ST(1)), (float) SvNV(ST(2)), (float) SvNV(ST(3))); - - quest_manager.rebind(zone_id, location); + if (items < 4 || items > 5) + Perl_croak(aTHX_ "Usage: quest::rebind(int zone_id, float x, float y, float z, [float heading])"); + int zone_id = (int) SvIV(ST(0)); + float target_x = (float) SvNV(ST(1)); + float target_y = (float) SvNV(ST(2)); + float target_z = (float) SvNV(ST(3)); + if (items > 4) { + float target_heading = (float) SvNV(ST(4)); + quest_manager.rebind(zone_id, glm::vec4(target_x, target_y, target_z, target_heading)); + } else { + quest_manager.rebind(zone_id, glm::vec3(target_x, target_y, target_z)); + } XSRETURN_EMPTY; } diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 9541176c8..1a71026f2 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -299,6 +299,11 @@ void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x, float n self->SetBindPoint(0, to_zone, to_instance, glm::vec3(new_x, new_y, new_z)); } +void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x, float new_y, float new_z, float new_heading) { + Lua_Safe_Call_Void(); + self->SetBindPoint2(0, to_zone, to_instance, glm::vec4(new_x, new_y, new_z, new_heading)); +} + float Lua_Client::GetBindX() { Lua_Safe_Call_Real(); return self->GetBindX(); @@ -2116,7 +2121,8 @@ luabind::scope lua_register_client() { .def("SetBindPoint", (void(Lua_Client::*)(int,int))&Lua_Client::SetBindPoint) .def("SetBindPoint", (void(Lua_Client::*)(int,int,float))&Lua_Client::SetBindPoint) .def("SetBindPoint", (void(Lua_Client::*)(int,int,float,float))&Lua_Client::SetBindPoint) - .def("SetBindPoint", (void(Lua_Client::*)(int,int,float,float, float))&Lua_Client::SetBindPoint) + .def("SetBindPoint", (void(Lua_Client::*)(int,int,float,float,float))&Lua_Client::SetBindPoint) + .def("SetBindPoint", (void(Lua_Client::*)(int,int,float,float,float,float))&Lua_Client::SetBindPoint) .def("GetBindX", (float(Lua_Client::*)(void))&Lua_Client::GetBindX) .def("GetBindX", (float(Lua_Client::*)(int))&Lua_Client::GetBindX) .def("GetBindY", (float(Lua_Client::*)(void))&Lua_Client::GetBindY) diff --git a/zone/lua_client.h b/zone/lua_client.h index 923231808..6d28656c1 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -86,6 +86,7 @@ public: void SetBindPoint(int to_zone, int to_instance, float new_x); void SetBindPoint(int to_zone, int to_instance, float new_x, float new_y); void SetBindPoint(int to_zone, int to_instance, float new_x, float new_y, float new_z); + void SetBindPoint(int to_zone, int to_instance, float new_x, float new_y, float new_z, float new_heading); float GetBindX(); float GetBindX(int index); float GetBindY(); @@ -249,6 +250,7 @@ public: void SetStartZone(int zone_id, float x); void SetStartZone(int zone_id, float x, float y); void SetStartZone(int zone_id, float x, float y, float z); + void SetStartZone(int zone_id, float x, float y, float z, float heading); void KeyRingAdd(uint32 item); bool KeyRingCheck(uint32 item); void AddPVPPoints(uint32 points); diff --git a/zone/npc.h b/zone/npc.h index de64e6b59..b23d15568 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -178,8 +178,8 @@ public: FACTION_VALUE CheckNPCFactionAlly(int32 other_faction); virtual FACTION_VALUE GetReverseFactionCon(Mob* iOther); - void GoToBind(uint8 bindnum = 0) { GMMove(m_SpawnPoint.x, m_SpawnPoint.y, m_SpawnPoint.z, m_SpawnPoint.w); } - void Gate(uint8 bindnum = 0); + void GoToBind(uint8 bind_number = 0) { GMMove(m_SpawnPoint.x, m_SpawnPoint.y, m_SpawnPoint.z, m_SpawnPoint.w); } + void Gate(uint8 bind_number = 0); void GetPetState(SpellBuff_Struct *buffs, uint32 *items, char *name); void SetPetState(SpellBuff_Struct *buffs, uint32 *items); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 567067f64..e3b5f4f64 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -753,47 +753,28 @@ XS(XS_Client_SetEXP) { XS(XS_Client_SetBindPoint); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_SetBindPoint) { dXSARGS; - if (items < 1 || items > 6) - Perl_croak(aTHX_ "Usage: Client::SetBindPoint(THIS, int to_zone = -1, int to_instance = 0, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f)"); // @categories Account and Character, Stats and Attributes + if (items < 1 || items > 7) + Perl_croak(aTHX_ "Usage: Client::SetBindPoint(THIS, [int to_zone = -1, int to_instance = 0, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f, float new_heading = 0.0f])"); // @categories Account and Character, Stats and Attributes { Client *THIS; - int to_zone; - int to_instance; - float new_x; - float new_y; - float new_z; + int to_zone = -1; + int to_instance = 0; + float new_x = 0.0f, new_y = 0.0f, new_z = 0.0f, new_heading = 0.0f; VALIDATE_THIS_IS_CLIENT; - if (items < 2) - to_zone = -1; - else { + if (items > 1) to_zone = (int) SvIV(ST(1)); - } - - if (items < 3) - to_instance = 0; - else { + if (items > 2) to_instance = (int) SvIV(ST(2)); - } - - if (items < 4) - new_x = 0.0f; - else { + if (items > 3) new_x = (float) SvNV(ST(3)); - } - - if (items < 5) - new_y = 0.0f; - else { + if (items > 4) new_y = (float) SvNV(ST(4)); - } - - if (items < 6) - new_z = 0.0f; - else { + if (items > 5) new_z = (float) SvNV(ST(5)); - } + if (items > 6) + new_heading = (float) SvNV(ST(6)); - THIS->SetBindPoint(0, to_zone, to_instance, glm::vec3(new_x, new_y, new_z)); + THIS->SetBindPoint2(0, to_zone, to_instance, glm::vec4(new_x, new_y, new_z, new_heading)); } XSRETURN_EMPTY; } @@ -3258,23 +3239,22 @@ XS(XS_Client_GetStartZone) { XS(XS_Client_SetStartZone); XS(XS_Client_SetStartZone) { dXSARGS; - if (items != 2 && items != 5) - Perl_croak(aTHX_ - "Usage: Client::SetStartZone(THIS, uint32 zone_id, [float x = 0], [float y = 0], [float z = 0])"); + if (items != 2 && items != 5 && items != 6) + Perl_croak(aTHX_ "Usage: Client::SetStartZone(THIS, uint32 zone_id, [float x = 0, float y = 0, float z = 0, [float heading = 0]])"); { Client *THIS; uint32 zoneid = (uint32) SvUV(ST(1)); - float x = 0; - float y = 0; - float z = 0; + float x = 0.0f, y = 0.0f, z = 0.0f, heading = 0.0f; VALIDATE_THIS_IS_CLIENT; if (items == 5) { - x = SvNV(ST(2)); - y = SvNV(ST(3)); - z = SvNV(ST(4)); + x = (float) SvNV(ST(2)); + y = (float) SvNV(ST(3)); + z = (float) SvNV(ST(4)); } + if (items == 6) + heading = (float) SvNV(ST(5)); - THIS->SetStartZone(zoneid, x, y, z); + THIS->SetStartZone(zoneid, x, y, z, heading); } XSRETURN_EMPTY; } @@ -5485,7 +5465,7 @@ XS(boot_Client) { newXSproto(strcpy(buf, "SetBaseRace"), XS_Client_SetBaseRace, file, "$$"); newXSproto(strcpy(buf, "SetBecomeNPC"), XS_Client_SetBecomeNPC, file, "$$"); newXSproto(strcpy(buf, "SetBecomeNPCLevel"), XS_Client_SetBecomeNPCLevel, file, "$$"); - newXSproto(strcpy(buf, "SetBindPoint"), XS_Client_SetBindPoint, file, "$;$$$$$"); + newXSproto(strcpy(buf, "SetBindPoint"), XS_Client_SetBindPoint, file, "$;$$$$$$"); newXSproto(strcpy(buf, "SetConsumption"), XS_Client_SetConsumption, file, "$$$"); newXSproto(strcpy(buf, "SetClientMaxLevel"), XS_Client_SetClientMaxLevel, file, "$$"); newXSproto(strcpy(buf, "SetCustomItemData"), XS_Client_SetCustomItemData, file, "$$$$"); @@ -5509,7 +5489,7 @@ XS(boot_Client) { newXSproto(strcpy(buf, "SetSecondaryWeaponOrnamentation"), XS_Client_SetSecondaryWeaponOrnamentation, file, "$$"); newXSproto(strcpy(buf, "SetSkill"), XS_Client_SetSkill, file, "$$$"); newXSproto(strcpy(buf, "SetSkillPoints"), XS_Client_SetSkillPoints, file, "$$"); - newXSproto(strcpy(buf, "SetStartZone"), XS_Client_SetStartZone, file, "$$"); + newXSproto(strcpy(buf, "SetStartZone"), XS_Client_SetStartZone, file, "$$;$$$$"); newXSproto(strcpy(buf, "SetStats"), XS_Client_SetStats, file, "$$$"); newXSproto(strcpy(buf, "SetThirst"), XS_Client_SetThirst, file, "$$"); newXSproto(strcpy(buf, "SetTint"), XS_Client_SetTint, file, "$$$"); diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index fc3e27239..c84633822 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -1673,10 +1673,17 @@ void QuestManager::ding() { } -void QuestManager::rebind(int zoneid, const glm::vec3& location) { +void QuestManager::rebind(int zone_id, const glm::vec3& location) { QuestManagerCurrentQuestVars(); if(initiator && initiator->IsClient()) { - initiator->SetBindPoint(0, zoneid, 0, location); + initiator->SetBindPoint(0, zone_id, 0, location); + } +} + +void QuestManager::rebind(int zone_id, const glm::vec4& location) { + QuestManagerCurrentQuestVars(); + if(initiator && initiator->IsClient()) { + initiator->SetBindPoint2(0, zone_id, 0, location); } } @@ -4285,4 +4292,4 @@ std::string QuestManager::secondstotime(int duration) { time_string = fmt::format("{} {}", seconds, second_string); } return time_string; -} \ No newline at end of file +} diff --git a/zone/questmgr.h b/zone/questmgr.h index 0bb765fed..3c109f4f5 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -151,7 +151,8 @@ public: void targlobal(const char *varname, const char *value, const char *duration, int npcid, int charid, int zoneid); void delglobal(const char *varname); void ding(); - void rebind(int zoneid, const glm::vec3& location); + void rebind(int zone_id, const glm::vec3& location); + void rebind(int zone_id, const glm::vec4& location); void start(int wp); void stop(); void pause(int duration); diff --git a/zone/zone.cpp b/zone/zone.cpp index b69e9f2f3..2f974c35a 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -941,7 +941,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) spawn2_timer(1000), hot_reload_timer(1000), qglobal_purge_timer(30000), - m_SafePoint(0.0f,0.0f,0.0f), + m_SafePoint(0.0f,0.0f,0.0f,0.0f), m_Graveyard(0.0f,0.0f,0.0f,0.0f) { zoneid = in_zoneid; diff --git a/zone/zone.h b/zone/zone.h index 8b2e6b57c..c7c6daf12 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -167,7 +167,7 @@ public: inline const uint32 &graveyard_zoneid() { return pgraveyard_zoneid; } inline const uint32 GetInstanceID() const { return instanceid; } inline const uint32 GetZoneID() const { return zoneid; } - inline glm::vec3 GetSafePoint() { return m_SafePoint; } + inline glm::vec4 GetSafePoint() { return m_SafePoint; } inline glm::vec4 GetGraveyardPoint() { return m_Graveyard; } inline std::vector GetGlobalLootTables(NPC *mob) const { return m_global_loot.GetGlobalLootTables(mob); } inline Timer *GetInstanceTimer() { return Instance_Timer; } @@ -376,7 +376,7 @@ private: char *map_name; char *short_name; char file_name[16]; - glm::vec3 m_SafePoint; + glm::vec4 m_SafePoint; glm::vec4 m_Graveyard; int default_ruleset; int zone_total_blocked_spells; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 27f54862b..d68620c38 100755 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1470,7 +1470,7 @@ bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Str if (index < 0 || index > 4) continue; - pp->binds[index].zoneId = atoi(row[1]); + pp->binds[index].zone_id = atoi(row[1]); pp->binds[index].instance_id = atoi(row[2]); pp->binds[index].x = atoi(row[3]); pp->binds[index].y = atoi(row[4]); @@ -1493,10 +1493,10 @@ bool ZoneDatabase::SaveCharacterBindPoint(uint32 character_id, const BindStruct 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)", - character_id, bind.zoneId, bind.instance_id, bind.x, bind.y, bind.z, bind.heading, bind_num); + character_id, bind.zone_id, bind.instance_id, bind.x, bind.y, bind.z, bind.heading, bind_num); LogDebug("ZoneDatabase::SaveCharacterBindPoint for character ID: [{}] zone_id: [{}] instance_id: [{}] position: [{}] [{}] [{}] [{}] bind_num: [{}]", - character_id, bind.zoneId, bind.instance_id, bind.x, bind.y, bind.z, bind.heading, bind_num); + character_id, bind.zone_id, bind.instance_id, bind.x, bind.y, bind.z, bind.heading, bind_num); auto results = QueryDatabase(query); if (!results.RowsAffected()) diff --git a/zone/zonedb.h b/zone/zonedb.h index d2fae4232..b77c157d3 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -319,7 +319,7 @@ public: bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level, uint32 charges); bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name); - bool SaveCharacterBindPoint(uint32 character_id, const BindStruct &bind, uint32 bind_num); + bool SaveCharacterBindPoint(uint32 character_id, const BindStruct &bind, uint32 bind_number); bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp); bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id); diff --git a/zone/zoning.cpp b/zone/zoning.cpp index 675767754..854671260 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -78,11 +78,11 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { target_zone_id = zonesummon_id; break; case GateToBindPoint: - target_zone_id = m_pp.binds[0].zoneId; + target_zone_id = m_pp.binds[0].zone_id; target_instance_id = m_pp.binds[0].instance_id; break; case ZoneToBindPoint: - target_zone_id = m_pp.binds[0].zoneId; + target_zone_id = m_pp.binds[0].zone_id; target_instance_id = m_pp.binds[0].instance_id; break; case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going. @@ -170,11 +170,21 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { } /* Load up the Safe Coordinates, restrictions and verify the zone name*/ - float safe_x, safe_y, safe_z; - int16 minstatus = 0; - uint8 minlevel = 0; + float safe_x, safe_y, safe_z, safe_heading; + int16 min_status = 0; + uint8 min_level = 0; char flag_needed[128]; - if(!content_db.GetSafePoints(target_zone_name, database.GetInstanceVersion(target_instance_id), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_needed)) { + if(!content_db.GetSafePoints( + target_zone_name, + database.GetInstanceVersion(target_instance_id), + &safe_x, + &safe_y, + &safe_z, + &safe_heading, + &min_status, + &min_level, + flag_needed + )) { //invalid zone... Message(Chat::Red, "Invalid target zone while getting safe points."); LogError("Zoning [{}]: Unable to get safe coordinates for zone [{}]", GetName(), target_zone_name); @@ -189,41 +199,54 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { //handle circumvention of zone restrictions //we need the value when creating the outgoing packet as well. - uint8 ignorerestrictions = zonesummon_ignorerestrictions; + uint8 ignore_restrictions = zonesummon_ignorerestrictions; zonesummon_ignorerestrictions = 0; - float dest_x=0, dest_y=0, dest_z=0, dest_h; - dest_h = GetHeading(); + float target_x = 0, target_y = 0, target_z = 0, target_heading = 0; switch(zone_mode) { case EvacToSafeCoords: case ZoneToSafeCoords: - LogDebug("Zoning [{}] to safe coords ([{}],[{}],[{}]) in [{}] ([{}])", GetName(), safe_x, safe_y, safe_z, target_zone_name, target_zone_id); - dest_x = safe_x; - dest_y = safe_y; - dest_z = safe_z; + LogDebug( + "Zoning [{}] to safe coords ([{}], [{}], [{}], [{}]) in [{}] ([{}])", + GetName(), + safe_x, + safe_y, + safe_z, + safe_heading, + target_zone_name, + target_zone_id + ); + target_x = safe_x; + target_y = safe_y; + target_z = safe_z; + target_heading = safe_heading; break; case GMSummon: - dest_x = m_ZoneSummonLocation.x; - dest_y = m_ZoneSummonLocation.y; - dest_z = m_ZoneSummonLocation.z; - ignorerestrictions = 1; + target_x = m_ZoneSummonLocation.x; + target_y = m_ZoneSummonLocation.y; + target_z = m_ZoneSummonLocation.z; + target_heading = m_ZoneSummonLocation.w; + ignore_restrictions = 1; break; case GateToBindPoint: - dest_x = m_pp.binds[0].x; - dest_y = m_pp.binds[0].y; - dest_z = m_pp.binds[0].z; + target_x = m_pp.binds[0].x; + target_x = m_pp.binds[0].y; + target_x = m_pp.binds[0].z; + target_x = m_pp.binds[0].heading; break; case ZoneToBindPoint: - dest_x = m_pp.binds[0].x; - dest_y = m_pp.binds[0].y; - dest_z = m_pp.binds[0].z; - ignorerestrictions = 1; //can always get to our bind point? seems exploitable + target_x = m_pp.binds[0].x; + target_y = m_pp.binds[0].y; + target_z = m_pp.binds[0].z; + target_heading = m_pp.binds[0].heading; + ignore_restrictions = 1; //can always get to our bind point? seems exploitable break; case ZoneSolicited: //we told the client to zone somewhere, so we know where they are going. //recycle zonesummon variables - dest_x = m_ZoneSummonLocation.x; - dest_y = m_ZoneSummonLocation.y; - dest_z = m_ZoneSummonLocation.z; + target_x = m_ZoneSummonLocation.x; + target_y = m_ZoneSummonLocation.y; + target_z = m_ZoneSummonLocation.z; + target_heading = m_ZoneSummonLocation.w; break; case ZoneUnsolicited: //client came up with this on its own. //client requested a zoning... what are the cases when this could happen? @@ -234,21 +257,24 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { //999999 is a placeholder for 'same as where they were from' if(zone_point->target_x == 999999) - dest_x = GetX(); + target_x = GetX(); else - dest_x = zone_point->target_x; + target_x = zone_point->target_x; + if(zone_point->target_y == 999999) - dest_y = GetY(); + target_y = GetY(); else - dest_y = zone_point->target_y; + target_y = zone_point->target_y; + if(zone_point->target_z == 999999) - dest_z=GetZ(); + target_z = GetZ(); else - dest_z = zone_point->target_z; + target_z = zone_point->target_z; + if(zone_point->target_heading == 999) - dest_h = GetHeading(); + target_heading = GetHeading(); else - dest_h = zone_point->target_heading; + target_heading = zone_point->target_heading; break; } @@ -272,12 +298,12 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { //not sure when we would use ZONE_ERROR_NOTREADY //enforce min status and level - if (!ignorerestrictions && (Admin() < minstatus || GetLevel() < minlevel)) + if (!ignore_restrictions && (Admin() < min_status || GetLevel() < min_level)) { myerror = ZONE_ERROR_NOEXPERIENCE; } - if(!ignorerestrictions && flag_needed[0] != '\0') { + if(!ignore_restrictions && flag_needed[0] != '\0') { //the flag needed string is not empty, meaning a flag is required. if(Admin() < minStatusToIgnoreZoneFlags && !HasZoneFlag(target_zone_id)) { @@ -343,7 +369,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { if(myerror == 1) { //we have successfully zoned - DoZoneSuccess(zc, target_zone_id, target_instance_id, dest_x, dest_y, dest_z, dest_h, ignorerestrictions); + DoZoneSuccess(zc, target_zone_id, target_instance_id, target_x, target_y, target_z, target_heading, ignore_restrictions); } else { LogError("Zoning [{}]: Rules prevent this char from zoning into [{}]", GetName(), target_zone_name); SendZoneError(zc, myerror); @@ -463,7 +489,7 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc //reset to unsolicited. zone_mode = ZoneUnsolicited; - m_ZoneSummonLocation = glm::vec3(); + m_ZoneSummonLocation = glm::vec4(); zonesummon_id = 0; zonesummon_ignorerestrictions = 0; } @@ -647,29 +673,24 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z return; } iZoneNameLength = strlen(pZoneName); - glm::vec3 safePoint; - + glm::vec4 zone_safe_point; switch(zm) { case EvacToSafeCoords: case ZoneToSafeCoords: - safePoint = zone->GetSafePoint(); - x = safePoint.x; - y = safePoint.y; - z = safePoint.z; - SetHeading(heading); + zone_safe_point = zone->GetSafePoint(); + x = zone_safe_point.x; + y = zone_safe_point.y; + z = zone_safe_point.z; + heading = zone_safe_point.w; break; case GMSummon: m_Position = glm::vec4(x, y, z, heading); - m_ZoneSummonLocation = glm::vec3(m_Position); - SetHeading(heading); - + m_ZoneSummonLocation = m_Position; zonesummon_id = zoneID; zonesummon_ignorerestrictions = 1; break; case ZoneSolicited: - m_ZoneSummonLocation = glm::vec3(x,y,z); - SetHeading(heading); - + m_ZoneSummonLocation = glm::vec4(x, y, z, heading); zonesummon_id = zoneID; zonesummon_ignorerestrictions = ignorerestrictions; break; @@ -684,23 +705,20 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z y = m_Position.y = m_pp.binds[0].y; z = m_Position.z = m_pp.binds[0].z; heading = m_pp.binds[0].heading; - zonesummon_ignorerestrictions = 1; LogDebug("Player [{}] has died and will be zoned to bind point in zone: [{}] at LOC x=[{}], y=[{}], z=[{}], heading=[{}]", GetName(), pZoneName, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, m_pp.binds[0].heading); break; case SummonPC: - m_ZoneSummonLocation = glm::vec3(x, y, z); - m_Position = glm::vec4(m_ZoneSummonLocation, 0.0f); - SetHeading(heading); + m_ZoneSummonLocation = glm::vec4(x, y, z, heading); + m_Position = m_ZoneSummonLocation; break; case Rewind: LogDebug("[{}] has requested a /rewind from [{}], [{}], [{}], to [{}], [{}], [{}] in [{}]", GetName(), m_Position.x, m_Position.y, m_Position.z, m_RewindLocation.x, m_RewindLocation.y, m_RewindLocation.z, zone->GetShortName()); - m_ZoneSummonLocation = glm::vec3(x, y, z); - m_Position = glm::vec4(m_ZoneSummonLocation, 0.0f); - SetHeading(heading); + m_ZoneSummonLocation = glm::vec4(x, y, z, heading); + m_Position = m_ZoneSummonLocation; break; default: LogError("Client::ZonePC() received a reguest to perform an unsupported client zone operation"); @@ -847,7 +865,7 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z { if(zm != EvacToSafeCoords && zm != ZoneToSafeCoords && zm != ZoneToBindPoint) { - m_ZoneSummonLocation = glm::vec3(); + m_ZoneSummonLocation = glm::vec4(); zonesummon_id = 0; zonesummon_ignorerestrictions = 0; zone_mode = ZoneUnsolicited; @@ -866,61 +884,100 @@ void Client::GoToSafeCoords(uint16 zone_id, uint16 instance_id) { } -void Mob::Gate(uint8 bindnum) { - GoToBind(bindnum); +void Mob::Gate(uint8 bind_number) { + GoToBind(bind_number); if (RuleB(NPC, NPCHealOnGate) && this->IsNPC() && this->GetHPRatio() <= RuleR(NPC, NPCHealOnGateAmount)) { auto HealAmount = (RuleR(NPC, NPCHealOnGateAmount) / 100); SetHP(int(this->GetMaxHP() * HealAmount)); } } -void Client::Gate(uint8 bindnum) { - Mob::Gate(bindnum); +void Client::Gate(uint8 bind_number) { + Mob::Gate(bind_number); } -void NPC::Gate(uint8 bindnum) { +void NPC::Gate(uint8 bind_number) { entity_list.MessageCloseString(this, true, RuleI(Range, SpellMessages), Chat::Spells, GATES, GetCleanName()); - Mob::Gate(bindnum); + Mob::Gate(bind_number); } -void Client::SetBindPoint(int bind_num, int to_zone, int to_instance, const glm::vec3 &location) +void Client::SetBindPoint(int bind_number, int to_zone, int to_instance, const glm::vec3 &location) { - if (bind_num < 0 || bind_num >= 4) - bind_num = 0; + if (bind_number < 0 || bind_number >= 4) + bind_number = 0; if (to_zone == -1) { - m_pp.binds[bind_num].zoneId = zone->GetZoneID(); - m_pp.binds[bind_num].instance_id = - (zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) ? zone->GetInstanceID() : 0; - m_pp.binds[bind_num].x = m_Position.x; - m_pp.binds[bind_num].y = m_Position.y; - m_pp.binds[bind_num].z = m_Position.z; + m_pp.binds[bind_number].zone_id = zone->GetZoneID(); + m_pp.binds[bind_number].instance_id = (zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) ? zone->GetInstanceID() : 0; + m_pp.binds[bind_number].x = m_Position.x; + m_pp.binds[bind_number].y = m_Position.y; + m_pp.binds[bind_number].z = m_Position.z; } else { - m_pp.binds[bind_num].zoneId = to_zone; - m_pp.binds[bind_num].instance_id = to_instance; - m_pp.binds[bind_num].x = location.x; - m_pp.binds[bind_num].y = location.y; - m_pp.binds[bind_num].z = location.z; + m_pp.binds[bind_number].zone_id = to_zone; + m_pp.binds[bind_number].instance_id = to_instance; + m_pp.binds[bind_number].x = location.x; + m_pp.binds[bind_number].y = location.y; + m_pp.binds[bind_number].z = location.z; } - database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[bind_num], bind_num); + database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[bind_number], bind_number); } -void Client::GoToBind(uint8 bindnum) { +void Client::SetBindPoint2(int bind_number, int to_zone, int to_instance, const glm::vec4 &location) +{ + if (bind_number < 0 || bind_number >= 4) + bind_number = 0; + + if (to_zone == -1) { + m_pp.binds[bind_number].zone_id = zone->GetZoneID(); + m_pp.binds[bind_number].instance_id = (zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) ? zone->GetInstanceID() : 0; + m_pp.binds[bind_number].x = m_Position.x; + m_pp.binds[bind_number].y = m_Position.y; + m_pp.binds[bind_number].z = m_Position.z; + m_pp.binds[bind_number].heading = m_Position.w; + } else { + m_pp.binds[bind_number].zone_id = to_zone; + m_pp.binds[bind_number].instance_id = to_instance; + m_pp.binds[bind_number].x = location.x; + m_pp.binds[bind_number].y = location.y; + m_pp.binds[bind_number].z = location.z; + m_pp.binds[bind_number].heading = location.w; + } + database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[bind_number], bind_number); +} + +void Client::GoToBind(uint8 bind_number) { // if the bind number is invalid, use the primary bind - if(bindnum > 4) - bindnum = 0; + if(bind_number > 4) + bind_number = 0; // move the client, which will zone them if needed. // ignore restrictions on the zone request..? - if(bindnum == 0) - MovePC(m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, 0.0f, 0.0f, 0.0f, 0.0f, 1, GateToBindPoint); + if(bind_number == 0) + MovePC( + m_pp.binds[0].zone_id, + m_pp.binds[0].instance_id, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1, + GateToBindPoint + ); else - MovePC(m_pp.binds[bindnum].zoneId, m_pp.binds[bindnum].instance_id, m_pp.binds[bindnum].x, m_pp.binds[bindnum].y, m_pp.binds[bindnum].z, m_pp.binds[bindnum].heading, 1); + MovePC( + m_pp.binds[bind_number].zone_id, + m_pp.binds[bind_number].instance_id, + m_pp.binds[bind_number].x, + m_pp.binds[bind_number].y, + m_pp.binds[bind_number].z, + m_pp.binds[bind_number].heading, + 1 + ); } void Client::GoToDeath() { - MovePC(m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, 0.0f, 0.0f, 0.0f, 0.0f, 1, ZoneToBindPoint); + MovePC(m_pp.binds[0].zone_id, m_pp.binds[0].instance_id, 0.0f, 0.0f, 0.0f, 0.0f, 1, ZoneToBindPoint); } void Client::SetZoneFlag(uint32 zone_id) { @@ -982,26 +1039,28 @@ void Client::SendZoneFlagInfo(Client *to) const { to->Message(Chat::White, "Flags for %s:", GetName()); for(; cur != end; ++cur) { - uint32 zoneid = *cur; - - const char *short_name = ZoneName(zoneid); - - char *long_name = nullptr; - content_db.GetZoneLongName(short_name, &long_name); - if(long_name == nullptr) - long_name = empty; - - float safe_x, safe_y, safe_z; - int16 minstatus = 0; - uint8 minlevel = 0; + uint32 zone_id = *cur; + const char* zone_short_name = ZoneName(zone_id); + std::string zone_long_name = zone_store.GetZoneLongName(zone_id); + float safe_x, safe_y, safe_z, safe_heading; + int16 min_status = 0; + uint8 min_level = 0; char flag_name[128]; - if(!content_db.GetSafePoints(short_name, 0, &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_name)) { + if(!content_db.GetSafePoints( + zone_short_name, + 0, + &safe_x, + &safe_y, + &safe_z, + &safe_heading, + &min_status, + &min_level, + flag_name + )) { strcpy(flag_name, "(ERROR GETTING NAME)"); } - to->Message(Chat::White, "Has Flag %s for zone %s (%d,%s)", flag_name, long_name, zoneid, short_name); - if(long_name != empty) - delete[] long_name; + to->Message(Chat::White, "Has Flag %s for zone %s (%d,%s)", flag_name, zone_long_name.c_str(), zone_id, zone_short_name); } } @@ -1013,22 +1072,32 @@ bool Client::CanBeInZone() { if(Admin() >= RuleI(GM, MinStatusToZoneAnywhere)) return(true); - float safe_x, safe_y, safe_z; - int16 minstatus = 0; - uint8 minlevel = 0; + float safe_x, safe_y, safe_z, safe_heading; + int16 min_status = 0; + uint8 min_level = 0; char flag_needed[128]; - if(!content_db.GetSafePoints(zone->GetShortName(), zone->GetInstanceVersion(), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_needed)) { + if(!content_db.GetSafePoints( + zone->GetShortName(), + zone->GetInstanceVersion(), + &safe_x, + &safe_y, + &safe_z, + &safe_heading, + &min_status, + &min_level, + flag_needed + )) { //this should not happen... LogDebug("[CLIENT] Unable to query zone info for ourself [{}]", zone->GetShortName()); return(false); } - if(GetLevel() < minlevel) { - LogDebug("[CLIENT] Character does not meet min level requirement ([{}] < [{}])!", GetLevel(), minlevel); + if(GetLevel() < min_level) { + LogDebug("[CLIENT] Character does not meet min level requirement ([{}] < [{}])!", GetLevel(), min_level); return(false); } - if(Admin() < minstatus) { - LogDebug("[CLIENT] Character does not meet min status requirement ([{}] < [{}])!", Admin(), minstatus); + if(Admin() < min_status) { + LogDebug("[CLIENT] Character does not meet min status requirement ([{}] < [{}])!", Admin(), min_status); return(false); }