mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Bug Fix] Zone Heading for Binds, Summons, Teleports, and Zoning. (#1328)
* For as long as I can remember people have had issues with zoning in, facing the wrong way, and walking through a zone line. With this we will be able to set zone's safe heading as well as preserve heading on summon (NPC or GM) and teleports between zones. This affects several pre-existing quest methods and extends their parameters to allow for the addition of heading. The following functions have had heading added. Lua - client:SetBindPoint() - client:SetStartZone() Perl - $client->SetBindPoint() - $client->SetStartZone() - quest::rebind() SetStartZone parameter list was fixed also. This converts some pre-existing methods from glm::vec3() to glm::vec4() and has an overload where necessary to use a glm::vec3() method versus glm::vec4() method. This shouldn't affect any pre-existing servers and will allow PEQ and others to document safe headings for zones properly. * Removed possible memory leaks. * Fix SQL. * Fix client message. * Fix debug log. * Fix log message. * Fix call in rebind overload. * Fix floats. * Add default to column.
This commit is contained in:
parent
5893730704
commit
00fb9bc9f9
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -0,0 +1 @@
|
||||
ALTER TABLE zone ADD COLUMN safe_heading float NOT NULL DEFAULT 0 AFTER safe_z;
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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, "$$$");
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<int> 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;
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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);
|
||||
|
||||
293
zone/zoning.cpp
293
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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user