diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 7c663f18e..368cdf931 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -831,17 +831,18 @@ struct BindStruct { /*008*/ float y; /*012*/ float z; /*016*/ float heading; - /*020*/ + /*020*/ uint32 instance_id; + /*024*/ }; struct SuspendedMinion_Struct { - /*000*/ uint16 SpellID; - /*002*/ uint32 HP; - /*006*/ uint32 Mana; - /*010*/ SpellBuff_Struct Buffs[BUFF_COUNT]; - /*510*/ uint32 Items[_MaterialCount]; - /*546*/ char Name[64]; + /*000*/ uint16 SpellID; + /*002*/ uint32 HP; + /*006*/ uint32 Mana; + /*010*/ SpellBuff_Struct Buffs[BUFF_COUNT]; + /*510*/ uint32 Items[_MaterialCount]; + /*546*/ char Name[64]; /*610*/ }; @@ -2663,6 +2664,17 @@ struct Translocate_Struct { /*088*/ uint32 Complete; }; +struct PendingTranslocate_Struct +{ + uint32 zone_id; + uint16 instance_id; + float heading; + float x; + float y; + float z; + uint32 spell_id; +}; + struct Sacrifice_Struct { /*000*/ uint32 CasterID; /*004*/ uint32 TargetID; diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 3c9e3f128..d2e092c22 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -222,15 +222,37 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) { /* if an invalid bind point is specified, use the primary bind */ - if (bindnum > 4){ bindnum = 0; } - int is_home = 0; - if (bindnum == 4){ is_home = 1; } - - std::string query = StringFormat("SELECT `zone_id` FROM `character_bind` WHERE `id` = %u AND `is_home` = %u LIMIT 1", CharID, is_home); - auto results = database.QueryDatabase(query); int i = 0; - for (auto row = results.begin(); row != results.end(); ++row) { - return atoi(row[0]); + if (bindnum > 4) + { + bindnum = 0; } + + std::string query = StringFormat("SELECT zone_id, instance_id, x, y, z FROM character_bind WHERE id = %u AND is_home = %u LIMIT 1", CharID, bindnum == 4 ? 1 : 0); + auto results = database.QueryDatabase(query); + if(!results.Success() || results.RowCount() == 0) { + return 0; + } + + int zone_id, instance_id; + double x, y, z, heading; + for (auto row = results.begin(); row != results.end(); ++row) { + zone_id = atoi(row[0]); + instance_id = atoi(row[1]); + x = atof(row[2]); + y = atof(row[3]); + z = atof(row[4]); + heading = atof(row[5]); + } + + query = StringFormat("UPDATE character_data SET zone_id = '%d', zone_instance = '%d', x = '%f', y = '%f', z = '%f', heading = '%f'", + zone_id, instance_id, x, y, z, heading); + + results = database.QueryDatabase(query); + if(!results.Success()) { + return 0; + } + + return zone_id; } bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc) @@ -239,7 +261,7 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* return false; in_pp->x = in_pp->y = in_pp->z = in_pp->heading = in_pp->zone_id = 0; - in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = 0; + in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = in_pp->binds[0].instance_id = 0; std::string query = StringFormat("SELECT x, y, z, heading, zone_id, bind_id " "FROM start_zones WHERE player_choice = % i " @@ -267,79 +289,79 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* } case 1: { - in_pp->zone_id =2; // qeynos2 + in_pp->zone_id = 2; // qeynos2 in_pp->binds[0].zoneId = 2; // qeynos2 break; } case 2: { - in_pp->zone_id =29; // halas + in_pp->zone_id = 29; // halas in_pp->binds[0].zoneId = 30; // everfrost break; } case 3: { - in_pp->zone_id =19; // rivervale + in_pp->zone_id = 19; // rivervale in_pp->binds[0].zoneId = 20; // kithicor break; } case 4: { - in_pp->zone_id =9; // freportw + in_pp->zone_id = 9; // freportw in_pp->binds[0].zoneId = 9; // freportw break; } case 5: { - in_pp->zone_id =40; // neriaka + in_pp->zone_id = 40; // neriaka in_pp->binds[0].zoneId = 25; // nektulos break; } case 6: { - in_pp->zone_id =52; // gukta + in_pp->zone_id = 52; // gukta in_pp->binds[0].zoneId = 46; // innothule break; } case 7: { - in_pp->zone_id =49; // oggok + in_pp->zone_id = 49; // oggok in_pp->binds[0].zoneId = 47; // feerrott break; } case 8: { - in_pp->zone_id =60; // kaladima + in_pp->zone_id = 60; // kaladima in_pp->binds[0].zoneId = 68; // butcher break; } case 9: { - in_pp->zone_id =54; // gfaydark + in_pp->zone_id = 54; // gfaydark in_pp->binds[0].zoneId = 54; // gfaydark break; } case 10: { - in_pp->zone_id =61; // felwithea + in_pp->zone_id = 61; // felwithea in_pp->binds[0].zoneId = 54; // gfaydark break; } case 11: { - in_pp->zone_id =55; // akanon + in_pp->zone_id = 55; // akanon in_pp->binds[0].zoneId = 56; // steamfont break; } case 12: { - in_pp->zone_id =82; // cabwest + in_pp->zone_id = 82; // cabwest in_pp->binds[0].zoneId = 78; // fieldofbone break; } case 13: { - in_pp->zone_id =155; // sharvahl + in_pp->zone_id = 155; // sharvahl in_pp->binds[0].zoneId = 155; // sharvahl break; } @@ -378,7 +400,7 @@ bool WorldDatabase::GetStartZoneSoF(PlayerProfile_Struct* in_pp, CharCreate_Stru return false; in_pp->x = in_pp->y = in_pp->z = in_pp->heading = in_pp->zone_id = 0; - in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = 0; + in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = in_pp->binds[0].instance_id = 0; std::string query = StringFormat("SELECT x, y, z, heading, bind_id FROM start_zones WHERE zone_id = %i " "AND player_class = %i AND player_deity = %i AND player_race = %i", diff --git a/zone/attack.cpp b/zone/attack.cpp index 569466f68..da812e724 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1695,7 +1695,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att dead_timer.Start(5000, true); m_pp.zone_id = m_pp.binds[0].zoneId; - m_pp.zoneInstance = 0; + m_pp.zoneInstance = m_pp.binds[0].instance_id; database.MoveCharacterToZone(this->CharacterID(), database.GetZoneName(m_pp.zone_id)); Save(); GoToDeath(); diff --git a/zone/client.cpp b/zone/client.cpp index 25dbb2840..3237240c9 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -398,7 +398,7 @@ Client::~Client() { if(IsHoveringForRespawn()) { m_pp.zone_id = m_pp.binds[0].zoneId; - m_pp.zoneInstance = 0; + m_pp.zoneInstance = m_pp.binds[0].instance_id; x_pos = m_pp.binds[0].x; y_pos = m_pp.binds[0].y; z_pos = m_pp.binds[0].z; @@ -543,11 +543,11 @@ bool Client::Save(uint8 iCommitNow) { m_pp.endurance = cur_end; /* Save Character Currency */ - database.SaveCharacterCurrency(this->CharacterID(), &m_pp); + database.SaveCharacterCurrency(CharacterID(), &m_pp); - /* Save Current Bind Points : Sets Instance to 0 because it is currently not implemented */ - database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, 0, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0); /* Regular bind */ - database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[4].zoneId, 0, m_pp.binds[4].x, m_pp.binds[4].y, m_pp.binds[4].z, 0, 1); /* Home Bind */ + /* Save Current Bind Points */ + database.SaveCharacterBindPoint(CharacterID(), m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0); /* Regular bind */ + database.SaveCharacterBindPoint(CharacterID(), m_pp.binds[4].zoneId, m_pp.binds[4].instance_id, m_pp.binds[4].x, m_pp.binds[4].y, m_pp.binds[4].z, 0, 1); /* Home Bind */ /* Save Character Buffs */ database.SaveBuffs(this); @@ -3848,7 +3848,8 @@ void Client::Sacrifice(Client *caster) void Client::SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID) { - if(!Caster || PendingTranslocate) return; + if(!Caster || PendingTranslocate) + return; const SPDat_Spell_Struct &Spell = spells[SpellID]; @@ -3856,26 +3857,29 @@ void Client::SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID) { Translocate_Struct *ts = (Translocate_Struct*)outapp->pBuffer; strcpy(ts->Caster, Caster->GetName()); - ts->SpellID = SpellID; + PendingTranslocateData.spell_id = ts->SpellID = SpellID; if((SpellID == 1422) || (SpellID == 1334) || (SpellID == 3243)) { - ts->ZoneID = m_pp.binds[0].zoneId; - ts->x = m_pp.binds[0].x; - ts->y = m_pp.binds[0].y; - ts->z = m_pp.binds[0].z; + PendingTranslocateData.zone_id = ts->ZoneID = m_pp.binds[0].zoneId; + 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; + PendingTranslocateData.z = ts->z = m_pp.binds[0].z; + PendingTranslocateData.heading = m_pp.binds[0].heading; } else { ts->ZoneID = database.GetZoneID(Spell.teleport_zone); + PendingTranslocateData.instance_id = 0; ts->y = Spell.base[0]; ts->x = Spell.base[1]; ts->z = Spell.base[2]; + PendingTranslocateData.heading = 0.0; } ts->unknown008 = 0; ts->Complete = 0; - PendingTranslocateData = *ts; - PendingTranslocate=true; + PendingTranslocate = true; TranslocateTime = time(nullptr); QueuePacket(outapp); @@ -4473,7 +4477,8 @@ void Client::SendRespawnBinds() BindStruct* b = &m_pp.binds[0]; RespawnOption opt; opt.name = "Bind Location"; - opt.zoneid = b->zoneId; + opt.zone_id = b->zoneId; + opt.instance_id = b->instance_id; opt.x = b->x; opt.y = b->y; opt.z = b->z; @@ -4483,7 +4488,8 @@ void Client::SendRespawnBinds() //Rez is always added at the end RespawnOption rez; rez.name = "Resurrect"; - rez.zoneid = zone->GetZoneID(); + rez.zone_id = zone->GetZoneID(); + rez.instance_id = zone->GetInstanceID(); rez.x = GetX(); rez.y = GetY(); rez.z = GetZ(); @@ -4518,7 +4524,7 @@ void Client::SendRespawnBinds() { opt = &(*itr); VARSTRUCT_ENCODE_TYPE(uint32, buffer, count++); //option num (from 0) - VARSTRUCT_ENCODE_TYPE(uint32, buffer, opt->zoneid); + VARSTRUCT_ENCODE_TYPE(uint32, buffer, opt->zone_id); VARSTRUCT_ENCODE_TYPE(float, buffer, opt->x); VARSTRUCT_ENCODE_TYPE(float, buffer, opt->y); VARSTRUCT_ENCODE_TYPE(float, buffer, opt->z); @@ -4891,6 +4897,10 @@ void Client::SetStartZone(uint32 zoneid, float x, float y, float z) return; m_pp.binds[4].zoneId = zoneid; + if(zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) { + m_pp.binds[4].instance_id = zone->GetInstanceID(); + } + if (x == 0 && y == 0 && z ==0) database.GetSafePoints(m_pp.binds[4].zoneId, 0, &m_pp.binds[4].x, &m_pp.binds[4].y, &m_pp.binds[4].z); else { @@ -7937,7 +7947,7 @@ void Client::SendItemScale(ItemInst *inst) { } } -void Client::AddRespawnOption(std::string option_name, uint32 zoneid, float x, float y, float z, float heading, bool initial_selection, int8 position) +void Client::AddRespawnOption(std::string option_name, uint32 zoneid, uint16 instance_id, float x, float y, float z, float heading, bool initial_selection, int8 position) { //If respawn window is already open, any changes would create an inconsistency with the client if (IsHoveringForRespawn()) { return; } @@ -7948,7 +7958,8 @@ void Client::AddRespawnOption(std::string option_name, uint32 zoneid, float x, f //Create respawn option RespawnOption res_opt; res_opt.name = option_name; - res_opt.zoneid = zoneid; + res_opt.zone_id = zoneid; + res_opt.instance_id = instance_id; res_opt.x = x; res_opt.y = y; res_opt.z = z; diff --git a/zone/client.h b/zone/client.h index c2dabdc62..fd797c1b7 100644 --- a/zone/client.h +++ b/zone/client.h @@ -177,7 +177,8 @@ struct XTarget_Struct struct RespawnOption { std::string name; - uint32 zoneid; + uint32 zone_id; + uint16 instance_id; float x; float y; float z; @@ -376,6 +377,7 @@ public: 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 GetBindInstanceID(uint32 index = 0) const { return m_pp.binds[index].instance_id; } int32 CalcMaxMana(); int32 CalcBaseMana(); const int32& SetMana(int32 amount); @@ -573,10 +575,11 @@ public: uint32 GetGroupEXP() { return(m_pp.group_leadership_exp); } uint32 GetTotalSecondsPlayed() { return(TotalSecondsPlayed); } virtual void SetLevel(uint8 set_level, bool command = false); + void GoToBind(uint8 bindnum = 0); void GoToSafeCoords(uint16 zone_id, uint16 instance_id); void Gate(); - void SetBindPoint(int to_zone = -1, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f); + void SetBindPoint(int to_zone = -1, int to_instance = 0, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f); void SetStartZone(uint32 zoneid, float x = 0.0f, float y =0.0f, float z = 0.0f); uint32 GetStartZone(void); void MovePC(const char* zonename, float x, float y, float z, float heading, uint8 ignorerestrictions = 0, ZoneMode zm = ZoneSolicited); @@ -613,6 +616,7 @@ public: inline uint32 GetWID() const { return WID; } inline void SetWID(uint32 iWID) { WID = iWID; } inline uint32 AccountID() const { return account_id; } + inline const char* AccountName()const { return account_name; } inline int16 Admin() const { return admin; } inline uint32 CharacterID() const { return character_id; } @@ -917,7 +921,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst); time_t TranslocateTime; bool PendingSacrifice; std::string SacrificeCaster; - struct Translocate_Struct PendingTranslocateData; + PendingTranslocate_Struct PendingTranslocateData; void SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID); // Task System Methods @@ -1057,7 +1061,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst); void HandleRespawnFromHover(uint32 Option); bool IsHoveringForRespawn() { return RespawnFromHoverTimer.Enabled(); } std::list respawn_options; - void AddRespawnOption(std::string option_name, uint32 zoneid, float x, float y, float z, float h = 0, bool initial_selection = false, int8 position = -1); + void AddRespawnOption(std::string option_name, uint32 zoneid, uint16 instance_id, float x, float y, float z, float h = 0, bool initial_selection = false, int8 position = -1); bool RemoveRespawnOption(std::string option_name); bool RemoveRespawnOption(uint8 position); void ClearRespawnOptions() { respawn_options.clear(); } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 15c4f3497..941eaf774 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13725,7 +13725,8 @@ void Client::Handle_OP_Translocate(const EQApplicationPacket *app) } Translocate_Struct *its = (Translocate_Struct*)app->pBuffer; - if (!PendingTranslocate) return; + if (!PendingTranslocate) + return; if ((RuleI(Spells, TranslocateTimeLimit) > 0) && (time(nullptr) > (TranslocateTime + RuleI(Spells, TranslocateTimeLimit)))) { Message(13, "You did not accept the Translocate within the required time limit."); @@ -13735,7 +13736,7 @@ void Client::Handle_OP_Translocate(const EQApplicationPacket *app) if (its->Complete == 1) { - int SpellID = PendingTranslocateData.SpellID; + int SpellID = PendingTranslocateData.spell_id; int i = parse->EventSpell(EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE, nullptr, this, SpellID, 0); if (i == 0) @@ -13745,20 +13746,19 @@ void Client::Handle_OP_Translocate(const EQApplicationPacket *app) // to the bind coords it has from the PlayerProfile, but with the X and Y reversed. I suspect they are // reversed in the pp, and since spells like Gate are handled serverside, this has not mattered before. if (((SpellID == 1422) || (SpellID == 1334) || (SpellID == 3243)) && - zone->GetZoneID() == PendingTranslocateData.ZoneID) + (zone->GetZoneID() == PendingTranslocateData.zone_id && + zone->GetInstanceID() == PendingTranslocateData.instance_id)) { PendingTranslocate = false; GoToBind(); return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Translocate, sizeof(Translocate_Struct)); - Translocate_Struct *ots = (Translocate_Struct*)outapp->pBuffer; - memcpy(ots, &PendingTranslocateData, sizeof(Translocate_Struct)); - - //Was sending the packet back to initiate client zone... - //but that could be abusable, so lets go through proper channels - MovePC(ots->ZoneID, 0, ots->x, ots->y, ots->z, GetHeading(), 0, ZoneSolicited); + ////Was sending the packet back to initiate client zone... + ////but that could be abusable, so lets go through proper channels + MovePC(PendingTranslocateData.zone_id, PendingTranslocateData.instance_id, + PendingTranslocateData.x, PendingTranslocateData.y, + PendingTranslocateData.z, PendingTranslocateData.heading, 0, ZoneSolicited); } } diff --git a/zone/client_process.cpp b/zone/client_process.cpp index e26dcd2e3..2f46a5688 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -147,11 +147,11 @@ bool Client::Process() { if(mana_timer.Check()) SendManaUpdatePacket(); - if(dead && dead_timer.Check()) - { - database.MoveCharacterToZone(GetName(),database.GetZoneName(m_pp.binds[0].zoneId)); + if(dead && dead_timer.Check()) { + database.MoveCharacterToZone(GetName(), database.GetZoneName(m_pp.binds[0].zoneId)); + m_pp.zone_id = m_pp.binds[0].zoneId; - m_pp.zoneInstance = 0; + 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; m_pp.z = m_pp.binds[0].z; @@ -2120,7 +2120,8 @@ 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->zoneid = b->zoneId; + default_to_bind->zone_id = b->zoneId; + default_to_bind->instance_id = b->instance_id; default_to_bind->x = b->x; default_to_bind->y = b->y; default_to_bind->z = b->z; @@ -2129,7 +2130,7 @@ void Client::HandleRespawnFromHover(uint32 Option) is_rez = false; } - if (chosen->zoneid == zone->GetZoneID()) //If they should respawn in the current zone... + if (chosen->zone_id == zone->GetZoneID() && chosen->instance_id == zone->GetInstanceID()) //If they should respawn in the current zone... { if (is_rez) { @@ -2185,6 +2186,7 @@ void Client::HandleRespawnFromHover(uint32 Option) ZonePlayerToBind_Struct* gmg = (ZonePlayerToBind_Struct*) outapp->pBuffer; gmg->bind_zone_id = zone->GetZoneID(); + gmg->bind_instance_id = chosen->instance_id; gmg->x = chosen->x; gmg->y = chosen->y; gmg->z = chosen->z; @@ -2230,13 +2232,13 @@ void Client::HandleRespawnFromHover(uint32 Option) if(r) r->MemberZoned(this); - m_pp.zone_id = chosen->zoneid; - m_pp.zoneInstance = 0; - database.MoveCharacterToZone(this->CharacterID(), database.GetZoneName(chosen->zoneid)); + m_pp.zone_id = chosen->zone_id; + m_pp.zoneInstance = chosen->instance_id; + database.MoveCharacterToZone(CharacterID(), database.GetZoneName(chosen->zone_id)); Save(); - MovePC(chosen->zoneid,chosen->x,chosen->y,chosen->z,chosen->heading,1); + MovePC(chosen->zone_id, chosen->instance_id, chosen->x, chosen->y, chosen->z, chosen->heading, 1); } safe_delete(default_to_bind); diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 56abe5f09..22e38b21d 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -235,19 +235,24 @@ void Lua_Client::SetBindPoint(int to_zone) { self->SetBindPoint(to_zone); } -void Lua_Client::SetBindPoint(int to_zone, float new_x) { +void Lua_Client::SetBindPoint(int to_zone, int to_instance) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, new_x); + self->SetBindPoint(to_zone, to_instance); } -void Lua_Client::SetBindPoint(int to_zone, float new_x, float new_y) { +void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, new_x, new_y); + self->SetBindPoint(to_zone, to_instance, new_x); } -void Lua_Client::SetBindPoint(int to_zone, float new_x, float new_y, float new_z) { +void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x, float new_y) { Lua_Safe_Call_Void(); - self->SetBindPoint(to_zone, new_x, new_y, new_z); + self->SetBindPoint(to_zone, to_instance, new_x, new_y); +} + +void Lua_Client::SetBindPoint(int to_zone, int to_instance, float new_x, float new_y, float new_z) { + Lua_Safe_Call_Void(); + self->SetBindPoint(to_zone, to_instance, new_x, new_y, new_z); } float Lua_Client::GetBindX() { @@ -1297,9 +1302,10 @@ luabind::scope lua_register_client() { .def("SetEXP", (void(Lua_Client::*)(uint32,uint32,bool))&Lua_Client::SetEXP) .def("SetBindPoint", (void(Lua_Client::*)(void))&Lua_Client::SetBindPoint) .def("SetBindPoint", (void(Lua_Client::*)(int))&Lua_Client::SetBindPoint) - .def("SetBindPoint", (void(Lua_Client::*)(int,float))&Lua_Client::SetBindPoint) - .def("SetBindPoint", (void(Lua_Client::*)(int,float,float))&Lua_Client::SetBindPoint) - .def("SetBindPoint", (void(Lua_Client::*)(int,float,float,float))&Lua_Client::SetBindPoint) + .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("GetBindX", (float(Lua_Client::*)(void))&Lua_Client::GetBindX) .def("GetBindX", (float(Lua_Client::*)(int))&Lua_Client::GetBindX) .def("GetBindY", (float(Lua_Client::*)(void))&Lua_Client::GetBindY) diff --git a/zone/lua_client.h b/zone/lua_client.h index ef2af1181..e2b0a6614 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -73,9 +73,10 @@ public: void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp); void SetBindPoint(); void SetBindPoint(int to_zone); - void SetBindPoint(int to_zone, float new_x); - void SetBindPoint(int to_zone, float new_x, float new_y); - void SetBindPoint(int to_zone, float new_x, float new_y, float new_z); + void SetBindPoint(int to_zone, int to_instance); + 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); float GetBindX(); float GetBindX(int index); float GetBindY(); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index aaaa5899f..2a0c055af 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -1023,11 +1023,12 @@ XS(XS_Client_SetBindPoint); /* prototype to pass -Wmissing-prototypes */ XS(XS_Client_SetBindPoint) { dXSARGS; - if (items < 1 || items > 5) - Perl_croak(aTHX_ "Usage: Client::SetBindPoint(THIS, to_zone= -1, new_x= 0.0f, new_y= 0.0f, new_z= 0.0f)"); + if (items < 1 || items > 6) + Perl_croak(aTHX_ "Usage: Client::SetBindPoint(THIS, to_zone= -1, to_instance = 0, new_x= 0.0f, new_y= 0.0f, new_z= 0.0f)"); { Client * THIS; int to_zone; + int to_instance; float new_x; float new_y; float new_z; @@ -1047,25 +1048,31 @@ XS(XS_Client_SetBindPoint) to_zone = (int)SvIV(ST(1)); } - if (items < 3) - new_x = 0.0f; + if(items < 3) + to_instance = 0; else { - new_x = (float)SvNV(ST(2)); + to_instance = (int)SvIV(ST(2)); } if (items < 4) - new_y = 0.0f; + new_x = 0.0f; else { - new_y = (float)SvNV(ST(3)); + new_x = (float)SvNV(ST(3)); } if (items < 5) - new_z = 0.0f; + new_y = 0.0f; else { - new_z = (float)SvNV(ST(4)); + new_y = (float)SvNV(ST(4)); } - THIS->SetBindPoint(to_zone, new_x, new_y, new_z); + if (items < 6) + new_z = 0.0f; + else { + new_z = (float)SvNV(ST(5)); + } + + THIS->SetBindPoint(to_zone, to_instance, new_x, new_y, new_z); } XSRETURN_EMPTY; } @@ -6155,7 +6162,7 @@ XS(boot_Client) newXSproto(strcpy(buf, "SetDeity"), XS_Client_SetDeity, file, "$$"); newXSproto(strcpy(buf, "AddEXP"), XS_Client_AddEXP, file, "$$;$$"); newXSproto(strcpy(buf, "SetEXP"), XS_Client_SetEXP, file, "$$$;$"); - newXSproto(strcpy(buf, "SetBindPoint"), XS_Client_SetBindPoint, file, "$;$$$$"); + newXSproto(strcpy(buf, "SetBindPoint"), XS_Client_SetBindPoint, file, "$;$$$$$"); newXSproto(strcpy(buf, "GetBindX"), XS_Client_GetBindX, file, "$$"); newXSproto(strcpy(buf, "GetBindY"), XS_Client_GetBindY, file, "$$"); newXSproto(strcpy(buf, "GetBindZ"), XS_Client_GetBindZ, file, "$$"); diff --git a/zone/qglobals.cpp b/zone/qglobals.cpp index f63e13dd4..bc7bf680e 100644 --- a/zone/qglobals.cpp +++ b/zone/qglobals.cpp @@ -172,5 +172,5 @@ void QGlobalCache::LoadBy(const std::string &query) return; for (auto row = results.begin(); row != results.end(); ++row) - AddGlobal(0, QGlobal(std::string(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5]? atoi(row[5]): 0xFFFFFFFF)); + AddGlobal(0, QGlobal(row[0], atoi(row[1]), atoi(row[2]), atoi(row[3]), row[4], row[5] ? atoi(row[5]) : 0xFFFFFFFF)); } diff --git a/zone/zone.cpp b/zone/zone.cpp index 7a4ad8bac..521684a0d 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -755,6 +755,7 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) zoneid = in_zoneid; instanceid = in_instanceid; instanceversion = database.GetInstanceVersion(instanceid); + pers_instance = false; zonemap = nullptr; watermap = nullptr; pathing = nullptr; @@ -824,11 +825,12 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name) if(!is_perma) { if(rem < 150) //give some leeway to people who are zoning in 2.5 minutes to finish zoning in and get ported out - rem = 150; + rem = 150; Instance_Timer = new Timer(rem * 1000); } else { + pers_instance = true; Instance_Timer = nullptr; } } diff --git a/zone/zone.h b/zone/zone.h index 9ad692fa0..0fa390512 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -104,6 +104,7 @@ public: inline const uint32 GetZoneID() const { return zoneid; } inline const uint32 GetInstanceID() const { return instanceid; } inline const uint16 GetInstanceVersion() const { return instanceversion; } + inline const bool IsInstancePersistent() const { return pers_instance; } inline const uint8 GetZoneType() const { return zone_type; } inline Timer* GetInstanceTimer() { return Instance_Timer; } @@ -274,6 +275,7 @@ private: uint32 zoneid; uint32 instanceid; uint16 instanceversion; + bool pers_instance; char* short_name; char file_name[16]; char* long_name; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index fa34e8d9e..bfbdb7424 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1197,21 +1197,21 @@ bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Str i = 0; /* Is home bind */ if (atoi(row[6]) == 1){ - pp->binds[4].zoneId = atoi(row[i]); i++; - i++; /* Instance ID can go here eventually */ - pp->binds[4].x = atoi(row[i]); i++; - pp->binds[4].y = atoi(row[i]); i++; - pp->binds[4].z = atoi(row[i]); i++; - pp->binds[4].heading = atoi(row[i]); i++; + pp->binds[4].zoneId = atoi(row[i++]); + pp->binds[4].instance_id = atoi(row[i++]); + pp->binds[4].x = atoi(row[i++]); + pp->binds[4].y = atoi(row[i++]); + pp->binds[4].z = atoi(row[i++]); + pp->binds[4].heading = atoi(row[i++]); } /* Is regular bind point */ else{ - pp->binds[0].zoneId = atoi(row[i]); i++; - i++; /* Instance ID can go here eventually */ - pp->binds[0].x = atoi(row[i]); i++; - pp->binds[0].y = atoi(row[i]); i++; - pp->binds[0].z = atoi(row[i]); i++; - pp->binds[0].heading = atoi(row[i]); i++; + pp->binds[0].zoneId = atoi(row[i++]); + pp->binds[0].instance_id = atoi(row[i++]); + pp->binds[0].x = atoi(row[i++]); + pp->binds[0].y = atoi(row[i++]); + pp->binds[0].z = atoi(row[i++]); + pp->binds[0].heading = atoi(row[i++]); } } return true; @@ -1224,12 +1224,18 @@ bool ZoneDatabase::SaveCharacterLanguage(uint32 character_id, uint32 lang_id, ui } bool ZoneDatabase::SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home){ - if (zone_id <= 0){ return false; } + if (zone_id <= 0) { + return false; + } + /* Save Home Bind Point */ std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", character_id, zone_id, instance_id, x, y, z, heading, is_home); LogFile->write(EQEMuLog::Debug, "ZoneDatabase::SaveCharacterBindPoint for character ID: %i zone_id: %u instance_id: %u x: %f y: %f z: %f heading: %f ishome: %u", character_id, zone_id, instance_id, x, y, z, heading, is_home); - auto results = QueryDatabase(query); if (!results.RowsAffected()){ std::cout << "ERROR Bind Home Save: " << results.ErrorMessage() << "\n\n" << query << "\n" << std::endl; } + auto results = QueryDatabase(query); + if (!results.RowsAffected()) { + LogFile->write(EQEMuLog::Debug, "ERROR Bind Home Save: %s. %s", results.ErrorMessage().c_str(), query.c_str()); + } ThrowDBError(results.ErrorMessage(), "ZoneDatabase::SaveCharacterBindPoint", query); return true; } @@ -3234,7 +3240,6 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in bool ZoneDatabase::LoadFactionData() { - std::string query = "SELECT MAX(id) FROM faction_list"; auto results = QueryDatabase(query); if (!results.Success()) { @@ -3265,7 +3270,6 @@ bool ZoneDatabase::LoadFactionData() strn0cpy(faction_array[index]->name, row[1], 50); faction_array[index]->base = atoi(row[2]); - query = StringFormat("SELECT `mod`, `mod_name` FROM `faction_list_mod` WHERE faction_id = %u", index); auto modResults = QueryDatabase(query); if (!modResults.Success()) @@ -3273,8 +3277,9 @@ bool ZoneDatabase::LoadFactionData() for (auto modRow = modResults.begin(); modRow != modResults.end(); ++modRow) faction_array[index]->mods[modRow[1]] = atoi(modRow[0]); - } + + return true; } bool ZoneDatabase::GetFactionIdsForNPC(uint32 nfl_id, std::list *faction_list, int32* primary_faction) { diff --git a/zone/zoning.cpp b/zone/zoning.cpp index 42d07810a..6ac85cff6 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -71,9 +71,11 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { break; case GateToBindPoint: target_zone_id = m_pp.binds[0].zoneId; + target_instance_id = m_pp.binds[0].instance_id; break; case ZoneToBindPoint: target_zone_id = m_pp.binds[0].zoneId; + 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. target_zone_id = zonesummon_id; @@ -717,20 +719,22 @@ void NPC::Gate() { Mob::Gate(); } -void Client::SetBindPoint(int to_zone, float new_x, float new_y, float new_z) { +void Client::SetBindPoint(int to_zone, int to_instance, float new_x, float new_y, float new_z) { if (to_zone == -1) { m_pp.binds[0].zoneId = zone->GetZoneID(); + m_pp.binds[0].instance_id = (zone->GetInstanceID() != 0 && zone->IsInstancePersistent()) ? zone->GetInstanceID() : 0; m_pp.binds[0].x = x_pos; m_pp.binds[0].y = y_pos; m_pp.binds[0].z = z_pos; } else { m_pp.binds[0].zoneId = to_zone; + m_pp.binds[0].instance_id = to_instance; m_pp.binds[0].x = new_x; m_pp.binds[0].y = new_y; m_pp.binds[0].z = new_z; } - database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, 0, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0); + database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0); } void Client::GoToBind(uint8 bindnum) { @@ -741,13 +745,13 @@ void Client::GoToBind(uint8 bindnum) { // move the client, which will zone them if needed. // ignore restrictions on the zone request..? if(bindnum == 0) - MovePC(m_pp.binds[0].zoneId, 0.0f, 0.0f, 0.0f, 0.0f, 1, GateToBindPoint); + MovePC(m_pp.binds[0].zoneId, 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].x, m_pp.binds[bindnum].y, m_pp.binds[bindnum].z, m_pp.binds[bindnum].heading, 1); + 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); } void Client::GoToDeath() { - MovePC(m_pp.binds[0].zoneId, 0.0f, 0.0f, 0.0f, 0.0f, 1, ZoneToBindPoint); + MovePC(m_pp.binds[0].zoneId, m_pp.binds[0].instance_id, 0.0f, 0.0f, 0.0f, 0.0f, 1, ZoneToBindPoint); } void Client::SetZoneFlag(uint32 zone_id) {