diff --git a/zone/client.cpp b/zone/client.cpp index bd8155e39..f05941ee6 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -9856,20 +9856,18 @@ void Client::SetDzRemovalTimer(bool enable_timer) void Client::SendDzCompassUpdate() { - // a client may be associated with multiple dynamic zones with compasses - // in the same zone. any systems that use dynamic zones need checked here + // client may be associated with multiple dynamic zone compasses in this zone std::vector compass_entries; - Expedition* expedition = GetExpedition(); - if (expedition) + for (const auto& client_dz : GetDynamicZones()) { - auto compass = expedition->GetDynamicZone().GetCompassLocation(); + auto compass = client_dz.dynamic_zone.GetCompassLocation(); if (zone && zone->GetZoneID() == compass.zone_id && zone->GetInstanceID() == 0) { DynamicZoneCompassEntry_Struct entry; - entry.dz_zone_id = static_cast(expedition->GetDynamicZone().GetZoneID()); - entry.dz_instance_id = static_cast(expedition->GetDynamicZone().GetInstanceID()); - entry.dz_type = static_cast(expedition->GetDynamicZone().GetType()); + entry.dz_zone_id = static_cast(client_dz.dynamic_zone.GetZoneID()); + entry.dz_instance_id = static_cast(client_dz.dynamic_zone.GetInstanceID()); + entry.dz_type = static_cast(client_dz.dynamic_zone.GetType()); entry.x = compass.x; entry.y = compass.y; entry.z = compass.z; @@ -9878,8 +9876,6 @@ void Client::SendDzCompassUpdate() } } - // todo: tasks, missions, and quests with an associated dz - // compass set via MarkSingleCompassLocation() if (m_has_quest_compass) { @@ -9922,57 +9918,52 @@ void Client::GoToDzSafeReturnOrBind(const DynamicZone& dynamic_zone) } } -void Client::MovePCDynamicZone(uint32 zone_id) +std::vector Client::GetDynamicZones(uint32_t zone_id, int zone_version) +{ + std::vector client_dzs; + + // check client systems for any associated dynamic zones optionally filtered by zone + Expedition* expedition = GetExpedition(); + if (expedition && + (zone_id == 0 || expedition->GetDynamicZone().GetZoneID() == zone_id) && + (zone_version < 0 || expedition->GetDynamicZone().GetZoneVersion() == zone_version)) + { + client_dzs.emplace_back(expedition->GetName(), expedition->GetLeaderName(), expedition->GetDynamicZone()); + } + + // todo: tasks, missions (shared tasks), and quests with an associated dz to zone_id + + return client_dzs; +} + +void Client::MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_invalid) { if (zone_id == 0) { return; } - // check client systems for any associated dynamic zones to the requested zone id - std::vector client_dzs; - DynamicZone single_dz; - - Expedition* expedition = GetExpedition(); - if (expedition && expedition->GetDynamicZone().GetZoneID() == zone_id) - { - single_dz = expedition->GetDynamicZone(); - - DynamicZoneChooseZoneEntry_Struct dz; - dz.dz_zone_id = expedition->GetDynamicZone().GetZoneID(); - dz.dz_instance_id = expedition->GetDynamicZone().GetInstanceID(); - dz.dz_type = static_cast(expedition->GetDynamicZone().GetType()); - strn0cpy(dz.description, expedition->GetName().c_str(), sizeof(dz.description)); - strn0cpy(dz.leader_name, expedition->GetLeaderName().c_str(), sizeof(dz.leader_name)); - - client_dzs.emplace_back(dz); - } - - // todo: check for Missions (Shared Tasks), Quests, or Tasks that have associated dzs to zone_id + auto client_dzs = GetDynamicZones(zone_id, zone_version); if (client_dzs.empty()) { - MessageString(Chat::Red, DYNAMICZONE_WAY_IS_BLOCKED); // unconfirmed message + if (msg_if_invalid) + { + MessageString(Chat::Red, DYNAMICZONE_WAY_IS_BLOCKED); // unconfirmed message + } } else if (client_dzs.size() == 1) { - if (single_dz.IsValid()) - { - DynamicZoneLocation zonein = single_dz.GetZoneInLocation(); - ZoneMode zone_mode = ZoneMode::ZoneToSafeCoords; - if (single_dz.HasZoneInLocation()) - { - zone_mode = ZoneMode::ZoneSolicited; - } - MovePC(zone_id, single_dz.GetInstanceID(), zonein.x, zonein.y, zonein.z, zonein.heading, 0, zone_mode); - } + const DynamicZone& dz = client_dzs[0].dynamic_zone; + DynamicZoneLocation zonein = dz.GetZoneInLocation(); + ZoneMode zone_mode = dz.HasZoneInLocation() ? ZoneMode::ZoneSolicited : ZoneMode::ZoneToSafeCoords; + MovePC(zone_id, dz.GetInstanceID(), zonein.x, zonein.y, zonein.z, zonein.heading, 0, zone_mode); } - else if (client_dzs.size() > 1) + else { LogDynamicZonesDetail( "Sending DzSwitchListWnd to character [{}] associated with [{}] dynamic zone(s)", - CharacterID(), client_dzs.size() - ); + CharacterID(), client_dzs.size()); // more than one dynamic zone to this zone, send out the switchlist window // note that this will most likely crash clients if they've reloaded the ui @@ -9983,14 +9974,20 @@ void Client::MovePCDynamicZone(uint32 zone_id) auto outapp = std::unique_ptr(new EQApplicationPacket(OP_DzChooseZone, outsize)); auto outbuf = reinterpret_cast(outapp->pBuffer); outbuf->count = count; - memcpy(outbuf->choices, client_dzs.data(), entries_size); - + for (int i = 0; i < client_dzs.size(); ++i) + { + outbuf->choices[i].dz_zone_id = client_dzs[i].dynamic_zone.GetZoneID(); + outbuf->choices[i].dz_instance_id = client_dzs[i].dynamic_zone.GetInstanceID(); + outbuf->choices[i].dz_type = static_cast(client_dzs[i].dynamic_zone.GetType()); + strn0cpy(outbuf->choices[i].description, client_dzs[i].description.c_str(), sizeof(outbuf->choices[i].description)); + strn0cpy(outbuf->choices[i].leader_name, client_dzs[i].leader_name.c_str(), sizeof(outbuf->choices[i].leader_name)); + } QueuePacket(outapp.get()); } } -void Client::MovePCDynamicZone(const std::string& zone_name) +void Client::MovePCDynamicZone(const std::string& zone_name, int zone_version, bool msg_if_invalid) { auto zone_id = ZoneID(zone_name.c_str()); - MovePCDynamicZone(zone_id); + MovePCDynamicZone(zone_id, zone_version, msg_if_invalid); } diff --git a/zone/client.h b/zone/client.h index 006b0b91a..3e19b6a92 100644 --- a/zone/client.h +++ b/zone/client.h @@ -31,6 +31,7 @@ class Object; class Raid; class Seperator; class ServerPacket; +struct DynamicZoneInfo; struct DynamicZoneLocation; enum WaterRegionType : int; @@ -1148,8 +1149,9 @@ public: void SetDzRemovalTimer(bool enable_timer); void SendDzCompassUpdate(); void GoToDzSafeReturnOrBind(const DynamicZone& dynamic_zone); - void MovePCDynamicZone(uint32 zone_id); - void MovePCDynamicZone(const std::string& zone_name); + void MovePCDynamicZone(uint32 zone_id, int zone_version = -1, bool msg_if_invalid = true); + void MovePCDynamicZone(const std::string& zone_name, int zone_version = -1, bool msg_if_invalid = true); + std::vector GetDynamicZones(uint32_t zone_id = 0, int zone_version = -1); void CalcItemScale(); bool CalcItemScale(uint32 slot_x, uint32 slot_y); // behavior change: 'slot_y' is now [RANGE]_END and not [RANGE]_END + 1 diff --git a/zone/dynamiczone.h b/zone/dynamiczone.h index cdff3c4e2..4d65b654e 100644 --- a/zone/dynamiczone.h +++ b/zone/dynamiczone.h @@ -116,4 +116,15 @@ private: std::chrono::time_point m_expire_time; }; +struct DynamicZoneInfo +{ + std::string description; // from owning system + std::string leader_name; + DynamicZone dynamic_zone; + + DynamicZoneInfo() = default; + DynamicZoneInfo(std::string desc, std::string leader, const DynamicZone& dz) + : description(std::move(desc)), leader_name(std::move(leader)), dynamic_zone(dz) {} +}; + #endif diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index c8f91936c..2946e90b9 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1837,11 +1837,31 @@ void Lua_Client::MovePCDynamicZone(uint32 zone_id) { return self->MovePCDynamicZone(zone_id); } +void Lua_Client::MovePCDynamicZone(uint32 zone_id, int zone_version) { + Lua_Safe_Call_Void(); + return self->MovePCDynamicZone(zone_id, zone_version); +} + +void Lua_Client::MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_invalid) { + Lua_Safe_Call_Void(); + return self->MovePCDynamicZone(zone_id, zone_version, msg_if_invalid); +} + void Lua_Client::MovePCDynamicZone(std::string zone_name) { Lua_Safe_Call_Void(); return self->MovePCDynamicZone(zone_name); } +void Lua_Client::MovePCDynamicZone(std::string zone_name, int zone_version) { + Lua_Safe_Call_Void(); + return self->MovePCDynamicZone(zone_name, zone_version); +} + +void Lua_Client::MovePCDynamicZone(std::string zone_name, int zone_version, bool msg_if_invalid) { + Lua_Safe_Call_Void(); + return self->MovePCDynamicZone(zone_name, zone_version, msg_if_invalid); +} + luabind::scope lua_register_client() { return luabind::class_("Client") .def(luabind::constructor<>()) @@ -2165,7 +2185,11 @@ luabind::scope lua_register_client() { .def("RemoveExpeditionLockout", (void(Lua_Client::*)(std::string, std::string))&Lua_Client::RemoveExpeditionLockout) .def("HasExpeditionLockout", (bool(Lua_Client::*)(std::string, std::string))&Lua_Client::HasExpeditionLockout) .def("MovePCDynamicZone", (void(Lua_Client::*)(uint32))&Lua_Client::MovePCDynamicZone) - .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string))&Lua_Client::MovePCDynamicZone); + .def("MovePCDynamicZone", (void(Lua_Client::*)(uint32, int))&Lua_Client::MovePCDynamicZone) + .def("MovePCDynamicZone", (void(Lua_Client::*)(uint32, int, bool))&Lua_Client::MovePCDynamicZone) + .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string))&Lua_Client::MovePCDynamicZone) + .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int))&Lua_Client::MovePCDynamicZone) + .def("MovePCDynamicZone", (void(Lua_Client::*)(std::string, int, bool))&Lua_Client::MovePCDynamicZone); } luabind::scope lua_register_inventory_where() { diff --git a/zone/lua_client.h b/zone/lua_client.h index 35782875b..41ce4e5cf 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -355,7 +355,11 @@ public: void RemoveExpeditionLockout(std::string expedition_name, std::string event_name); bool HasExpeditionLockout(std::string expedition_name, std::string event_name); void MovePCDynamicZone(uint32 zone_id); + void MovePCDynamicZone(uint32 zone_id, int zone_version); + void MovePCDynamicZone(uint32 zone_id, int zone_version, bool msg_if_invalid); void MovePCDynamicZone(std::string zone_name); + void MovePCDynamicZone(std::string zone_name, int zone_version); + void MovePCDynamicZone(std::string zone_name, int zone_version, bool msg_if_invalid); }; #endif