diff --git a/CHANGELOG.md b/CHANGELOG.md index 627baca5e..7d87da2db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +## [23.9.1] 8/2/2025 + +### Hotfix + +* Fix Quest Ownership Edge Case ([#4977](https://github.com/EQEmu/Server/pull/4977)) @Kinglykrab 2025-08-02 + +## [23.9.0] 8/2/2025 + +### Bots + +* Fix FinishBuffing rule ([#4961](https://github.com/EQEmu/Server/pull/4961)) @nytmyr 2025-07-01 +* Fix ^cast resurrects ([#4958](https://github.com/EQEmu/Server/pull/4958)) @nytmyr 2025-06-29 + +### Build + +* Fix Linking with GCC ([#4969](https://github.com/EQEmu/Server/pull/4969)) @solar984 2025-08-03 +* More Build Speed Improvements ([#4959](https://github.com/EQEmu/Server/pull/4959)) @Akkadius 2025-06-30 + +### Commands + +* Add #show keyring Subcommand ([#4973](https://github.com/EQEmu/Server/pull/4973)) @Kinglykrab 2025-08-03 + +### Database + +* Add Indexes to NPC's Spawns Loot ([#4972](https://github.com/EQEmu/Server/pull/4972)) @Akkadius 2025-07-30 + +### Feature + +* Zone Scripting ([#4908](https://github.com/EQEmu/Server/pull/4908)) @Kinglykrab 2025-07-10 + +### Fixes + +* Add a missing Froglok starting area for Titanium Startzone. ([#4962](https://github.com/EQEmu/Server/pull/4962)) @regneq 2025-07-04 +* Fix Hero's Forge Ingame and Character Select ([#4966](https://github.com/EQEmu/Server/pull/4966)) @Kinglykrab 2025-07-30 +* Show player count on the server list status. ([#4971](https://github.com/EQEmu/Server/pull/4971)) @regneq 2025-07-30 + +### Loginserver + +* Fix Legacy World When Using Local DB ([#4970](https://github.com/EQEmu/Server/pull/4970)) @solar984 2025-08-03 + +### Performance + +* Clear Wearchange Deduplication Cache ([#4960](https://github.com/EQEmu/Server/pull/4960)) @Akkadius 2025-06-30 + +### Quest API + +* Add GetMemberRole() to Perl/Lua ([#4963](https://github.com/EQEmu/Server/pull/4963)) @Barathos 2025-07-10 +* Add GetTimers() and GetPausedTimers() to Perl/Lua ([#4965](https://github.com/EQEmu/Server/pull/4965)) @Kinglykrab 2025-08-03 + ## [23.8.1] 6/28/2025 ### Crash Fix diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 0921cec5f..2a3c3ad72 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -104,9 +104,9 @@ SET(common_sources net/console_server.cpp net/console_server_connection.cpp net/crc32.cpp - net/daybreak_connection.cpp net/eqstream.cpp net/packet.cpp + net/reliable_stream_connection.cpp net/servertalk_client_connection.cpp net/servertalk_legacy_client_connection.cpp net/servertalk_server.cpp @@ -671,13 +671,13 @@ SET(common_headers net/console_server.h net/console_server_connection.h net/crc32.h - net/daybreak_connection.h - net/daybreak_pooling.h - net/daybreak_structs.h net/dns.h net/endian.h net/eqstream.h net/packet.h + net/reliable_stream_connection.h + net/reliable_stream_pooling.h + net/reliable_stream_structs.h net/servertalk_client_connection.h net/servertalk_legacy_client_connection.h net/servertalk_common.h @@ -743,10 +743,6 @@ SOURCE_GROUP(Net FILES net/console_server_connection.h net/crc32.cpp net/crc32.h - net/daybreak_connection.cpp - net/daybreak_connection.h - net/daybreak_pooling.h - net/daybreak_structs.h net/dns.h net/endian.h net/eqmq.cpp @@ -755,6 +751,10 @@ SOURCE_GROUP(Net FILES net/eqstream.h net/packet.cpp net/packet.h + net/reliable_stream_connection.cpp + net/reliable_stream_connection.h + net/reliable_stream_pooling.h + net/reliable_stream_structs.h net/servertalk_client_connection.cpp net/servertalk_client_connection.h net/servertalk_legacy_client_connection.cpp diff --git a/common/database/database_update_manifest.cpp b/common/database/database_update_manifest.cpp index 05984036e..f6eddc69b 100644 --- a/common/database/database_update_manifest.cpp +++ b/common/database/database_update_manifest.cpp @@ -7136,6 +7136,42 @@ ADD COLUMN `entity_variables` TEXT DEFAULT NULL AFTER `rezzable`; )", .content_schema_update = false }, + ManifestEntry{ + .version = 9326, + .description = "2025_07_27_add_indexes_npc_spawns_loot.sql", + .check = "SHOW INDEX FROM npc_types", + .condition = "missing", + .match = "idx_npc_types_loottable_id", + .sql = R"( +ALTER TABLE npc_types + ADD INDEX idx_npc_types_loottable_id (loottable_id); + +ALTER TABLE spawnentry + ADD INDEX idx_spawnentry_spawngroup_id (spawngroupID), + ADD INDEX idx_spawnentry_npc_id (npcID); + +ALTER TABLE lootdrop_entries + ADD INDEX idx_lootdrop_entries_lootdrop_id (lootdrop_id), + ADD INDEX idx_lootdrop_entries_item_id (item_id); + +ALTER TABLE loottable_entries + ADD INDEX idx_loottable_entries_lootdrop_id (lootdrop_id), + ADD INDEX idx_loottable_entries_loottable_id (loottable_id); +)", + .content_schema_update = true + }, + ManifestEntry{ + .version = 9327, + .description = "2025_08_13_character_stats_record_heal_amount.sql", + .check = "SHOW COLUMNS FROM `character_stats_record` LIKE 'heal_amount'", + .condition = "empty", + .match = "", + .sql = R"( +ALTER TABLE `character_stats_record` +ADD COLUMN `heal_amount` int(11) NULL DEFAULT 0 AFTER `spell_damage`; +)" + }, + // -- template; copy/paste this when you need to create a new entry // ManifestEntry{ // .version = 9228, diff --git a/common/emu_constants.cpp b/common/emu_constants.cpp index 670aeb981..ecb1e4c58 100644 --- a/common/emu_constants.cpp +++ b/common/emu_constants.cpp @@ -451,3 +451,23 @@ bool LDoNTheme::IsValid(uint32 theme_id) { return ldon_theme_names.find(theme_id) != ldon_theme_names.end(); } + +std::string PetCommand::GetName(uint8 pet_command) +{ + return IsValid(pet_command) ? pet_commands[pet_command] : "UNKNOWN PET COMMAND"; +} + +bool PetCommand::IsValid(uint8 pet_command) +{ + return pet_commands.find(pet_command) != pet_commands.end(); +} + +std::string PetType::GetName(uint8 pet_type) +{ + return IsValid(pet_type) ? pet_types[pet_type] : "UNKNOWN PET TYPE"; +} + +bool PetType::IsValid(uint8 pet_type) +{ + return pet_types.find(pet_type) != pet_types.end(); +} diff --git a/common/emu_constants.h b/common/emu_constants.h index 085fcd828..0c762ffb8 100644 --- a/common/emu_constants.h +++ b/common/emu_constants.h @@ -792,4 +792,131 @@ namespace BookType { constexpr uint8 ItemInfo = 2; } +namespace PetButton { + constexpr uint8 Sit = 0; + constexpr uint8 Stop = 1; + constexpr uint8 Regroup = 2; + constexpr uint8 Follow = 3; + constexpr uint8 Guard = 4; + constexpr uint8 Taunt = 5; + constexpr uint8 Hold = 6; + constexpr uint8 GreaterHold = 7; + constexpr uint8 Focus = 8; + constexpr uint8 SpellHold = 9; +} + +namespace PetButtonState { + constexpr uint8 Off = 0; + constexpr uint8 On = 1; +} + +namespace PetCommand { + constexpr uint8 HealthReport = 0; // /pet health or Pet Window + constexpr uint8 Leader = 1; // /pet leader or Pet Window + constexpr uint8 Attack = 2; // /pet attack or Pet Window + constexpr uint8 QAttack = 3; // /pet qattack or Pet Window + constexpr uint8 FollowMe = 4; // /pet follow or Pet Window + constexpr uint8 GuardHere = 5; // /pet guard or Pet Window + constexpr uint8 Sit = 6; // /pet sit or Pet Window + constexpr uint8 SitDown = 7; // /pet sit on + constexpr uint8 StandUp = 8; // /pet sit off + constexpr uint8 Stop = 9; // /pet stop or Pet Window - Not implemented + constexpr uint8 StopOn = 10; // /pet stop on - Not implemented + constexpr uint8 StopOff = 11; // /pet stop off - Not implemented + constexpr uint8 Taunt = 12; // /pet taunt or Pet Window + constexpr uint8 TauntOn = 13; // /pet taunt on + constexpr uint8 TauntOff = 14; // /pet taunt off + constexpr uint8 Hold = 15; // /pet hold or Pet Window, won't add to hate list unless attacking + constexpr uint8 HoldOn = 16; // /pet hold on + constexpr uint8 HoldOff = 17; // /pet hold off + constexpr uint8 GreaterHold = 18; // /pet ghold, will never add to hate list unless told to + constexpr uint8 GreaterHoldOn = 19; // /pet ghold on + constexpr uint8 GreaterHoldOff = 20; // /pet ghold off + constexpr uint8 SpellHold = 21; // /pet no cast or /pet spellhold or Pet Window + constexpr uint8 SpellHoldOn = 22; // /pet spellhold on + constexpr uint8 SpellHoldOff = 23; // /pet spellhold off + constexpr uint8 Focus = 24; // /pet focus or Pet Window + constexpr uint8 FocusOn = 25; // /pet focus on + constexpr uint8 FocusOff = 26; // /pet focus off + constexpr uint8 Feign = 27; // /pet feign + constexpr uint8 BackOff = 28; // /pet back off + constexpr uint8 GetLost = 29; // /pet get lost + constexpr uint8 GuardMe = 30; // Same as /pet follow, but different message in older clients + constexpr uint8 Regroup = 31; // /pet regroup, acts like classic hold + constexpr uint8 RegroupOn = 32; // /pet regroup on + constexpr uint8 RegroupOff = 33; // /pet regroup off + constexpr uint8 Max = 34; + + static std::map pet_commands = { + { PetCommand::HealthReport, "Health Report" }, + { PetCommand::Leader, "Leader" }, + { PetCommand::Attack, "Attack" }, + { PetCommand::QAttack, "QAttack" }, + { PetCommand::FollowMe, "Follow Me" }, + { PetCommand::GuardHere, "Guard Here" }, + { PetCommand::Sit, "Sit" }, + { PetCommand::SitDown, "Sit Down" }, + { PetCommand::StandUp, "Stand Up" }, + { PetCommand::Stop, "Stop" }, + { PetCommand::StopOn, "Stop On" }, + { PetCommand::StopOff, "Stop Off" }, + { PetCommand::Taunt, "Taunt" }, + { PetCommand::TauntOn, "Taunt On" }, + { PetCommand::TauntOff, "Taunt Off" }, + { PetCommand::Hold, "Hold" }, + { PetCommand::HoldOn, "Hold On" }, + { PetCommand::HoldOff, "Hold Off" }, + { PetCommand::GreaterHold, "Greater Hold" }, + { PetCommand::GreaterHoldOn, "Greater Hold On" }, + { PetCommand::GreaterHoldOff, "Greater Hold Off" }, + { PetCommand::SpellHold, "Spell Hold" }, + { PetCommand::SpellHoldOn, "Spell Hold On" }, + { PetCommand::SpellHoldOff, "Spell Hold Off" }, + { PetCommand::Focus, "Focus" }, + { PetCommand::FocusOn, "Focus On" }, + { PetCommand::FocusOff, "Focus Off" }, + { PetCommand::Feign, "Feign" }, + { PetCommand::BackOff, "Back Off" }, + { PetCommand::GetLost, "Get Lost" }, + { PetCommand::GuardMe, "Guard Me" }, + { PetCommand::Regroup, "Regroup" }, + { PetCommand::RegroupOn, "Regroup On" }, + { PetCommand::RegroupOff, "Regroup Off" }, + { PetCommand::Max, "Max" } + }; + + std::string GetName(uint8 pet_command); + bool IsValid(uint8 pet_command); +} + +namespace PetOrder { + constexpr uint8 Follow = 0; + constexpr uint8 Sit = 1; + constexpr uint8 Guard = 2; + constexpr uint8 Feign = 3; +} + +namespace PetType { + constexpr uint8 Familiar = 0; + constexpr uint8 Animation = 1; + constexpr uint8 Normal = 2; + constexpr uint8 Charmed = 3; + constexpr uint8 Follow = 4; + constexpr uint8 TargetLock = 5; + constexpr uint8 None = 255; + + static std::map pet_types = { + { PetType::Familiar, "Familiar" }, + { PetType::Animation, "Animation" }, + { PetType::Normal, "Normal" }, + { PetType::Charmed, "Charmed" }, + { PetType::Follow, "Follow" }, + { PetType::TargetLock, "Target Lock" }, + { PetType::None, "None" } + }; + + std::string GetName(uint8 pet_type); + bool IsValid(uint8 pet_type); +} + #endif /*COMMON_EMU_CONSTANTS_H*/ diff --git a/common/eq_stream_intf.h b/common/eq_stream_intf.h index e2b7b21c7..5b2d24c82 100644 --- a/common/eq_stream_intf.h +++ b/common/eq_stream_intf.h @@ -6,7 +6,7 @@ #include #include "emu_versions.h" #include "eq_packet.h" -#include "net/daybreak_connection.h" +#include "net/reliable_stream_connection.h" typedef enum { ESTABLISHED, @@ -33,18 +33,18 @@ struct EQStreamManagerInterfaceOptions //Login I had trouble getting to recognize compression at all //but that might be because it was still a bit buggy when i was testing that. if (compressed) { - daybreak_options.encode_passes[0] = EQ::Net::EncodeCompression; + reliable_stream_options.encode_passes[0] = EQ::Net::EncodeCompression; } else if (encoded) { - daybreak_options.encode_passes[0] = EQ::Net::EncodeXOR; + reliable_stream_options.encode_passes[0] = EQ::Net::EncodeXOR; } - daybreak_options.port = port; + reliable_stream_options.port = port; } int opcode_size; bool track_opcode_stats; - EQ::Net::DaybreakConnectionManagerOptions daybreak_options; + EQ::Net::ReliableStreamConnectionManagerOptions reliable_stream_options; }; class EQStreamManagerInterface @@ -80,7 +80,7 @@ public: struct Stats { - EQ::Net::DaybreakConnectionStats DaybreakStats; + EQ::Net::ReliableStreamConnectionStats ReliableStreamStats; int RecvCount[_maxEmuOpcode]; int SentCount[_maxEmuOpcode]; }; diff --git a/common/net/eqstream.cpp b/common/net/eqstream.cpp index 0e3c671d7..633dea4c9 100644 --- a/common/net/eqstream.cpp +++ b/common/net/eqstream.cpp @@ -1,11 +1,11 @@ #include "eqstream.h" #include "../eqemu_logsys.h" -EQ::Net::EQStreamManager::EQStreamManager(const EQStreamManagerInterfaceOptions &options) : EQStreamManagerInterface(options), m_daybreak(options.daybreak_options) +EQ::Net::EQStreamManager::EQStreamManager(const EQStreamManagerInterfaceOptions &options) : EQStreamManagerInterface(options), m_reliable_stream(options.reliable_stream_options) { - m_daybreak.OnNewConnection(std::bind(&EQStreamManager::DaybreakNewConnection, this, std::placeholders::_1)); - m_daybreak.OnConnectionStateChange(std::bind(&EQStreamManager::DaybreakConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); - m_daybreak.OnPacketRecv(std::bind(&EQStreamManager::DaybreakPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); + m_reliable_stream.OnNewConnection(std::bind(&EQStreamManager::ReliableStreamNewConnection, this, std::placeholders::_1)); + m_reliable_stream.OnConnectionStateChange(std::bind(&EQStreamManager::ReliableStreamConnectionStateChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + m_reliable_stream.OnPacketRecv(std::bind(&EQStreamManager::ReliableStreamPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); } EQ::Net::EQStreamManager::~EQStreamManager() @@ -15,11 +15,11 @@ EQ::Net::EQStreamManager::~EQStreamManager() void EQ::Net::EQStreamManager::SetOptions(const EQStreamManagerInterfaceOptions &options) { m_options = options; - auto &opts = m_daybreak.GetOptions(); - opts = options.daybreak_options; + auto &opts = m_reliable_stream.GetOptions(); + opts = options.reliable_stream_options; } -void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr connection) +void EQ::Net::EQStreamManager::ReliableStreamNewConnection(std::shared_ptr connection) { std::shared_ptr stream(new EQStream(this, connection)); m_streams.emplace(std::make_pair(connection, stream)); @@ -28,7 +28,7 @@ void EQ::Net::EQStreamManager::DaybreakNewConnection(std::shared_ptr connection, DbProtocolStatus from, DbProtocolStatus to) +void EQ::Net::EQStreamManager::ReliableStreamConnectionStateChange(std::shared_ptr connection, DbProtocolStatus from, DbProtocolStatus to) { auto iter = m_streams.find(connection); if (iter != m_streams.end()) { @@ -42,7 +42,7 @@ void EQ::Net::EQStreamManager::DaybreakConnectionStateChange(std::shared_ptr connection, const Packet &p) +void EQ::Net::EQStreamManager::ReliableStreamPacketRecv(std::shared_ptr connection, const Packet &p) { auto iter = m_streams.find(connection); if (iter != m_streams.end()) { @@ -53,7 +53,7 @@ void EQ::Net::EQStreamManager::DaybreakPacketRecv(std::shared_ptr connection) +EQ::Net::EQStream::EQStream(EQStreamManagerInterface *owner, std::shared_ptr connection) { m_owner = owner; m_connection = connection; @@ -235,7 +235,7 @@ EQStreamState EQ::Net::EQStream::GetState() { EQ::Net::EQStream::Stats EQ::Net::EQStream::GetStats() const { Stats ret; - ret.DaybreakStats = m_connection->GetStats(); + ret.ReliableStreamStats = m_connection->GetStats(); for (int i = 0; i < _maxEmuOpcode; ++i) { ret.RecvCount[i] = 0; diff --git a/common/net/eqstream.h b/common/net/eqstream.h index a87c6ec0b..4a8e6ddd9 100644 --- a/common/net/eqstream.h +++ b/common/net/eqstream.h @@ -3,7 +3,7 @@ #include "../eq_packet.h" #include "../eq_stream_intf.h" #include "../opcodemgr.h" -#include "daybreak_connection.h" +#include "reliable_stream_connection.h" #include #include #include @@ -23,21 +23,21 @@ namespace EQ void OnNewConnection(std::function)> func) { m_on_new_connection = func; } void OnConnectionStateChange(std::function, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; } private: - DaybreakConnectionManager m_daybreak; + ReliableStreamConnectionManager m_reliable_stream; std::function)> m_on_new_connection; std::function, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change; - std::map, std::shared_ptr> m_streams; + std::map, std::shared_ptr> m_streams; - void DaybreakNewConnection(std::shared_ptr connection); - void DaybreakConnectionStateChange(std::shared_ptr connection, DbProtocolStatus from, DbProtocolStatus to); - void DaybreakPacketRecv(std::shared_ptr connection, const Packet &p); + void ReliableStreamNewConnection(std::shared_ptr connection); + void ReliableStreamConnectionStateChange(std::shared_ptr connection, DbProtocolStatus from, DbProtocolStatus to); + void ReliableStreamPacketRecv(std::shared_ptr connection, const Packet &p); friend class EQStream; }; class EQStream : public EQStreamInterface { public: - EQStream(EQStreamManagerInterface *parent, std::shared_ptr connection); + EQStream(EQStreamManagerInterface *parent, std::shared_ptr connection); ~EQStream(); virtual void QueuePacket(const EQApplicationPacket *p, bool ack_req = true); @@ -67,7 +67,7 @@ namespace EQ virtual EQStreamManagerInterface* GetManager() const; private: EQStreamManagerInterface *m_owner; - std::shared_ptr m_connection; + std::shared_ptr m_connection; OpcodeManager **m_opcode_manager; std::deque> m_packet_queue; std::unordered_map m_packet_recv_count; diff --git a/common/net/daybreak_connection.cpp b/common/net/reliable_stream_connection.cpp similarity index 82% rename from common/net/daybreak_connection.cpp rename to common/net/reliable_stream_connection.cpp index 9d40eadb8..e1101f452 100644 --- a/common/net/daybreak_connection.cpp +++ b/common/net/reliable_stream_connection.cpp @@ -1,4 +1,4 @@ -#include "daybreak_connection.h" +#include "reliable_stream_connection.h" #include "../event/event_loop.h" #include "../data_verification.h" #include "crc32.h" @@ -12,7 +12,7 @@ constexpr size_t MAX_CLIENT_RECV_BYTES_PER_WINDOW = 140 * 1024; // buffer pools SendBufferPool send_buffer_pool; -EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager() +EQ::Net::ReliableStreamConnectionManager::ReliableStreamConnectionManager() { m_attached = nullptr; memset(&m_timer, 0, sizeof(uv_timer_t)); @@ -21,7 +21,7 @@ EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager() Attach(EQ::EventLoop::Get().Handle()); } -EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager(const DaybreakConnectionManagerOptions &opts) +EQ::Net::ReliableStreamConnectionManager::ReliableStreamConnectionManager(const ReliableStreamConnectionManagerOptions &opts) { m_attached = nullptr; m_options = opts; @@ -31,12 +31,12 @@ EQ::Net::DaybreakConnectionManager::DaybreakConnectionManager(const DaybreakConn Attach(EQ::EventLoop::Get().Handle()); } -EQ::Net::DaybreakConnectionManager::~DaybreakConnectionManager() +EQ::Net::ReliableStreamConnectionManager::~ReliableStreamConnectionManager() { Detach(); } -void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop) +void EQ::Net::ReliableStreamConnectionManager::Attach(uv_loop_t *loop) { if (!m_attached) { uv_timer_init(loop, &m_timer); @@ -45,7 +45,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop) auto update_rate = (uint64_t)(1000.0 / m_options.tic_rate_hertz); uv_timer_start(&m_timer, [](uv_timer_t *handle) { - DaybreakConnectionManager *c = (DaybreakConnectionManager*)handle->data; + ReliableStreamConnectionManager *c = (ReliableStreamConnectionManager*)handle->data; c->UpdateDataBudget(); c->Process(); c->ProcessResend(); @@ -71,7 +71,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop) buf->len = 65536; }, [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { - DaybreakConnectionManager *c = (DaybreakConnectionManager*)handle->data; + ReliableStreamConnectionManager *c = (ReliableStreamConnectionManager*)handle->data; if (nread < 0 || addr == nullptr) { return; } @@ -90,7 +90,7 @@ void EQ::Net::DaybreakConnectionManager::Attach(uv_loop_t *loop) } } -void EQ::Net::DaybreakConnectionManager::Detach() +void EQ::Net::ReliableStreamConnectionManager::Detach() { if (m_attached) { uv_udp_recv_stop(&m_socket); @@ -99,11 +99,11 @@ void EQ::Net::DaybreakConnectionManager::Detach() } } -void EQ::Net::DaybreakConnectionManager::Connect(const std::string &addr, int port) +void EQ::Net::ReliableStreamConnectionManager::Connect(const std::string &addr, int port) { //todo dns resolution - auto connection = std::shared_ptr(new DaybreakConnection(this, addr, port)); + auto connection = std::shared_ptr(new ReliableStreamConnection(this, addr, port)); connection->m_self = connection; if (m_on_new_connection) { @@ -113,7 +113,7 @@ void EQ::Net::DaybreakConnectionManager::Connect(const std::string &addr, int po m_connections.emplace(std::make_pair(std::make_pair(addr, port), connection)); } -void EQ::Net::DaybreakConnectionManager::Process() +void EQ::Net::ReliableStreamConnectionManager::Process() { auto now = Clock::now(); auto iter = m_connections.begin(); @@ -177,7 +177,7 @@ void EQ::Net::DaybreakConnectionManager::Process() } } -void EQ::Net::DaybreakConnectionManager::UpdateDataBudget() +void EQ::Net::ReliableStreamConnectionManager::UpdateDataBudget() { auto outgoing_data_rate = m_options.outgoing_data_rate; if (outgoing_data_rate <= 0.0) { @@ -196,7 +196,7 @@ void EQ::Net::DaybreakConnectionManager::UpdateDataBudget() } } -void EQ::Net::DaybreakConnectionManager::ProcessResend() +void EQ::Net::ReliableStreamConnectionManager::ProcessResend() { auto iter = m_connections.begin(); while (iter != m_connections.end()) { @@ -217,15 +217,15 @@ void EQ::Net::DaybreakConnectionManager::ProcessResend() } } -void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size) +void EQ::Net::ReliableStreamConnectionManager::ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size) { if (m_options.simulated_in_packet_loss && m_options.simulated_in_packet_loss >= m_rand.Int(0, 100)) { return; } - if (size < DaybreakHeader::size()) { + if (size < ReliableStreamHeader::size()) { if (m_on_error_message) { - m_on_error_message(fmt::format("Packet of size {0} which is less than {1}", size, DaybreakHeader::size())); + m_on_error_message(fmt::format("Packet of size {0} which is less than {1}", size, ReliableStreamHeader::size())); } return; } @@ -239,9 +239,9 @@ void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoi else { if (data[0] == 0 && data[1] == OP_SessionRequest) { StaticPacket p((void*)data, size); - auto request = p.GetSerialize(0); + auto request = p.GetSerialize(0); - connection = std::shared_ptr(new DaybreakConnection(this, request, endpoint, port)); + connection = std::shared_ptr(new ReliableStreamConnection(this, request, endpoint, port)); connection->m_self = connection; if (m_on_new_connection) { @@ -262,7 +262,7 @@ void EQ::Net::DaybreakConnectionManager::ProcessPacket(const std::string &endpoi } } -std::shared_ptr EQ::Net::DaybreakConnectionManager::FindConnectionByEndpoint(std::string addr, int port) +std::shared_ptr EQ::Net::ReliableStreamConnectionManager::FindConnectionByEndpoint(std::string addr, int port) { auto p = std::make_pair(addr, port); auto iter = m_connections.find(p); @@ -273,9 +273,9 @@ std::shared_ptr EQ::Net::DaybreakConnectionManager: return nullptr; } -void EQ::Net::DaybreakConnectionManager::SendDisconnect(const std::string &addr, int port) +void EQ::Net::ReliableStreamConnectionManager::SendDisconnect(const std::string &addr, int port) { - DaybreakDisconnect header; + ReliableStreamDisconnect header; header.zero = 0; header.opcode = OP_OutOfSession; header.connect_code = 0; @@ -300,7 +300,7 @@ void EQ::Net::DaybreakConnectionManager::SendDisconnect(const std::string &addr, } //new connection made as server -EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner, const DaybreakConnect &connect, const std::string &endpoint, int port) +EQ::Net::ReliableStreamConnection::ReliableStreamConnection(ReliableStreamConnectionManager *owner, const ReliableStreamConnect &connect, const std::string &endpoint, int port) { m_owner = owner; m_last_send = Clock::now(); @@ -327,7 +327,7 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner } //new connection made as client -EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner, const std::string &endpoint, int port) +EQ::Net::ReliableStreamConnection::ReliableStreamConnection(ReliableStreamConnectionManager *owner, const std::string &endpoint, int port) { m_owner = owner; m_last_send = Clock::now(); @@ -349,11 +349,11 @@ EQ::Net::DaybreakConnection::DaybreakConnection(DaybreakConnectionManager *owner m_outgoing_budget = owner->m_options.outgoing_data_rate; } -EQ::Net::DaybreakConnection::~DaybreakConnection() +EQ::Net::ReliableStreamConnection::~ReliableStreamConnection() { } -void EQ::Net::DaybreakConnection::Close() +void EQ::Net::ReliableStreamConnection::Close() { if (m_status != StatusDisconnected && m_status != StatusDisconnecting) { FlushBuffer(); @@ -367,17 +367,17 @@ void EQ::Net::DaybreakConnection::Close() ChangeStatus(StatusDisconnecting); } -void EQ::Net::DaybreakConnection::QueuePacket(Packet &p) +void EQ::Net::ReliableStreamConnection::QueuePacket(Packet &p) { QueuePacket(p, 0, true); } -void EQ::Net::DaybreakConnection::QueuePacket(Packet &p, int stream) +void EQ::Net::ReliableStreamConnection::QueuePacket(Packet &p, int stream) { QueuePacket(p, stream, true); } -void EQ::Net::DaybreakConnection::QueuePacket(Packet &p, int stream, bool reliable) +void EQ::Net::ReliableStreamConnection::QueuePacket(Packet &p, int stream, bool reliable) { if (*(char*)p.Data() == 0) { DynamicPacket packet; @@ -390,21 +390,21 @@ void EQ::Net::DaybreakConnection::QueuePacket(Packet &p, int stream, bool reliab InternalQueuePacket(p, stream, reliable); } -EQ::Net::DaybreakConnectionStats EQ::Net::DaybreakConnection::GetStats() +EQ::Net::ReliableStreamConnectionStats EQ::Net::ReliableStreamConnection::GetStats() { - EQ::Net::DaybreakConnectionStats ret = m_stats; + EQ::Net::ReliableStreamConnectionStats ret = m_stats; ret.datarate_remaining = m_outgoing_budget; ret.avg_ping = m_rolling_ping; return ret; } -void EQ::Net::DaybreakConnection::ResetStats() +void EQ::Net::ReliableStreamConnection::ResetStats() { m_stats.Reset(); } -void EQ::Net::DaybreakConnection::Process() +void EQ::Net::ReliableStreamConnection::Process() { try { auto now = Clock::now(); @@ -422,7 +422,7 @@ void EQ::Net::DaybreakConnection::Process() } } -void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p) +void EQ::Net::ReliableStreamConnection::ProcessPacket(Packet &p) { m_last_recv = Clock::now(); m_stats.recv_packets++; @@ -458,13 +458,13 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p) switch (m_encode_passes[i]) { case EncodeCompression: if(temp.GetInt8(0) == 0) - Decompress(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size()); + Decompress(temp, ReliableStreamHeader::size(), temp.Length() - ReliableStreamHeader::size()); else Decompress(temp, 1, temp.Length() - 1); break; case EncodeXOR: if (temp.GetInt8(0) == 0) - Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size()); + Decode(temp, ReliableStreamHeader::size(), temp.Length() - ReliableStreamHeader::size()); else Decode(temp, 1, temp.Length() - 1); break; @@ -483,7 +483,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p) switch (m_encode_passes[i]) { case EncodeXOR: if (temp.GetInt8(0) == 0) - Decode(temp, DaybreakHeader::size(), temp.Length() - DaybreakHeader::size()); + Decode(temp, ReliableStreamHeader::size(), temp.Length() - ReliableStreamHeader::size()); else Decode(temp, 1, temp.Length() - 1); break; @@ -502,7 +502,7 @@ void EQ::Net::DaybreakConnection::ProcessPacket(Packet &p) } } -void EQ::Net::DaybreakConnection::ProcessQueue() +void EQ::Net::ReliableStreamConnection::ProcessQueue() { for (int i = 0; i < 4; ++i) { auto stream = &m_streams[i]; @@ -521,7 +521,7 @@ void EQ::Net::DaybreakConnection::ProcessQueue() } } -void EQ::Net::DaybreakConnection::RemoveFromQueue(int stream, uint16_t seq) +void EQ::Net::ReliableStreamConnection::RemoveFromQueue(int stream, uint16_t seq) { auto s = &m_streams[stream]; auto iter = s->packet_queue.find(seq); @@ -532,7 +532,7 @@ void EQ::Net::DaybreakConnection::RemoveFromQueue(int stream, uint16_t seq) } } -void EQ::Net::DaybreakConnection::AddToQueue(int stream, uint16_t seq, const Packet &p) +void EQ::Net::ReliableStreamConnection::AddToQueue(int stream, uint16_t seq, const Packet &p) { auto s = &m_streams[stream]; auto iter = s->packet_queue.find(seq); @@ -544,7 +544,7 @@ void EQ::Net::DaybreakConnection::AddToQueue(int stream, uint16_t seq, const Pac } } -void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) +void EQ::Net::ReliableStreamConnection::ProcessDecodedPacket(const Packet &p) { if (p.GetInt8(0) == 0) { if (p.Length() < 2) { @@ -628,13 +628,13 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_SessionRequest: { if (m_status == StatusConnected) { - auto request = p.GetSerialize(0); + auto request = p.GetSerialize(0); if (NetworkToHost(request.connect_code) != m_connect_code) { return; } - DaybreakConnectReply reply; + ReliableStreamConnectReply reply; reply.zero = 0; reply.opcode = OP_SessionResponse; reply.connect_code = HostToNetwork(m_connect_code); @@ -656,13 +656,13 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_SessionResponse: { if (m_status == StatusConnecting) { - auto reply = p.GetSerialize(0); + auto reply = p.GetSerialize(0); if (m_connect_code == reply.connect_code) { m_encode_key = reply.encode_key; m_crc_bytes = reply.crc_bytes; - m_encode_passes[0] = (DaybreakEncodeType)reply.encode_pass1; - m_encode_passes[1] = (DaybreakEncodeType)reply.encode_pass2; + m_encode_passes[0] = (ReliableStreamEncodeType)reply.encode_pass1; + m_encode_passes[1] = (ReliableStreamEncodeType)reply.encode_pass2; m_max_packet_size = reply.max_packet_size; ChangeStatus(StatusConnected); @@ -686,7 +686,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) return; } - auto header = p.GetSerialize(0); + auto header = p.GetSerialize(0); auto sequence = NetworkToHost(header.sequence); auto stream_id = header.opcode - OP_Packet; auto stream = &m_streams[stream_id]; @@ -703,7 +703,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) RemoveFromQueue(stream_id, sequence); SendAck(stream_id, stream->sequence_in); stream->sequence_in++; - StaticPacket next((char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size()); + StaticPacket next((char*)p.Data() + ReliableStreamReliableHeader::size(), p.Length() - ReliableStreamReliableHeader::size()); ProcessDecodedPacket(next); } @@ -715,7 +715,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_Fragment3: case OP_Fragment4: { - auto header = p.GetSerialize(0); + auto header = p.GetSerialize(0); auto sequence = NetworkToHost(header.sequence); auto stream_id = header.opcode - OP_Fragment; auto stream = &m_streams[stream_id]; @@ -735,22 +735,22 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) stream->sequence_in++; if (stream->fragment_total_bytes == 0) { - auto fragheader = p.GetSerialize(0); + auto fragheader = p.GetSerialize(0); stream->fragment_total_bytes = NetworkToHost(fragheader.total_size); stream->fragment_current_bytes = 0; stream->fragment_packet.Reserve(stream->fragment_total_bytes); stream->fragment_packet.PutData( stream->fragment_current_bytes, - (char*)p.Data() + DaybreakReliableFragmentHeader::size(), p.Length() - DaybreakReliableFragmentHeader::size()); + (char*)p.Data() + ReliableStreamReliableFragmentHeader::size(), p.Length() - ReliableStreamReliableFragmentHeader::size()); - stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableFragmentHeader::size()); + stream->fragment_current_bytes += (uint32_t)(p.Length() - ReliableStreamReliableFragmentHeader::size()); } else { stream->fragment_packet.PutData( stream->fragment_current_bytes, - (char*)p.Data() + DaybreakReliableHeader::size(), p.Length() - DaybreakReliableHeader::size()); + (char*)p.Data() + ReliableStreamReliableHeader::size(), p.Length() - ReliableStreamReliableHeader::size()); - stream->fragment_current_bytes += (uint32_t)(p.Length() - DaybreakReliableHeader::size()); + stream->fragment_current_bytes += (uint32_t)(p.Length() - ReliableStreamReliableHeader::size()); if (stream->fragment_current_bytes >= stream->fragment_total_bytes) { ProcessDecodedPacket(stream->fragment_packet); @@ -769,7 +769,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_Ack3: case OP_Ack4: { - auto header = p.GetSerialize(0); + auto header = p.GetSerialize(0); auto sequence = NetworkToHost(header.sequence); auto stream_id = header.opcode - OP_Ack; Ack(stream_id, sequence); @@ -781,7 +781,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) case OP_OutOfOrderAck3: case OP_OutOfOrderAck4: { - auto header = p.GetSerialize(0); + auto header = p.GetSerialize(0); auto sequence = NetworkToHost(header.sequence); auto stream_id = header.opcode - OP_OutOfOrderAck; OutOfOrderAck(stream_id, sequence); @@ -815,13 +815,13 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) } case OP_SessionStatRequest: { - auto request = p.GetSerialize(0); + auto request = p.GetSerialize(0); m_stats.sync_remote_sent_packets = EQ::Net::NetworkToHost(request.packets_sent); m_stats.sync_remote_recv_packets = EQ::Net::NetworkToHost(request.packets_recv); m_stats.sync_sent_packets = m_stats.sent_packets; m_stats.sync_recv_packets = m_stats.recv_packets; - DaybreakSessionStatResponse response; + ReliableStreamSessionStatResponse response; response.zero = 0; response.opcode = OP_SessionStatResponse; response.timestamp = request.timestamp; @@ -836,7 +836,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) break; } case OP_SessionStatResponse: { - auto response = p.GetSerialize(0); + auto response = p.GetSerialize(0); m_stats.sync_remote_sent_packets = EQ::Net::NetworkToHost(response.server_sent); m_stats.sync_remote_recv_packets = EQ::Net::NetworkToHost(response.server_recv); m_stats.sync_sent_packets = m_stats.sent_packets; @@ -858,7 +858,7 @@ void EQ::Net::DaybreakConnection::ProcessDecodedPacket(const Packet &p) } } -bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p) +bool EQ::Net::ReliableStreamConnection::ValidateCRC(Packet &p) { if (m_crc_bytes == 0U) { return true; @@ -892,7 +892,7 @@ bool EQ::Net::DaybreakConnection::ValidateCRC(Packet &p) return false; } -void EQ::Net::DaybreakConnection::AppendCRC(Packet &p) +void EQ::Net::ReliableStreamConnection::AppendCRC(Packet &p) { if (m_crc_bytes == 0U) { return; @@ -911,7 +911,7 @@ void EQ::Net::DaybreakConnection::AppendCRC(Packet &p) } } -void EQ::Net::DaybreakConnection::ChangeStatus(DbProtocolStatus new_status) +void EQ::Net::ReliableStreamConnection::ChangeStatus(DbProtocolStatus new_status) { if (m_owner->m_on_connection_state_change) { if (auto self = m_self.lock()) { @@ -922,7 +922,7 @@ void EQ::Net::DaybreakConnection::ChangeStatus(DbProtocolStatus new_status) m_status = new_status; } -bool EQ::Net::DaybreakConnection::PacketCanBeEncoded(Packet &p) const +bool EQ::Net::ReliableStreamConnection::PacketCanBeEncoded(Packet &p) const { if (p.Length() < 2) { return false; @@ -941,7 +941,7 @@ bool EQ::Net::DaybreakConnection::PacketCanBeEncoded(Packet &p) const return true; } -void EQ::Net::DaybreakConnection::Decode(Packet &p, size_t offset, size_t length) +void EQ::Net::ReliableStreamConnection::Decode(Packet &p, size_t offset, size_t length) { int key = m_encode_key; char *buffer = (char*)p.Data() + offset; @@ -961,7 +961,7 @@ void EQ::Net::DaybreakConnection::Decode(Packet &p, size_t offset, size_t length } } -void EQ::Net::DaybreakConnection::Encode(Packet &p, size_t offset, size_t length) +void EQ::Net::ReliableStreamConnection::Encode(Packet &p, size_t offset, size_t length) { int key = m_encode_key; char *buffer = (char*)p.Data() + offset; @@ -1050,7 +1050,7 @@ uint32_t Deflate(const uint8_t* in, uint32_t in_len, uint8_t* out, uint32_t out_ } } -void EQ::Net::DaybreakConnection::Decompress(Packet &p, size_t offset, size_t length) +void EQ::Net::ReliableStreamConnection::Decompress(Packet &p, size_t offset, size_t length) { if (length < 2) { return; @@ -1075,7 +1075,7 @@ void EQ::Net::DaybreakConnection::Decompress(Packet &p, size_t offset, size_t le p.PutData(offset, new_buffer, new_length); } -void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t length) +void EQ::Net::ReliableStreamConnection::Compress(Packet &p, size_t offset, size_t length) { static thread_local uint8_t new_buffer[2048] = { 0 }; uint8_t *buffer = (uint8_t*)p.Data() + offset; @@ -1097,14 +1097,14 @@ void EQ::Net::DaybreakConnection::Compress(Packet &p, size_t offset, size_t leng p.PutData(offset, new_buffer, new_length); } -void EQ::Net::DaybreakConnection::ProcessResend() +void EQ::Net::ReliableStreamConnection::ProcessResend() { for (int i = 0; i < 4; ++i) { ProcessResend(i); } } -void EQ::Net::DaybreakConnection::ProcessResend(int stream) +void EQ::Net::ReliableStreamConnection::ProcessResend(int stream) { if (m_status == DbProtocolStatus::StatusDisconnected) { return; @@ -1201,7 +1201,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream) auto &sp = e.second; auto &p = sp.packet; - if (p.Length() >= DaybreakHeader::size()) { + if (p.Length() >= ReliableStreamHeader::size()) { if (p.GetInt8(0) == 0 && p.GetInt8(1) >= OP_Fragment && p.GetInt8(1) <= OP_Fragment4) { m_stats.resent_fragments++; } @@ -1232,7 +1232,7 @@ void EQ::Net::DaybreakConnection::ProcessResend(int stream) m_last_ack = now; } -void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq) +void EQ::Net::ReliableStreamConnection::Ack(int stream, uint16_t seq) { auto now = Clock::now(); auto s = &m_streams[stream]; @@ -1259,7 +1259,7 @@ void EQ::Net::DaybreakConnection::Ack(int stream, uint16_t seq) m_last_ack = now; } -void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq) +void EQ::Net::ReliableStreamConnection::OutOfOrderAck(int stream, uint16_t seq) { auto now = Clock::now(); auto s = &m_streams[stream]; @@ -1279,15 +1279,15 @@ void EQ::Net::DaybreakConnection::OutOfOrderAck(int stream, uint16_t seq) m_last_ack = now; } -void EQ::Net::DaybreakConnection::UpdateDataBudget(double budget_add) +void EQ::Net::ReliableStreamConnection::UpdateDataBudget(double budget_add) { auto outgoing_data_rate = m_owner->m_options.outgoing_data_rate; m_outgoing_budget = EQ::ClampUpper(m_outgoing_budget + budget_add, outgoing_data_rate); } -void EQ::Net::DaybreakConnection::SendAck(int stream_id, uint16_t seq) +void EQ::Net::ReliableStreamConnection::SendAck(int stream_id, uint16_t seq) { - DaybreakReliableHeader ack; + ReliableStreamReliableHeader ack; ack.zero = 0; ack.opcode = OP_Ack + stream_id; ack.sequence = HostToNetwork(seq); @@ -1298,9 +1298,9 @@ void EQ::Net::DaybreakConnection::SendAck(int stream_id, uint16_t seq) InternalBufferedSend(p); } -void EQ::Net::DaybreakConnection::SendOutOfOrderAck(int stream_id, uint16_t seq) +void EQ::Net::ReliableStreamConnection::SendOutOfOrderAck(int stream_id, uint16_t seq) { - DaybreakReliableHeader ack; + ReliableStreamReliableHeader ack; ack.zero = 0; ack.opcode = OP_OutOfOrderAck + stream_id; ack.sequence = HostToNetwork(seq); @@ -1311,9 +1311,9 @@ void EQ::Net::DaybreakConnection::SendOutOfOrderAck(int stream_id, uint16_t seq) InternalBufferedSend(p); } -void EQ::Net::DaybreakConnection::SendDisconnect() +void EQ::Net::ReliableStreamConnection::SendDisconnect() { - DaybreakDisconnect disconnect; + ReliableStreamDisconnect disconnect; disconnect.zero = 0; disconnect.opcode = OP_SessionDisconnect; disconnect.connect_code = HostToNetwork(m_connect_code); @@ -1322,7 +1322,7 @@ void EQ::Net::DaybreakConnection::SendDisconnect() InternalSend(out); } -void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p) +void EQ::Net::ReliableStreamConnection::InternalBufferedSend(Packet &p) { if (p.Length() > 0xFFU) { FlushBuffer(); @@ -1331,7 +1331,7 @@ void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p) } //we could add this packet to a combined - size_t raw_size = DaybreakHeader::size() + (size_t)m_crc_bytes + m_buffered_packets_length + m_buffered_packets.size() + 1 + p.Length(); + size_t raw_size = ReliableStreamHeader::size() + (size_t)m_crc_bytes + m_buffered_packets_length + m_buffered_packets.size() + 1 + p.Length(); if (raw_size > m_max_packet_size) { FlushBuffer(); } @@ -1346,9 +1346,9 @@ void EQ::Net::DaybreakConnection::InternalBufferedSend(Packet &p) } } -void EQ::Net::DaybreakConnection::SendConnect() +void EQ::Net::ReliableStreamConnection::SendConnect() { - DaybreakConnect connect; + ReliableStreamConnect connect; connect.zero = 0; connect.opcode = OP_SessionRequest; connect.protocol_version = HostToNetwork(3U); @@ -1361,9 +1361,9 @@ void EQ::Net::DaybreakConnection::SendConnect() InternalSend(p); } -void EQ::Net::DaybreakConnection::SendKeepAlive() +void EQ::Net::ReliableStreamConnection::SendKeepAlive() { - DaybreakHeader keep_alive; + ReliableStreamHeader keep_alive; keep_alive.zero = 0; keep_alive.opcode = OP_KeepAlive; @@ -1373,7 +1373,7 @@ void EQ::Net::DaybreakConnection::SendKeepAlive() InternalSend(p); } -void EQ::Net::DaybreakConnection::InternalSend(Packet &p) { +void EQ::Net::ReliableStreamConnection::InternalSend(Packet &p) { if (m_owner->m_options.outgoing_data_rate > 0.0) { auto new_budget = m_outgoing_budget - (p.Length() / 1024.0); if (new_budget <= 0.0) { @@ -1409,14 +1409,14 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) { switch (m_encode_passe) { case EncodeCompression: if (out.GetInt8(0) == 0) { - Compress(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size()); + Compress(out, ReliableStreamHeader::size(), out.Length() - ReliableStreamHeader::size()); } else { Compress(out, 1, out.Length() - 1); } break; case EncodeXOR: if (out.GetInt8(0) == 0) { - Encode(out, DaybreakHeader::size(), out.Length() - DaybreakHeader::size()); + Encode(out, ReliableStreamHeader::size(), out.Length() - ReliableStreamHeader::size()); } else { Encode(out, 1, out.Length() - 1); } @@ -1466,7 +1466,7 @@ void EQ::Net::DaybreakConnection::InternalSend(Packet &p) { } } -void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, bool reliable) +void EQ::Net::ReliableStreamConnection::InternalQueuePacket(Packet &p, int stream_id, bool reliable) { if (!reliable) { auto max_raw_size = 0xFFU - m_crc_bytes; @@ -1480,23 +1480,23 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, } auto stream = &m_streams[stream_id]; - auto max_raw_size = m_max_packet_size - m_crc_bytes - DaybreakReliableHeader::size() - 1; // -1 for compress flag + auto max_raw_size = m_max_packet_size - m_crc_bytes - ReliableStreamReliableHeader::size() - 1; // -1 for compress flag size_t length = p.Length(); if (length > max_raw_size) { - DaybreakReliableFragmentHeader first_header; + ReliableStreamReliableFragmentHeader first_header; first_header.reliable.zero = 0; first_header.reliable.opcode = OP_Fragment + stream_id; first_header.reliable.sequence = HostToNetwork(stream->sequence_out); first_header.total_size = (uint32_t)HostToNetwork((uint32_t)length); size_t used = 0; - size_t sublen = m_max_packet_size - m_crc_bytes - DaybreakReliableFragmentHeader::size() - 1; // -1 for compress flag + size_t sublen = m_max_packet_size - m_crc_bytes - ReliableStreamReliableFragmentHeader::size() - 1; // -1 for compress flag DynamicPacket first_packet; first_packet.PutSerialize(0, first_header); - first_packet.PutData(DaybreakReliableFragmentHeader::size(), (char*)p.Data() + used, sublen); + first_packet.PutData(ReliableStreamReliableFragmentHeader::size(), (char*)p.Data() + used, sublen); used += sublen; - DaybreakSentPacket sent; + ReliableStreamSentPacket sent; sent.packet.PutPacket(0, first_packet); sent.last_sent = Clock::now(); sent.first_sent = Clock::now(); @@ -1513,22 +1513,22 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, while (used < length) { auto left = length - used; DynamicPacket packet; - DaybreakReliableHeader header; + ReliableStreamReliableHeader header; header.zero = 0; header.opcode = OP_Fragment + stream_id; header.sequence = HostToNetwork(stream->sequence_out); packet.PutSerialize(0, header); if (left > max_raw_size) { - packet.PutData(DaybreakReliableHeader::size(), (char*)p.Data() + used, max_raw_size); + packet.PutData(ReliableStreamReliableHeader::size(), (char*)p.Data() + used, max_raw_size); used += max_raw_size; } else { - packet.PutData(DaybreakReliableHeader::size(), (char*)p.Data() + used, left); + packet.PutData(ReliableStreamReliableHeader::size(), (char*)p.Data() + used, left); used += left; } - DaybreakSentPacket sent; + ReliableStreamSentPacket sent; sent.packet.PutPacket(0, packet); sent.last_sent = Clock::now(); sent.first_sent = Clock::now(); @@ -1545,14 +1545,14 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, } else { DynamicPacket packet; - DaybreakReliableHeader header; + ReliableStreamReliableHeader header; header.zero = 0; header.opcode = OP_Packet + stream_id; header.sequence = HostToNetwork(stream->sequence_out); packet.PutSerialize(0, header); - packet.PutPacket(DaybreakReliableHeader::size(), p); + packet.PutPacket(ReliableStreamReliableHeader::size(), p); - DaybreakSentPacket sent; + ReliableStreamSentPacket sent; sent.packet.PutPacket(0, packet); sent.last_sent = Clock::now(); sent.first_sent = Clock::now(); @@ -1568,7 +1568,7 @@ void EQ::Net::DaybreakConnection::InternalQueuePacket(Packet &p, int stream_id, } } -void EQ::Net::DaybreakConnection::FlushBuffer() +void EQ::Net::ReliableStreamConnection::FlushBuffer() { if (m_buffered_packets.empty()) { return; @@ -1595,7 +1595,7 @@ void EQ::Net::DaybreakConnection::FlushBuffer() m_buffered_packets_length = 0; } -EQ::Net::SequenceOrder EQ::Net::DaybreakConnection::CompareSequence(uint16_t expected, uint16_t actual) const +EQ::Net::SequenceOrder EQ::Net::ReliableStreamConnection::CompareSequence(uint16_t expected, uint16_t actual) const { int diff = (int)actual - (int)expected; diff --git a/common/net/daybreak_connection.h b/common/net/reliable_stream_connection.h similarity index 72% rename from common/net/daybreak_connection.h rename to common/net/reliable_stream_connection.h index 1fddc09c9..97e1982c7 100644 --- a/common/net/daybreak_connection.h +++ b/common/net/reliable_stream_connection.h @@ -2,8 +2,8 @@ #include "../random.h" #include "packet.h" -#include "daybreak_structs.h" -#include "daybreak_pooling.h" +#include "reliable_stream_structs.h" +#include "reliable_stream_pooling.h" #include #include #include @@ -16,7 +16,7 @@ namespace EQ { namespace Net { - enum DaybreakProtocolOpcode + enum ReliableStreamProtocolOpcode { OP_Padding = 0x00, OP_SessionRequest = 0x01, @@ -55,7 +55,7 @@ namespace EQ StatusDisconnected }; - enum DaybreakEncodeType + enum ReliableStreamEncodeType { EncodeNone = 0, EncodeCompression = 1, @@ -72,9 +72,9 @@ namespace EQ typedef std::chrono::steady_clock::time_point Timestamp; typedef std::chrono::steady_clock Clock; - struct DaybreakConnectionStats + struct ReliableStreamConnectionStats { - DaybreakConnectionStats() { + ReliableStreamConnectionStats() { recv_bytes = 0; sent_bytes = 0; recv_packets = 0; @@ -134,14 +134,14 @@ namespace EQ uint64_t bytes_before_encode; }; - class DaybreakConnectionManager; - class DaybreakConnection; - class DaybreakConnection + class ReliableStreamConnectionManager; + class ReliableStreamConnection; + class ReliableStreamConnection { public: - DaybreakConnection(DaybreakConnectionManager *owner, const DaybreakConnect &connect, const std::string &endpoint, int port); - DaybreakConnection(DaybreakConnectionManager *owner, const std::string &endpoint, int port); - ~DaybreakConnection(); + ReliableStreamConnection(ReliableStreamConnectionManager *owner, const ReliableStreamConnect &connect, const std::string &endpoint, int port); + ReliableStreamConnection(ReliableStreamConnectionManager *owner, const std::string &endpoint, int port); + ~ReliableStreamConnection(); const std::string& RemoteEndpoint() const { return m_endpoint; } int RemotePort() const { return m_port; } @@ -151,23 +151,23 @@ namespace EQ void QueuePacket(Packet &p, int stream); void QueuePacket(Packet &p, int stream, bool reliable); - DaybreakConnectionStats GetStats(); + ReliableStreamConnectionStats GetStats(); void ResetStats(); size_t GetRollingPing() const { return m_rolling_ping; } DbProtocolStatus GetStatus() const { return m_status; } - const DaybreakEncodeType* GetEncodePasses() const { return m_encode_passes; } - const DaybreakConnectionManager* GetManager() const { return m_owner; } - DaybreakConnectionManager* GetManager() { return m_owner; } + const ReliableStreamEncodeType* GetEncodePasses() const { return m_encode_passes; } + const ReliableStreamConnectionManager* GetManager() const { return m_owner; } + ReliableStreamConnectionManager* GetManager() { return m_owner; } private: - DaybreakConnectionManager *m_owner; + ReliableStreamConnectionManager *m_owner; std::string m_endpoint; int m_port; uint32_t m_connect_code; uint32_t m_encode_key; uint32_t m_max_packet_size; uint32_t m_crc_bytes; - DaybreakEncodeType m_encode_passes[2]; + ReliableStreamEncodeType m_encode_passes[2]; Timestamp m_last_send; Timestamp m_last_recv; @@ -176,7 +176,7 @@ namespace EQ std::list m_buffered_packets; size_t m_buffered_packets_length; std::unique_ptr m_combined; - DaybreakConnectionStats m_stats; + ReliableStreamConnectionStats m_stats; Timestamp m_last_session_stats; size_t m_rolling_ping; Timestamp m_close_time; @@ -188,7 +188,7 @@ namespace EQ bool m_acked_since_last_resend = false; Timestamp m_last_ack; - struct DaybreakSentPacket + struct ReliableStreamSentPacket { DynamicPacket packet; Timestamp last_sent; @@ -197,9 +197,9 @@ namespace EQ size_t resend_delay; }; - struct DaybreakStream + struct ReliableStream { - DaybreakStream() { + ReliableStream() { sequence_in = 0; sequence_out = 0; fragment_current_bytes = 0; @@ -214,11 +214,11 @@ namespace EQ uint32_t fragment_current_bytes; uint32_t fragment_total_bytes; - std::map sent_packets; + std::map sent_packets; }; - DaybreakStream m_streams[4]; - std::weak_ptr m_self; + ReliableStream m_streams[4]; + std::weak_ptr m_self; void Process(); void ProcessPacket(Packet &p); @@ -251,12 +251,12 @@ namespace EQ void FlushBuffer(); SequenceOrder CompareSequence(uint16_t expected, uint16_t actual) const; - friend class DaybreakConnectionManager; + friend class ReliableStreamConnectionManager; }; - struct DaybreakConnectionManagerOptions + struct ReliableStreamConnectionManagerOptions { - DaybreakConnectionManagerOptions() { + ReliableStreamConnectionManagerOptions() { max_connection_count = 0; keepalive_delay_ms = 9000; resend_delay_ms = 30; @@ -268,8 +268,8 @@ namespace EQ connect_stale_ms = 5000; crc_length = 2; max_packet_size = 512; - encode_passes[0] = DaybreakEncodeType::EncodeNone; - encode_passes[1] = DaybreakEncodeType::EncodeNone; + encode_passes[0] = ReliableStreamEncodeType::EncodeNone; + encode_passes[1] = ReliableStreamEncodeType::EncodeNone; port = 0; hold_size = 512; hold_length_ms = 50; @@ -299,28 +299,28 @@ namespace EQ double tic_rate_hertz; size_t resend_timeout; size_t connection_close_time; - DaybreakEncodeType encode_passes[2]; + ReliableStreamEncodeType encode_passes[2]; int port; double outgoing_data_rate; }; - class DaybreakConnectionManager + class ReliableStreamConnectionManager { public: - DaybreakConnectionManager(); - DaybreakConnectionManager(const DaybreakConnectionManagerOptions &opts); - ~DaybreakConnectionManager(); + ReliableStreamConnectionManager(); + ReliableStreamConnectionManager(const ReliableStreamConnectionManagerOptions &opts); + ~ReliableStreamConnectionManager(); void Connect(const std::string &addr, int port); void Process(); void UpdateDataBudget(); void ProcessResend(); - void OnNewConnection(std::function)> func) { m_on_new_connection = func; } - void OnConnectionStateChange(std::function, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; } - void OnPacketRecv(std::function, const Packet &)> func) { m_on_packet_recv = func; } + void OnNewConnection(std::function)> func) { m_on_new_connection = func; } + void OnConnectionStateChange(std::function, DbProtocolStatus, DbProtocolStatus)> func) { m_on_connection_state_change = func; } + void OnPacketRecv(std::function, const Packet &)> func) { m_on_packet_recv = func; } void OnErrorMessage(std::function func) { m_on_error_message = func; } - DaybreakConnectionManagerOptions& GetOptions() { return m_options; } + ReliableStreamConnectionManagerOptions& GetOptions() { return m_options; } private: void Attach(uv_loop_t *loop); void Detach(); @@ -329,18 +329,18 @@ namespace EQ uv_timer_t m_timer; uv_udp_t m_socket; uv_loop_t *m_attached; - DaybreakConnectionManagerOptions m_options; - std::function)> m_on_new_connection; - std::function, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change; - std::function, const Packet&)> m_on_packet_recv; + ReliableStreamConnectionManagerOptions m_options; + std::function)> m_on_new_connection; + std::function, DbProtocolStatus, DbProtocolStatus)> m_on_connection_state_change; + std::function, const Packet&)> m_on_packet_recv; std::function m_on_error_message; - std::map, std::shared_ptr> m_connections; + std::map, std::shared_ptr> m_connections; void ProcessPacket(const std::string &endpoint, int port, const char *data, size_t size); - std::shared_ptr FindConnectionByEndpoint(std::string addr, int port); + std::shared_ptr FindConnectionByEndpoint(std::string addr, int port); void SendDisconnect(const std::string &addr, int port); - friend class DaybreakConnection; + friend class ReliableStreamConnection; }; } } diff --git a/common/net/daybreak_pooling.h b/common/net/reliable_stream_pooling.h similarity index 100% rename from common/net/daybreak_pooling.h rename to common/net/reliable_stream_pooling.h diff --git a/common/net/daybreak_structs.h b/common/net/reliable_stream_structs.h similarity index 86% rename from common/net/daybreak_structs.h rename to common/net/reliable_stream_structs.h index 3047897b2..f48e1f9c3 100644 --- a/common/net/daybreak_structs.h +++ b/common/net/reliable_stream_structs.h @@ -8,7 +8,7 @@ namespace EQ { namespace Net { - struct DaybreakHeader + struct ReliableStreamHeader { static size_t size() { return 2; } uint8_t zero; @@ -22,7 +22,7 @@ namespace EQ } }; - struct DaybreakConnect + struct ReliableStreamConnect { static size_t size() { return 14; } uint8_t zero; @@ -42,7 +42,7 @@ namespace EQ } }; - struct DaybreakConnectReply + struct ReliableStreamConnectReply { static size_t size() { return 17; } uint8_t zero; @@ -68,7 +68,7 @@ namespace EQ } }; - struct DaybreakDisconnect + struct ReliableStreamDisconnect { static size_t size() { return 8; } uint8_t zero; @@ -84,7 +84,7 @@ namespace EQ } }; - struct DaybreakReliableHeader + struct ReliableStreamReliableHeader { static size_t size() { return 4; } uint8_t zero; @@ -100,10 +100,10 @@ namespace EQ } }; - struct DaybreakReliableFragmentHeader + struct ReliableStreamReliableFragmentHeader { - static size_t size() { return 4 + DaybreakReliableHeader::size(); } - DaybreakReliableHeader reliable; + static size_t size() { return 4 + ReliableStreamReliableHeader::size(); } + ReliableStreamReliableHeader reliable; uint32_t total_size; template @@ -114,7 +114,7 @@ namespace EQ } }; - struct DaybreakSessionStatRequest + struct ReliableStreamSessionStatRequest { static size_t size() { return 40; } uint8_t zero; @@ -144,7 +144,7 @@ namespace EQ } }; - struct DaybreakSessionStatResponse + struct ReliableStreamSessionStatResponse { static size_t size() { return 40; } uint8_t zero; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 19d93addb..c93b92581 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1059,7 +1059,7 @@ namespace Titanium OUT(spawnid); OUT_str(charname); - if (emu->race > 473) + if (emu->race > 474) eq->race = 1; else OUT(race); @@ -1840,7 +1840,7 @@ namespace Titanium emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; eq->Race[char_index] = emu_cse->Race; - if (eq->Race[char_index] > 473) + if (eq->Race[char_index] > 474) eq->Race[char_index] = 1; for (int index = 0; index < EQ::textures::materialCount; ++index) { @@ -2421,7 +2421,7 @@ namespace Titanium strcpy(eq->title, emu->title); // eq->unknown0274 = emu->unknown0274; eq->helm = emu->helm; - if (emu->race > 473) + if (emu->race > 474) eq->race = 1; else eq->race = emu->race; diff --git a/common/repositories/base/base_character_stats_record_repository.h b/common/repositories/base/base_character_stats_record_repository.h index d4bd8d041..aac41280a 100644 --- a/common/repositories/base/base_character_stats_record_repository.h +++ b/common/repositories/base/base_character_stats_record_repository.h @@ -70,6 +70,7 @@ public: int32_t endurance_regen; int32_t shielding; int32_t spell_damage; + int32_t heal_amount; int32_t spell_shielding; int32_t strikethrough; int32_t stun_resist; @@ -154,6 +155,7 @@ public: "endurance_regen", "shielding", "spell_damage", + "heal_amount", "spell_shielding", "strikethrough", "stun_resist", @@ -234,6 +236,7 @@ public: "endurance_regen", "shielding", "spell_damage", + "heal_amount", "spell_shielding", "strikethrough", "stun_resist", @@ -348,6 +351,7 @@ public: e.endurance_regen = 0; e.shielding = 0; e.spell_damage = 0; + e.heal_amount = 0; e.spell_shielding = 0; e.strikethrough = 0; e.stun_resist = 0; @@ -458,29 +462,30 @@ public: e.endurance_regen = row[48] ? static_cast(atoi(row[48])) : 0; e.shielding = row[49] ? static_cast(atoi(row[49])) : 0; e.spell_damage = row[50] ? static_cast(atoi(row[50])) : 0; - e.spell_shielding = row[51] ? static_cast(atoi(row[51])) : 0; - e.strikethrough = row[52] ? static_cast(atoi(row[52])) : 0; - e.stun_resist = row[53] ? static_cast(atoi(row[53])) : 0; - e.backstab = row[54] ? static_cast(atoi(row[54])) : 0; - e.wind = row[55] ? static_cast(atoi(row[55])) : 0; - e.brass = row[56] ? static_cast(atoi(row[56])) : 0; - e.string = row[57] ? static_cast(atoi(row[57])) : 0; - e.percussion = row[58] ? static_cast(atoi(row[58])) : 0; - e.singing = row[59] ? static_cast(atoi(row[59])) : 0; - e.baking = row[60] ? static_cast(atoi(row[60])) : 0; - e.alchemy = row[61] ? static_cast(atoi(row[61])) : 0; - e.tailoring = row[62] ? static_cast(atoi(row[62])) : 0; - e.blacksmithing = row[63] ? static_cast(atoi(row[63])) : 0; - e.fletching = row[64] ? static_cast(atoi(row[64])) : 0; - e.brewing = row[65] ? static_cast(atoi(row[65])) : 0; - e.jewelry = row[66] ? static_cast(atoi(row[66])) : 0; - e.pottery = row[67] ? static_cast(atoi(row[67])) : 0; - e.research = row[68] ? static_cast(atoi(row[68])) : 0; - e.alcohol = row[69] ? static_cast(atoi(row[69])) : 0; - e.fishing = row[70] ? static_cast(atoi(row[70])) : 0; - e.tinkering = row[71] ? static_cast(atoi(row[71])) : 0; - e.created_at = strtoll(row[72] ? row[72] : "-1", nullptr, 10); - e.updated_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); + e.heal_amount = row[51] ? static_cast(atoi(row[51])) : 0; + e.spell_shielding = row[52] ? static_cast(atoi(row[52])) : 0; + e.strikethrough = row[53] ? static_cast(atoi(row[53])) : 0; + e.stun_resist = row[54] ? static_cast(atoi(row[54])) : 0; + e.backstab = row[55] ? static_cast(atoi(row[55])) : 0; + e.wind = row[56] ? static_cast(atoi(row[56])) : 0; + e.brass = row[57] ? static_cast(atoi(row[57])) : 0; + e.string = row[58] ? static_cast(atoi(row[58])) : 0; + e.percussion = row[59] ? static_cast(atoi(row[59])) : 0; + e.singing = row[60] ? static_cast(atoi(row[60])) : 0; + e.baking = row[61] ? static_cast(atoi(row[61])) : 0; + e.alchemy = row[62] ? static_cast(atoi(row[62])) : 0; + e.tailoring = row[63] ? static_cast(atoi(row[63])) : 0; + e.blacksmithing = row[64] ? static_cast(atoi(row[64])) : 0; + e.fletching = row[65] ? static_cast(atoi(row[65])) : 0; + e.brewing = row[66] ? static_cast(atoi(row[66])) : 0; + e.jewelry = row[67] ? static_cast(atoi(row[67])) : 0; + e.pottery = row[68] ? static_cast(atoi(row[68])) : 0; + e.research = row[69] ? static_cast(atoi(row[69])) : 0; + e.alcohol = row[70] ? static_cast(atoi(row[70])) : 0; + e.fishing = row[71] ? static_cast(atoi(row[71])) : 0; + e.tinkering = row[72] ? static_cast(atoi(row[72])) : 0; + e.created_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); + e.updated_at = strtoll(row[74] ? row[74] : "-1", nullptr, 10); return e; } @@ -565,29 +570,30 @@ public: v.push_back(columns[48] + " = " + std::to_string(e.endurance_regen)); v.push_back(columns[49] + " = " + std::to_string(e.shielding)); v.push_back(columns[50] + " = " + std::to_string(e.spell_damage)); - v.push_back(columns[51] + " = " + std::to_string(e.spell_shielding)); - v.push_back(columns[52] + " = " + std::to_string(e.strikethrough)); - v.push_back(columns[53] + " = " + std::to_string(e.stun_resist)); - v.push_back(columns[54] + " = " + std::to_string(e.backstab)); - v.push_back(columns[55] + " = " + std::to_string(e.wind)); - v.push_back(columns[56] + " = " + std::to_string(e.brass)); - v.push_back(columns[57] + " = " + std::to_string(e.string)); - v.push_back(columns[58] + " = " + std::to_string(e.percussion)); - v.push_back(columns[59] + " = " + std::to_string(e.singing)); - v.push_back(columns[60] + " = " + std::to_string(e.baking)); - v.push_back(columns[61] + " = " + std::to_string(e.alchemy)); - v.push_back(columns[62] + " = " + std::to_string(e.tailoring)); - v.push_back(columns[63] + " = " + std::to_string(e.blacksmithing)); - v.push_back(columns[64] + " = " + std::to_string(e.fletching)); - v.push_back(columns[65] + " = " + std::to_string(e.brewing)); - v.push_back(columns[66] + " = " + std::to_string(e.jewelry)); - v.push_back(columns[67] + " = " + std::to_string(e.pottery)); - v.push_back(columns[68] + " = " + std::to_string(e.research)); - v.push_back(columns[69] + " = " + std::to_string(e.alcohol)); - v.push_back(columns[70] + " = " + std::to_string(e.fishing)); - v.push_back(columns[71] + " = " + std::to_string(e.tinkering)); - v.push_back(columns[72] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")"); - v.push_back(columns[73] + " = FROM_UNIXTIME(" + (e.updated_at > 0 ? std::to_string(e.updated_at) : "null") + ")"); + v.push_back(columns[51] + " = " + std::to_string(e.heal_amount)); + v.push_back(columns[52] + " = " + std::to_string(e.spell_shielding)); + v.push_back(columns[53] + " = " + std::to_string(e.strikethrough)); + v.push_back(columns[54] + " = " + std::to_string(e.stun_resist)); + v.push_back(columns[55] + " = " + std::to_string(e.backstab)); + v.push_back(columns[56] + " = " + std::to_string(e.wind)); + v.push_back(columns[57] + " = " + std::to_string(e.brass)); + v.push_back(columns[58] + " = " + std::to_string(e.string)); + v.push_back(columns[59] + " = " + std::to_string(e.percussion)); + v.push_back(columns[60] + " = " + std::to_string(e.singing)); + v.push_back(columns[61] + " = " + std::to_string(e.baking)); + v.push_back(columns[62] + " = " + std::to_string(e.alchemy)); + v.push_back(columns[63] + " = " + std::to_string(e.tailoring)); + v.push_back(columns[64] + " = " + std::to_string(e.blacksmithing)); + v.push_back(columns[65] + " = " + std::to_string(e.fletching)); + v.push_back(columns[66] + " = " + std::to_string(e.brewing)); + v.push_back(columns[67] + " = " + std::to_string(e.jewelry)); + v.push_back(columns[68] + " = " + std::to_string(e.pottery)); + v.push_back(columns[69] + " = " + std::to_string(e.research)); + v.push_back(columns[70] + " = " + std::to_string(e.alcohol)); + v.push_back(columns[71] + " = " + std::to_string(e.fishing)); + v.push_back(columns[72] + " = " + std::to_string(e.tinkering)); + v.push_back(columns[73] + " = FROM_UNIXTIME(" + (e.created_at > 0 ? std::to_string(e.created_at) : "null") + ")"); + v.push_back(columns[74] + " = FROM_UNIXTIME(" + (e.updated_at > 0 ? std::to_string(e.updated_at) : "null") + ")"); auto results = db.QueryDatabase( fmt::format( @@ -660,6 +666,7 @@ public: v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.spell_damage)); + v.push_back(std::to_string(e.heal_amount)); v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.stun_resist)); @@ -763,6 +770,7 @@ public: v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.spell_damage)); + v.push_back(std::to_string(e.heal_amount)); v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.stun_resist)); @@ -870,29 +878,30 @@ public: e.endurance_regen = row[48] ? static_cast(atoi(row[48])) : 0; e.shielding = row[49] ? static_cast(atoi(row[49])) : 0; e.spell_damage = row[50] ? static_cast(atoi(row[50])) : 0; - e.spell_shielding = row[51] ? static_cast(atoi(row[51])) : 0; - e.strikethrough = row[52] ? static_cast(atoi(row[52])) : 0; - e.stun_resist = row[53] ? static_cast(atoi(row[53])) : 0; - e.backstab = row[54] ? static_cast(atoi(row[54])) : 0; - e.wind = row[55] ? static_cast(atoi(row[55])) : 0; - e.brass = row[56] ? static_cast(atoi(row[56])) : 0; - e.string = row[57] ? static_cast(atoi(row[57])) : 0; - e.percussion = row[58] ? static_cast(atoi(row[58])) : 0; - e.singing = row[59] ? static_cast(atoi(row[59])) : 0; - e.baking = row[60] ? static_cast(atoi(row[60])) : 0; - e.alchemy = row[61] ? static_cast(atoi(row[61])) : 0; - e.tailoring = row[62] ? static_cast(atoi(row[62])) : 0; - e.blacksmithing = row[63] ? static_cast(atoi(row[63])) : 0; - e.fletching = row[64] ? static_cast(atoi(row[64])) : 0; - e.brewing = row[65] ? static_cast(atoi(row[65])) : 0; - e.jewelry = row[66] ? static_cast(atoi(row[66])) : 0; - e.pottery = row[67] ? static_cast(atoi(row[67])) : 0; - e.research = row[68] ? static_cast(atoi(row[68])) : 0; - e.alcohol = row[69] ? static_cast(atoi(row[69])) : 0; - e.fishing = row[70] ? static_cast(atoi(row[70])) : 0; - e.tinkering = row[71] ? static_cast(atoi(row[71])) : 0; - e.created_at = strtoll(row[72] ? row[72] : "-1", nullptr, 10); - e.updated_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); + e.heal_amount = row[51] ? static_cast(atoi(row[51])) : 0; + e.spell_shielding = row[52] ? static_cast(atoi(row[52])) : 0; + e.strikethrough = row[53] ? static_cast(atoi(row[53])) : 0; + e.stun_resist = row[54] ? static_cast(atoi(row[54])) : 0; + e.backstab = row[55] ? static_cast(atoi(row[55])) : 0; + e.wind = row[56] ? static_cast(atoi(row[56])) : 0; + e.brass = row[57] ? static_cast(atoi(row[57])) : 0; + e.string = row[58] ? static_cast(atoi(row[58])) : 0; + e.percussion = row[59] ? static_cast(atoi(row[59])) : 0; + e.singing = row[60] ? static_cast(atoi(row[60])) : 0; + e.baking = row[61] ? static_cast(atoi(row[61])) : 0; + e.alchemy = row[62] ? static_cast(atoi(row[62])) : 0; + e.tailoring = row[63] ? static_cast(atoi(row[63])) : 0; + e.blacksmithing = row[64] ? static_cast(atoi(row[64])) : 0; + e.fletching = row[65] ? static_cast(atoi(row[65])) : 0; + e.brewing = row[66] ? static_cast(atoi(row[66])) : 0; + e.jewelry = row[67] ? static_cast(atoi(row[67])) : 0; + e.pottery = row[68] ? static_cast(atoi(row[68])) : 0; + e.research = row[69] ? static_cast(atoi(row[69])) : 0; + e.alcohol = row[70] ? static_cast(atoi(row[70])) : 0; + e.fishing = row[71] ? static_cast(atoi(row[71])) : 0; + e.tinkering = row[72] ? static_cast(atoi(row[72])) : 0; + e.created_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); + e.updated_at = strtoll(row[74] ? row[74] : "-1", nullptr, 10); all_entries.push_back(e); } @@ -968,29 +977,30 @@ public: e.endurance_regen = row[48] ? static_cast(atoi(row[48])) : 0; e.shielding = row[49] ? static_cast(atoi(row[49])) : 0; e.spell_damage = row[50] ? static_cast(atoi(row[50])) : 0; - e.spell_shielding = row[51] ? static_cast(atoi(row[51])) : 0; - e.strikethrough = row[52] ? static_cast(atoi(row[52])) : 0; - e.stun_resist = row[53] ? static_cast(atoi(row[53])) : 0; - e.backstab = row[54] ? static_cast(atoi(row[54])) : 0; - e.wind = row[55] ? static_cast(atoi(row[55])) : 0; - e.brass = row[56] ? static_cast(atoi(row[56])) : 0; - e.string = row[57] ? static_cast(atoi(row[57])) : 0; - e.percussion = row[58] ? static_cast(atoi(row[58])) : 0; - e.singing = row[59] ? static_cast(atoi(row[59])) : 0; - e.baking = row[60] ? static_cast(atoi(row[60])) : 0; - e.alchemy = row[61] ? static_cast(atoi(row[61])) : 0; - e.tailoring = row[62] ? static_cast(atoi(row[62])) : 0; - e.blacksmithing = row[63] ? static_cast(atoi(row[63])) : 0; - e.fletching = row[64] ? static_cast(atoi(row[64])) : 0; - e.brewing = row[65] ? static_cast(atoi(row[65])) : 0; - e.jewelry = row[66] ? static_cast(atoi(row[66])) : 0; - e.pottery = row[67] ? static_cast(atoi(row[67])) : 0; - e.research = row[68] ? static_cast(atoi(row[68])) : 0; - e.alcohol = row[69] ? static_cast(atoi(row[69])) : 0; - e.fishing = row[70] ? static_cast(atoi(row[70])) : 0; - e.tinkering = row[71] ? static_cast(atoi(row[71])) : 0; - e.created_at = strtoll(row[72] ? row[72] : "-1", nullptr, 10); - e.updated_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); + e.heal_amount = row[51] ? static_cast(atoi(row[51])) : 0; + e.spell_shielding = row[52] ? static_cast(atoi(row[52])) : 0; + e.strikethrough = row[53] ? static_cast(atoi(row[53])) : 0; + e.stun_resist = row[54] ? static_cast(atoi(row[54])) : 0; + e.backstab = row[55] ? static_cast(atoi(row[55])) : 0; + e.wind = row[56] ? static_cast(atoi(row[56])) : 0; + e.brass = row[57] ? static_cast(atoi(row[57])) : 0; + e.string = row[58] ? static_cast(atoi(row[58])) : 0; + e.percussion = row[59] ? static_cast(atoi(row[59])) : 0; + e.singing = row[60] ? static_cast(atoi(row[60])) : 0; + e.baking = row[61] ? static_cast(atoi(row[61])) : 0; + e.alchemy = row[62] ? static_cast(atoi(row[62])) : 0; + e.tailoring = row[63] ? static_cast(atoi(row[63])) : 0; + e.blacksmithing = row[64] ? static_cast(atoi(row[64])) : 0; + e.fletching = row[65] ? static_cast(atoi(row[65])) : 0; + e.brewing = row[66] ? static_cast(atoi(row[66])) : 0; + e.jewelry = row[67] ? static_cast(atoi(row[67])) : 0; + e.pottery = row[68] ? static_cast(atoi(row[68])) : 0; + e.research = row[69] ? static_cast(atoi(row[69])) : 0; + e.alcohol = row[70] ? static_cast(atoi(row[70])) : 0; + e.fishing = row[71] ? static_cast(atoi(row[71])) : 0; + e.tinkering = row[72] ? static_cast(atoi(row[72])) : 0; + e.created_at = strtoll(row[73] ? row[73] : "-1", nullptr, 10); + e.updated_at = strtoll(row[74] ? row[74] : "-1", nullptr, 10); all_entries.push_back(e); } @@ -1116,6 +1126,7 @@ public: v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.spell_damage)); + v.push_back(std::to_string(e.heal_amount)); v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.stun_resist)); @@ -1212,6 +1223,7 @@ public: v.push_back(std::to_string(e.endurance_regen)); v.push_back(std::to_string(e.shielding)); v.push_back(std::to_string(e.spell_damage)); + v.push_back(std::to_string(e.heal_amount)); v.push_back(std::to_string(e.spell_shielding)); v.push_back(std::to_string(e.strikethrough)); v.push_back(std::to_string(e.stun_resist)); diff --git a/common/repositories/command_subsettings_repository.h b/common/repositories/command_subsettings_repository.h index 7faaf76b1..aa99d164a 100644 --- a/common/repositories/command_subsettings_repository.h +++ b/common/repositories/command_subsettings_repository.h @@ -49,6 +49,7 @@ public: // these are the base definitions for command_subsettings and can be over-ridden by the database std::vector static_records = { {.parent_command = "find", .sub_command = "aa", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaa"}, + {.parent_command = "find", .sub_command = "account", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findaccount"}, {.parent_command = "find", .sub_command = "body_type", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbodytype"}, {.parent_command = "find", .sub_command = "bug_category", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findbugcategory"}, {.parent_command = "find", .sub_command = "character", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "findcharacter"}, @@ -142,6 +143,7 @@ public: {.parent_command = "show", .sub_command = "hatelist", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "hatelist"}, {.parent_command = "show", .sub_command = "inventory", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "peekinv"}, {.parent_command = "show", .sub_command = "ip_lookup", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "iplookup"}, + {.parent_command = "show", .sub_command = "keyring", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "showkeyring"}, {.parent_command = "show", .sub_command = "line_of_sight", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "checklos"}, {.parent_command = "show", .sub_command = "network", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "network"}, {.parent_command = "show", .sub_command = "network_stats", .access_level = AccountStatus::QuestTroupe, .top_level_aliases = "netstats"}, diff --git a/common/spdat.h b/common/spdat.h index afc00f4dd..4cea6e098 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -1057,7 +1057,7 @@ typedef enum { } DmgShieldType; //Spell Effect IDs -// https://forums.daybreakgames.com/eq/index.php?threads/enumerated-spa-list.206288/ +// https://web.archive.org/web/20250816011656/https://forums.everquest.com/index.php?threads/enumerated-spa-list.206288/ // mirror: http://pastebin.com/MYeQqGwe #define SE_CurrentHP 0 // implemented - Heals and nukes, repeates every tic if in a buff #define SE_ArmorClass 1 // implemented diff --git a/common/strings.cpp b/common/strings.cpp index 52990aa85..eb56ab2f5 100644 --- a/common/strings.cpp +++ b/common/strings.cpp @@ -313,6 +313,12 @@ std::string Strings::Commify(const std::string &number) auto string_length = static_cast(number.length()); + if (string_length == 3) { + return number; + } else if (string_length == 4 && number.starts_with("-")) { + return number; + } + int i = 0; for (i = string_length - 3; i >= 0; i -= 3) { if (i > 0) { diff --git a/common/version.h b/common/version.h index 82382af86..bf8c83fba 100644 --- a/common/version.h +++ b/common/version.h @@ -25,7 +25,7 @@ // Build variables // these get injected during the build pipeline -#define CURRENT_VERSION "23.8.1-dev" // always append -dev to the current version for custom-builds +#define CURRENT_VERSION "23.9.1-dev" // always append -dev to the current version for custom-builds #define LOGIN_VERSION "0.8.0" #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ @@ -42,7 +42,7 @@ * Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9325 +#define CURRENT_BINARY_DATABASE_VERSION 9327 #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9054 #define CUSTOM_BINARY_DATABASE_VERSION 0 diff --git a/hc/eq.cpp b/hc/eq.cpp index aab481e82..d8f2877d8 100644 --- a/hc/eq.cpp +++ b/hc/eq.cpp @@ -33,7 +33,7 @@ EverQuest::EverQuest(const std::string &host, int port, const std::string &user, } else { m_host = addr; - m_login_connection_manager.reset(new EQ::Net::DaybreakConnectionManager()); + m_login_connection_manager.reset(new EQ::Net::ReliableStreamConnectionManager()); m_login_connection_manager->OnNewConnection(std::bind(&EverQuest::LoginOnNewConnection, this, std::placeholders::_1)); m_login_connection_manager->OnConnectionStateChange(std::bind(&EverQuest::LoginOnStatusChangeReconnectEnabled, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); @@ -48,13 +48,13 @@ EverQuest::~EverQuest() { } -void EverQuest::LoginOnNewConnection(std::shared_ptr connection) +void EverQuest::LoginOnNewConnection(std::shared_ptr connection) { m_login_connection = connection; Log.OutF(Logs::General, Logs::Headless_Client, "Connecting..."); } -void EverQuest::LoginOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void EverQuest::LoginOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusConnected) { Log.OutF(Logs::General, Logs::Headless_Client, "Login connected."); @@ -70,14 +70,14 @@ void EverQuest::LoginOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void EverQuest::LoginOnStatusChangeReconnectDisabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusDisconnected) { m_login_connection.reset(); } } -void EverQuest::LoginOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet & p) +void EverQuest::LoginOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet & p) { auto opcode = p.GetUInt16(0); switch (opcode) { @@ -251,20 +251,20 @@ void EverQuest::LoginDisableReconnect() void EverQuest::ConnectToWorld() { - m_world_connection_manager.reset(new EQ::Net::DaybreakConnectionManager()); + m_world_connection_manager.reset(new EQ::Net::ReliableStreamConnectionManager()); m_world_connection_manager->OnNewConnection(std::bind(&EverQuest::WorldOnNewConnection, this, std::placeholders::_1)); m_world_connection_manager->OnConnectionStateChange(std::bind(&EverQuest::WorldOnStatusChangeReconnectEnabled, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_world_connection_manager->OnPacketRecv(std::bind(&EverQuest::WorldOnPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); m_world_connection_manager->Connect(m_host, 9000); } -void EverQuest::WorldOnNewConnection(std::shared_ptr connection) +void EverQuest::WorldOnNewConnection(std::shared_ptr connection) { m_world_connection = connection; Log.OutF(Logs::General, Logs::Headless_Client, "Connecting to world..."); } -void EverQuest::WorldOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void EverQuest::WorldOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusConnected) { Log.OutF(Logs::General, Logs::Headless_Client, "World connected."); @@ -278,14 +278,14 @@ void EverQuest::WorldOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void EverQuest::WorldOnStatusChangeReconnectDisabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusDisconnected) { m_world_connection.reset(); } } -void EverQuest::WorldOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet & p) +void EverQuest::WorldOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet & p) { auto opcode = p.GetUInt16(0); switch (opcode) { diff --git a/hc/eq.h b/hc/eq.h index 7cdbfe1cd..63467b318 100644 --- a/hc/eq.h +++ b/hc/eq.h @@ -1,7 +1,7 @@ #pragma once #include "../common/eqemu_logsys.h" -#include "../common/net/daybreak_connection.h" +#include "../common/net/reliable_stream_connection.h" #include "../common/event/timer.h" #include #include @@ -26,10 +26,10 @@ public: private: //Login - void LoginOnNewConnection(std::shared_ptr connection); - void LoginOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void LoginOnStatusChangeReconnectDisabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void LoginOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); + void LoginOnNewConnection(std::shared_ptr connection); + void LoginOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void LoginOnStatusChangeReconnectDisabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void LoginOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); void LoginSendSessionReady(); void LoginSendLogin(); @@ -41,25 +41,25 @@ private: void LoginDisableReconnect(); - std::unique_ptr m_login_connection_manager; - std::shared_ptr m_login_connection; + std::unique_ptr m_login_connection_manager; + std::shared_ptr m_login_connection; std::map m_world_servers; //World void ConnectToWorld(); - void WorldOnNewConnection(std::shared_ptr connection); - void WorldOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void WorldOnStatusChangeReconnectDisabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void WorldOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); + void WorldOnNewConnection(std::shared_ptr connection); + void WorldOnStatusChangeReconnectEnabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void WorldOnStatusChangeReconnectDisabled(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void WorldOnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); void WorldSendClientAuth(); void WorldSendEnterWorld(const std::string &character); void WorldProcessCharacterSelect(const EQ::Net::Packet &p); - std::unique_ptr m_world_connection_manager; - std::shared_ptr m_world_connection; + std::unique_ptr m_world_connection_manager; + std::shared_ptr m_world_connection; //Variables std::string m_host; diff --git a/hc/login.cpp b/hc/login.cpp index 170a32bf7..f6dca7c78 100644 --- a/hc/login.cpp +++ b/hc/login.cpp @@ -26,7 +26,7 @@ LoginConnection::LoginConnection(const std::string &username, const std::string m_host_port = host_port; m_server = server; - m_connection_manager.reset(new EQ::Net::DaybreakConnectionManager()); + m_connection_manager.reset(new EQ::Net::ReliableStreamConnectionManager()); m_connection_manager->OnNewConnection(std::bind(&LoginConnection::OnNewConnection, this, std::placeholders::_1)); m_connection_manager->OnConnectionStateChange(std::bind(&LoginConnection::OnStatusChangeActive, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); @@ -39,13 +39,13 @@ LoginConnection::~LoginConnection() { } -void LoginConnection::OnNewConnection(std::shared_ptr connection) +void LoginConnection::OnNewConnection(std::shared_ptr connection) { m_connection = connection; Log.OutF(Logs::General, Logs::Headless_Client, "Connecting..."); } -void LoginConnection::OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void LoginConnection::OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusConnected) { Log.OutF(Logs::General, Logs::Headless_Client, "Login connected."); @@ -61,7 +61,7 @@ void LoginConnection::OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void LoginConnection::OnStatusChangeInactive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusDisconnected) { m_key.clear(); @@ -70,7 +70,7 @@ void LoginConnection::OnStatusChangeInactive(std::shared_ptr conn, const EQ::Net::Packet &p) +void LoginConnection::OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p) { auto opcode = p.GetUInt16(0); switch (opcode) { diff --git a/hc/login.h b/hc/login.h index 31a448b70..bec7c3cdd 100644 --- a/hc/login.h +++ b/hc/login.h @@ -1,6 +1,6 @@ #pragma once -#include "../common/net/daybreak_connection.h" +#include "../common/net/reliable_stream_connection.h" #include "../common/event/timer.h" #include @@ -23,10 +23,10 @@ public: ~LoginConnection(); private: - void OnNewConnection(std::shared_ptr connection); - void OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void OnStatusChangeInactive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); + void OnNewConnection(std::shared_ptr connection); + void OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void OnStatusChangeInactive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); void Kill(); void Start(); @@ -38,8 +38,8 @@ private: void ProcessServerPacketList(const EQ::Net::Packet &p); void ProcessServerPlayResponse(const EQ::Net::Packet &p); - std::unique_ptr m_connection_manager; - std::shared_ptr m_connection; + std::unique_ptr m_connection_manager; + std::shared_ptr m_connection; bool m_connecting; std::unique_ptr m_connect_timer; diff --git a/hc/world.cpp b/hc/world.cpp index 7be7cecb4..c9d690f62 100644 --- a/hc/world.cpp +++ b/hc/world.cpp @@ -8,7 +8,7 @@ WorldConnection::WorldConnection(const std::string &key, uint32_t dbid, const st m_key = key; m_dbid = dbid; - m_connection_manager.reset(new EQ::Net::DaybreakConnectionManager()); + m_connection_manager.reset(new EQ::Net::ReliableStreamConnectionManager()); m_connection_manager->OnNewConnection(std::bind(&WorldConnection::OnNewConnection, this, std::placeholders::_1)); m_connection_manager->OnConnectionStateChange(std::bind(&WorldConnection::OnStatusChangeActive, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); m_connection_manager->OnPacketRecv(std::bind(&WorldConnection::OnPacketRecv, this, std::placeholders::_1, std::placeholders::_2)); @@ -18,13 +18,13 @@ WorldConnection::WorldConnection(const std::string &key, uint32_t dbid, const st WorldConnection::~WorldConnection() { } -void WorldConnection::OnNewConnection(std::shared_ptr connection) +void WorldConnection::OnNewConnection(std::shared_ptr connection) { m_connection = connection; Log.OutF(Logs::General, Logs::Headless_Client, "Connecting to world..."); } -void WorldConnection::OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void WorldConnection::OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusConnected) { Log.OutF(Logs::General, Logs::Headless_Client, "World connected."); @@ -38,14 +38,14 @@ void WorldConnection::OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) +void WorldConnection::OnStatusChangeInactive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to) { if (to == EQ::Net::StatusDisconnected) { m_connection.reset(); } } -void WorldConnection::OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p) +void WorldConnection::OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p) { auto opcode = p.GetUInt16(0); Log.OutF(Logs::General, Logs::Headless_Client, "Packet in:\n{0}", p.ToString()); diff --git a/hc/world.h b/hc/world.h index 7ca0e96d7..b1df83894 100644 --- a/hc/world.h +++ b/hc/world.h @@ -1,6 +1,6 @@ #pragma once -#include "../common/net/daybreak_connection.h" +#include "../common/net/reliable_stream_connection.h" #include "../common/event/timer.h" #include @@ -10,17 +10,17 @@ public: WorldConnection(const std::string &key, uint32_t dbid, const std::string &host); ~WorldConnection(); private: - void OnNewConnection(std::shared_ptr connection); - void OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void OnStatusChangeInactive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); - void OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); + void OnNewConnection(std::shared_ptr connection); + void OnStatusChangeActive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void OnStatusChangeInactive(std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to); + void OnPacketRecv(std::shared_ptr conn, const EQ::Net::Packet &p); void Kill(); void Start(); void SendClientAuth(); - std::unique_ptr m_connection_manager; - std::shared_ptr m_connection; + std::unique_ptr m_connection_manager; + std::shared_ptr m_connection; bool m_connecting; std::unique_ptr m_connect_timer; diff --git a/loginserver/account_management.cpp b/loginserver/account_management.cpp index a76ae894b..f7c0ed535 100644 --- a/loginserver/account_management.cpp +++ b/loginserver/account_management.cpp @@ -124,18 +124,18 @@ uint64 AccountManagement::CheckExternalLoginserverUserCredentials(LoginAccountCo bool running = true; uint32 ret = 0; - EQ::Net::DaybreakConnectionManager mgr; - std::shared_ptr conn; + EQ::Net::ReliableStreamConnectionManager mgr; + std::shared_ptr conn; mgr.OnNewConnection( - [&](std::shared_ptr connection) { + [&](std::shared_ptr connection) { conn = connection; } ); mgr.OnConnectionStateChange( [&]( - std::shared_ptr conn, + std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to ) { @@ -152,7 +152,7 @@ uint64 AccountManagement::CheckExternalLoginserverUserCredentials(LoginAccountCo ); mgr.OnPacketRecv( - [&](std::shared_ptr conn, const EQ::Net::Packet &p) { + [&](std::shared_ptr conn, const EQ::Net::Packet &p) { auto opcode = p.GetUInt16(0); switch (opcode) { case 0x0017: //OP_ChatMessage @@ -250,18 +250,18 @@ uint64 AccountManagement::HealthCheckUserLogin() bool running = true; uint64 ret = 0; - EQ::Net::DaybreakConnectionManager mgr; - std::shared_ptr c; + EQ::Net::ReliableStreamConnectionManager mgr; + std::shared_ptr c; mgr.OnNewConnection( - [&](std::shared_ptr connection) { + [&](std::shared_ptr connection) { c = connection; } ); mgr.OnConnectionStateChange( [&]( - std::shared_ptr conn, + std::shared_ptr conn, EQ::Net::DbProtocolStatus from, EQ::Net::DbProtocolStatus to ) { @@ -278,7 +278,7 @@ uint64 AccountManagement::HealthCheckUserLogin() ); mgr.OnPacketRecv( - [&](std::shared_ptr conn, const EQ::Net::Packet &p) { + [&](std::shared_ptr conn, const EQ::Net::Packet &p) { auto opcode = p.GetUInt16(0); switch (opcode) { case 0x0017: //OP_ChatMessage diff --git a/loginserver/client.h b/loginserver/client.h index 5c62f2c83..0dc71d00c 100644 --- a/loginserver/client.h +++ b/loginserver/client.h @@ -6,7 +6,7 @@ #include "../common/random.h" #include "../common/eq_stream_intf.h" #include "../common/net/dns.h" -#include "../common/net/daybreak_connection.h" +#include "../common/net/reliable_stream_connection.h" #include "login_types.h" #include "../common/repositories/login_accounts_repository.h" #include @@ -54,8 +54,8 @@ private: unsigned int m_selected_play_server_id; unsigned int m_play_sequence_id; std::string m_key; - std::unique_ptr m_login_connection_manager; - std::shared_ptr m_login_connection; + std::unique_ptr m_login_connection_manager; + std::shared_ptr m_login_connection; LoginBaseMessage m_login_base_message; std::string m_stored_username; std::string m_stored_password; diff --git a/loginserver/options.h b/loginserver/options.h index 31976f142..73d6f6216 100644 --- a/loginserver/options.h +++ b/loginserver/options.h @@ -31,7 +31,7 @@ public: inline void DefaultLoginServerName(const std::string &v) { m_default_loginserver_name = v; } inline std::string GetDefaultLoginServerName() const { return m_default_loginserver_name; } inline bool IsShowPlayerCountEnabled() const { return m_show_player_count; } - inline void SetShowPlayerCount(bool show_player_count) { show_player_count = show_player_count; } + inline void SetShowPlayerCount(bool show_player_count) { m_show_player_count = show_player_count; } inline bool IsWorldDevTestServersListBottom() const { return m_world_dev_list_bottom; } inline void SetWorldDevTestServersListBottom(bool list_bottom) { m_world_dev_list_bottom = list_bottom; } inline bool IsWorldSpecialCharacterStartListBottom() const { return m_special_char_list_bottom; } diff --git a/loginserver/world_server.cpp b/loginserver/world_server.cpp index 1ff7b1492..44e6049d1 100644 --- a/loginserver/world_server.cpp +++ b/loginserver/world_server.cpp @@ -155,7 +155,11 @@ void WorldServer::ProcessUserToWorldResponseLegacy(uint16_t opcode, const EQ::Ne auto *res = (UsertoWorldResponseLegacy *) packet.Data(); LogDebug("Trying to find client with user id of [{}]", res->lsaccountid); - Client *c = server.client_manager->GetClient(res->lsaccountid, "eqemu"); + std::string db_loginserver = "local"; + if (std::getenv("LSPX")) { + db_loginserver = "eqemu"; + } + Client *c = server.client_manager->GetClient(res->lsaccountid, db_loginserver); if (c) { LogDebug( "Found client with user id of [{}] and account name of [{}]", diff --git a/package.json b/package.json index 05a5664fa..d148cc68b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eqemu-server", - "version": "23.8.1", + "version": "23.9.1", "repository": { "type": "git", "url": "https://github.com/EQEmu/Server.git" diff --git a/ucs/clientlist.cpp b/ucs/clientlist.cpp index 251fd8f05..749b9276f 100644 --- a/ucs/clientlist.cpp +++ b/ucs/clientlist.cpp @@ -469,11 +469,11 @@ static void ProcessCommandIgnore(Client *c, std::string Ignoree) { Clientlist::Clientlist(int ChatPort) { EQStreamManagerInterfaceOptions chat_opts(ChatPort, false, false); chat_opts.opcode_size = 1; - chat_opts.daybreak_options.stale_connection_ms = 600000; - chat_opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); - chat_opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); - chat_opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); - chat_opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); + chat_opts.reliable_stream_options.stale_connection_ms = 600000; + chat_opts.reliable_stream_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); + chat_opts.reliable_stream_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); + chat_opts.reliable_stream_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); + chat_opts.reliable_stream_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); chatsf = new EQ::Net::EQStreamManager(chat_opts); diff --git a/utils/scripts/build/should-release/go.mod b/utils/scripts/build/should-release/go.mod index eaa798134..df899a9e1 100644 --- a/utils/scripts/build/should-release/go.mod +++ b/utils/scripts/build/should-release/go.mod @@ -6,13 +6,10 @@ toolchain go1.23.5 require ( github.com/google/go-github/v41 v41.0.0 - golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be + golang.org/x/oauth2 v0.27.0 ) require ( - github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-querystring v1.1.0 // indirect golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.38.0 // indirect - google.golang.org/appengine v1.6.7 // indirect ) diff --git a/utils/scripts/build/should-release/go.sum b/utils/scripts/build/should-release/go.sum index 88fd4be02..d821c4071 100644 --- a/utils/scripts/build/should-release/go.sum +++ b/utils/scripts/build/should-release/go.sum @@ -1,9 +1,9 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -14,10 +14,9 @@ golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -27,5 +26,4 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/world/main.cpp b/world/main.cpp index 9ea0f26cb..c9386128e 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -333,11 +333,11 @@ int main(int argc, char **argv) WorldBoot::CheckForPossibleConfigurationIssues(); EQStreamManagerInterfaceOptions opts(9000, false, false); - opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); - opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); - opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); - opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); - opts.daybreak_options.outgoing_data_rate = RuleR(Network, ClientDataRate); + opts.reliable_stream_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); + opts.reliable_stream_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); + opts.reliable_stream_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); + opts.reliable_stream_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); + opts.reliable_stream_options.outgoing_data_rate = RuleR(Network, ClientDataRate); EQ::Net::EQStreamManager eqsm(opts); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 9501670fd..f47cdb608 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -901,9 +901,13 @@ bool WorldDatabase::GetCharSelInventory( inst->SetCustomDataString(e.custom_data); } - inst->SetOrnamentIcon(e.ornament_icon); - inst->SetOrnamentationIDFile(e.ornament_idfile); - inst->SetOrnamentHeroModel(e.ornament_hero_model); + if (e.ornament_icon != 0 || e.ornament_idfile != 0 || e.ornament_hero_model != 0) { + inst->SetOrnamentIcon(e.ornament_icon); + inst->SetOrnamentationIDFile(e.ornament_idfile); + inst->SetOrnamentHeroModel(e.ornament_hero_model); + } else if (item->HerosForgeModel > 0) { + inst->SetOrnamentHeroModel(item->HerosForgeModel); + } inv->PutItem(e.slot_id, *inst); diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index e497b5ed5..ffea99f78 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -502,7 +502,7 @@ if (EQEMU_BUILD_STATIC AND PERL_LIBRARY) endif() # link zone against common libraries -target_link_libraries(zone PRIVATE ${ZONE_LIBS} lua_zone perl_zone gm_commands_zone) +target_link_libraries(zone PRIVATE lua_zone perl_zone gm_commands_zone ${ZONE_LIBS}) SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) diff --git a/zone/api_service.cpp b/zone/api_service.cpp index 6f1c16d9d..607ab64c6 100644 --- a/zone/api_service.cpp +++ b/zone/api_service.cpp @@ -82,7 +82,7 @@ Json::Value ApiGetPacketStatistics(EQ::Net::WebsocketServerConnection *connectio auto connection = client->Connection(); auto opts = connection->GetManager()->GetOptions(); auto eqs_stats = connection->GetStats(); - auto &stats = eqs_stats.DaybreakStats; + auto &stats = eqs_stats.ReliableStreamStats; auto now = EQ::Net::Clock::now(); auto sec_since_stats_reset = std::chrono::duration_cast>( now - stats.created diff --git a/zone/attack.cpp b/zone/attack.cpp index e28eac7cc..5a26a9b8f 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -401,8 +401,8 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit) */ /* Order according to current (SoF+?) dev quotes: - * https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3261772 - * https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3268227 + * https://web.archive.org/web/20250816014133/https://forums.everquest.com/index.php?threads/test-update-06-10-15.223510/page-2#post-3261772 + * https://web.archive.org/web/20250816014133/https://forums.everquest.com/index.php?threads/test-update-06-10-15.223510/page-2#post-3268227 * Riposte 50, hDEX, must have weapon/fists, doesn't work on archery/throwing * Block 25, hDEX, works on archery/throwing, behind block done here if back to attacker base1 is chance * Parry 45, hDEX, doesn't work on throwing/archery, must be facing target @@ -461,7 +461,7 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit) } /* Heroic Strikethrough Implementation per Dev Quotes (2018): - * https://forums.daybreakgames.com/eq/index.php?threads/illusions-benefit-neza-10-dodge.246757/#post-3622670 + * https://web.archive.org/web/20250816014810/https://forums.everquest.com/index.php?threads/illusions-benefit-neza-10-dodge.246757/#post-3622670 * Step1 = HeroicStrikethrough(NPC) * Step2 = HeroicAgility / 25 * Step3 = MIN( Step1, Step2 ) @@ -3039,6 +3039,25 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy DispatchZoneControllerEvent(EVENT_DEATH_ZONE, owner_or_self, export_string, 0, &args); } + if (parse->ZoneHasQuestSub(EVENT_DEATH_ZONE)) { + const auto& export_string = fmt::format( + "{} {} {} {} {} {} {} {} {}", + killer_mob ? killer_mob->GetID() : 0, + damage, + spell, + static_cast(attack_skill), + entity_id, + m_combat_record.GetStartTime(), + m_combat_record.GetEndTime(), + m_combat_record.GetDamageReceived(), + m_combat_record.GetHealingReceived() + ); + + std::vector args = { corpse, this, owner_or_self }; + + parse->EventZone(EVENT_DEATH_ZONE, zone, export_string, 0, &args); + } + return true; } @@ -3395,7 +3414,7 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) { uint8 Mob::GetWeaponDamageBonus(const EQ::ItemData *weapon, bool offhand) { // dev quote with old and new formulas - // https://forums.daybreakgames.com/eq/index.php?threads/test-update-09-17-15.226618/page-5#post-3326194 + // https://web.archive.org/web/20250816013618/https://forums.everquest.com/index.php?threads/test-update-09-17-15.226618/page-5#post-3326194 // // We assume that the level check is done before calling this function and sinister strikes is checked before // calling for offhand DB @@ -4094,11 +4113,11 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons if (IsPet()) { Mob *owner = GetOwner(); if (owner && owner->IsClient()) { - if (GetPetOrder() == SPO_Sit) { + if (GetPetOrder() == PetOrder::Sit) { SetPetOrder(GetPreviousPetOrder()); } // fix GUI sit button to be unpressed and stop sitting regen - owner->CastToClient()->SetPetCommandState(PET_BUTTON_SIT, 0); + owner->CastToClient()->SetPetCommandState(PetButton::Sit, PetButtonState::Off); SetAppearance(eaStanding); } } @@ -4128,12 +4147,12 @@ void Mob::CommonDamage(Mob* attacker, int64 &damage, const uint16 spell_id, cons if (IsClient() && !pet->IsPetStop()) { // if pet was sitting his new mode is previous setting of // follow or guard after the battle (live verified) - if (pet->GetPetOrder() == SPO_Sit) { + if (pet->GetPetOrder() == PetOrder::Sit) { pet->SetPetOrder(pet->GetPreviousPetOrder()); } // fix GUI sit button to be unpressed and stop sitting regen - CastToClient()->SetPetCommandState(PET_BUTTON_SIT, 0); + CastToClient()->SetPetCommandState(PetButton::Sit, PetButtonState::Off); pet->SetAppearance(eaStanding); } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index d81c3ddf8..640e9ddd1 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1549,7 +1549,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) break; case SE_AddPetCommand: - if (base_value && limit_value < PET_MAXCOMMANDS) + if (base_value && limit_value < PetCommand::Max) newbon->PetCommands[limit_value] = true; break; @@ -1557,7 +1557,7 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) if (newbon->FeignedMinionChance < base_value) { newbon->FeignedMinionChance = base_value; } - newbon->PetCommands[PET_FEIGN] = true; + newbon->PetCommands[PetCommand::Feign] = true; break; case SE_AdditionalAura: diff --git a/zone/bot.cpp b/zone/bot.cpp index 7f1be1688..2716c88c6 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -99,7 +99,7 @@ Bot::Bot(NPCType *npcTypeData, Client* botOwner) : NPC(npcTypeData, nullptr, glm SetPullingFlag(false); SetReturningFlag(false); SetIsUsingItemClick(false); - m_previous_pet_order = SPO_Guard; + m_previous_pet_order = PetOrder::Guard; rest_timer.Disable(); m_ping_timer.Disable(); @@ -232,7 +232,7 @@ Bot::Bot( SetPullingFlag(false); SetReturningFlag(false); SetIsUsingItemClick(false); - m_previous_pet_order = SPO_Guard; + m_previous_pet_order = PetOrder::Guard; rest_timer.Disable(); m_ping_timer.Disable(); @@ -2313,7 +2313,7 @@ void Bot::AI_Process() bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } @@ -2569,7 +2569,7 @@ void Bot::DoOutOfCombatChecks(Client* bot_owner, Mob* follow_mob, float leash_di bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } } @@ -3198,7 +3198,7 @@ bool Bot::IsValidTarget( bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } } @@ -3233,7 +3233,7 @@ Mob* Bot::GetBotTarget(Client* bot_owner) bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } } @@ -3269,7 +3269,7 @@ bool Bot::ReturningFlagChecks(Client* bot_owner, Mob* leash_owner, float fm_dist bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); if (HasControllablePet(BotAnimEmpathy::BackOff)) { @@ -3313,7 +3313,7 @@ bool Bot::PullingFlagChecks(Client* bot_owner) { bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } @@ -3494,7 +3494,7 @@ Client* Bot::SetLeashOwner(Client* bot_owner, Group* bot_group, Raid* raid, uint void Bot::SetOwnerTarget(Client* bot_owner) { if (GetPet() && (PULLING_BOT || RETURNING_BOT)) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); } SetAttackFlag(false); @@ -3533,7 +3533,7 @@ void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) { bot_owner->SetBotPulling(false); if (GetPet()) { - GetPet()->SetPetOrder(SPO_Follow); + GetPet()->SetPetOrder(PetOrder::Follow); GetPet()->CastToNPC()->SaveGuardSpot(true); } @@ -3562,7 +3562,7 @@ void Bot::BotPullerProcess(Client* bot_owner, Raid* raid) { if (HasControllablePet(BotAnimEmpathy::Guard)) { m_previous_pet_order = GetPet()->GetPetOrder(); GetPet()->CastToNPC()->SaveGuardSpot(GetPosition()); - GetPet()->SetPetOrder(SPO_Guard); + GetPet()->SetPetOrder(PetOrder::Guard); } } } @@ -13456,6 +13456,6 @@ bool Bot::HasControllablePet(uint8 ranks_required) { } return GetClass() != Class::Enchanter || - GetPet()->GetPetType() != petAnimation || + GetPet()->GetPetType() != PetType::Animation || GetAA(aaAnimationEmpathy) >= ranks_required; } diff --git a/zone/client.cpp b/zone/client.cpp index f296f2729..2fa767d09 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -4780,9 +4780,21 @@ bool Client::KeyRingClear() ); } -void Client::KeyRingList() +void Client::KeyRingList(Client* c) { - Message(Chat::LightBlue, "Keys on Keyring:"); + if (!c) { + return; + } + + std::string message = "Keys on Keyring:"; + if (c != this) { + message = fmt::format( + "Keys on Keyring for {}:", + GetCleanName() + ); + } + + c->Message(Chat::LightBlue, message.c_str()); const EQ::ItemData *item = nullptr; @@ -4795,7 +4807,7 @@ void Client::KeyRingList() item->Name ); - Message(Chat::LightBlue, item_string.c_str()); + c->Message(Chat::LightBlue, item_string.c_str()); } } } @@ -6403,17 +6415,17 @@ void Client::SuspendMinion(int value) // TODO: These pet command states need to be synced ... // Will just fix them for now if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { - SetPetCommandState(PET_BUTTON_SIT, 0); - SetPetCommandState(PET_BUTTON_STOP, 0); - SetPetCommandState(PET_BUTTON_REGROUP, 0); - SetPetCommandState(PET_BUTTON_FOLLOW, 1); - SetPetCommandState(PET_BUTTON_GUARD, 0); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + SetPetCommandState(PetButton::Follow, PetButtonState::On); + SetPetCommandState(PetButton::Guard, PetButtonState::Off); // Taunt saved on client side for logging on with pet // In our db for when we zone. - SetPetCommandState(PET_BUTTON_HOLD, 0); - SetPetCommandState(PET_BUTTON_GHOLD, 0); - SetPetCommandState(PET_BUTTON_FOCUS, 0); - SetPetCommandState(PET_BUTTON_SPELLHOLD, 0); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + SetPetCommandState(PetButton::Focus, PetButtonState::Off); + SetPetCommandState(PetButton::SpellHold, PetButtonState::Off); } } else @@ -6894,9 +6906,9 @@ void Client::CheckLDoNHail(NPC* n) auto pet = GetPet(); if (pet) { - if (pet->GetPetType() == petCharmed) { + if (pet->GetPetType() == PetType::Charmed) { pet->BuffFadeByEffect(SE_Charm); - } else if (pet->GetPetType() == petNPCFollow) { + } else if (pet->GetPetType() == PetType::Follow) { pet->SetOwnerID(0); } else { pet->Depop(); @@ -9438,12 +9450,15 @@ void Client::ProcessAggroMeter() } } -void Client::SetPetCommandState(int button, int state) +void Client::SetPetCommandState(uint8 button, uint8 state) { auto app = new EQApplicationPacket(OP_PetCommandState, sizeof(PetCommandState_Struct)); - auto pcs = (PetCommandState_Struct *)app->pBuffer; - pcs->button_id = button; - pcs->state = state; + + auto s = (PetCommandState_Struct*) app->pBuffer; + + s->button_id = button; + s->state = state; + FastQueuePacket(&app); } diff --git a/zone/client.h b/zone/client.h index b75fb56f0..d5e8f3ef4 100644 --- a/zone/client.h +++ b/zone/client.h @@ -326,12 +326,13 @@ public: void TraderStartTrader(const EQApplicationPacket *app); // void TraderPriceUpdate(const EQApplicationPacket *app); uint8 WithCustomer(uint16 NewCustomer); + std::vector GetKeyRing() { return keyring; } void KeyRingLoad(); bool KeyRingAdd(uint32 item_id); bool KeyRingCheck(uint32 item_id); bool KeyRingClear(); bool KeyRingRemove(uint32 item_id); - void KeyRingList(); + void KeyRingList(Client* c = nullptr); bool IsNameChangeAllowed(); void InvokeChangeNameWindow(bool immediate = true); bool ClearNameChange(); @@ -523,7 +524,7 @@ public: inline const InspectMessage_Struct& GetInspectMessage() const { return m_inspect_message; } void ReloadExpansionProfileSetting(); - void SetPetCommandState(int button, int state); + void SetPetCommandState(uint8 button, uint8 state); bool AutoAttackEnabled() const { return auto_attack; } bool AutoFireEnabled() const { return auto_fire; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index a69a6b96e..1f273a191 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -795,6 +795,11 @@ void Client::CompleteConnect() parse->EventPlayer(EVENT_ENTER_ZONE, this, "", 0); } + if (parse->ZoneHasQuestSub(EVENT_ENTER_ZONE)) { + std::vector args = { this }; + parse->EventZone(EVENT_ENTER_ZONE, zone, "", 0, &args); + } + DeleteEntityVariable(SEE_BUFFS_FLAG); // the way that the client deals with positions during the initial spawn struct @@ -950,17 +955,17 @@ void Client::CompleteConnect() // TODO: load these states // We at least will set them to the correct state for now if (m_ClientVersionBit & EQ::versions::maskUFAndLater && GetPet()) { - SetPetCommandState(PET_BUTTON_SIT, 0); - SetPetCommandState(PET_BUTTON_STOP, 0); - SetPetCommandState(PET_BUTTON_REGROUP, 0); - SetPetCommandState(PET_BUTTON_FOLLOW, 1); - SetPetCommandState(PET_BUTTON_GUARD, 0); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + SetPetCommandState(PetButton::Follow, PetButtonState::On); + SetPetCommandState(PetButton::Guard, PetButtonState::Off); // Taunt saved on client side for logging on with pet // In our db for when we zone. - SetPetCommandState(PET_BUTTON_HOLD, 0); - SetPetCommandState(PET_BUTTON_GHOLD, 0); - SetPetCommandState(PET_BUTTON_FOCUS, 0); - SetPetCommandState(PET_BUTTON_SPELLHOLD, 0); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + SetPetCommandState(PetButton::Focus, PetButtonState::Off); + SetPetCommandState(PetButton::SpellHold, PetButtonState::Off); } database.LoadAuras(this); // this ends up spawning them so probably safer to load this later (here) @@ -4709,6 +4714,12 @@ void Client::Handle_OP_ClickDoor(const EQApplicationPacket *app) quest_return = parse->EventPlayer(EVENT_CLICK_DOOR, this, std::to_string(cd->doorid), 0, &args); } + if (parse->ZoneHasQuestSub(EVENT_CLICK_DOOR)) { + std::vector args = { currentdoor, this }; + + quest_return = parse->EventZone(EVENT_CLICK_DOOR, zone, std::to_string(cd->doorid), 0, &args); + } + if (quest_return == 0) { currentdoor->HandleClick(this, 0); } @@ -4741,6 +4752,11 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app) parse->EventPlayer(EVENT_CLICK_OBJECT, this, std::to_string(click_object->drop_id), GetID(), &args); } + if (parse->ZoneHasQuestSub(EVENT_CLICK_OBJECT)) { + std::vector args = { object, this }; + parse->EventZone(EVENT_CLICK_OBJECT, zone, std::to_string(click_object->drop_id), GetID(), &args); + } + if (IsDevToolsEnabled()) { SetObjectToolEntityId(entity->GetID()); ObjectManipulation::CommandHeader(this); @@ -4967,9 +4983,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { m_Proximity = glm::vec3(cx, cy, cz); } - /* Update internal state */ - m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); - if (RuleB(Skills, TrackingAutoRefreshSkillUps) && IsTracking() && ((m_Position.x != cx) || (m_Position.y != cy))) { if (zone->random.Real(0, 100) < 70)//should be good CheckIncreaseSkill(EQ::skills::SkillTracking, nullptr, -20); @@ -5003,6 +5016,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { rewind_timer.Start(30000, true); } + glm::vec4 prevDelta = m_Delta; // SetMoving clears m_Delta SetMoving(!(cy == m_Position.y && cx == m_Position.x)); if (RuleB(Character, EnableAutoAFK)) { @@ -5017,12 +5031,13 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { CheckSendBulkNpcPositions(); - int32 new_animation = ppu->animation; - /* Update internal server position from what the client has sent */ - m_Position.x = cx; - m_Position.y = cy; - m_Position.z = cz; + glm::vec4 prevPosition = m_Position; + m_Position = glm::vec4(cx, cy, cz, new_heading); + m_Delta = glm::vec4(ppu->delta_x, ppu->delta_y, ppu->delta_z, EQ10toFloat(ppu->delta_heading)); + int32 prevAnimation = ppu->animation; + animation = ppu->animation; + bool positionUpdated = m_Position != prevPosition || m_Delta != prevDelta || m_Delta != glm::vec4(0.0f) || prevAnimation != animation; /* Visual Debugging */ if (RuleB(Character, OPClientUpdateVisualDebug)) { @@ -5032,11 +5047,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { } /* Only feed real time updates when client is moving */ - if (IsMoving() || new_heading != m_Position.w || new_animation != animation) { - - animation = ppu->animation; - m_Position.w = new_heading; - + if (positionUpdated) { /* Broadcast update to other clients */ static EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct)); PlayerPositionUpdateServer_Struct *position_update = (PlayerPositionUpdateServer_Struct *) outapp.pBuffer; @@ -5049,7 +5060,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { entity_list.QueueCloseClients(this, &outapp, true, RuleI(Range, ClientPositionUpdates), nullptr, true); } - /* Always send position updates to group - send when beyond normal ClientPositionUpdate range */ Group *group = GetGroup(); Raid *raid = GetRaid(); @@ -5075,7 +5085,6 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app) { } CheckVirtualZoneLines(); - } void Client::Handle_OP_CombatAbility(const EQApplicationPacket *app) @@ -9773,7 +9782,7 @@ void Client::Handle_OP_Jump(const EQApplicationPacket *app) void Client::Handle_OP_KeyRing(const EQApplicationPacket *app) { - KeyRingList(); + KeyRingList(this); } void Client::Handle_OP_KickPlayers(const EQApplicationPacket *app) @@ -11064,661 +11073,913 @@ void Client::Handle_OP_PDeletePetition(const EQApplicationPacket *app) return; } + void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) { if (app->size != sizeof(PetCommand_Struct)) { LogError("Wrong size: OP_PetCommands, size=[{}], expected [{}]", app->size, sizeof(PetCommand_Struct)); return; } - char val1[20] = { 0 }; - PetCommand_Struct* pet = (PetCommand_Struct*)app->pBuffer; - Mob* mypet = GetPet(); - Mob *target = entity_list.GetMob(pet->target); - if (!mypet || pet->command == PET_LEADER) { - if (pet->command == PET_LEADER) { + auto* s = (PetCommand_Struct*) app->pBuffer; + + char val1[20] = { 0 }; + + Mob* pet = GetPet(); + Mob* t = entity_list.GetMob(s->target); + + if (!pet || s->command == PetCommand::Leader) { + if (s->command == PetCommand::Leader) { // we either send the ID of an NPC we're interested in or no ID for our own pet - if (target) { - auto owner = target->GetOwner(); - if (owner) - target->SayString(PET_LEADERIS, owner->GetCleanName()); - else - target->SayString(I_FOLLOW_NOONE); - } else if (mypet) { - mypet->SayString(PET_LEADERIS, GetName()); + if (t) { + Mob* owner = t->GetOwner(); + if (owner) { + t->SayString(PET_LEADERIS, owner->GetCleanName()); + } else { + t->SayString(I_FOLLOW_NOONE); + } + } else if (pet) { + pet->SayString(PET_LEADERIS, GetName()); } } return; } - if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST)) + if (!pet->IsNPC()) { return; + } + + if ( + pet->GetPetType() == PetType::TargetLock && + s->command != PetCommand::HealthReport && + s->command != PetCommand::GetLost + ) { + return; + } // just let the command "/pet get lost" work for familiars - if (mypet->GetPetType() == petFamiliar && pet->command != PET_GETLOST) + if (pet->GetPetType() == PetType::Familiar && s->command != PetCommand::GetLost) { return; - - uint32 PetCommand = pet->command; - - // Handle Sit/Stand toggle in UF and later. - /* - if (GetClientVersion() >= EQClientUnderfoot) - { - if (PetCommand == PET_SITDOWN) - if (mypet->GetPetOrder() == SPO_Sit) - PetCommand = PET_STANDUP; } - */ - switch (PetCommand) - { - case PET_ATTACK: { - if (!target) - break; + const bool can_use_command = ( + (pet->GetPetType() == PetType::Animation && aabonuses.PetCommands[s->command]) || + pet->GetPetType() != PetType::Animation + ); - if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(target)) { - mypet->SayString(this, NOT_LEGAL_TARGET); - break; - } - - if (target->IsMezzed()) { - MessageString(Chat::NPCQuestSay, CANNOT_WAKE, mypet->GetCleanName(), target->GetCleanName()); - break; - } - - if (mypet->IsFeared()) - break; //prevent pet from attacking stuff while feared - - if (!mypet->IsAttackAllowed(target)) { - mypet->SayString(this, NOT_LEGAL_TARGET); - break; - } - - // default range is 200, takes Z into account - // really they do something weird where they're added to the aggro list then remove them - // and will attack if they come in range -- too lazy, lets remove exploits for now - if (DistanceSquared(mypet->GetPosition(), target->GetPosition()) >= RuleR(Aggro, PetAttackRange)) { - // they say they're attacking then remove on live ... so they don't really say anything in this case ... - break; - } - - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (target != this && DistanceSquared(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { - mypet->SetFeigned(false); - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); - } - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - SetPetCommandState(PET_BUTTON_REGROUP, 0); - } - - // fix GUI sit button to be unpressed and stop sitting regen - SetPetCommandState(PET_BUTTON_SIT, 0); - if (mypet->GetPetOrder() == SPO_Sit || mypet->GetPetOrder() == SPO_FeignDeath) { - mypet->SetPetOrder(mypet->GetPreviousPetOrder()); - mypet->SetAppearance(eaStanding); - } - - zone->AddAggroMob(); - // classic acts like qattack - int hate = 1; - if (mypet->IsEngaged()) { - auto top = mypet->GetHateMost(); - if (top && top != target) - hate += mypet->GetHateAmount(top) - mypet->GetHateAmount(target) + 100; // should be enough to cause target change - } - mypet->AddToHateList(target, hate, 0, true, false, false, SPELL_UNKNOWN, true); - MessageString(Chat::PetResponse, PET_ATTACKING, mypet->GetCleanName(), target->GetCleanName()); - SetTarget(target); + switch (s->command) { + case PetCommand::Attack: { + if ( + !t || + pet->IsFeared() || + !can_use_command || + t == this || + !( + DistanceSquaredNoZ(pet->GetPosition(), GetTarget()->GetPosition()) <= + (RuleR(Pets, AttackCommandRange) * RuleR(Pets, AttackCommandRange)) + ) || + DistanceSquared(pet->GetPosition(), t->GetPosition()) >= RuleR(Aggro, PetAttackRange) + ) { + break; } - } - break; - } - case PET_QATTACK: { - if (mypet->IsFeared()) - break; //prevent pet from attacking stuff while feared - if (!GetTarget()) { - break; - } - - if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(GetTarget())) { - mypet->SayString(this, NOT_LEGAL_TARGET); - break; - } - - if (GetTarget()->IsMezzed()) { - MessageString(Chat::NPCQuestSay, CANNOT_WAKE, mypet->GetCleanName(), GetTarget()->GetCleanName()); - break; - } - - if (!mypet->IsAttackAllowed(GetTarget())) { - mypet->SayString(this, NOT_LEGAL_TARGET); - break; - } - - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { - mypet->SetFeigned(false); - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); - } - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - SetPetCommandState(PET_BUTTON_REGROUP, 0); - } - - // fix GUI sit button to be unpressed and stop sitting regen - SetPetCommandState(PET_BUTTON_SIT, 0); - if (mypet->GetPetOrder() == SPO_Sit || mypet->GetPetOrder() == SPO_FeignDeath) { - mypet->SetPetOrder(mypet->GetPreviousPetOrder()); - mypet->SetAppearance(eaStanding); - } - - zone->AddAggroMob(); - mypet->AddToHateList(GetTarget(), 1, 0, true, false, false, SPELL_UNKNOWN, true); - MessageString(Chat::PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); + if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(t)) { + pet->SayString(this, NOT_LEGAL_TARGET); + break; } - } - break; - } - case PET_BACKOFF: { - if (mypet->IsFeared()) break; //keeps pet running while feared - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SayString(this, Chat::PetResponse, PET_CALMING); - mypet->WipeHateList(); - mypet->SetTarget(nullptr); - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); + if (t->IsMezzed()) { + MessageString(Chat::NPCQuestSay, CANNOT_WAKE, pet->GetCleanName(), t->GetCleanName()); + break; } - } - break; - } - case PET_HEALTHREPORT: { - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - MessageString(Chat::PetResponse, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1)); - mypet->ShowBuffs(this); - } - break; - } - case PET_GETLOST: { - if (mypet->Charmed()) - break; - if (mypet->GetPetType() == petCharmed || !mypet->IsNPC()) { - // eqlive ignores this command - // we could just remove the charm - // and continue - mypet->BuffFadeByEffect(SE_Charm); - break; - } - else { - SetPet(nullptr); - } - mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - mypet->CastToNPC()->Depop(); + if (!pet->IsAttackAllowed(t)) { + pet->SayString(this, NOT_LEGAL_TARGET); + break; + } - //Oddly, the client (Titanium) will still allow "/pet get lost" command despite me adding the code below. If someone can figure that out, you can uncomment this code and use it. - /* - if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 2) || mypet->GetPetType() != petAnimation) { - mypet->SayString(PET_GETLOST_STRING); - mypet->CastToNPC()->Depop(); - } - */ + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; - break; - } - case PET_GUARDHERE: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (mypet->IsNPC()) { + pet->SetFeigned(false); - // Set Sit button to unpressed - send stand anim/end hpregen - mypet->SetFeigned(false); - SetPetCommandState(PET_BUTTON_SIT, 0); - mypet->SetAppearance(eaStanding); + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } - mypet->SayString(this, Chat::PetResponse, PET_GUARDINGLIFE); - mypet->SetPetOrder(SPO_Guard); - mypet->CastToNPC()->SaveGuardSpot(mypet->GetPosition()); - if (!mypet->GetTarget()) // want them to not twitch if they're chasing something down - mypet->StopNavigation(); - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); + if (pet->IsPetRegroup()) { + pet->SetPetRegroup(false); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + } + + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + + if (pet->GetPetOrder() == PetOrder::Sit || pet->GetPetOrder() == PetOrder::Feign) { + pet->SetPetOrder(pet->GetPreviousPetOrder()); + pet->SetAppearance(eaStanding); + } + + zone->AddAggroMob(); + + int hate = 1; // classic acts like qattack + if (pet->IsEngaged()) { + Mob* top = pet->GetHateMost(); + if (top && top != t) { + hate += pet->GetHateAmount(top) - pet->GetHateAmount(t) + 100; } } - } - break; - } - case PET_FOLLOWME: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SetFeigned(false); - mypet->SayString(this, Chat::PetResponse, PET_FOLLOWING); - mypet->SetPetOrder(SPO_Follow); - - // fix GUI sit button to be unpressed - send stand anim/end hpregen - SetPetCommandState(PET_BUTTON_SIT, 0); - mypet->SetAppearance(eaStanding); - - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); - } + pet->AddToHateList(t, hate, 0, true, false, false, SPELL_UNKNOWN, true); + MessageString(Chat::PetResponse, PET_ATTACKING, pet->GetCleanName(), t->GetCleanName()); + SetTarget(t); + break; } - break; - } - case PET_TAUNT: { - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (mypet->CastToNPC()->IsTaunting()) - { - MessageString(Chat::PetResponse, PET_NO_TAUNT); - mypet->CastToNPC()->SetTaunting(false); + case PetCommand::QAttack: { + if ( + pet->IsFeared() || + !GetTarget() || + GetTarget() == this || + !can_use_command || + !( + DistanceSquaredNoZ(pet->GetPosition(), GetTarget()->GetPosition()) <= + (RuleR(Pets, AttackCommandRange) * RuleR(Pets, AttackCommandRange)) + ) + ) { + break; } - else - { - MessageString(Chat::PetResponse, PET_DO_TAUNT); - mypet->CastToNPC()->SetTaunting(true); + + if (RuleB(Pets, PetsRequireLoS) && !DoLosChecks(GetTarget())) { + pet->SayString(this, NOT_LEGAL_TARGET); + break; } + + if (GetTarget()->IsMezzed()) { + MessageString(Chat::NPCQuestSay, CANNOT_WAKE, pet->GetCleanName(), GetTarget()->GetCleanName()); + break; + } + + if (!pet->IsAttackAllowed(GetTarget())) { + pet->SayString(this, NOT_LEGAL_TARGET); + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + + if (pet->IsPetRegroup()) { + pet->SetPetRegroup(false); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + } + + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + + if (pet->GetPetOrder() == PetOrder::Sit || pet->GetPetOrder() == PetOrder::Feign) { + pet->SetPetOrder(pet->GetPreviousPetOrder()); + pet->SetAppearance(eaStanding); + } + + zone->AddAggroMob(); + pet->AddToHateList(GetTarget(), 1, 0, true, false, false, SPELL_UNKNOWN, true); + MessageString(Chat::PetResponse, PET_ATTACKING, pet->GetCleanName(), GetTarget()->GetCleanName()); + break; } - break; - } - case PET_TAUNT_ON: { - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + case PetCommand::BackOff: { + if (pet->IsFeared() || !can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SayString(this, Chat::PetResponse, PET_CALMING); + pet->WipeHateList(); + pet->SetTarget(nullptr); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + + break; + } + case PetCommand::HealthReport: { + if (!can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, PET_REPORT_HP, ConvertArrayF(pet->GetHPRatio(), val1)); + pet->ShowBuffs(this); + break; + } + case PetCommand::GetLost: { + if (pet->Charmed()) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (pet->GetPetType() == PetType::Charmed) { + pet->BuffFadeByEffect(SE_Charm); + break; + } else { + SetPet(nullptr); + } + + pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + pet->CastToNPC()->Depop(); + break; + } + case PetCommand::GuardHere: { + if (pet->IsFeared() || !can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + pet->SetAppearance(eaStanding); + pet->SayString(this, Chat::PetResponse, PET_GUARDINGLIFE); + pet->SetPetOrder(PetOrder::Guard); + pet->CastToNPC()->SaveGuardSpot(pet->GetPosition()); + + if (!pet->GetTarget()) { + pet->StopNavigation(); + } + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + + break; + } + case PetCommand::FollowMe: { + if (pet->IsFeared() || !can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + pet->SayString(this, Chat::PetResponse, PET_FOLLOWING); + pet->SetPetOrder(PetOrder::Follow); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + pet->SetAppearance(eaStanding); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + + break; + } + case PetCommand::Taunt: { + if (!can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, pet->CastToNPC()->IsTaunting() ? PET_NO_TAUNT : PET_DO_TAUNT); + pet->CastToNPC()->SetTaunting(!pet->CastToNPC()->IsTaunting()); + break; + } + case PetCommand::TauntOn: { + if (!can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + MessageString(Chat::PetResponse, PET_DO_TAUNT); - mypet->CastToNPC()->SetTaunting(true); + pet->CastToNPC()->SetTaunting(true); + break; } - break; - } - case PET_TAUNT_OFF: { - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + case PetCommand::TauntOff: { + if (!can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + MessageString(Chat::PetResponse, PET_NO_TAUNT); - mypet->CastToNPC()->SetTaunting(false); + pet->CastToNPC()->SetTaunting(false); + break; } - break; - } - case PET_GUARDME: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SetFeigned(false); - mypet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING); - mypet->SetPetOrder(SPO_Follow); - - // Set Sit button to unpressed - send stand anim/end hpregen - SetPetCommandState(PET_BUTTON_SIT, 0); - mypet->SetAppearance(eaStanding); - - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); + case PetCommand::GuardMe: { + if (pet->IsFeared() || can_use_command) { + break; } - } - break; - } - case PET_SIT: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (mypet->GetPetOrder() == SPO_Sit) - { - mypet->SetFeigned(false); - mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - mypet->SetPetOrder(mypet->GetPreviousPetOrder()); - mypet->SetAppearance(eaStanding); + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + pet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING); + pet->SetPetOrder(PetOrder::Follow); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + pet->SetAppearance(eaStanding); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); } - else - { - mypet->SetFeigned(false); - mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - mypet->SetPetOrder(SPO_Sit); - mypet->SetRunAnimSpeed(0); - if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet - mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting - mypet->SetAppearance(eaSitting); + + break; + } + case PetCommand::Sit: { + if (pet->IsFeared() || !can_use_command) { + break; } - } - break; - } - case PET_STANDUP: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SetFeigned(false); - mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - SetPetCommandState(PET_BUTTON_SIT, 0); - mypet->SetPetOrder(mypet->GetPreviousPetOrder()); - mypet->SetAppearance(eaStanding); - } - break; - } - case PET_SITDOWN: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SetFeigned(false); - mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); - SetPetCommandState(PET_BUTTON_SIT, 1); - mypet->SetPetOrder(SPO_Sit); - mypet->SetRunAnimSpeed(0); - if (!mypet->UseBardSpellLogic()) //maybe we can have a bard pet - mypet->InterruptSpell(); //No cast 4 u. //i guess the pet should start casting - mypet->SetAppearance(eaSitting); + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + pet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + pet->SetPetOrder(pet->GetPetOrder() == PetOrder::Sit ? pet->GetPreviousPetOrder() : PetOrder::Sit); + pet->SetAppearance(pet->GetPetOrder() == PetOrder::Sit ? eaStanding : eaSitting); + + if (pet->GetPetOrder() != PetOrder::Sit) { + pet->SetRunAnimSpeed(0); + + if (!pet->UseBardSpellLogic()) { + pet->InterruptSpell(); + } + } + + break; } - break; - } - case PET_HOLD: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsHeld()) - { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + case PetCommand::StandUp: { + if (pet->IsFeared() || !can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + pet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + SetPetCommandState(PetButton::Sit, PetButtonState::Off); + pet->SetPetOrder(pet->GetPreviousPetOrder()); + pet->SetAppearance(eaStanding); + break; + } + case PetCommand::SitDown: { + if (pet->IsFeared() || !can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetFeigned(false); + pet->SayString(this, Chat::PetResponse, PET_SIT_STRING); + SetPetCommandState(PetButton::Sit, PetButtonState::On); + pet->SetPetOrder(PetOrder::Sit); + pet->SetRunAnimSpeed(0); + + if (!pet->UseBardSpellLogic()){ + pet->InterruptSpell(); + } + + pet->SetAppearance(eaSitting); + break; + } + case PetCommand::Hold: { + if (!aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (pet->IsHeld()) { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); - mypet->SetHeld(false); - } - else - { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + } + + pet->SetHeld(false); + } else { + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { MessageString(Chat::PetResponse, PET_HOLD_SET_ON); + } - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) - mypet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); - else - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { + pet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); + } else { + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + } - mypet->SetHeld(true); + pet->SetHeld(true); } - mypet->SetGHeld(false); - SetPetCommandState(PET_BUTTON_GHOLD, 0); + + pet->SetGHeld(false); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + break; } - break; - } - case PET_HOLD_ON: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && !mypet->IsHeld()) { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) + case PetCommand::HoldOn: { + if (!pet->IsHeld() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { MessageString(Chat::PetResponse, PET_HOLD_SET_ON); - - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) - mypet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); - else - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); - mypet->SetHeld(true); - mypet->SetGHeld(false); - SetPetCommandState(PET_BUTTON_GHOLD, 0); - } - break; - } - case PET_HOLD_OFF: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsHeld()) { - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); - mypet->SetHeld(false); - } - break; - } - case PET_GHOLD: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsGHeld()) - { - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) - MessageString(Chat::PetResponse, PET_OFF_GHOLD); - mypet->SetGHeld(false); } - else - { + + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { + pet->SayString(this, Chat::PetResponse, PET_NOW_HOLDING); + } else { + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + } + + pet->SetHeld(true); + pet->SetGHeld(false); + SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + break; + } + case PetCommand::HoldOff: { + if (!pet->IsHeld() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, PET_HOLD_SET_OFF); + } + + pet->SetHeld(false); + break; + } + case PetCommand::GreaterHold: { + if (!aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (pet->IsGHeld()) { + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { + MessageString(Chat::PetResponse, PET_OFF_GHOLD); + } + + pet->SetGHeld(false); + } else { if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_ON_GHOLD); - mypet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); + pet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); } else { - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); } - mypet->SetGHeld(true); + + pet->SetGHeld(true); } - mypet->SetHeld(false); - SetPetCommandState(PET_BUTTON_HOLD, 0); + + pet->SetHeld(false); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + break; } - break; - } - case PET_GHOLD_ON: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + case PetCommand::GreaterHoldOn: { + if (!aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_ON_GHOLD); - mypet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); + pet->SayString(this, Chat::PetResponse, PET_GHOLD_ON_MSG); } else { - mypet->SayString(this, Chat::PetResponse, PET_ON_HOLD); + pet->SayString(this, Chat::PetResponse, PET_ON_HOLD); } - mypet->SetGHeld(true); - mypet->SetHeld(false); - SetPetCommandState(PET_BUTTON_HOLD, 0); + + pet->SetGHeld(true); + pet->SetHeld(false); + SetPetCommandState(PetButton::Hold, PetButtonState::Off); + break; } - break; - } - case PET_GHOLD_OFF: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC() && mypet->IsGHeld()) { - if (m_ClientVersionBit & EQ::versions::maskUFAndLater) + case PetCommand::GreaterHoldOff: { + if (!pet->IsGHeld() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (m_ClientVersionBit & EQ::versions::maskUFAndLater) { MessageString(Chat::PetResponse, PET_OFF_GHOLD); - mypet->SetGHeld(false); - } - break; - } - case PET_SPELLHOLD: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - if (mypet->IsNoCast()) { - MessageString(Chat::PetResponse, PET_CASTING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_OFF); - mypet->SetNoCast(false); } - else { - MessageString(Chat::PetResponse, PET_NOT_CASTING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); - mypet->SetNoCast(true); - } - } - break; - } - case PET_SPELLHOLD_ON: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - if (!mypet->IsNoCast()) { - MessageString(Chat::PetResponse, PET_NOT_CASTING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); - mypet->SetNoCast(true); - } - } - break; - } - case PET_SPELLHOLD_OFF: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - if (mypet->IsNoCast()) { - MessageString(Chat::PetResponse, PET_CASTING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_OFF); - mypet->SetNoCast(false); - } - } - break; - } - case PET_FOCUS: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - if (mypet->IsFocused()) { - MessageString(Chat::PetResponse, PET_NOT_FOCUSING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_FOCUS_SET_OFF); - mypet->SetFocused(false); - } - else { - MessageString(Chat::PetResponse, PET_NOW_FOCUSING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); - mypet->SetFocused(true); - } - } - break; - } - case PET_FOCUS_ON: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - if (!mypet->IsFocused()) { - MessageString(Chat::PetResponse, PET_NOW_FOCUSING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); - mypet->SetFocused(true); - } - } - break; - } - case PET_FOCUS_OFF: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - if (mypet->IsFocused()) { - MessageString(Chat::PetResponse, PET_NOT_FOCUSING); - if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) - MessageString(Chat::PetResponse, PET_FOCUS_SET_OFF); - mypet->SetFocused(false); - } - } - break; - } - case PET_FEIGN: { - if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { - if (mypet->IsFeared()) - break; - - int pet_fd_chance = aabonuses.FeignedMinionChance; - if (zone->random.Int(0, 99) > pet_fd_chance) { - mypet->SetFeigned(false); - entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, mypet->GetCleanName()); - } - else { - bool has_aggro_immunity = GetSpecialAbility(SpecialAbility::AggroImmunity); - mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 1); - mypet->WipeHateList(); - mypet->SetPetOrder(SPO_FeignDeath); - mypet->SetRunAnimSpeed(0); - mypet->StopNavigation(); - mypet->SetAppearance(eaDead); - mypet->SetFeigned(true); - mypet->SetTarget(nullptr); - if (!mypet->UseBardSpellLogic()) { - mypet->InterruptSpell(); - } - - if (!has_aggro_immunity) { - mypet->SetSpecialAbility(SpecialAbility::AggroImmunity, 0); - } - } + pet->SetGHeld(false); + break; } - break; - } - case PET_STOP: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + case PetCommand::SpellHold: { + if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, pet->IsNoCast() ? PET_CASTING : PET_NOT_CASTING); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, pet->IsNoCast() ? PET_SPELLHOLD_SET_OFF : PET_SPELLHOLD_SET_ON); + } + + pet->SetNoCast(!pet->IsNoCast()); + break; + } + case PetCommand::SpellHoldOn: { + if (pet->IsFeared() || pet->IsNoCast() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, PET_NOT_CASTING); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_ON); + } + + pet->SetNoCast(true); + break; + } + case PetCommand::SpellHoldOff: { + if (pet->IsFeared() || !pet->IsNoCast() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, PET_CASTING); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, PET_SPELLHOLD_SET_OFF); + } + + pet->SetNoCast(false); + break; + } + case PetCommand::Focus: { + if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, pet->IsFocused() ? PET_NOT_FOCUSING : PET_NOW_FOCUSING); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, pet->IsFocused() ? PET_FOCUS_SET_OFF : PET_FOCUS_SET_ON); + } + + pet->SetFocused(!pet->IsFocused()); + break; + } + case PetCommand::FocusOn: { + if (pet->IsFeared() || pet->IsFocused() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, PET_NOW_FOCUSING); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, PET_FOCUS_SET_ON); + } + + pet->SetFocused(true); + break; + } + case PetCommand::FocusOff: { + if (pet->IsFeared() || !pet->IsFocused() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + MessageString(Chat::PetResponse, PET_NOT_FOCUSING); + + if (m_ClientVersionBit & EQ::versions::maskSoDAndLater) { + MessageString(Chat::PetResponse, PET_FOCUS_SET_OFF); + } + + pet->SetFocused(false); + break; + } + case PetCommand::Feign: { + if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (zone->random.Int(0, 99) > aabonuses.FeignedMinionChance) { + pet->SetFeigned(false); + entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, pet->GetCleanName()); } else { - mypet->SetPetStop(true); - mypet->StopNavigation(); - mypet->SetTarget(nullptr); - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - SetPetCommandState(PET_BUTTON_REGROUP, 0); + pet->SetSpecialAbility(SpecialAbility::AggroImmunity, 1); + pet->WipeHateList(); + pet->SetPetOrder(PetOrder::Feign); + pet->SetRunAnimSpeed(0); + pet->StopNavigation(); + pet->SetAppearance(eaDead); + pet->SetFeigned(true); + pet->SetTarget(nullptr); + + if (!pet->UseBardSpellLogic()) { + pet->InterruptSpell(); + } + + if (!GetSpecialAbility(SpecialAbility::AggroImmunity)) { + pet->SetSpecialAbility(SpecialAbility::AggroImmunity, 0); } } - mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - } - break; - } - case PET_STOP_ON: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SetPetStop(true); - mypet->StopNavigation(); - mypet->SetTarget(nullptr); - mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - SetPetCommandState(PET_BUTTON_REGROUP, 0); + break; + } + case PetCommand::Stop: { + if (pet->IsFeared() || !can_use_command) { + break; } - } - break; - } - case PET_STOP_OFF: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { - mypet->SetPetStop(false); - mypet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); - } - break; - } - case PET_REGROUP: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; - if (aabonuses.PetCommands[PetCommand]) { - if (mypet->IsPetRegroup()) { - mypet->SetPetRegroup(false); - mypet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); } else { - mypet->SetPetRegroup(true); - mypet->SetTarget(nullptr); - mypet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); + pet->SetPetStop(true); + pet->StopNavigation(); + pet->SetTarget(nullptr); + + if (pet->IsPetRegroup()) { + pet->SetPetRegroup(false); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); } } - } - break; - } - case PET_REGROUP_ON: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if (aabonuses.PetCommands[PetCommand]) { - mypet->SetPetRegroup(true); - mypet->SetTarget(nullptr); - mypet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); - if (mypet->IsPetStop()) { - mypet->SetPetStop(false); - SetPetCommandState(PET_BUTTON_STOP, 0); + pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + break; + } + case PetCommand::StopOn: { + if (pet->IsFeared() || pet->IsPetStop() || !can_use_command) { + break; } - } - break; - } - case PET_REGROUP_OFF: { - if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - if (aabonuses.PetCommands[PetCommand]) { - mypet->SetPetRegroup(false); - mypet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetPetStop(true); + pet->StopNavigation(); + pet->SetTarget(nullptr); + pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + + if (pet->IsPetRegroup()) { + pet->SetPetRegroup(false); + SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + } + + break; + } + case PetCommand::StopOff: { + if (pet->IsFeared() || !pet->IsPetStop() || !can_use_command) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetPetStop(false); + pet->SayString(this, Chat::PetResponse, PET_GETLOST_STRING); + break; + } + case PetCommand::Regroup: { + if (pet->IsFeared() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + if (pet->IsPetRegroup()) { + pet->SetPetRegroup(false); + pet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); + } else { + pet->SetPetRegroup(true); + pet->SetTarget(nullptr); + pet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + } + + break; + } + case PetCommand::RegroupOn: { + if (pet->IsFeared() || pet->IsPetRegroup() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetPetRegroup(true); + pet->SetTarget(nullptr); + pet->SayString(this, Chat::PetResponse, PET_ON_REGROUPING); + + if (pet->IsPetStop()) { + pet->SetPetStop(false); + SetPetCommandState(PetButton::Stop, PetButtonState::Off); + } + + break; + } + case PetCommand::RegroupOff: { + if (pet->IsFeared() || !pet->IsPetRegroup() || !aabonuses.PetCommands[s->command]) { + break; + } + + std::function f = [&s]() { + return PetCommand::GetName(s->command); + }; + + parse->EventMob(EVENT_PET_COMMAND, pet, CastToMob(), f, s->command); + parse->EventMob(EVENT_PET_COMMAND, CastToMob(), pet, f, s->command); + + pet->SetPetRegroup(false); + pet->SayString(this, Chat::PetResponse, PET_OFF_REGROUPING); + break; + } + default: { + LogError("[{}] attempted to use an unknown pet command: [{}]", GetCleanName(), s->command); + break; } - break; - } - default: - printf("Client attempted to use a unknown pet command:\n"); - break; } } @@ -12042,6 +12303,11 @@ void Client::Handle_OP_PopupResponse(const EQApplicationPacket *app) parse->EventPlayer(EVENT_POPUP_RESPONSE, this, std::to_string(popup_response->popupid), 0); } + if (parse->ZoneHasQuestSub(EVENT_POPUP_RESPONSE)) { + std::vector args = { this }; + parse->EventZone(EVENT_POPUP_RESPONSE, zone, std::to_string(popup_response->popupid), 0, &args); + } + auto t = GetTarget(); if (t) { parse->EventBotMercNPC(EVENT_POPUP_RESPONSE, t, this, [&]() { return std::to_string(popup_response->popupid); }); @@ -16804,6 +17070,7 @@ void Client::RecordStats() r.endurance_regen = GetEnduranceRegen() - GetSpellBonuses().EnduranceRegen; r.shielding = GetShielding() - GetSpellBonuses().MeleeMitigation; r.spell_damage = GetSpellDmg() - GetSpellBonuses().SpellDmg; + r.heal_amount = GetHealAmt() - GetSpellBonuses().HealAmt; r.spell_shielding = GetSpellShield() - GetSpellBonuses().SpellShield; r.strikethrough = GetStrikeThrough() - GetSpellBonuses().StrikeThrough; r.stun_resist = GetStunResist() - GetSpellBonuses().StunResist; diff --git a/zone/common.h b/zone/common.h index 10c17b7a6..5c5e12f79 100644 --- a/zone/common.h +++ b/zone/common.h @@ -3,6 +3,7 @@ #include "../common/types.h" #include "../common/spdat.h" +#include "../common/emu_constants.h" #include @@ -45,55 +46,6 @@ namespace Archetype { //Maximum distance from a zone point if zone was specified #define ZONEPOINT_ZONE_RANGE 40000.0f -// Defines based on the RoF2 Client -#define PET_HEALTHREPORT 0 // 0x00 - /pet health or Pet Window -#define PET_LEADER 1 // 0x01 - /pet leader or Pet Window -#define PET_ATTACK 2 // 0x02 - /pet attack or Pet Window -#define PET_QATTACK 3 // 0x03 - /pet qattack or Pet Window -#define PET_FOLLOWME 4 // 0x04 - /pet follow or Pet Window -#define PET_GUARDHERE 5 // 0x05 - /pet guard or Pet Window -#define PET_SIT 6 // 0x06 - /pet sit or Pet Window -#define PET_SITDOWN 7 // 0x07 - /pet sit on -#define PET_STANDUP 8 // 0x08 - /pet sit off -#define PET_STOP 9 // 0x09 - /pet stop or Pet Window - Not implemented -#define PET_STOP_ON 10 // 0x0a - /pet stop on - Not implemented -#define PET_STOP_OFF 11 // 0x0b - /pet stop off - Not implemented -#define PET_TAUNT 12 // 0x0c - /pet taunt or Pet Window -#define PET_TAUNT_ON 13 // 0x0d - /pet taunt on -#define PET_TAUNT_OFF 14 // 0x0e - /pet taunt off -#define PET_HOLD 15 // 0x0f - /pet hold or Pet Window, won't add to hate list unless attacking -#define PET_HOLD_ON 16 // 0x10 - /pet hold on -#define PET_HOLD_OFF 17 // 0x11 - /pet hold off -#define PET_GHOLD 18 // 0x12 - /pet ghold, will never add to hate list unless told to -#define PET_GHOLD_ON 19 // 0x13 - /pet ghold on -#define PET_GHOLD_OFF 20 // 0x14 - /pet ghold off -#define PET_SPELLHOLD 21 // 0x15 - /pet no cast or /pet spellhold or Pet Window -#define PET_SPELLHOLD_ON 22 // 0x16 - /pet spellhold on -#define PET_SPELLHOLD_OFF 23 // 0x17 - /pet spellhold off -#define PET_FOCUS 24 // 0x18 - /pet focus or Pet Window -#define PET_FOCUS_ON 25 // 0x19 - /pet focus on -#define PET_FOCUS_OFF 26 // 0x1a - /pet focus off -#define PET_FEIGN 27 // 0x1b - /pet feign -#define PET_BACKOFF 28 // 0x1c - /pet back off -#define PET_GETLOST 29 // 0x1d - /pet get lost -#define PET_GUARDME 30 // 0x1e - Same as /pet follow, but different message in older clients - define not from client /pet target in modern clients but doesn't send packet -#define PET_REGROUP 31 // 0x1f - /pet regroup, acts like classic hold. Stops attack and moves back to guard/you but doesn't clear hate list -#define PET_REGROUP_ON 32 // 0x20 - /pet regroup on, turns on regroup -#define PET_REGROUP_OFF 33 // 0x21 - /pet regroup off, turns off regroup -#define PET_MAXCOMMANDS PET_REGROUP_OFF + 1 - -// can change the state of these buttons with a packet -#define PET_BUTTON_SIT 0 -#define PET_BUTTON_STOP 1 -#define PET_BUTTON_REGROUP 2 -#define PET_BUTTON_FOLLOW 3 -#define PET_BUTTON_GUARD 4 -#define PET_BUTTON_TAUNT 5 -#define PET_BUTTON_HOLD 6 -#define PET_BUTTON_GHOLD 7 -#define PET_BUTTON_FOCUS 8 -#define PET_BUTTON_SPELLHOLD 9 - #define AURA_HARDCAP 2 #define WEAPON_STANCE_TYPE_MAX 2 @@ -617,7 +569,7 @@ struct StatBonuses { uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill. int16 NoBreakAESneak; // Percent value int16 FeignedCastOnChance; // Percent Value - bool PetCommands[PET_MAXCOMMANDS]; // SPA 267 + bool PetCommands[PetCommand::Max]; // SPA 267 int FeignedMinionChance; // SPA 281 base1 = chance, just like normal FD int GrantForage; // affects max skill of forage as well as granting non-forage classes forage int aura_slots; @@ -781,16 +733,6 @@ enum { GridRandomPath }; -typedef enum { - petFamiliar, //only listens to /pet get lost - petAnimation, //does not listen to any commands - petOther, - petCharmed, - petNPCFollow, - petTargetLock, //remain active as long something is on the hatelist. Don't listen to any commands - petNone = 0xFF // not a pet -} PetType; - typedef enum { SingleTarget, // causes effect to spell_target AETarget, // causes effect in aerange of target + target diff --git a/zone/corpse.cpp b/zone/corpse.cpp index f0b04a8f5..9bd13d63b 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1586,6 +1586,21 @@ void Corpse::LootCorpseItem(Client *c, const EQApplicationPacket *app) } } + if (parse->ZoneHasQuestSub(EVENT_LOOT_ZONE)) { + const auto &export_string = fmt::format( + "{} {} {} {}", + inst->GetItem()->ID, + inst->GetCharges(), + EntityList::RemoveNumbers(corpse_name), + GetID() + ); + + std::vector args = {inst, this, c}; + if (parse->EventZone(EVENT_LOOT_ZONE, zone, export_string, 0, &args) != 0) { + prevent_loot = true; + } + } + if (inst && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::LOOT_ITEM) && !IsPlayerCorpse()) { auto e = PlayerEvent::LootItemEvent{ .item_id = inst->GetItem()->ID, diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 16a662482..6d220b8d8 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -207,6 +207,7 @@ const char* QuestEventSubroutines[_LargestEventID] = { "EVENT_AA_LOSS", "EVENT_SPELL_BLOCKED", "EVENT_READ_ITEM", + "EVENT_PET_COMMAND", // Add new events before these or Lua crashes "EVENT_SPELL_EFFECT_BOT", @@ -222,6 +223,8 @@ PerlembParser::PerlembParser() : perl(nullptr) global_bot_quest_status_ = questUnloaded; merc_quest_status_ = questUnloaded; global_merc_quest_status_ = questUnloaded; + zone_quest_status_ = questUnloaded; + global_zone_quest_status_ = questUnloaded; } PerlembParser::~PerlembParser() @@ -265,6 +268,8 @@ void PerlembParser::ReloadQuests() global_bot_quest_status_ = questUnloaded; merc_quest_status_ = questUnloaded; global_merc_quest_status_ = questUnloaded; + zone_quest_status_ = questUnloaded; + global_zone_quest_status_ = questUnloaded; item_quest_status_.clear(); spell_quest_status_.clear(); @@ -278,6 +283,7 @@ int PerlembParser::EventCommon( EQ::ItemInstance* inst, const SPDat_Spell_Struct* spell, Mob* mob, + Zone* zone, uint32 extra_data, bool is_global, std::vector* extra_pointers @@ -287,52 +293,22 @@ int PerlembParser::EventCommon( return 0; } - bool is_player_quest = false; - bool is_global_player_quest = false; - bool is_global_npc_quest = false; - bool is_bot_quest = false; - bool is_global_bot_quest = false; - bool is_merc_quest = false; - bool is_global_merc_quest = false; - bool is_item_quest = false; - bool is_spell_quest = false; - - std::string package_name; - - GetQuestTypes( - is_player_quest, - is_global_player_quest, - is_bot_quest, - is_global_bot_quest, - is_merc_quest, - is_global_merc_quest, - is_global_npc_quest, - is_item_quest, - is_spell_quest, + QuestType quest_type = GetQuestTypes( event_id, npc_mob, inst, mob, + zone, is_global ); - GetQuestPackageName( - is_player_quest, - is_global_player_quest, - is_bot_quest, - is_global_bot_quest, - is_merc_quest, - is_global_merc_quest, - is_global_npc_quest, - is_item_quest, - is_spell_quest, - package_name, + std::string package_name = GetQuestPackageName( + quest_type, event_id, object_id, data, npc_mob, - inst, - is_global + inst ); const std::string& sub_name = QuestEventSubroutines[event_id]; @@ -348,15 +324,7 @@ int PerlembParser::EventCommon( /* Check for QGlobal export event enable */ if (parse->perl_event_export_settings[event_id].qglobals) { ExportQGlobals( - is_player_quest, - is_global_player_quest, - is_bot_quest, - is_global_bot_quest, - is_merc_quest, - is_global_merc_quest, - is_global_npc_quest, - is_item_quest, - is_spell_quest, + quest_type, package_name, npc_mob, mob, @@ -367,15 +335,7 @@ int PerlembParser::EventCommon( /* Check for Mob export event enable */ if (parse->perl_event_export_settings[event_id].mob) { ExportMobVariables( - is_player_quest, - is_global_player_quest, - is_bot_quest, - is_global_bot_quest, - is_merc_quest, - is_global_merc_quest, - is_global_npc_quest, - is_item_quest, - is_spell_quest, + quest_type, package_name, mob, npc_mob @@ -397,19 +357,24 @@ int PerlembParser::EventCommon( ExportEventVariables(package_name, event_id, object_id, data, npc_mob, inst, mob, extra_data, extra_pointers); } - if (is_player_quest || is_global_player_quest) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, nullptr); - } else if (is_bot_quest || is_global_bot_quest || is_merc_quest || is_global_merc_quest) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, nullptr); - } else if (is_item_quest) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, inst, nullptr); - } else if (is_spell_quest) { + if (quest_type == QuestType::Player || quest_type == QuestType::PlayerGlobal) { + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, nullptr, nullptr); + } else if ( + quest_type == QuestType::Bot || + quest_type == QuestType::BotGlobal || + quest_type == QuestType::Merc || + quest_type == QuestType::MercGlobal + ) { + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, nullptr, nullptr); + } else if (quest_type == QuestType::Item || quest_type == QuestType::ItemGlobal) { + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, inst, nullptr, nullptr); + } else if (quest_type == QuestType::Spell || quest_type == QuestType::SpellGlobal) { if (mob) { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, spell); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, mob, mob, nullptr, spell, nullptr); } else { - return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, spell); + return SendCommands(package_name.c_str(), QuestEventSubroutines[event_id], 0, npc_mob, mob, nullptr, spell, nullptr); } - } else { + } else if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) { return SendCommands( package_name.c_str(), QuestEventSubroutines[event_id], @@ -417,8 +382,20 @@ int PerlembParser::EventCommon( npc_mob, mob, nullptr, + nullptr, nullptr ); + } else if (quest_type == QuestType::Zone || quest_type == QuestType::ZoneGlobal) { + return SendCommands( + package_name.c_str(), + QuestEventSubroutines[event_id], + 0, + nullptr, + nullptr, + nullptr, + nullptr, + zone + ); } } @@ -439,6 +416,7 @@ int PerlembParser::EventNPC( nullptr, nullptr, mob, + nullptr, extra_data, false, extra_pointers @@ -462,6 +440,7 @@ int PerlembParser::EventGlobalNPC( nullptr, nullptr, mob, + nullptr, extra_data, true, extra_pointers @@ -484,6 +463,7 @@ int PerlembParser::EventPlayer( nullptr, nullptr, client, + nullptr, extra_data, false, extra_pointers @@ -506,6 +486,7 @@ int PerlembParser::EventGlobalPlayer( nullptr, nullptr, client, + nullptr, extra_data, true, extra_pointers @@ -534,6 +515,7 @@ int PerlembParser::EventItem( inst, nullptr, client, + nullptr, extra_data, false, extra_pointers @@ -558,6 +540,7 @@ int PerlembParser::EventSpell( nullptr, &spells[spell_id], client, + nullptr, extra_data, false, extra_pointers @@ -1006,7 +989,8 @@ int PerlembParser::SendCommands( Mob* other, Mob* mob, EQ::ItemInstance* inst, - const SPDat_Spell_Struct* spell + const SPDat_Spell_Struct* spell, + Zone* zone ) { if (!perl) { @@ -1014,12 +998,22 @@ int PerlembParser::SendCommands( } int ret_value = 0; + RunningQuest q; + + q.owner = other; + q.questitem = inst; + q.questspell = spell; + if (mob && mob->IsClient()) { - quest_manager.StartQuest(other, mob->CastToClient(), inst, spell); - } else { - quest_manager.StartQuest(other); + q.initiator = mob->CastToClient(); } + if (zone) { + q.zone = zone; + } + + quest_manager.StartQuest(q); + try { perl->eval(fmt::format("package {};", prefix).c_str()); @@ -1033,7 +1027,8 @@ int PerlembParser::SendCommands( "merc", "npc", "questitem", - "spell" + "spell", + "zone" }; for (const auto& suffix : suffixes) { @@ -1058,21 +1053,23 @@ int PerlembParser::SendCommands( sv_setsv(client, _empty_sv); } - if (other->IsBot()) { - Bot* b = quest_manager.GetBot(); - buf = fmt::format("{}::bot", prefix); - SV* bot = get_sv(buf.c_str(), true); - sv_setref_pv(bot, "Bot", b); - } else if (other->IsMerc()) { - Merc* m = quest_manager.GetMerc(); - buf = fmt::format("{}::merc", prefix); - SV* merc = get_sv(buf.c_str(), true); - sv_setref_pv(merc, "Merc", m); - } else if (other->IsNPC()) { - NPC* n = quest_manager.GetNPC(); - buf = fmt::format("{}::npc", prefix); - SV* npc = get_sv(buf.c_str(), true); - sv_setref_pv(npc, "NPC", n); + if (other) { + if (other->IsBot()) { + Bot* b = quest_manager.GetBot(); + buf = fmt::format("{}::bot", prefix); + SV* bot = get_sv(buf.c_str(), true); + sv_setref_pv(bot, "Bot", b); + } else if (other->IsMerc()) { + Merc* m = quest_manager.GetMerc(); + buf = fmt::format("{}::merc", prefix); + SV* merc = get_sv(buf.c_str(), true); + sv_setref_pv(merc, "Merc", m); + } else if (other->IsNPC()) { + NPC* n = quest_manager.GetNPC(); + buf = fmt::format("{}::npc", prefix); + SV* npc = get_sv(buf.c_str(), true); + sv_setref_pv(npc, "NPC", n); + } } //only export QuestItem if it's an inst quest @@ -1110,7 +1107,8 @@ int PerlembParser::SendCommands( "merc", "npc", "questitem", - "spell" + "spell", + "zone" }; for (const auto& suffix : suffixes) { @@ -1192,20 +1190,12 @@ void PerlembParser::MapFunctions() #endif // EMBPERL_XS_CLASSES } -void PerlembParser::GetQuestTypes( - bool& is_player_quest, - bool& is_global_player_quest, - bool& is_bot_quest, - bool& is_global_bot_quest, - bool& is_merc_quest, - bool& is_global_merc_quest, - bool& is_global_npc_quest, - bool& is_item_quest, - bool& is_spell_quest, +QuestType PerlembParser::GetQuestTypes( QuestEventID event_id, Mob* npc_mob, EQ::ItemInstance* inst, Mob* mob, + Zone* zone, bool is_global ) { @@ -1219,100 +1209,74 @@ void PerlembParser::GetQuestTypes( event_id == EVENT_SPELL_FADE || event_id == EVENT_SPELL_EFFECT_TRANSLOCATE_COMPLETE ) { - is_spell_quest = true; + return is_global ? QuestType::SpellGlobal : QuestType::Spell; } else { if (npc_mob) { if (!inst) { - if (is_global) { - if (npc_mob->IsBot()) { - is_global_bot_quest = true; - } else if (npc_mob->IsMerc()) { - is_global_merc_quest = true; - } - } else { - if (npc_mob->IsBot()) { - is_bot_quest = true; - } else if (npc_mob->IsMerc()) { - is_merc_quest = true; - } + if (npc_mob->IsBot()) { + return is_global ? QuestType::BotGlobal : QuestType::Bot; + } else if (npc_mob->IsMerc()) { + return is_global ? QuestType::MercGlobal : QuestType::Merc; + } else if (npc_mob->IsNPC()) { + return is_global ? QuestType::NPCGlobal : QuestType::NPC; } } else { - is_item_quest = true; + return is_global ? QuestType::ItemGlobal : QuestType::Item; } } else if (!npc_mob && mob) { if (!inst) { - if (is_global) { - if (mob->IsClient()) { - is_global_player_quest = true; - } - } else { - if (mob->IsClient()) { - is_player_quest = true; - } + if (mob->IsClient()) { + return is_global ? QuestType::PlayerGlobal : QuestType::Player; } } else { - is_item_quest = true; + return is_global ? QuestType::ItemGlobal : QuestType::Item; } + } else if (zone) { + return is_global ? QuestType::ZoneGlobal : QuestType::Zone; } } } -void PerlembParser::GetQuestPackageName( - bool& is_player_quest, - bool& is_global_player_quest, - bool& is_bot_quest, - bool& is_global_bot_quest, - bool& is_merc_quest, - bool& is_global_merc_quest, - bool& is_global_npc_quest, - bool& is_item_quest, - bool& is_spell_quest, - std::string& package_name, +std::string PerlembParser::GetQuestPackageName( + QuestType quest_type, QuestEventID event_id, uint32 object_id, const char* data, Mob* npc_mob, - EQ::ItemInstance* inst, - bool is_global + EQ::ItemInstance* inst ) { - if ( - !is_player_quest && - !is_global_player_quest && - !is_bot_quest && - !is_global_bot_quest && - !is_merc_quest && - !is_global_merc_quest && - !is_item_quest && - !is_spell_quest - ) { - if (is_global) { - is_global_npc_quest = true; - package_name = "qst_global_npc"; - } else { - package_name = fmt::format("qst_npc_{}", npc_mob->GetNPCTypeID()); - } - } else if (is_item_quest) { + if (quest_type == QuestType::NPC) { + return fmt::format("qst_npc_{}", npc_mob->GetNPCTypeID()); + } else if (quest_type == QuestType::NPCGlobal) { + return "qst_global_npc"; + } else if (quest_type == QuestType::Item || quest_type == QuestType::ItemGlobal) { if (!inst) { - return; + return ""; } - package_name = fmt::format("qst_item_{}", inst->GetID()); - } else if (is_player_quest) { - package_name = "qst_player"; - } else if (is_global_player_quest) { - package_name = "qst_global_player"; - } else if (is_bot_quest) { - package_name = "qst_bot"; - } else if (is_global_bot_quest) { - package_name = "qst_global_bot"; - } else if (is_merc_quest) { - package_name = "qst_merc"; - } else if (is_global_merc_quest) { - package_name = "qst_global_merc"; - } else { - package_name = fmt::format("qst_spell_{}", object_id); + return fmt::format("qst_item_{}", inst->GetID()); + } else if (quest_type == QuestType::Player) { + return "qst_player"; + } else if (quest_type == QuestType::PlayerGlobal) { + return "qst_global_player"; + } else if (quest_type == QuestType::Bot) { + return "qst_bot"; + } else if (quest_type == QuestType::BotGlobal) { + return "qst_global_bot"; + } else if (quest_type == QuestType::Merc) { + return "qst_merc"; + } else if (quest_type == QuestType::MercGlobal) { + return "qst_global_merc"; + } else if (quest_type == QuestType::Spell || quest_type == QuestType::SpellGlobal) { + return fmt::format("qst_spell_{}", object_id); + } else if (quest_type == QuestType::Zone) { + return "qst_zone"; + } else if (quest_type == QuestType::ZoneGlobal) { + return "qst_global_zone"; } + + return ""; } void PerlembParser::ExportCharID(const std::string& package_name, int& char_id, Mob* npc_mob, Mob* mob) @@ -1331,15 +1295,7 @@ void PerlembParser::ExportCharID(const std::string& package_name, int& char_id, } void PerlembParser::ExportQGlobals( - bool is_player_quest, - bool is_global_player_quest, - bool is_bot_quest, - bool is_global_bot_quest, - bool is_merc_quest, - bool is_global_merc_quest, - bool is_global_npc_quest, - bool is_item_quest, - bool is_spell_quest, + QuestType quest_type, std::string& package_name, Mob* npc_mob, Mob* mob, @@ -1347,16 +1303,7 @@ void PerlembParser::ExportQGlobals( ) { //NPC quest - if ( - !is_player_quest && - !is_global_player_quest && - !is_bot_quest && - !is_global_bot_quest && - !is_merc_quest && - !is_global_merc_quest && - !is_item_quest && - !is_spell_quest - ) { + if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) { //only export for npcs that are global enabled. if (npc_mob && npc_mob->GetQglobal()) { std::map globhash; @@ -1485,15 +1432,7 @@ void PerlembParser::ExportQGlobals( } void PerlembParser::ExportMobVariables( - bool is_player_quest, - bool is_global_player_quest, - bool is_bot_quest, - bool is_global_bot_quest, - bool is_merc_quest, - bool is_global_merc_quest, - bool is_global_npc_quest, - bool is_item_quest, - bool is_spell_quest, + QuestType quest_type, std::string& package_name, Mob* mob, Mob* npc_mob @@ -1511,15 +1450,7 @@ void PerlembParser::ExportMobVariables( ExportVar(package_name.c_str(), "bot_owner_char_id", mob->CastToBot()->GetBotOwnerCharacterID()); } - if ( - !is_player_quest && - !is_global_player_quest && - !is_bot_quest && - !is_global_bot_quest && - !is_merc_quest && - !is_global_merc_quest && - !is_item_quest - ) { + if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) { if (mob && mob->IsClient() && npc_mob && npc_mob->IsNPC()) { Client* c = mob->CastToClient(); @@ -1543,16 +1474,7 @@ void PerlembParser::ExportMobVariables( ExportVar(package_name.c_str(), "userid", mob->GetID()); } - if ( - !is_player_quest && - !is_global_player_quest && - !is_bot_quest && - !is_global_bot_quest && - !is_merc_quest && - !is_global_merc_quest && - !is_item_quest && - !is_spell_quest - ) { + if (quest_type == QuestType::NPC || quest_type == QuestType::NPCGlobal) { if (npc_mob->IsNPC()) { ExportVar(package_name.c_str(), "mname", npc_mob->GetName()); ExportVar(package_name.c_str(), "mobid", npc_mob->GetID()); @@ -1758,10 +1680,14 @@ void PerlembParser::ExportEventVariables( ExportVar(package_name.c_str(), "doorid", data); ExportVar(package_name.c_str(), "version", zone->GetInstanceVersion()); - if (extra_pointers && extra_pointers->size() == 1) { + if (extra_pointers && extra_pointers->size() >= 1) { ExportVar(package_name.c_str(), "door", "Doors", std::any_cast(extra_pointers->at(0))); } + if (extra_pointers && extra_pointers->size() == 2) { + ExportVar(package_name.c_str(), "player", "Client", std::any_cast(extra_pointers->at(1))); + } + break; } @@ -1782,10 +1708,14 @@ void PerlembParser::ExportEventVariables( ); } - if (extra_pointers && extra_pointers->size() == 2) { + if (extra_pointers && extra_pointers->size() >= 2) { ExportVar(package_name.c_str(), "corpse", "Corpse", std::any_cast(extra_pointers->at(1))); } + if (extra_pointers && extra_pointers->size() == 3) { + ExportVar(package_name.c_str(), "player", "Client", std::any_cast(extra_pointers->at(2))); + } + break; } @@ -1852,7 +1782,7 @@ void PerlembParser::ExportEventVariables( ExportVar(package_name.c_str(), "picked_up_id", data); ExportVar(package_name.c_str(), "picked_up_entity_id", extra_data); - if (extra_pointers && extra_pointers->size() == 1) { + if (extra_pointers && extra_pointers->size() >= 1) { ExportVar( package_name.c_str(), "item", @@ -1861,6 +1791,10 @@ void PerlembParser::ExportEventVariables( ); } + if (extra_pointers && extra_pointers->size() == 2) { + ExportVar(package_name.c_str(), "player", "Client", std::any_cast(extra_pointers->at(1))); + } + break; } @@ -1873,6 +1807,11 @@ void PerlembParser::ExportEventVariables( case EVENT_POPUP_RESPONSE: { ExportVar(package_name.c_str(), "popupid", data); + + if (extra_pointers && extra_pointers->size() == 1) { + ExportVar(package_name.c_str(), "player", "Client", std::any_cast(extra_pointers->at(0))); + } + break; } @@ -2036,10 +1975,14 @@ void PerlembParser::ExportEventVariables( ExportVar(package_name.c_str(), "objectid", data); ExportVar(package_name.c_str(), "clicker_id", extra_data); - if (extra_pointers && extra_pointers->size() == 1) { + if (extra_pointers && extra_pointers->size() >= 1) { ExportVar(package_name.c_str(), "object", "Object", std::any_cast(extra_pointers->at(0))); } + if (extra_pointers && extra_pointers->size() == 2) { + ExportVar(package_name.c_str(), "player", "Client", std::any_cast(extra_pointers->at(1))); + } + break; } @@ -2115,6 +2058,13 @@ void PerlembParser::ExportEventVariables( ExportVar(package_name.c_str(), "killed_npc_id", !killed->IsMerc() && killed->IsNPC() ? killed->GetNPCTypeID() : 0); } } + + if (extra_pointers && extra_pointers->size() == 3) { + Mob* killer = std::any_cast(extra_pointers->at(2)); + if (killer) { + ExportVar(package_name.c_str(), "killer", "Mob", killer); + } + } break; } @@ -2142,10 +2092,21 @@ void PerlembParser::ExportEventVariables( } case EVENT_SPAWN_ZONE: { - ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID()); - ExportVar(package_name.c_str(), "spawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0); - ExportVar(package_name.c_str(), "spawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0); - ExportVar(package_name.c_str(), "spawned", "Mob", mob); + if (mob) { + ExportVar(package_name.c_str(), "spawned", "Mob", mob); + ExportVar(package_name.c_str(), "spawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0); + ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID()); + ExportVar(package_name.c_str(), "spawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0); + } + + if (extra_pointers && extra_pointers->size() == 1) { + NPC* spawn_npc = std::any_cast(extra_pointers->at(0)); + ExportVar(package_name.c_str(), "spawned", "NPC", spawn_npc); + ExportVar(package_name.c_str(), "spawned_bot_id", spawn_npc->IsBot() ? spawn_npc->CastToBot()->GetBotID() : 0); + ExportVar(package_name.c_str(), "spawned_entity_id", spawn_npc->GetID()); + ExportVar(package_name.c_str(), "spawned_npc_id", spawn_npc->IsNPC() ? spawn_npc->GetNPCTypeID() : 0); + } + break; } @@ -2386,6 +2347,7 @@ void PerlembParser::ExportEventVariables( } case EVENT_DESPAWN: { + ExportVar(package_name.c_str(), "despawned", "Mob", npc_mob); ExportVar(package_name.c_str(), "despawned_entity_id", npc_mob->GetID()); ExportVar(package_name.c_str(), "despawned_bot_id", npc_mob->IsBot() ? npc_mob->CastToBot()->GetBotID() : 0); ExportVar(package_name.c_str(), "despawned_merc_id", npc_mob->IsMerc() ? npc_mob->CastToMerc()->GetMercenaryID() : 0); @@ -2394,9 +2356,21 @@ void PerlembParser::ExportEventVariables( } case EVENT_DESPAWN_ZONE: { - ExportVar(package_name.c_str(), "despawned_entity_id", mob->GetID()); - ExportVar(package_name.c_str(), "despawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0); - ExportVar(package_name.c_str(), "despawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0); + if (mob) { + ExportVar(package_name.c_str(), "despawned", "Mob", mob); + ExportVar(package_name.c_str(), "despawned_bot_id", mob->IsBot() ? mob->CastToBot()->GetBotID() : 0); + ExportVar(package_name.c_str(), "despawned_entity_id", mob->GetID()); + ExportVar(package_name.c_str(), "despawned_npc_id", mob->IsNPC() ? mob->GetNPCTypeID() : 0); + } + + if (extra_pointers && extra_pointers->size() == 1) { + NPC* spawn_npc = std::any_cast(extra_pointers->at(0)); + ExportVar(package_name.c_str(), "despawned", "NPC", spawn_npc); + ExportVar(package_name.c_str(), "despawned_bot_id", spawn_npc->IsBot() ? spawn_npc->CastToBot()->GetBotID() : 0); + ExportVar(package_name.c_str(), "despawned_entity_id", spawn_npc->GetID()); + ExportVar(package_name.c_str(), "despawned_npc_id", spawn_npc->IsNPC() ? spawn_npc->GetNPCTypeID() : 0); + } + break; } @@ -2551,6 +2525,20 @@ void PerlembParser::ExportEventVariables( break; } + case EVENT_ENTER_ZONE: { + if (extra_pointers && extra_pointers->size() == 1) { + ExportVar(package_name.c_str(), "player", "Client", std::any_cast(extra_pointers->at(0))); + } + + break; + } + + case EVENT_PET_COMMAND: { + ExportVar(package_name.c_str(), "pet_command", extra_data); + ExportVar(package_name.c_str(), "pet_command_name", data); + break; + } + default: { break; } @@ -2648,6 +2636,7 @@ int PerlembParser::EventBot( nullptr, nullptr, mob, + nullptr, extra_data, false, extra_pointers @@ -2671,6 +2660,7 @@ int PerlembParser::EventGlobalBot( nullptr, nullptr, mob, + nullptr, extra_data, true, extra_pointers @@ -2768,6 +2758,7 @@ int PerlembParser::EventMerc( nullptr, nullptr, mob, + nullptr, extra_data, false, extra_pointers @@ -2791,6 +2782,127 @@ int PerlembParser::EventGlobalMerc( nullptr, nullptr, mob, + nullptr, + extra_data, + true, + extra_pointers + ); +} + +void PerlembParser::LoadZoneScript(std::string filename) +{ + if (!perl || zone_quest_status_ != questUnloaded) { + return; + } + + try { + perl->eval_file("qst_zone", filename.c_str()); + } catch (std::string e) { + AddError( + fmt::format( + "Error Compiling Zone Quest File [{}] Error [{}]", + filename, + e + ) + ); + + zone_quest_status_ = questFailedToLoad; + return; + } + + zone_quest_status_ = questLoaded; +} + +void PerlembParser::LoadGlobalZoneScript(std::string filename) +{ + if (!perl || global_zone_quest_status_ != questUnloaded) { + return; + } + + try { + perl->eval_file("qst_global_zone", filename.c_str()); + } catch (std::string e) { + AddError( + fmt::format( + "Error Compiling Global Zone Quest File [{}] Error [{}]", + filename, + e + ) + ); + + global_zone_quest_status_ = questFailedToLoad; + return; + } + + global_zone_quest_status_ = questLoaded; +} + +bool PerlembParser::ZoneHasQuestSub(QuestEventID event_id) +{ + if ( + !perl || + zone_quest_status_ != questLoaded || + event_id >= _LargestEventID + ) { + return false; + } + + return perl->SubExists("qst_zone", QuestEventSubroutines[event_id]); +} + +bool PerlembParser::GlobalZoneHasQuestSub(QuestEventID event_id) +{ + if ( + !perl || + global_zone_quest_status_ != questLoaded || + event_id >= _LargestEventID + ) { + return false; + } + + return perl->SubExists("qst_global_zone", QuestEventSubroutines[event_id]); +} + +int PerlembParser::EventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers +) +{ + return EventCommon( + event_id, + 0, + data.c_str(), + nullptr, + nullptr, + nullptr, + nullptr, + zone, + extra_data, + false, + extra_pointers + ); +} + +int PerlembParser::EventGlobalZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers +) +{ + return EventCommon( + event_id, + 0, + data.c_str(), + nullptr, + nullptr, + nullptr, + nullptr, + zone, extra_data, true, extra_pointers diff --git a/zone/embparser.h b/zone/embparser.h index dd4ffe8d8..5817ce15b 100644 --- a/zone/embparser.h +++ b/zone/embparser.h @@ -41,6 +41,23 @@ typedef enum { questFailedToLoad } PerlQuestStatus; +enum class QuestType { + Bot, + BotGlobal, + Item, + ItemGlobal, + Merc, + MercGlobal, + NPC, + NPCGlobal, + Player, + PlayerGlobal, + Spell, + SpellGlobal, + Zone, + ZoneGlobal +}; + class PerlembParser : public QuestInterface { public: PerlembParser(); @@ -136,6 +153,22 @@ public: std::vector* extra_pointers ); + virtual int EventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); + + virtual int EventGlobalZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); + virtual bool HasQuestSub(uint32 npc_id, QuestEventID event_id); virtual bool HasGlobalQuestSub(QuestEventID event_id); virtual bool PlayerHasQuestSub(QuestEventID event_id); @@ -146,6 +179,8 @@ public: virtual bool GlobalBotHasQuestSub(QuestEventID event_id); virtual bool MercHasQuestSub(QuestEventID event_id); virtual bool GlobalMercHasQuestSub(QuestEventID event_id); + virtual bool ZoneHasQuestSub(QuestEventID event_id); + virtual bool GlobalZoneHasQuestSub(QuestEventID event_id); virtual void LoadNPCScript(std::string filename, int npc_id); virtual void LoadGlobalNPCScript(std::string filename); @@ -157,6 +192,8 @@ public: virtual void LoadGlobalBotScript(std::string filename); virtual void LoadMercScript(std::string filename); virtual void LoadGlobalMercScript(std::string filename); + virtual void LoadZoneScript(std::string filename); + virtual void LoadGlobalZoneScript(std::string filename); virtual void AddVar(std::string name, std::string val); virtual std::string GetVar(std::string name); @@ -182,6 +219,7 @@ private: EQ::ItemInstance* inst, const SPDat_Spell_Struct* spell, Mob* mob, + Zone* zone, uint32 extra_data, bool is_global, std::vector* extra_pointers @@ -194,59 +232,34 @@ private: Mob* other, Mob* mob, EQ::ItemInstance* inst, - const SPDat_Spell_Struct* spell + const SPDat_Spell_Struct* spell, + Zone* zone ); void MapFunctions(); - void GetQuestTypes( - bool& is_player_quest, - bool& is_global_player_quest, - bool& is_bot_quest, - bool& is_global_bot_quest, - bool& is_merc_quest, - bool& is_global_merc_quest, - bool& is_global_npc_quest, - bool& is_item_quest, - bool& is_spell_quest, + QuestType GetQuestTypes( QuestEventID event, Mob* npc_mob, EQ::ItemInstance* inst, Mob* mob, + Zone* zone, bool is_global ); - void GetQuestPackageName( - bool& is_player_quest, - bool& is_global_player_quest, - bool& is_bot_quest, - bool& is_global_bot_quest, - bool& is_merc_quest, - bool& is_global_merc_quest, - bool& is_global_npc_quest, - bool& is_item_quest, - bool& is_spell_quest, - std::string& package_name, + std::string GetQuestPackageName( + QuestType quest_type, QuestEventID event, uint32 object_id, const char* data, Mob* npc_mob, - EQ::ItemInstance* inst, - bool is_global + EQ::ItemInstance* inst ); void ExportCharID(const std::string& package_name, int& char_id, Mob* npc_mob, Mob* mob); void ExportQGlobals( - bool is_player_quest, - bool is_global_player_quest, - bool is_bot_quest, - bool is_global_bot_quest, - bool is_merc_quest, - bool is_global_merc_quest, - bool is_global_npc_quest, - bool is_item_quest, - bool is_spell_quest, + QuestType quest_type, std::string& package_name, Mob* npc_mob, Mob* mob, @@ -254,15 +267,7 @@ private: ); void ExportMobVariables( - bool is_player_quest, - bool is_global_player_quest, - bool is_bot_quest, - bool is_global_bot_quest, - bool is_merc_quest, - bool is_global_merc_quest, - bool is_global_npc_quest, - bool is_item_quest, - bool is_spell_quest, + QuestType quest_type, std::string& package_name, Mob* mob, Mob* npc_mob @@ -295,6 +300,8 @@ private: PerlQuestStatus global_bot_quest_status_; PerlQuestStatus merc_quest_status_; PerlQuestStatus global_merc_quest_status_; + PerlQuestStatus zone_quest_status_; + PerlQuestStatus global_zone_quest_status_; SV* _empty_sv; diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 8bd0bfa94..feedab7fd 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -6005,6 +6005,50 @@ bool Perl__handin(perl::reference handin_ref) return quest_manager.handin(handin_map); } +perl::array Perl__get_paused_timers(Mob* m) +{ + perl::array a; + + const auto& l = quest_manager.GetPausedTimers(m); + + if (!l.empty()) { + a.reserve(l.size()); + + for (const auto& v : l) { + a.push_back(v); + } + } + + return a; +} + +perl::array Perl__get_timers(Mob* m) +{ + perl::array a; + + const auto& l = quest_manager.GetTimers(m); + + if (!l.empty()) { + a.reserve(l.size()); + + for (const auto& v: l) { + a.push_back(v); + } + } + + return a; +} + +std::string Perl__get_pet_command_name(uint8 pet_command) +{ + return PetCommand::GetName(pet_command); +} + +std::string Perl__get_pet_type_name(uint8 pet_type) +{ + return PetType::GetName(pet_type); +} + void perl_register_quest() { perl::interpreter perl(PERL_GET_THX); @@ -6694,6 +6738,9 @@ void perl_register_quest() package.add("getguildidbycharid", &Perl__getguildidbycharid); package.add("getgroupidbycharid", &Perl__getgroupidbycharid); package.add("getinventoryslotname", &Perl__getinventoryslotname); + package.add("get_paused_timers", &Perl__get_paused_timers); + package.add("get_pet_command_name", &Perl__get_pet_command_name); + package.add("get_pet_type_name", &Perl__get_pet_type_name); package.add("getraididbycharid", &Perl__getraididbycharid); package.add("get_race_bitmask", &Perl__get_race_bitmask); package.add("get_recipe_component_item_ids", &Perl__GetRecipeComponentItemIDs); @@ -6713,6 +6760,7 @@ void perl_register_quest() package.add("getspellstat", (int(*)(uint32, std::string))&Perl__getspellstat); package.add("getspellstat", (int(*)(uint32, std::string, uint8))&Perl__getspellstat); package.add("getskillname", &Perl__getskillname); + package.add("get_timers", &Perl__get_timers); package.add("getlevel", &Perl__getlevel); package.add("getplayerburiedcorpsecount", &Perl__getplayerburiedcorpsecount); package.add("getplayercorpsecount", &Perl__getplayercorpsecount); diff --git a/zone/entity.cpp b/zone/entity.cpp index b87895001..0b94fc7ac 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -743,6 +743,11 @@ void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue) npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr); } + if (parse->ZoneHasQuestSub(EVENT_SPAWN_ZONE)) { + std::vector args = { npc }; + parse->EventZone(EVENT_SPAWN_ZONE, zone, "", 0, &args); + } + if (zone->HasMap() && zone->HasWaterMap()) { npc->SetSpawnedInWater(false); if (zone->watermap->InLiquid(npc->GetPosition())) { diff --git a/zone/event_codes.h b/zone/event_codes.h index aeee13393..0d14f565d 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -145,6 +145,7 @@ typedef enum { EVENT_AA_LOSS, EVENT_SPELL_BLOCKED, EVENT_READ_ITEM, + EVENT_PET_COMMAND, // Add new events before these or Lua crashes EVENT_SPELL_EFFECT_BOT, diff --git a/zone/gm_commands/find.cpp b/zone/gm_commands/find.cpp index 0bdbcbe70..6ee5815cb 100644 --- a/zone/gm_commands/find.cpp +++ b/zone/gm_commands/find.cpp @@ -1,5 +1,6 @@ #include "../client.h" #include "find/aa.cpp" +#include "find/account.cpp" #include "find/body_type.cpp" #include "find/bot.cpp" #include "find/bug_category.cpp" @@ -38,6 +39,7 @@ void command_find(Client *c, const Seperator *sep) std::vector commands = { Cmd{.cmd = "aa", .u = "aa [Search Criteria]", .fn = FindAA, .a = {"#findaa"}}, + Cmd{.cmd = "account", .u = "account [Search Criteria]", .fn = FindAccount, .a = {"#findaccount"}}, Cmd{.cmd = "body_type", .u = "body_type [Search Criteria]", .fn = FindBodyType, .a = {"#findbodytype"}}, Cmd{.cmd = "bug_category", .u = "bug_category [Search Criteria]", .fn = FindBugCategory, .a = {"#findbugcategory"}}, Cmd{.cmd = "character", .u = "character [Search Criteria]", .fn = FindCharacter, .a = {"#findcharacter"}}, @@ -72,7 +74,7 @@ void command_find(Client *c, const Seperator *sep) commands.emplace_back( Cmd{.cmd = "bot", .u = "bot [Search Criteria]", .fn = FindBot, .a = {"#findbot"}} ); - + std::sort(commands.begin(), commands.end(), [](const Cmd& a, const Cmd& b) { return a.cmd < b.cmd; }); diff --git a/zone/gm_commands/find/account.cpp b/zone/gm_commands/find/account.cpp new file mode 100644 index 000000000..1265c8431 --- /dev/null +++ b/zone/gm_commands/find/account.cpp @@ -0,0 +1,50 @@ +#include "../../client.h" +#include "../../common/repositories/account_repository.h" + +void FindAccount(Client *c, const Seperator *sep) +{ + const uint16 arguments = sep->argnum; + if (arguments < 2) { + c->Message(Chat::White, "Usage: #find account [Character Name]"); + c->Message(Chat::White, "Note: Used to print the account ID and name of the account a character belongs to."); + return; + } + + const std::string& character_name = sep->arg[2]; + + const auto& e = CharacterDataRepository::FindByName(database, character_name); + + if (!e.id) { + c->Message( + Chat::White, + fmt::format( + "Character '{}' does not exist.", + character_name + ).c_str() + ); + return; + } + + auto a = AccountRepository::FindOne(database, e.account_id); + + if (!a.id) { + c->Message( + Chat::White, + fmt::format( + "Character '{}' is not attached to an account.", + character_name + ).c_str() + ); + return; + } + + c->Message( + Chat::White, + fmt::format( + "Account {} ({}) owns the character {}.", + a.name, + a.id, + character_name + ).c_str() + ); +} diff --git a/zone/gm_commands/npcedit.cpp b/zone/gm_commands/npcedit.cpp index 4f372b1e0..ff0080e67 100755 --- a/zone/gm_commands/npcedit.cpp +++ b/zone/gm_commands/npcedit.cpp @@ -110,6 +110,7 @@ void SendNPCEditSubCommands(Client *c) c->Message(Chat::White, "Usage: #npcedit setanimation [Animation ID] - Sets an NPC's Animation on Spawn (Stored in spawn2 table)"); c->Message(Chat::White, "Usage: #npcedit respawntime [Respawn Time] - Sets an NPC's Respawn Timer in Seconds (Stored in spawn2 table)"); c->Message(Chat::White, "Usage: #npcedit set_grid [Grid ID] - Sets an NPC's Grid ID"); + c->Message(Chat::White, "Usage: #npcedit npc_tint_id [NPC Tint ID] - Sets an NPC's Tint ID (0 to 78 for RoF2)"); } void command_npcedit(Client *c, const Seperator *sep) @@ -1836,4 +1837,4 @@ void command_npcedit(Client *c, const Seperator *sep) } c->Message(Chat::White, d.c_str()); -} \ No newline at end of file +} diff --git a/zone/gm_commands/show.cpp b/zone/gm_commands/show.cpp index 8f45ee869..5a5de4560 100755 --- a/zone/gm_commands/show.cpp +++ b/zone/gm_commands/show.cpp @@ -15,6 +15,7 @@ #include "show/group_info.cpp" #include "show/hatelist.cpp" #include "show/inventory.cpp" +#include "show/keyring.cpp" #include "show/ip_lookup.cpp" #include "show/line_of_sight.cpp" #include "show/network.cpp" @@ -78,6 +79,7 @@ void command_show(Client *c, const Seperator *sep) Cmd{.cmd = "hatelist", .u = "hatelist", .fn = ShowHateList, .a = {"#hatelist"}}, Cmd{.cmd = "inventory", .u = "inventory", .fn = ShowInventory, .a = {"#peekinv"}}, Cmd{.cmd = "ip_lookup", .u = "ip_lookup", .fn = ShowIPLookup, .a = {"#iplookup"}}, + Cmd{.cmd = "keyring", .u = "keyring", .fn = ShowKeyring, .a = {"#showkeyring"}}, Cmd{.cmd = "line_of_sight", .u = "line_of_sight", .fn = ShowLineOfSight, .a = {"#checklos"}}, Cmd{.cmd = "network", .u = "network", .fn = ShowNetwork, .a = {"#network"}}, Cmd{.cmd = "network_stats", .u = "network_stats", .fn = ShowNetworkStats, .a = {"#netstats"}}, diff --git a/zone/gm_commands/show/keyring.cpp b/zone/gm_commands/show/keyring.cpp new file mode 100644 index 000000000..39552f8cc --- /dev/null +++ b/zone/gm_commands/show/keyring.cpp @@ -0,0 +1,12 @@ +#include "../../client.h" +#include "../../dialogue_window.h" + +void ShowKeyring(Client *c, const Seperator *sep) +{ + Client* t = c; + if (c->GetTarget() && c->GetTarget()->IsClient()) { + t = c->GetTarget()->CastToClient(); + } + + t->KeyRingList(c); +} diff --git a/zone/gm_commands/show/network.cpp b/zone/gm_commands/show/network.cpp index d9eff2c16..46d32a69c 100644 --- a/zone/gm_commands/show/network.cpp +++ b/zone/gm_commands/show/network.cpp @@ -16,17 +16,17 @@ void ShowNetwork(Client *c, const Seperator *sep) popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Max Packet Size") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.max_packet_size)) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.max_packet_size)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Max Connection Count") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.max_connection_count)) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.max_connection_count)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Keep Alive Delay") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.keepalive_delay_ms)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.keepalive_delay_ms)) ); popup_table += DialogueWindow::TableRow( @@ -34,64 +34,64 @@ void ShowNetwork(Client *c, const Seperator *sep) DialogueWindow::TableCell( fmt::format( "{:.2f}", - opts.daybreak_options.resend_delay_factor + opts.reliable_stream_options.resend_delay_factor ) ) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Resend Delay") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.resend_delay_ms)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.resend_delay_ms)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Resend Delay Minimum") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.resend_delay_min)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.resend_delay_min)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Resend Delay Maximum") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.resend_delay_max)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.resend_delay_max)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Connect Delay") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.connect_delay_ms)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.connect_delay_ms)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Connect Stale") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.connect_stale_ms)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.connect_stale_ms)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Stale Connection") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.stale_connection_ms)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.stale_connection_ms)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("CRC Length") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.crc_length)) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.crc_length)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Hold Size") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.hold_size)) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.hold_size)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Hold Length") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.hold_length_ms)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.hold_length_ms)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Simulated In Packet Loss") + - DialogueWindow::TableCell(std::to_string(opts.daybreak_options.simulated_in_packet_loss)) + DialogueWindow::TableCell(std::to_string(opts.reliable_stream_options.simulated_in_packet_loss)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Simulated Out Packet Loss") + - DialogueWindow::TableCell(std::to_string(opts.daybreak_options.simulated_out_packet_loss)) + DialogueWindow::TableCell(std::to_string(opts.reliable_stream_options.simulated_out_packet_loss)) ); popup_table += DialogueWindow::TableRow( @@ -99,34 +99,34 @@ void ShowNetwork(Client *c, const Seperator *sep) DialogueWindow::TableCell( fmt::format( "{:.2f}", - opts.daybreak_options.tic_rate_hertz + opts.reliable_stream_options.tic_rate_hertz ) ) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Resend Timeout") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.resend_timeout)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.resend_timeout)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Connection Close Time") + - DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.daybreak_options.connection_close_time)) + DialogueWindow::TableCell(Strings::MillisecondsToTime(opts.reliable_stream_options.connection_close_time)) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Encode Passes (1)") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.encode_passes[0])) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.encode_passes[0])) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Encode Passes (2)") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.encode_passes[1])) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.encode_passes[1])) ); popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Port") + - DialogueWindow::TableCell(Strings::Commify(opts.daybreak_options.port)) + DialogueWindow::TableCell(Strings::Commify(opts.reliable_stream_options.port)) ); popup_table = DialogueWindow::Table(popup_table); diff --git a/zone/gm_commands/show/network_stats.cpp b/zone/gm_commands/show/network_stats.cpp index 8d51e8f69..75bf2b25f 100644 --- a/zone/gm_commands/show/network_stats.cpp +++ b/zone/gm_commands/show/network_stats.cpp @@ -7,7 +7,7 @@ void ShowNetworkStats(Client *c, const Seperator *sep) const auto opts = connection->GetManager()->GetOptions(); const auto eqs_stats = connection->GetStats(); - const auto& stats = eqs_stats.DaybreakStats; + const auto& stats = eqs_stats.ReliableStreamStats; const auto sec_since_stats_reset = std::chrono::duration_cast>( EQ::Net::Clock::now() - stats.created @@ -217,7 +217,7 @@ void ShowNetworkStats(Client *c, const Seperator *sep) ) ); - if (opts.daybreak_options.outgoing_data_rate > 0.0) { + if (opts.reliable_stream_options.outgoing_data_rate > 0.0) { popup_table += DialogueWindow::TableRow( DialogueWindow::TableCell("Outgoing Link Saturation") + DialogueWindow::TableCell( @@ -229,14 +229,14 @@ void ShowNetworkStats(Client *c, const Seperator *sep) 1.0 - ( ( - opts.daybreak_options.outgoing_data_rate - + opts.reliable_stream_options.outgoing_data_rate - stats.datarate_remaining ) / - opts.daybreak_options.outgoing_data_rate + opts.reliable_stream_options.outgoing_data_rate ) ) ), - opts.daybreak_options.outgoing_data_rate + opts.reliable_stream_options.outgoing_data_rate ) ) ); diff --git a/zone/gm_commands/show/recipe.cpp b/zone/gm_commands/show/recipe.cpp index e4bd45ad1..e9f8db666 100644 --- a/zone/gm_commands/show/recipe.cpp +++ b/zone/gm_commands/show/recipe.cpp @@ -10,7 +10,7 @@ void ShowRecipe(Client *c, const Seperator *sep) return; } - const uint16 recipe_id = static_cast(Strings::ToUnsignedInt(sep->arg[2])); + const uint32 recipe_id = Strings::ToUnsignedInt(sep->arg[2]); const auto& re = TradeskillRecipeEntriesRepository::GetWhere( content_db, diff --git a/zone/groups.cpp b/zone/groups.cpp index 821546e7e..b70f44f18 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -2472,19 +2472,63 @@ bool Group::AmIPuller(const char *mob_name) return !((bool)PullerName.compare(mob_name)); } -bool Group::HasRole(Mob *m, uint8 Role) +bool Group::HasRole(Mob* m, uint8 Role) { - if(!m) + if (!m) { return false; - - for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) - { - if((m == members[i]) && (MemberRoles[i] & Role)) - return true; } + + for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) { + if (m == members[i] && MemberRoles[i] & Role) { + return true; + } + } + return false; } +uint8 Group::GetMemberRole(Mob* m) +{ + if (!m) { + return 0; + } + + for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) { + if (m == members[i]) { + uint8 role = MemberRoles[i]; + + if (m == leader) { + role |= RoleLeader; + } + + return role; + } + } + + return 0; +} + +uint8 Group::GetMemberRole(const char* name) +{ + if (!name) { + return 0; + } + + for (uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) { + if (!strcasecmp(membername[i], name)) { + uint8 role = MemberRoles[i]; + + if (leader && !strcasecmp(leader->GetName(), name)) { + role |= RoleLeader; + } + + return role; + } + } + + return 0; +} + void Group::QueueClients(Mob *sender, const EQApplicationPacket *app, bool ack_required /*= true*/, bool ignore_sender /*= true*/, float distance /*= 0*/) { if (sender && sender->IsClient()) { for (uint32 i = 0; i < MAX_GROUP_MEMBERS; i++) { diff --git a/zone/groups.h b/zone/groups.h index a07ecc61c..8c312f6ef 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -30,7 +30,12 @@ class Mob; #define MAX_MARKED_NPCS 3 -enum { RoleAssist = 1, RoleTank = 2, RolePuller = 4 }; +enum { + RoleAssist = 1, + RoleTank = 2, + RolePuller = 4, + RoleLeader = 8 +}; class GroupIDConsumer { public: @@ -119,6 +124,8 @@ public: void SetGroupTankTarget(Mob *m); void SetGroupPullerTarget(Mob *m); bool HasRole(Mob *m, uint8 Role); + uint8 GetMemberRole(Mob* m); + uint8 GetMemberRole(const char* name); void NotifyAssistTarget(Client *c); void NotifyTankTarget(Client *c); void NotifyPullerTarget(Client *c); diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index b99636f19..15ec526b6 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -3575,7 +3575,13 @@ bool Lua_Client::KeyRingClear() void Lua_Client::KeyRingList() { Lua_Safe_Call_Void(); - self->KeyRingList(); + self->KeyRingList(self); +} + +void Lua_Client::KeyRingList(Lua_Client c) +{ + Lua_Safe_Call_Void(); + self->KeyRingList(self); } bool Lua_Client::KeyRingRemove(uint32 item_id) @@ -3602,6 +3608,22 @@ void Lua_Client::EnableTitleSet(uint32 title_set) { self->EnableTitle(title_set); } +luabind::object Lua_Client::GetKeyRing(lua_State* L) +{ + auto lua_table = luabind::newtable(L); + + if (d_) { + auto self = reinterpret_cast(d_); + int index = 1; + for (const uint32& item_id: self->GetKeyRing()) { + lua_table[index] = item_id; + index++; + } + } + + return lua_table; +} + luabind::scope lua_register_client() { return luabind::class_("Client") .def(luabind::constructor<>()) @@ -3832,6 +3854,7 @@ luabind::scope lua_register_client() { .def("GetInvulnerableEnvironmentDamage", (bool(Lua_Client::*)(void))&Lua_Client::GetInvulnerableEnvironmentDamage) .def("GetItemIDAt", (int(Lua_Client::*)(int))&Lua_Client::GetItemIDAt) .def("GetItemCooldown", (uint32(Lua_Client::*)(uint32))&Lua_Client::GetItemCooldown) + .def("GetKeyRing", (luabind::object(Lua_Client::*)(lua_State* L))&Lua_Client::GetKeyRing) .def("GetLDoNLosses", (int(Lua_Client::*)(void))&Lua_Client::GetLDoNLosses) .def("GetLDoNLossesTheme", (int(Lua_Client::*)(int))&Lua_Client::GetLDoNLossesTheme) .def("GetLDoNPointsTheme", (int(Lua_Client::*)(int))&Lua_Client::GetLDoNPointsTheme) @@ -3932,6 +3955,7 @@ luabind::scope lua_register_client() { .def("KeyRingCheck", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingCheck) .def("KeyRingClear", (bool(Lua_Client::*)(void))&Lua_Client::KeyRingClear) .def("KeyRingList", (void(Lua_Client::*)(void))&Lua_Client::KeyRingList) + .def("KeyRingList", (void(Lua_Client::*)(Lua_Client))&Lua_Client::KeyRingList) .def("KeyRingRemove", (bool(Lua_Client::*)(uint32))&Lua_Client::KeyRingRemove) .def("Kick", (void(Lua_Client::*)(void))&Lua_Client::Kick) .def("LearnDisciplines", (uint16(Lua_Client::*)(uint8,uint8))&Lua_Client::LearnDisciplines) diff --git a/zone/lua_client.h b/zone/lua_client.h index 04b9da273..c85c061b6 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -521,9 +521,11 @@ public: bool KeyRingCheck(uint32 item_id); bool KeyRingClear(); void KeyRingList(); + void KeyRingList(Lua_Client c); bool KeyRingRemove(uint32 item_id); bool CompleteTask(int task_id); bool UncompleteTask(int task_id); + luabind::object GetKeyRing(lua_State* L); // account data buckets void SetAccountBucket(std::string bucket_name, std::string bucket_value); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index b7e1964d9..ae8c4b2af 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -5675,6 +5675,42 @@ bool lua_handin(luabind::adl::object handin_table) return quest_manager.handin(handin_map); } +luabind::object lua_get_paused_timers(lua_State* L, Mob* m) { + auto t = luabind::newtable(L); + auto v = quest_manager.GetPausedTimers(m); + int i = 1; + + for (const auto& e : v) { + t[i] = e; + i++; + } + + return t; +} + +luabind::object lua_get_timers(lua_State* L, Mob* m) { + auto t = luabind::newtable(L); + auto v = quest_manager.GetTimers(m); + int i = 1; + + for (const auto& e : v) { + t[i] = e; + i++; + } + + return t; +} + +std::string lua_get_pet_command_name(uint8 pet_command) +{ + return PetCommand::GetName(pet_command); +} + +std::string lua_get_pet_type_name(uint8 pet_type) +{ + return PetType::GetName(pet_type); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ @@ -6486,6 +6522,10 @@ luabind::scope lua_register_general() { luabind::def("spawn_grid", &lua_spawn_grid), luabind::def("get_zone", &lua_get_zone), luabind::def("handin", &lua_handin), + luabind::def("get_paused_timers", &lua_get_paused_timers), + luabind::def("get_timers", &lua_get_timers), + luabind::def("get_pet_command_name", &lua_get_pet_command_name), + luabind::def("get_pet_type_name", &lua_get_pet_type_name), /* Cross Zone */ @@ -6951,7 +6991,8 @@ luabind::scope lua_register_events() { luabind::value("entity_variable_set", static_cast(EVENT_ENTITY_VARIABLE_SET)), luabind::value("entity_variable_update", static_cast(EVENT_ENTITY_VARIABLE_UPDATE)), luabind::value("aa_loss", static_cast(EVENT_AA_LOSS)), - luabind::value("read", static_cast(EVENT_READ_ITEM)) + luabind::value("read", static_cast(EVENT_READ_ITEM)), + luabind::value("pet_command", static_cast(EVENT_PET_COMMAND)) )]; } diff --git a/zone/lua_group.cpp b/zone/lua_group.cpp index a427ef3d3..4bb1f4c4f 100644 --- a/zone/lua_group.cpp +++ b/zone/lua_group.cpp @@ -122,6 +122,16 @@ Lua_Mob Lua_Group::GetMember(int member_index) { return self->members[member_index]; } +uint8 Lua_Group::GetMemberRole(Lua_Mob member) { + Lua_Safe_Call_Int(); + return self->GetMemberRole(member); +} + +uint8 Lua_Group::GetMemberRole(const char* name) { + Lua_Safe_Call_Int(); + return self->GetMemberRole(name); +} + bool Lua_Group::DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name) { Lua_Safe_Call_Bool(); @@ -155,6 +165,8 @@ luabind::scope lua_register_group() { .def("GetLeaderName", (const char*(Lua_Group::*)(void))&Lua_Group::GetLeaderName) .def("GetLowestLevel", (uint32(Lua_Group::*)(void))&Lua_Group::GetLowestLevel) .def("GetMember", (Lua_Mob(Lua_Group::*)(int))&Lua_Group::GetMember) + .def("GetMemberRole", (uint8(Lua_Group::*)(Lua_Mob))&Lua_Group::GetMemberRole) + .def("GetMemberRole", (uint8(Lua_Group::*)(const char*))&Lua_Group::GetMemberRole) .def("GetTotalGroupDamage", (uint32(Lua_Group::*)(Lua_Mob))&Lua_Group::GetTotalGroupDamage) .def("GroupCount", (int(Lua_Group::*)(void))&Lua_Group::GroupCount) .def("GroupMessage", (void(Lua_Group::*)(Lua_Mob,const char*))&Lua_Group::GroupMessage) diff --git a/zone/lua_group.h b/zone/lua_group.h index 949740d66..ee4e353bc 100644 --- a/zone/lua_group.h +++ b/zone/lua_group.h @@ -49,6 +49,8 @@ public: void TeleportGroup(Lua_Mob sender, uint32 zone_id, uint32 instance_id, float x, float y, float z, float h); int GetID(); Lua_Mob GetMember(int member_index); + uint8 GetMemberRole(Lua_Mob member); + uint8 GetMemberRole(const char* name); bool DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name); bool DoesAnyMemberHaveExpeditionLockout(std::string expedition_name, std::string event_name, int max_check_count); }; diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 27ab7bbd8..e23eb2d03 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1241,12 +1241,12 @@ float Lua_Mob::GetAssistRange() { return self->GetAssistRange(); } -void Lua_Mob::SetPetOrder(int order) { +void Lua_Mob::SetPetOrder(uint8 pet_order) { Lua_Safe_Call_Void(); - self->SetPetOrder(static_cast(order)); + self->SetPetOrder(pet_order); } -int Lua_Mob::GetPetOrder() { +uint8 Lua_Mob::GetPetOrder() { Lua_Safe_Call_Int(); return self->GetPetOrder(); } @@ -3482,6 +3482,54 @@ void Lua_Mob::BuffFadeSongs() self->BuffFadeSongs(); } +luabind::object Lua_Mob::GetPausedTimers(lua_State* L) { + auto t = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto l = quest_manager.GetPausedTimers(self); + int i = 1; + for (const auto& v : l) { + t[i] = v; + i++; + } + } + + return t; +} + +luabind::object Lua_Mob::GetTimers(lua_State* L) { + auto t = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto l = quest_manager.GetTimers(self); + int i = 1; + for (const auto& v : l) { + t[i] = v; + i++; + } + } + + return t; +} + +uint8 Lua_Mob::GetPetType() +{ + Lua_Safe_Call_Int(); + return self->GetPetType(); +} + +std::string Lua_Mob::GetPetTypeName() +{ + Lua_Safe_Call_String(); + return PetType::GetName(self->GetPetType()); +} + +void Lua_Mob::SetPetType(uint8 pet_type) +{ + Lua_Safe_Call_Void(); + self->SetPetType(pet_type); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -3822,8 +3870,11 @@ luabind::scope lua_register_mob() { .def("GetOwner", &Lua_Mob::GetOwner) .def("GetOwnerID", &Lua_Mob::GetOwnerID) .def("GetPR", &Lua_Mob::GetPR) + .def("GetPausedTimers", &Lua_Mob::GetPausedTimers) .def("GetPet", &Lua_Mob::GetPet) - .def("GetPetOrder", (int(Lua_Mob::*)(void))&Lua_Mob::GetPetOrder) + .def("GetPetOrder", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetPetOrder) + .def("GetPetType", &Lua_Mob::GetPetType) + .def("GetPetTypeName", &Lua_Mob::GetPetTypeName) .def("GetPhR", &Lua_Mob::GetPhR) .def("GetRace", &Lua_Mob::GetRace) .def("GetRaceName", &Lua_Mob::GetRaceName) @@ -3847,6 +3898,7 @@ luabind::scope lua_register_mob() { .def("GetTarget", &Lua_Mob::GetTarget) .def("GetTexture", &Lua_Mob::GetTexture) .def("GetTimerDurationMS", &Lua_Mob::GetTimerDurationMS) + .def("GetTimers", &Lua_Mob::GetTimers) .def("GetUltimateOwner", &Lua_Mob::GetUltimateOwner) .def("GetWIS", &Lua_Mob::GetWIS) .def("GetWalkspeed", &Lua_Mob::GetWalkspeed) @@ -3908,7 +3960,7 @@ luabind::scope lua_register_mob() { .def("IsPausedTimer", &Lua_Mob::IsPausedTimer) .def("IsPet", (bool(Lua_Mob::*)(void))&Lua_Mob::IsPet) .def("IsPetOwnerBot", &Lua_Mob::IsPetOwnerBot) - .def("IsPetOwnerClient", &Lua_Mob::IsPetOwnerClient) + .def("IsPetOwnerClient", &Lua_Mob::IsPetOwnerClient) .def("IsPetOwnerNPC", &Lua_Mob::IsPetOwnerNPC) .def("IsPetOwnerOfClientBot", &Lua_Mob::IsPetOwnerOfClientBot) .def("IsPureMeleeClass", &Lua_Mob::IsPureMeleeClass) @@ -4017,7 +4069,8 @@ luabind::scope lua_register_mob() { .def("SetMana", &Lua_Mob::SetMana) .def("SetOOCRegen", (void(Lua_Mob::*)(int64))&Lua_Mob::SetOOCRegen) .def("SetPet", &Lua_Mob::SetPet) - .def("SetPetOrder", (void(Lua_Mob::*)(int))&Lua_Mob::SetPetOrder) + .def("SetPetOrder", (void(Lua_Mob::*)(uint8))&Lua_Mob::SetPetOrder) + .def("SetPetType", &Lua_Mob::SetPetType) .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot) .def("SetRace", (void(Lua_Mob::*)(uint16))&Lua_Mob::SetRace) .def("SetRunning", (void(Lua_Mob::*)(bool))&Lua_Mob::SetRunning) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index 0f3d4f6c4..b5019aa5f 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -280,8 +280,8 @@ public: bool IsAIControlled(); float GetAggroRange(); float GetAssistRange(); - void SetPetOrder(int order); - int GetPetOrder(); + void SetPetOrder(uint8 pet_order); + uint8 GetPetOrder(); bool IsRoamer(); bool IsRooted(); bool IsEngaged(); @@ -574,7 +574,7 @@ public: bool IsFamiliar(); bool IsTargetLockPet(); bool IsPetOwnerBot(); - bool IsPetOwnerClient(); + bool IsPetOwnerClient(); bool IsPetOwnerNPC(); bool IsPetOwnerOfClientBot(); bool IsDestructibleObject(); @@ -612,6 +612,11 @@ public: void BuffFadeDetrimentalByCaster(Lua_Mob caster); void BuffFadeNonPersistDeath(); void BuffFadeSongs(); + luabind::object GetPausedTimers(lua_State* L); + luabind::object GetTimers(lua_State* L); + uint8 GetPetType(); + std::string GetPetTypeName(); + void SetPetType(uint8 pet_type); }; #endif diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 67f26155d..b0cd59c49 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -945,10 +945,16 @@ bool Lua_NPC::IsResumedFromZoneSuspend() return self->IsResumedFromZoneSuspend(); } -void Lua_NPC::SetNPCTintIndex(uint32 id) +void Lua_NPC::SetNPCTintIndex(uint32 index) { Lua_Safe_Call_Void(); - self->SendAppearancePacket(AppearanceType::NPCTintIndex, id); + self->SetNPCTintIndex(index); +} + +uint32 Lua_NPC::GetNPCTintIndex() +{ + Lua_Safe_Call_Int(); + return self->GetNPCTintIndex(); } luabind::scope lua_register_npc() { @@ -1018,6 +1024,7 @@ luabind::scope lua_register_npc() { .def("GetNPCSpellsEffectsID", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsEffectsID) .def("GetNPCSpellsID", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetNPCStat", (float(Lua_NPC::*)(std::string))&Lua_NPC::GetNPCStat) + .def("GetNPCTintIndex", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetNPCTintIndex) .def("GetPetSpellID", (int(Lua_NPC::*)(void))&Lua_NPC::GetPetSpellID) .def("GetPlatinum", (uint32(Lua_NPC::*)(void))&Lua_NPC::GetPlatinum) .def("GetPrimSkill", (int(Lua_NPC::*)(void))&Lua_NPC::GetPrimSkill) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 90d6e2142..d166ccdff 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -200,6 +200,7 @@ public: Lua_Spawn GetSpawn(lua_State* L); bool IsResumedFromZoneSuspend(); void SetNPCTintIndex(uint32 id); + uint32 GetNPCTintIndex(); }; diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index d44fb2bfa..c3f37aec5 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -188,7 +188,8 @@ const char *LuaEvents[_LargestEventID] = { "event_entity_variable_update", "event_aa_loss", "event_spell_blocked", - "event_read_item" + "event_read_item", + "event_pet_command" }; extern Zone *zone; @@ -219,6 +220,7 @@ LuaParser::LuaParser() { SpellArgumentDispatch[i] = handle_spell_null; EncounterArgumentDispatch[i] = handle_encounter_null; BotArgumentDispatch[i] = handle_bot_null; + ZoneArgumentDispatch[i] = handle_zone_null; } NPCArgumentDispatch[EVENT_SAY] = handle_npc_event_say; @@ -263,6 +265,7 @@ LuaParser::LuaParser() { NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_npc_entity_variable; NPCArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_npc_entity_variable; NPCArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_npc_spell_blocked; + NPCArgumentDispatch[EVENT_PET_COMMAND] = handle_npc_pet_command; PlayerArgumentDispatch[EVENT_SAY] = handle_player_say; PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage; @@ -354,6 +357,7 @@ LuaParser::LuaParser() { PlayerArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_player_spell_blocked; PlayerArgumentDispatch[EVENT_READ_ITEM] = handle_player_read_item; PlayerArgumentDispatch[EVENT_CONNECT] = handle_player_connect; + PlayerArgumentDispatch[EVENT_PET_COMMAND] = handle_player_pet_command; ItemArgumentDispatch[EVENT_ITEM_CLICK] = handle_item_click; ItemArgumentDispatch[EVENT_ITEM_CLICK_CAST] = handle_item_click; @@ -409,6 +413,23 @@ LuaParser::LuaParser() { BotArgumentDispatch[EVENT_ENTITY_VARIABLE_SET] = handle_bot_entity_variable; BotArgumentDispatch[EVENT_ENTITY_VARIABLE_UPDATE] = handle_bot_entity_variable; BotArgumentDispatch[EVENT_SPELL_BLOCKED] = handle_bot_spell_blocked; + + ZoneArgumentDispatch[EVENT_CLICK_DOOR] = handle_zone_click_door; + ZoneArgumentDispatch[EVENT_CLICK_OBJECT] = handle_zone_click_object; + ZoneArgumentDispatch[EVENT_DEATH_ZONE] = handle_zone_death; + ZoneArgumentDispatch[EVENT_DESPAWN_ZONE] = handle_zone_despawn; + ZoneArgumentDispatch[EVENT_ENTER_ZONE] = handle_zone_enter; + ZoneArgumentDispatch[EVENT_LOOT_ZONE] = handle_zone_loot; + ZoneArgumentDispatch[EVENT_PAYLOAD] = handle_zone_payload; + ZoneArgumentDispatch[EVENT_PLAYER_PICKUP] = handle_zone_pickup; + ZoneArgumentDispatch[EVENT_POPUP_RESPONSE] = handle_zone_popup; + ZoneArgumentDispatch[EVENT_SIGNAL] = handle_zone_signal; + ZoneArgumentDispatch[EVENT_SPAWN_ZONE] = handle_zone_spawn; + ZoneArgumentDispatch[EVENT_TIMER] = handle_zone_timer; + ZoneArgumentDispatch[EVENT_TIMER_PAUSE] = handle_zone_timer_pause_resume_start; + ZoneArgumentDispatch[EVENT_TIMER_RESUME] = handle_zone_timer_pause_resume_start; + ZoneArgumentDispatch[EVENT_TIMER_START] = handle_zone_timer_pause_resume_start; + ZoneArgumentDispatch[EVENT_TIMER_STOP] = handle_zone_timer_stop; #endif L = nullptr; @@ -489,7 +510,13 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M arg_function(this, L, npc, init, data, extra_data, extra_pointers); Client *c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - quest_manager.StartQuest(npc, c); + RunningQuest q; + + q.owner = npc; + q.initiator = c; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -582,7 +609,13 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client * auto arg_function = PlayerArgumentDispatch[evt]; arg_function(this, L, client, data, extra_data, extra_pointers); - quest_manager.StartQuest(client, client); + RunningQuest q; + + q.owner = client; + q.initiator = client; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -666,7 +699,14 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl auto arg_function = ItemArgumentDispatch[evt]; arg_function(this, L, client, item, mob, data, extra_data, extra_pointers); - quest_manager.StartQuest(client, client, item); + RunningQuest q; + + q.owner = client; + q.initiator = client; + q.questitem = item; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -748,7 +788,14 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, Mob* mob, auto arg_function = SpellArgumentDispatch[evt]; arg_function(this, L, mob, client, spell_id, data, extra_data, extra_pointers); - quest_manager.StartQuest(mob, client, nullptr, const_cast(&spells[spell_id])); + RunningQuest q; + + q.owner = client; + q.initiator = client; + q.questspell = const_cast(&spells[spell_id]); + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -814,7 +861,13 @@ int LuaParser::_EventEncounter(std::string package_name, QuestEventID evt, std:: auto arg_function = EncounterArgumentDispatch[evt]; arg_function(this, L, enc, data, extra_data, extra_pointers); - quest_manager.StartQuest(enc, nullptr, nullptr, nullptr, encounter_name); + RunningQuest q; + + q.owner = enc; + q.encounter = encounter_name; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -1757,7 +1810,13 @@ int LuaParser::_EventBot( arg_function(this, L, bot, init, data, extra_data, extra_pointers); auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - quest_manager.StartQuest(bot, c); + RunningQuest q; + + q.owner = bot; + q.initiator = c; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -1936,7 +1995,13 @@ int LuaParser::_EventMerc( arg_function(this, L, merc, init, data, extra_data, extra_pointers); auto* c = (init && init->IsClient()) ? init->CastToClient() : nullptr; - quest_manager.StartQuest(merc, c); + RunningQuest q; + + q.owner = merc; + q.initiator = c; + + quest_manager.StartQuest(q); + if(lua_pcall(L, 1, 1, start + 1)) { std::string error = lua_tostring(L, -1); AddError(error); @@ -2039,3 +2104,190 @@ void LuaParser::LoadMercScript(std::string filename) { void LuaParser::LoadGlobalMercScript(std::string filename) { LoadScript(filename, "global_merc"); } + +int LuaParser::EventZone( + QuestEventID evt, + Zone *zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + evt = ConvertLuaEvent(evt); + if (evt >= _LargestEventID) { + return 0; + } + + if (!zone) { + return 0; + } + + if (!ZoneHasQuestSub(evt)) { + return 0; + } + + return _EventZone("zone", evt, zone, data, extra_data, extra_pointers); +} + +int LuaParser::EventGlobalZone( + QuestEventID evt, + Zone *zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + evt = ConvertLuaEvent(evt); + if (evt >= _LargestEventID) { + return 0; + } + + if (!zone) { + return 0; + } + + if (!GlobalZoneHasQuestSub(evt)) { + return 0; + } + + return _EventZone("global_zone", evt, zone, data, extra_data, extra_pointers); +} + +int LuaParser::_EventZone( + std::string package_name, + QuestEventID evt, + Zone *zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers, + luabind::adl::object *l_func +) { + const char *sub_name = LuaEvents[evt]; + int start = lua_gettop(L); + + try { + int npop = 2; + PushErrorHandler(L); + if(l_func != nullptr) { + l_func->push(L); + } else { + lua_getfield(L, LUA_REGISTRYINDEX, package_name.c_str()); + lua_getfield(L, -1, sub_name); + npop = 3; + } + + lua_createtable(L, 0, 0); + //push self + Lua_Zone l_zone(zone); + luabind::adl::object l_zone_o = luabind::adl::object(L, l_zone); + l_zone_o.push(L); + lua_setfield(L, -2, "self"); + + auto arg_function = ZoneArgumentDispatch[evt]; + arg_function(this, L, zone, data, extra_data, extra_pointers); + + RunningQuest q; + + q.zone = zone; + + quest_manager.StartQuest(q); + + if(lua_pcall(L, 1, 1, start + 1)) { + std::string error = lua_tostring(L, -1); + AddError(error); + quest_manager.EndQuest(); + lua_pop(L, npop); + return 0; + } + quest_manager.EndQuest(); + + if(lua_isnumber(L, -1)) { + int ret = static_cast(lua_tointeger(L, -1)); + lua_pop(L, npop); + return ret; + } + + lua_pop(L, npop); + } catch(std::exception &ex) { + AddError( + fmt::format( + "Lua Exception | [{}] for Zone [{}] in [{}]: {}", + sub_name, + zone->GetShortName(), + package_name, + ex.what() + ) + ); + + //Restore our stack to the best of our ability + int end = lua_gettop(L); + int n = end - start; + if(n > 0) { + lua_pop(L, n); + } + } + + return 0; +} + +int LuaParser::DispatchEventZone( + QuestEventID evt, + Zone *zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + evt = ConvertLuaEvent(evt); + if (evt >= _LargestEventID) { + return 0; + } + + std::string package_name = "zone"; + + auto iter = lua_encounter_events_registered.find(package_name); + if (iter == lua_encounter_events_registered.end()) { + return 0; + } + + int ret = 0; + auto riter = iter->second.begin(); + while (riter != iter->second.end()) { + if (riter->event_id == evt) { + package_name = fmt::format("encounter_{}", riter->encounter_name); + int i = _EventZone(package_name, evt, zone, data, extra_data, extra_pointers, &riter->lua_reference); + if (i != 0) { + ret = i; + } + } + + ++riter; + } + + return ret; +} + +bool LuaParser::ZoneHasQuestSub(QuestEventID evt) { + evt = ConvertLuaEvent(evt); + if (evt >= _LargestEventID) { + return false; + } + + const char *subname = LuaEvents[evt]; + return HasFunction(subname, "zone"); +} + +bool LuaParser::GlobalZoneHasQuestSub(QuestEventID evt) { + evt = ConvertLuaEvent(evt); + if (evt >= _LargestEventID) { + return false; + } + + const char *subname = LuaEvents[evt]; + return HasFunction(subname, "global_zone"); +} + +void LuaParser::LoadZoneScript(std::string filename) { + LoadScript(filename, "zone"); +} + +void LuaParser::LoadGlobalZoneScript(std::string filename) { + LoadScript(filename, "global_zone"); +} diff --git a/zone/lua_parser.h b/zone/lua_parser.h index fbd50a984..c1bad7088 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -125,6 +125,20 @@ public: uint32 extra_data, std::vector* extra_pointers ); + virtual int EventZone( + QuestEventID evt, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); + virtual int EventGlobalZone( + QuestEventID evt, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); virtual bool HasQuestSub(uint32 npc_id, QuestEventID evt); virtual bool HasGlobalQuestSub(QuestEventID evt); @@ -138,6 +152,8 @@ public: virtual bool GlobalBotHasQuestSub(QuestEventID evt); virtual bool MercHasQuestSub(QuestEventID evt); virtual bool GlobalMercHasQuestSub(QuestEventID evt); + virtual bool ZoneHasQuestSub(QuestEventID evt); + virtual bool GlobalZoneHasQuestSub(QuestEventID evt); virtual void LoadNPCScript(std::string filename, int npc_id); virtual void LoadGlobalNPCScript(std::string filename); @@ -150,6 +166,8 @@ public: virtual void LoadGlobalBotScript(std::string filename); virtual void LoadMercScript(std::string filename); virtual void LoadGlobalMercScript(std::string filename); + virtual void LoadZoneScript(std::string filename); + virtual void LoadGlobalZoneScript(std::string filename); virtual void AddVar(std::string name, std::string val); virtual std::string GetVar(std::string name); @@ -207,6 +225,13 @@ public: uint32 extra_data, std::vector* extra_pointers ); + virtual int DispatchEventZone( + QuestEventID evt, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); static LuaParser* Instance() { static LuaParser inst; @@ -307,6 +332,15 @@ private: std::vector* extra_pointers, luabind::adl::object* l_func = nullptr ); + int _EventZone( + std::string package_name, + QuestEventID evt, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers, + luabind::adl::object* l_func = nullptr + ); void LoadScript(std::string filename, std::string package_name); void MapFunctions(lua_State *L); @@ -317,12 +351,13 @@ private: std::vector mods_; lua_State *L; - NPCArgumentHandler NPCArgumentDispatch[_LargestEventID]; - PlayerArgumentHandler PlayerArgumentDispatch[_LargestEventID]; - ItemArgumentHandler ItemArgumentDispatch[_LargestEventID]; - SpellArgumentHandler SpellArgumentDispatch[_LargestEventID]; + NPCArgumentHandler NPCArgumentDispatch[_LargestEventID]; + PlayerArgumentHandler PlayerArgumentDispatch[_LargestEventID]; + ItemArgumentHandler ItemArgumentDispatch[_LargestEventID]; + SpellArgumentHandler SpellArgumentDispatch[_LargestEventID]; EncounterArgumentHandler EncounterArgumentDispatch[_LargestEventID]; - BotArgumentHandler BotArgumentDispatch[_LargestEventID]; + BotArgumentHandler BotArgumentDispatch[_LargestEventID]; + ZoneArgumentHandler ZoneArgumentDispatch[_LargestEventID]; }; #endif diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index 8d2517fe3..68dd7ca2a 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -668,6 +668,23 @@ void handle_npc_spell_blocked( lua_setfield(L, -2, "cast_spell"); } +void handle_npc_pet_command( + QuestInterface *parse, + lua_State* L, + NPC* npc, + Mob *init, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) +{ + lua_pushinteger(L, extra_data); + lua_setfield(L, -2, "pet_command"); + + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "pet_command_name"); +} + // Player void handle_player_say( QuestInterface *parse, @@ -1829,6 +1846,22 @@ void handle_player_connect( lua_setfield(L, -2, "is_first_login"); } +void handle_player_pet_command( + QuestInterface *parse, + lua_State* L, + Client* client, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) +{ + lua_pushinteger(L, extra_data); + lua_setfield(L, -2, "pet_command"); + + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "pet_command_name"); +} + // Item void handle_item_click( QuestInterface *parse, @@ -2873,4 +2906,293 @@ void handle_bot_spell_blocked( lua_setfield(L, -2, "cast_spell"); } +// Zone + +void handle_zone_null( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { +} + +void handle_zone_click_door( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_Door l_door(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_door_o = luabind::adl::object(L, l_door); + l_door_o.push(L); + lua_setfield(L, -2, "door"); + + Lua_Client l_client(std::any_cast(extra_pointers->at(1))); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); + l_client_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_click_object( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_Object l_object(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_object_o = luabind::adl::object(L, l_object); + l_object_o.push(L); + lua_setfield(L, -2, "object"); + + Lua_Client l_client(std::any_cast(extra_pointers->at(1))); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); + l_client_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_death( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Seperator sep(data.c_str()); + + Lua_Mob l_mob(std::any_cast(extra_pointers->at(2))); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); + l_mob_o.push(L); + lua_setfield(L, -2, "other"); + + lua_pushinteger(L, Strings::ToInt(sep.arg[0])); + lua_setfield(L, -2, "killer_id"); + + lua_pushinteger(L, Strings::ToInt(sep.arg[1])); + lua_setfield(L, -2, "damage"); + + const uint32 spell_id = Strings::ToUnsignedInt(sep.arg[2]); + if (IsValidSpell(spell_id)) { + Lua_Spell l_spell(&spells[spell_id]); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); + l_spell_o.push(L); + lua_setfield(L, -2, "spell"); + } else { + Lua_Spell l_spell(nullptr); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); + l_spell_o.push(L); + lua_setfield(L, -2, "spell"); + } + + lua_pushinteger(L, Strings::ToInt(sep.arg[3])); + lua_setfield(L, -2, "skill_id"); + + lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[4])); + lua_setfield(L, -2, "killed_entity_id"); + + lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[5])); + lua_setfield(L, -2, "combat_start_time"); + + lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[6])); + lua_setfield(L, -2, "combat_end_time"); + + lua_pushinteger(L, Strings::ToBigInt(sep.arg[7])); + lua_setfield(L, -2, "damage_received"); + + lua_pushinteger(L, Strings::ToBigInt(sep.arg[8])); + lua_setfield(L, -2, "healing_received"); + + if (extra_pointers && extra_pointers->size() >= 1) { + Lua_Corpse l_corpse(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); + l_corpse_o.push(L); + lua_setfield(L, -2, "corpse"); + } + + if (extra_pointers && extra_pointers->size() >= 2) { + Lua_NPC l_npc(std::any_cast(extra_pointers->at(1))); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); + l_npc_o.push(L); + lua_setfield(L, -2, "killed"); + } +} + +void handle_zone_despawn( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_NPC l_npc(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); + l_npc_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_enter( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_Client l_client(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); + l_client_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_loot( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_Client l_client(std::any_cast(extra_pointers->at(2))); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); + l_client_o.push(L); + lua_setfield(L, -2, "other"); + + Lua_ItemInst l_item(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); + l_item_o.push(L); + lua_setfield(L, -2, "item"); + + Lua_Corpse l_corpse(std::any_cast(extra_pointers->at(1))); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); + l_corpse_o.push(L); + lua_setfield(L, -2, "corpse"); +} + +void handle_zone_payload( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Seperator sep(data.c_str()); + + lua_pushinteger(L, Strings::ToInt(sep.arg[0])); + lua_setfield(L, -2, "payload_id"); + + lua_pushstring(L, sep.argplus[1]); + lua_setfield(L, -2, "payload_value"); +} + +void handle_zone_pickup( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_ItemInst l_item(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); + l_item_o.push(L); + lua_setfield(L, -2, "item"); + + Lua_Client l_client(std::any_cast(extra_pointers->at(1))); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); + l_client_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_popup( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + lua_pushinteger(L, Strings::ToInt(data)); + lua_setfield(L, -2, "popup_id"); + + Lua_Client l_client(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); + l_client_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_signal( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + lua_pushinteger(L, Strings::ToInt(data)); + lua_setfield(L, -2, "signal"); +} + +void handle_zone_spawn( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Lua_NPC l_npc(std::any_cast(extra_pointers->at(0))); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); + l_npc_o.push(L); + lua_setfield(L, -2, "other"); +} + +void handle_zone_timer( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "timer"); +} + +void handle_zone_timer_pause_resume_start( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + Seperator sep(data.c_str()); + + lua_pushstring(L, sep.arg[0]); + lua_setfield(L, -2, "timer"); + + lua_pushinteger(L, Strings::ToUnsignedInt(sep.arg[1])); + lua_setfield(L, -2, "duration"); +} + +void handle_zone_timer_stop( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +) { + lua_pushstring(L, data.c_str()); + lua_setfield(L, -2, "timer"); +} + #endif diff --git a/zone/lua_parser_events.h b/zone/lua_parser_events.h index 3cb428c58..79135bd6e 100644 --- a/zone/lua_parser_events.h +++ b/zone/lua_parser_events.h @@ -9,6 +9,7 @@ typedef void(*SpellArgumentHandler)(QuestInterface*, lua_State*, Mob*, Client*, typedef void(*EncounterArgumentHandler)(QuestInterface*, lua_State*, Encounter* encounter, std::string, uint32, std::vector*); typedef void(*BotArgumentHandler)(QuestInterface*, lua_State*, Bot*, Mob*, std::string, uint32, std::vector*); typedef void(*MercArgumentHandler)(QuestInterface*, lua_State*, Merc*, Mob*, std::string, uint32, std::vector*); +typedef void(*ZoneArgumentHandler)(QuestInterface*, lua_State*, Zone*, std::string, uint32, std::vector*); // NPC void handle_npc_event_say( @@ -261,6 +262,16 @@ void handle_npc_spell_blocked( std::vector *extra_pointers ); +void handle_npc_pet_command( + QuestInterface *parse, + lua_State* L, + NPC* npc, + Mob *init, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + // Player void handle_player_say( QuestInterface *parse, @@ -874,6 +885,15 @@ void handle_player_connect( std::vector *extra_pointers ); +void handle_player_pet_command( + QuestInterface *parse, + lua_State* L, + Client* client, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + // Item void handle_item_click( QuestInterface *parse, @@ -1278,5 +1298,141 @@ void handle_bot_spell_blocked( std::vector *extra_pointers ); +// Zone +void handle_zone_null( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_click_door( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_click_object( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_death( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_despawn( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_enter( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_loot( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_payload( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_pickup( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_popup( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_signal( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_spawn( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_timer( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_timer_pause_resume_start( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + +void handle_zone_timer_stop( + QuestInterface *parse, + lua_State* L, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector *extra_pointers +); + #endif #endif diff --git a/zone/lua_zone.cpp b/zone/lua_zone.cpp index 8250296ff..037571620 100644 --- a/zone/lua_zone.cpp +++ b/zone/lua_zone.cpp @@ -772,6 +772,102 @@ bool Lua_Zone::VariableExists(const std::string& variable_name) return self->VariableExists(variable_name); } +uint32 Lua_Zone::GetTimerDuration(std::string name) +{ + Lua_Safe_Call_Int(); + return self->GetTimerDuration(name); +} + +uint32 Lua_Zone::GetTimerRemainingTime(std::string name) +{ + Lua_Safe_Call_Int(); + return self->GetTimerRemainingTime(name); +} + +bool Lua_Zone::HasTimer(std::string name) +{ + Lua_Safe_Call_Bool(); + return self->HasTimer(name); +} + +bool Lua_Zone::IsPausedTimer(std::string name) +{ + Lua_Safe_Call_Bool(); + return self->IsPausedTimer(name); +} + +void Lua_Zone::PauseTimer(std::string name) +{ + Lua_Safe_Call_Void(); + self->PauseTimer(name); +} + +void Lua_Zone::ResumeTimer(std::string name) +{ + Lua_Safe_Call_Void(); + self->ResumeTimer(name); +} + +void Lua_Zone::SetTimer(std::string name, uint32 duration) +{ + Lua_Safe_Call_Void(); + self->SetTimer(name, duration); +} + +void Lua_Zone::StopTimer(std::string name) +{ + Lua_Safe_Call_Void(); + self->StopTimer(name); +} + +void Lua_Zone::StopAllTimers() +{ + Lua_Safe_Call_Void(); + self->StopAllTimers(); +} + +void Lua_Zone::SendPayload(int payload_id, std::string payload_value) +{ + Lua_Safe_Call_Void(); + self->SendPayload(payload_id, payload_value); +} + +void Lua_Zone::Signal(int signal_id) +{ + Lua_Safe_Call_Void(); + self->Signal(signal_id); +} + +luabind::object Lua_Zone::GetPausedTimers(lua_State* L) { + auto t = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto l = self->GetPausedTimers(); + int i = 1; + for (const auto& v : l) { + t[i] = v; + i++; + } + } + + return t; +} + +luabind::object Lua_Zone::GetTimers(lua_State* L) { + auto t = luabind::newtable(L); + if (d_) { + auto self = reinterpret_cast(d_); + auto l = self->GetTimers(); + int i = 1; + for (const auto& v : l) { + t[i] = v; + i++; + } + } + + return t; +} + luabind::scope lua_register_zone() { return luabind::class_("Zones") .def(luabind::constructor<>()) @@ -840,6 +936,7 @@ luabind::scope lua_register_zone() { .def("GetMinimumStatus", &Lua_Zone::GetMinimumStatus) .def("GetNote", &Lua_Zone::GetNote) .def("GetNPCMaximumAggroDistance", &Lua_Zone::GetNPCMaximumAggroDistance) + .def("GetPausedTimers", &Lua_Zone::GetPausedTimers) .def("GetPEQZone", &Lua_Zone::GetPEQZone) .def("GetRainChance", (int(Lua_Zone::*)(void))&Lua_Zone::GetRainChance) .def("GetRainChance", (int(Lua_Zone::*)(uint8))&Lua_Zone::GetRainChance) @@ -861,6 +958,9 @@ luabind::scope lua_register_zone() { .def("GetSnowDuration", (int(Lua_Zone::*)(uint8))&Lua_Zone::GetSnowDuration) .def("GetTimeType", &Lua_Zone::GetTimeType) .def("GetTimeZone", &Lua_Zone::GetTimeZone) + .def("GetTimerDuration", &Lua_Zone::GetTimerDuration) + .def("GetTimerRemainingTime", &Lua_Zone::GetTimerRemainingTime) + .def("GetTimers", &Lua_Zone::GetTimers) .def("GetZoneDescription", &Lua_Zone::GetZoneDescription) .def("GetZoneID", &Lua_Zone::GetZoneID) .def("GetZoneType", &Lua_Zone::GetZoneType) @@ -875,10 +975,12 @@ luabind::scope lua_register_zone() { .def("HasMap", &Lua_Zone::HasMap) .def("HasWaterMap", &Lua_Zone::HasWaterMap) .def("HasWeather", &Lua_Zone::HasWeather) + .def("HasTimer", &Lua_Zone::HasTimer) .def("IsCity", &Lua_Zone::IsCity) .def("IsHotzone", &Lua_Zone::IsHotzone) .def("IsInstancePersistent", &Lua_Zone::IsInstancePersistent) .def("IsIdleWhenEmpty", &Lua_Zone::IsIdleWhenEmpty) + .def("IsPausedTimer", &Lua_Zone::IsPausedTimer) .def("IsPVPZone", &Lua_Zone::IsPVPZone) .def("IsRaining", &Lua_Zone::IsRaining) .def("IsSnowing", &Lua_Zone::IsSnowing) @@ -887,8 +989,11 @@ luabind::scope lua_register_zone() { .def("IsStaticZone", &Lua_Zone::IsStaticZone) .def("IsUCSServerAvailable", &Lua_Zone::IsUCSServerAvailable) .def("IsWaterZone", &Lua_Zone::IsWaterZone) + .def("PauseTimer", &Lua_Zone::PauseTimer) .def("Repop", (void(Lua_Zone::*)(void))&Lua_Zone::Repop) .def("Repop", (void(Lua_Zone::*)(bool))&Lua_Zone::Repop) + .def("ResumeTimer", &Lua_Zone::ResumeTimer) + .def("SendPayload", &Lua_Zone::SendPayload) .def("SetAAEXPModifier", &Lua_Zone::SetAAEXPModifier) .def("SetAAEXPModifierByCharacterID", &Lua_Zone::SetAAEXPModifierByCharacterID) .def("SetBucket", (void(Lua_Zone::*)(const std::string&,const std::string&))&Lua_Zone::SetBucket) @@ -898,8 +1003,12 @@ luabind::scope lua_register_zone() { .def("SetInstanceTimer", &Lua_Zone::SetInstanceTimer) .def("SetInstanceTimeRemaining", &Lua_Zone::SetInstanceTimeRemaining) .def("SetIsHotzone", &Lua_Zone::SetIsHotzone) + .def("SetTimer", &Lua_Zone::SetTimer) .def("SetVariable", &Lua_Zone::SetVariable) .def("ShowZoneGlobalLoot", &Lua_Zone::ShowZoneGlobalLoot) + .def("Signal", &Lua_Zone::Signal) + .def("StopTimer", &Lua_Zone::StopTimer) + .def("StopAllTimers", &Lua_Zone::StopAllTimers) .def("VariableExists", &Lua_Zone::VariableExists); } diff --git a/zone/lua_zone.h b/zone/lua_zone.h index 48d297bb6..42a1d8841 100644 --- a/zone/lua_zone.h +++ b/zone/lua_zone.h @@ -147,6 +147,19 @@ public: luabind::object GetVariables(lua_State* L); void SetVariable(const std::string& variable_name, const std::string& variable_value); bool VariableExists(const std::string& variable_name); + uint32 GetTimerDuration(std::string name); + uint32 GetTimerRemainingTime(std::string name); + bool HasTimer(std::string name); + bool IsPausedTimer(std::string name); + void PauseTimer(std::string name); + void ResumeTimer(std::string name); + void SetTimer(std::string name, uint32 duration); + void StopTimer(std::string name); + void StopAllTimers(); + void Signal(int signal_id); + void SendPayload(int payload_id, std::string payload_value); + luabind::object GetPausedTimers(lua_State* L); + luabind::object GetTimers(lua_State* L); // data buckets void SetBucket(const std::string& bucket_name, const std::string& bucket_value); diff --git a/zone/main.cpp b/zone/main.cpp index 6177ce562..4f5916078 100644 --- a/zone/main.cpp +++ b/zone/main.cpp @@ -555,11 +555,11 @@ int main(int argc, char **argv) LogInfo("Starting EQ Network server on port [{}]", Config->ZonePort); EQStreamManagerInterfaceOptions opts(Config->ZonePort, false, RuleB(Network, CompressZoneStream)); - opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); - opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); - opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); - opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); - opts.daybreak_options.outgoing_data_rate = RuleR(Network, ClientDataRate); + opts.reliable_stream_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); + opts.reliable_stream_options.resend_delay_factor = RuleR(Network, ResendDelayFactor); + opts.reliable_stream_options.resend_delay_min = RuleI(Network, ResendDelayMinMS); + opts.reliable_stream_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS); + opts.reliable_stream_options.outgoing_data_rate = RuleR(Network, ClientDataRate); eqsm = std::make_unique(opts); eqsf_open = true; diff --git a/zone/mob.cpp b/zone/mob.cpp index 16774bfbc..0a167201d 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -392,7 +392,7 @@ Mob::Mob( spellbonuses.AssistRange = -1; SetPetID(0); SetOwnerID(0); - SetPetType(petNone); // default to not a pet + SetPetType(PetType::None); // default to not a pet SetPetPower(0); held = false; gheld = false; @@ -454,8 +454,8 @@ Mob::Mob( weaponstance.itembonus_buff_spell_id = 0; weaponstance.aabonus_buff_spell_id = 0; - pStandingPetOrder = SPO_Follow; - m_previous_pet_order = SPO_Follow; + m_pet_order = PetOrder::Follow; + m_previous_pet_order = PetOrder::Follow; pseudo_rooted = false; nobuff_invisible = 0; @@ -623,7 +623,7 @@ bool Mob::HasAnInvisibilityEffect() { void Mob::BreakCharmPetIfConditionsMet() { auto pet = GetPet(); - if (pet && pet->GetPetType() == petCharmed && HasAnInvisibilityEffect()) { + if (pet && pet->GetPetType() == PetType::Charmed && HasAnInvisibilityEffect()) { if (RuleB(Pets, LivelikeBreakCharmOnInvis) || IsInvisible(pet)) { pet->BuffFadeByEffect(SE_Charm); } @@ -655,14 +655,14 @@ void Mob::CalcInvisibleLevel() BreakCharmPetIfConditionsMet(); } -void Mob::SetPetOrder(eStandingPetOrder i) { - if (i == SPO_Sit || i == SPO_FeignDeath) { - if (pStandingPetOrder == SPO_Follow || pStandingPetOrder == SPO_Guard) { - m_previous_pet_order = pStandingPetOrder; +void Mob::SetPetOrder(uint8 pet_order) { + if (pet_order == PetOrder::Sit || pet_order == PetOrder::Feign) { + if (m_pet_order == PetOrder::Follow || m_pet_order == PetOrder::Guard) { + m_previous_pet_order = m_pet_order; } } - pStandingPetOrder = i; + m_pet_order = pet_order; } void Mob::SetInvisible(uint8 state, bool set_on_bonus_calc) { @@ -1317,7 +1317,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) ns->spawn.IsMercenary = IsMerc() ? 1 : 0; ns->spawn.targetable_with_hotkey = no_target_hotkey ? 0 : 1; // opposite logic! ns->spawn.untargetable = IsTargetable(); - + ns->spawn.petOwnerId = ownerid; ns->spawn.haircolor = haircolor; @@ -2361,7 +2361,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window) // Attack 2 final_string += fmt::format( - "Offense: {}{} | {}{}", + "Offense: {}{}{}{}", Strings::Commify(offense(skill)), ( itembonuses.ATK ? @@ -4567,8 +4567,8 @@ void Mob::SetOwnerID(uint16 new_owner_id) { if ( !ownerid && IsNPC() && - GetPetType() != petCharmed && - GetPetType() != petNone + GetPetType() != PetType::Charmed && + GetPetType() != PetType::None ) { Depop(); } @@ -8792,4 +8792,4 @@ bool Mob::LoadDataBucketsCache() } return true; -} \ No newline at end of file +} diff --git a/zone/mob.h b/zone/mob.h index 193d8aae2..ca0abe268 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -98,7 +98,6 @@ class Mob : public Entity { public: enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD, CLIENT_KICKED, DISCONNECTED, CLIENT_ERROR, CLIENT_CONNECTINGALL }; - enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard, SPO_FeignDeath }; struct MobSpecialAbility { MobSpecialAbility() { @@ -601,7 +600,7 @@ public: inline const char* GetName() const { return name; } inline const char* GetOrigName() const { return orig_name; } inline const char* GetLastName() const { return lastname; } - inline const eStandingPetOrder GetPreviousPetOrder() const { return m_previous_pet_order; } + inline const uint8 GetPreviousPetOrder() const { return m_previous_pet_order; } const char *GetCleanName(); virtual void SetName(const char *new_name = nullptr) { new_name ? strn0cpy(name, new_name, 64) : strn0cpy(name, GetName(), 64); return; }; @@ -1083,14 +1082,14 @@ public: Mob* GetUltimateOwner(); void SetPetID(uint16 NewPetID); inline uint16 GetPetID() const { return petid; } - inline PetType GetPetType() const { return type_of_pet; } - void SetPetType(PetType p) { type_of_pet = p; } + inline uint8 GetPetType() const { return type_of_pet; } + void SetPetType(uint8 pet_type) { type_of_pet = pet_type; } inline int16 GetPetPower() const { return (petpower < 0) ? 0 : petpower; } void SetPetPower(int16 p) { if (p < 0) petpower = 0; else petpower = p; } - bool IsFamiliar() const { return type_of_pet == petFamiliar; } - bool IsAnimation() const { return type_of_pet == petAnimation; } - bool IsCharmed() const { return type_of_pet == petCharmed; } - bool IsTargetLockPet() const { return type_of_pet == petTargetLock; } + bool IsFamiliar() const { return type_of_pet == PetType::Familiar; } + bool IsAnimation() const { return type_of_pet == PetType::Animation; } + bool IsCharmed() const { return type_of_pet == PetType::Charmed; } + bool IsTargetLockPet() const { return type_of_pet == PetType::TargetLock; } inline uint32 GetPetTargetLockID() { return pet_targetlock_id; }; inline void SetPetTargetLockID(uint32 value) { pet_targetlock_id = value; }; void SetOwnerID(uint16 new_owner_id); @@ -1212,8 +1211,8 @@ public: inline const float GetAssistRange() const { return (spellbonuses.AssistRange == -1) ? pAssistRange : spellbonuses.AssistRange; } - void SetPetOrder(eStandingPetOrder i); - inline const eStandingPetOrder GetPetOrder() const { return pStandingPetOrder; } + void SetPetOrder(uint8 pet_order); + inline const uint8 GetPetOrder() const { return m_pet_order; } inline void SetHeld(bool nState) { held = nState; } inline const bool IsHeld() const { return held; } inline void SetGHeld(bool nState) { gheld = nState; } @@ -1300,7 +1299,7 @@ public: bool IsPetAggroExempt(Mob *pet_owner); void InstillDoubt(Mob *who); - bool Charmed() const { return type_of_pet == petCharmed; } + bool Charmed() const { return type_of_pet == PetType::Charmed; } static uint32 GetLevelHP(uint8 tlevel); uint32 GetZoneID() const; //for perl uint16 GetInstanceVersion() const; //for perl @@ -1596,7 +1595,7 @@ protected: StatBonuses aabonuses; uint16 petid; uint16 ownerid; - PetType type_of_pet; + uint8 type_of_pet; int16 petpower; uint32 follow_id; uint32 follow_dist; @@ -1825,8 +1824,8 @@ protected: Timer viral_timer; // MobAI stuff - eStandingPetOrder pStandingPetOrder; - eStandingPetOrder m_previous_pet_order; + uint8 m_pet_order; + uint8 m_previous_pet_order; uint32 minLastFightingDelayMoving; uint32 maxLastFightingDelayMoving; float pAggroRange = 0; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index f39797c10..173fae7a5 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1397,8 +1397,8 @@ void Mob::AI_Process() { else if (AI_movement_timer->Check() && !IsRooted()) { if (IsPet()) { // we're a pet, do as we're told - switch (pStandingPetOrder) { - case SPO_Follow: { + switch (m_pet_order) { + case PetOrder::Follow: { Mob *owner = GetOwner(); if (owner == nullptr) { @@ -1447,18 +1447,18 @@ void Mob::AI_Process() { break; } - case SPO_Sit: { + case PetOrder::Sit: { SetAppearance(eaSitting, false); break; } - case SPO_Guard: { + case PetOrder::Guard: { //only NPCs can guard stuff. (forced by where the guard movement code is in the AI) if (IsNPC()) { CastToNPC()->NextGuardPosition(); } break; } - case SPO_FeignDeath: { + case PetOrder::Feign: { SetAppearance(eaDead, false); break; } diff --git a/zone/mob_appearance.cpp b/zone/mob_appearance.cpp index 430247443..2556a41b1 100644 --- a/zone/mob_appearance.cpp +++ b/zone/mob_appearance.cpp @@ -286,8 +286,8 @@ uint32 Mob::GetHerosForgeModel(uint8 material_slot) const if (augment) { item = augment->GetItem(); heros_forge_model = item->HerosForgeModel; - } else if (inst->GetOrnamentHeroModel()) { - heros_forge_model = inst->GetOrnamentHeroModel(); + } else if (inst->GetOrnamentHeroModel(material_slot)) { + heros_forge_model = inst->GetOrnamentHeroModel(material_slot); } } } @@ -421,7 +421,7 @@ void Mob::SendWearChange(uint8 material_slot, Client *one_client) return key; }; - + auto dedupe_key = build_key(*w); auto send_if_changed = [&](Client* client) { auto& last_key = m_last_seen_wearchange[client->GetID()][material_slot]; diff --git a/zone/npc.cpp b/zone/npc.cpp index ade7c8e93..de97d0fb5 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -864,6 +864,11 @@ void NPC::Depop(bool start_spawn_timer) { DispatchZoneControllerEvent(EVENT_DESPAWN_ZONE, this, "", 0, nullptr); } + if (parse->ZoneHasQuestSub(EVENT_DESPAWN_ZONE)) { + std::vector args = { this }; + parse->EventZone(EVENT_DESPAWN_ZONE, zone, "", 0, &args); + } + p_depop = true; if (respawn2) { if (start_spawn_timer) { @@ -4009,7 +4014,7 @@ void NPC::SetTaunting(bool is_taunting) { taunting = is_taunting; if (IsPet() && IsPetOwnerClient()) { - GetOwner()->CastToClient()->SetPetCommandState(PET_BUTTON_TAUNT, is_taunting); + GetOwner()->CastToClient()->SetPetCommandState(PetButton::Taunt, is_taunting); } } @@ -4935,3 +4940,16 @@ void NPC::ResetMultiQuest() { m_hand_in = {}; } + +void NPC::SetNPCTintIndex(uint32 index) +{ + auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + auto* s = (SpawnAppearance_Struct*) outapp->pBuffer; + + s->spawn_id = GetID(); + s->type = AppearanceType::NPCTintIndex; + s->parameter = index; + + entity_list.QueueClients(this, outapp); + safe_delete(outapp); +} diff --git a/zone/npc.h b/zone/npc.h index 31a4e09f9..4c4d3cb1b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -552,6 +552,9 @@ public: void ScaleNPC(uint8 npc_level, bool always_scale = false, bool override_special_abilities = false); + uint32 GetNPCTintIndex() { return m_npc_tint_id; } + void SetNPCTintIndex(uint32 index); + void RecalculateSkills(); void ReloadSpells(); diff --git a/zone/object.cpp b/zone/object.cpp index eb6daad49..6da171b23 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -657,6 +657,30 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) } } + if (parse->ZoneHasQuestSub(EVENT_PLAYER_PICKUP)) { + std::vector args = { m_inst, sender }; + + if (parse->EventZone(EVENT_PLAYER_PICKUP, zone, std::to_string(item->ID), GetID(), &args)) { + auto outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct)); + + memcpy(outapp->pBuffer, click_object, sizeof(ClickObject_Struct)); + + auto co = (ClickObject_Struct*) outapp->pBuffer; + + co->drop_id = 0; + + entity_list.QueueClients(nullptr, outapp, false); + + safe_delete(outapp); + + sender->SetTradeskillObject(nullptr); + + user = nullptr; + + return true; + } + } + // Transfer item to client sender->PutItemInInventory(EQ::invslot::slotCursor, *m_inst, false); sender->SendItemPacket(EQ::invslot::slotCursor, m_inst, ItemPacketTrade); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 2f853c9cb..49a2d9d02 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -3328,7 +3328,12 @@ bool Perl_Client_KeyRingClear(Client* self) void Perl_Client_KeyRingList(Client* self) { - self->KeyRingList(); + self->KeyRingList(self); +} + +void Perl_Client_KeyRingList(Client* self, Client* c) +{ + self->KeyRingList(c); } bool Perl_Client_KeyRingRemove(Client* self, uint32 item_id) @@ -3346,6 +3351,18 @@ bool Perl_Client_UncompleteTask(Client* self, int task_id) return self->UncompleteTask(task_id); } +perl::array Perl_Client_GetKeyRing(Client* self) +{ + perl::array result; + const auto& v = self->GetKeyRing(); + + for (int i = 0; i < v.size(); ++i) { + result.push_back(v[i]); + } + + return result; +} + void perl_register_client() { perl::interpreter perl(PERL_GET_THX); @@ -3577,6 +3594,7 @@ void perl_register_client() package.add("GetItemCooldown", &Perl_Client_GetItemCooldown); package.add("GetItemIDAt", &Perl_Client_GetItemIDAt); package.add("GetItemInInventory", &Perl_Client_GetItemInInventory); + package.add("GetKeyRing", &Perl_Client_GetKeyRing); package.add("GetLDoNLosses", &Perl_Client_GetLDoNLosses); package.add("GetLDoNLossesTheme", &Perl_Client_GetLDoNLossesTheme); package.add("GetLDoNPointsTheme", &Perl_Client_GetLDoNPointsTheme); @@ -3675,7 +3693,8 @@ void perl_register_client() package.add("KeyRingAdd", &Perl_Client_KeyRingAdd); package.add("KeyRingCheck", &Perl_Client_KeyRingCheck); package.add("KeyRingClear", &Perl_Client_KeyRingClear); - package.add("KeyRingList", &Perl_Client_KeyRingList); + package.add("KeyRingList", (void(*)(Client*))&Perl_Client_KeyRingList); + package.add("KeyRingList", (void(*)(Client*, Client*))&Perl_Client_KeyRingList); package.add("KeyRingRemove", &Perl_Client_KeyRingRemove); package.add("Kick", &Perl_Client_Kick); package.add("LearnDisciplines", &Perl_Client_LearnDisciplines); diff --git a/zone/perl_groups.cpp b/zone/perl_groups.cpp index f93e31db8..a97716a28 100644 --- a/zone/perl_groups.cpp +++ b/zone/perl_groups.cpp @@ -127,6 +127,16 @@ Client* Perl_Group_GetMember(Group* self, int member_index) // @categories Accou return member ? member->CastToClient() : nullptr; } +uint8_t Perl_Group_GetMemberRole(Group* self, Mob* member) // @categories Account and Character, Script Utility, Group +{ + return self->GetMemberRole(member); +} + +uint8_t Perl_Group_GetMemberRole(Group* self, const char* name) // @categories Account and Character, Script Utility, Group +{ + return self->GetMemberRole(name); +} + bool Perl_Group_DoesAnyMemberHaveExpeditionLockout(Group* self, std::string expedition_name, std::string event_name) { return self->AnyMemberHasDzLockout(expedition_name, event_name); @@ -163,6 +173,8 @@ void perl_register_group() package.add("GetLeaderName", &Perl_Group_GetLeaderName); package.add("GetLowestLevel", &Perl_Group_GetLowestLevel); package.add("GetMember", &Perl_Group_GetMember); + package.add("GetMemberRole", (uint8_t(*)(Group*, Mob*))&Perl_Group_GetMemberRole); + package.add("GetMemberRole", (uint8_t(*)(Group*, const char*))&Perl_Group_GetMemberRole); package.add("GetTotalGroupDamage", &Perl_Group_GetTotalGroupDamage); package.add("GroupCount", &Perl_Group_GroupCount); package.add("GroupMessage", (void(*)(Group*, Mob*, const char*))&Perl_Group_GroupMessage); diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index af564d3b7..dd06db33b 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -1114,11 +1114,16 @@ uint16 Perl_Mob_GetOwnerID(Mob* self) // @categories Script Utility, Pet return self->GetOwnerID(); } -int Perl_Mob_GetPetType(Mob* self) // @categories Script Utility, Pet +uint8 Perl_Mob_GetPetType(Mob* self) // @categories Script Utility, Pet { return self->GetPetType(); } +std::string Perl_Mob_GetPetTypeName(Mob* self) // @categories Script Utility, Pet +{ + return PetType::GetName(self->GetPetType()); +} + int Perl_Mob_GetBodyType(Mob* self) // @categories Stats and Attributes { return self->GetBodyType(); @@ -1254,12 +1259,12 @@ float Perl_Mob_GetAssistRange(Mob* self) // @categories Stats and Attributes, Ha return self->GetAssistRange(); } -void Perl_Mob_SetPetOrder(Mob* self, int order) // @categories Pet +void Perl_Mob_SetPetOrder(Mob* self, uint8 pet_order) // @categories Pet { - self->SetPetOrder(static_cast(order)); + self->SetPetOrder(pet_order); } -int Perl_Mob_GetPetOrder(Mob* self) // @categories Script Utility, Pet +uint8 Perl_Mob_GetPetOrder(Mob* self) // @categories Script Utility, Pet { return self->GetPetOrder(); } @@ -3573,6 +3578,35 @@ void Perl_Mob_BuffFadeSongs(Mob* self) self->BuffFadeSongs(); } +perl::array Perl_Mob_GetPausedTimers(Mob* self) +{ + perl::array a; + + const auto& l = quest_manager.GetPausedTimers(self); + for (const auto& v : l) { + a.push_back(v); + } + + return a; +} + +perl::array Perl_Mob_GetTimers(Mob* self) +{ + perl::array a; + + const auto& l = quest_manager.GetTimers(self); + for (const auto& v : l) { + a.push_back(v); + } + + return a; +} + +void Perl_Mob_SetPetType(Mob* self, uint8 pet_type) +{ + self->SetPetType(pet_type); +} + void perl_register_mob() { perl::interpreter perl(PERL_GET_THX); @@ -3897,10 +3931,12 @@ void perl_register_mob() package.add("GetOwner", &Perl_Mob_GetOwner); package.add("GetOwnerID", &Perl_Mob_GetOwnerID); package.add("GetPR", &Perl_Mob_GetPR); + package.add("GetPausedTimers", &Perl_Mob_GetPausedTimers); package.add("GetPet", &Perl_Mob_GetPet); package.add("GetPetID", &Perl_Mob_GetPetID); package.add("GetPetOrder", &Perl_Mob_GetPetOrder); package.add("GetPetType", &Perl_Mob_GetPetType); + package.add("GetPetTypeName", &Perl_Mob_GetPetTypeName); package.add("GetPhR", &Perl_Mob_GetPhR); package.add("GetRace", &Perl_Mob_GetRace); package.add("GetRaceName", &Perl_Mob_GetRaceName); @@ -3927,6 +3963,7 @@ void perl_register_mob() package.add("GetTarget", &Perl_Mob_GetTarget); package.add("GetTexture", &Perl_Mob_GetTexture); package.add("GetTimerDurationMS", &Perl_Mob_GetTimerDurationMS); + package.add("GetTimers", &Perl_Mob_GetTimers); package.add("GetUltimateOwner", &Perl_Mob_GetUltimateOwner); package.add("GetWIS", &Perl_Mob_GetWIS); package.add("GetWalkspeed", &Perl_Mob_GetWalkspeed); @@ -4161,6 +4198,7 @@ void perl_register_mob() package.add("SetPet", &Perl_Mob_SetPet); package.add("SetPetID", &Perl_Mob_SetPetID); package.add("SetPetOrder", &Perl_Mob_SetPetOrder); + package.add("SetPetType", &Perl_Mob_SetPetType); package.add("SetRace", &Perl_Mob_SetRace); package.add("SetRunAnimSpeed", &Perl_Mob_SetRunAnimSpeed); package.add("SetRunning", &Perl_Mob_SetRunning); diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index df8b5a924..6eaf0ac47 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -885,9 +885,14 @@ Spawn2* Perl_NPC_GetSpawn(NPC* self) return self->GetSpawn(); } -void Perl_NPC_SetNPCTintIndex(NPC* self, uint32 id) +void Perl_NPC_SetNPCTintIndex(NPC* self, uint32 index) { - return self->SendAppearancePacket(AppearanceType::NPCTintIndex, id); + self->SetNPCTintIndex(index); +} + +uint32 Perl_NPC_GetNPCTintIndex(NPC* self) +{ + return self->GetNPCTintIndex(); } void perl_register_npc() @@ -959,6 +964,7 @@ void perl_register_npc() package.add("GetNPCSpellsEffectsID", &Perl_NPC_GetNPCSpellsEffectsID); package.add("GetNPCSpellsID", &Perl_NPC_GetNPCSpellsID); package.add("GetNPCStat", &Perl_NPC_GetNPCStat); + package.add("GetNPCTintIndex", &Perl_NPC_GetNPCTintIndex); package.add("GetPetSpellID", &Perl_NPC_GetPetSpellID); package.add("GetPlatinum", &Perl_NPC_GetPlatinum); package.add("GetPrimSkill", &Perl_NPC_GetPrimSkill); diff --git a/zone/perl_zone.cpp b/zone/perl_zone.cpp index 6cb49f557..b81bfe344 100644 --- a/zone/perl_zone.cpp +++ b/zone/perl_zone.cpp @@ -598,6 +598,95 @@ bool Perl_Zone_VariableExists(Zone* self, const std::string variable_name) return self->VariableExists(variable_name); } +uint32 Perl_Zone_GetTimerDuration(Zone* self, std::string name) +{ + return self->GetTimerDuration(name); +} + +uint32 Perl_Zone_GetTimerRemainingTime(Zone* self, std::string name) +{ + return self->GetTimerRemainingTime(name); +} + +bool Perl_Zone_HasTimer(Zone* self, std::string name) +{ + return self->HasTimer(name); +} + +bool Perl_Zone_IsPausedTimer(Zone* self, std::string name) +{ + return self->IsPausedTimer(name); +} + +void Perl_Zone_PauseTimer(Zone* self, std::string name) +{ + self->PauseTimer(name); +} + +void Perl_Zone_ResumeTimer(Zone* self, std::string name) +{ + self->ResumeTimer(name); +} + +void Perl_Zone_SetTimer(Zone* self, std::string name, uint32 duration) +{ + self->SetTimer(name, duration); +} + +void Perl_Zone_StopTimer(Zone* self, std::string name) +{ + self->StopTimer(name); +} + +void Perl_Zone_StopAllTimers(Zone* self) +{ + self->StopAllTimers(); +} + +void Perl_Zone_SendPayload(Zone* self, int payload_id, std::string payload_value) +{ + self->SendPayload(payload_id, payload_value); +} + +void Perl_Zone_Signal(Zone* self, int signal_id) +{ + self->Signal(signal_id); +} + +perl::array Perl_Zone_GetPausedTimers(Zone* self) +{ + perl::array a; + + const auto& l = self->GetPausedTimers(); + + if (!l.empty()) { + a.reserve(l.size()); + + for (const auto& v : l) { + a.push_back(v); + } + } + + return a; +} + +perl::array Perl_Zone_GetTimers(Zone* self) +{ + perl::array a; + + const auto& l = self->GetTimers(); + + if (!l.empty()) { + a.reserve(l.size()); + + for (const auto& v : l) { + a.push_back(v); + } + } + + return a; +} + void perl_register_zone() { perl::interpreter perl(PERL_GET_THX); @@ -668,6 +757,7 @@ void perl_register_zone() package.add("GetMinimumStatus", &Perl_Zone_GetMinimumStatus); package.add("GetNote", &Perl_Zone_GetNote); package.add("GetNPCMaximumAggroDistance", &Perl_Zone_GetNPCMaximumAggroDistance); + package.add("GetPausedTimers", &Perl_Zone_GetPausedTimers); package.add("GetPEQZone", &Perl_Zone_GetPEQZone); package.add("GetRainChance", (int(*)(Zone*))&Perl_Zone_GetRainChance); package.add("GetRainChance", (int(*)(Zone*, uint8))&Perl_Zone_GetRainChance); @@ -689,6 +779,9 @@ void perl_register_zone() package.add("GetSnowDuration", (int(*)(Zone*, uint8))&Perl_Zone_GetSnowDuration); package.add("GetTimeType", &Perl_Zone_GetTimeType); package.add("GetTimeZone", &Perl_Zone_GetTimeZone); + package.add("GetTimerDuration", &Perl_Zone_GetTimerDuration); + package.add("GetTimerRemainingTime", &Perl_Zone_GetTimerRemainingTime); + package.add("GetTimers", &Perl_Zone_GetTimers); package.add("GetZoneDescription", &Perl_Zone_GetZoneDescription); package.add("GetZoneID", &Perl_Zone_GetZoneID); package.add("GetZoneType", &Perl_Zone_GetZoneType); @@ -701,12 +794,14 @@ void perl_register_zone() package.add("GetZoneTotalBlockedSpells", &Perl_Zone_GetZoneTotalBlockedSpells); package.add("HasGraveyard", &Perl_Zone_HasGraveyard); package.add("HasMap", &Perl_Zone_HasMap); + package.add("HasTimer", &Perl_Zone_HasTimer); package.add("HasWaterMap", &Perl_Zone_HasWaterMap); package.add("HasWeather", &Perl_Zone_HasWeather); package.add("IsCity", &Perl_Zone_IsCity); package.add("IsHotzone", &Perl_Zone_IsHotzone); package.add("IsInstancePersistent", &Perl_Zone_IsInstancePersistent); package.add("IsIdleWhenEmpty", &Perl_Zone_IsIdleWhenEmpty); + package.add("IsPausedTimer", &Perl_Zone_IsPausedTimer); package.add("IsPVPZone", &Perl_Zone_IsPVPZone); package.add("IsRaining", &Perl_Zone_IsRaining); package.add("IsSnowing", &Perl_Zone_IsSnowing); @@ -715,8 +810,11 @@ void perl_register_zone() package.add("IsStaticZone", &Perl_Zone_IsStaticZone); package.add("IsUCSServerAvailable", &Perl_Zone_IsUCSServerAvailable); package.add("IsWaterZone", &Perl_Zone_IsWaterZone); + package.add("PauseTimer", &Perl_Zone_PauseTimer); package.add("Repop", (void(*)(Zone*))&Perl_Zone_Repop); package.add("Repop", (void(*)(Zone*, bool))&Perl_Zone_Repop); + package.add("ResumeTimer", &Perl_Zone_ResumeTimer); + package.add("SendPayload", &Perl_Zone_SendPayload); package.add("SetAAEXPModifier", &Perl_Zone_SetAAEXPModifier); package.add("SetAAEXPModifierByCharacterID", &Perl_Zone_SetAAEXPModifierByCharacterID); package.add("SetBucket", (void(*)(Zone*, const std::string, const std::string))&Perl_Zone_SetBucket); @@ -726,7 +824,11 @@ void perl_register_zone() package.add("SetInstanceTimer", &Perl_Zone_SetInstanceTimer); package.add("SetInstanceTimeRemaining", &Perl_Zone_SetInstanceTimeRemaining); package.add("SetIsHotzone", &Perl_Zone_SetIsHotzone); + package.add("SetTimer", &Perl_Zone_SetTimer); package.add("SetVariable", &Perl_Zone_SetVariable); + package.add("Signal", &Perl_Zone_Signal); + package.add("StopTimer", &Perl_Zone_StopTimer); + package.add("StopAllTimers", &Perl_Zone_StopAllTimers); package.add("ShowZoneGlobalLoot", &Perl_Zone_ShowZoneGlobalLoot); package.add("VariableExists", &Perl_Zone_VariableExists); } diff --git a/zone/pets.cpp b/zone/pets.cpp index 37028e60a..2c8db2d31 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -267,7 +267,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } //this takes ownership of the npc_type data - auto npc = new Pet(npc_type, this, (PetType)record.petcontrol, spell_id, record.petpower); + auto npc = new Pet(npc_type, this, record.petcontrol, spell_id, record.petpower); // Now that we have an actual object to interact with, load // the base items for the pet. These are always loaded @@ -295,7 +295,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, SetPetID(npc->GetID()); // We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet - if (record.petcontrol == petTargetLock) + if (record.petcontrol == PetType::TargetLock) { Mob* m_target = GetTarget(); @@ -341,7 +341,7 @@ void NPC::TryDepopTargetLockedPets(Mob* current_target) { return; } //Use when pets are given petype 5 - if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()) { + if (IsPet() && GetPetType() == PetType::TargetLock && GetPetTargetLockID()) { CastSpell(SPELL_UNSUMMON_SELF, GetID()); //Live like behavior, damages self for 20K if (!HasDied()) { Kill(); //Ensure pet dies if over 20k HP. @@ -356,11 +356,11 @@ void NPC::TryDepopTargetLockedPets(Mob* current_target) { /* This is why the pets ghost - pets were being spawned too far away from its npc owner and some into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I could get while it still looked good). I also noticed this can happen if an NPC is spawned on the same spot of another or in a related bad spot.*/ -Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power) +Pet::Pet(NPCType *type_data, Mob *owner, uint8 pet_type, uint16 spell_id, int16 power) : NPC(type_data, 0, owner->GetPosition() + glm::vec4(2.0f, 2.0f, 0.0f, 0.0f), GravityBehavior::Water) { GiveNPCTypeData(type_data); - SetPetType(type); + SetPetType(pet_type); SetPetPower(power); SetOwnerID(owner ? owner->GetID() : 0); SetPetSpellID(spell_id); @@ -374,8 +374,8 @@ Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 po if (owner && owner->IsClient()) { if (!(owner->CastToClient()->ClientVersionBit() & EQ::versions::maskUFAndLater)) { if ( - (GetPetType() != petFamiliar && GetPetType() != petAnimation) || - aabonuses.PetCommands[PET_TAUNT] + (GetPetType() != PetType::Familiar && GetPetType() != PetType::Animation) || + aabonuses.PetCommands[PetCommand::Taunt] ) { SetTaunting(true); } @@ -587,7 +587,7 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) { if (item2) { bool noDrop = (item2->NoDrop == 0); // Field is reverse logic - bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) && _CLIENTPET(this) && GetPetType() <= petOther); + bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) && _CLIENTPET(this) && GetPetType() <= PetType::Normal); if (!noDrop || petCanHaveNoDrop) { AddLootDrop(item2, LootdropEntriesRepository::NewNpcEntity(), true); diff --git a/zone/pets.h b/zone/pets.h index f8ab50eca..dc656fb08 100644 --- a/zone/pets.h +++ b/zone/pets.h @@ -6,7 +6,7 @@ struct NPCType; class Pet : public NPC { public: - Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 power); + Pet(NPCType *type_data, Mob *owner, uint8 pet_type, uint16 spell_id, int16 power); virtual bool CheckSpellLevelRestriction(Mob *caster, uint16 spell_id); }; diff --git a/zone/quest_interface.h b/zone/quest_interface.h index 687a90f58..f18e1dbec 100644 --- a/zone/quest_interface.h +++ b/zone/quest_interface.h @@ -163,6 +163,28 @@ public: return 0; } + virtual int EventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ) + { + return 0; + } + + virtual int EventGlobalZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ) + { + return 0; + } + virtual bool HasQuestSub(uint32 npc_id, QuestEventID event_id) { return false; @@ -223,6 +245,16 @@ public: return false; } + virtual bool ZoneHasQuestSub(QuestEventID event_id) + { + return false; + } + + virtual bool GlobalZoneHasQuestSub(QuestEventID event_id) + { + return false; + } + virtual void LoadNPCScript(std::string filename, int npc_id) { } virtual void LoadGlobalNPCScript(std::string filename) { } virtual void LoadPlayerScript(std::string filename) { } @@ -234,6 +266,8 @@ public: virtual void LoadGlobalBotScript(std::string filename) { } virtual void LoadMercScript(std::string filename) { } virtual void LoadGlobalMercScript(std::string filename) { } + virtual void LoadZoneScript(std::string filename) { } + virtual void LoadGlobalZoneScript(std::string filename) { } virtual int DispatchEventNPC( QuestEventID event_id, @@ -308,6 +342,17 @@ public: return 0; } + virtual int DispatchEventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ) + { + return 0; + } + virtual void AddVar(std::string name, std::string val) { } virtual std::string GetVar(std::string name) { diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 2ab537c64..9535cb89a 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -49,6 +49,8 @@ QuestParserCollection::QuestParserCollection() _global_bot_quest_status = QuestUnloaded; _merc_quest_status = QuestUnloaded; _global_merc_quest_status = QuestUnloaded; + _zone_quest_status = QuestUnloaded; + _global_zone_quest_status = QuestUnloaded; } QuestParserCollection::~QuestParserCollection() { } @@ -85,6 +87,7 @@ void QuestParserCollection::ReloadQuests(bool reset_timers) { if (reset_timers) { quest_manager.ClearAllTimers(); + zone->StopAllTimers(); } MapOpcodes(); @@ -98,6 +101,8 @@ void QuestParserCollection::ReloadQuests(bool reset_timers) _global_bot_quest_status = QuestUnloaded; _merc_quest_status = QuestUnloaded; _global_merc_quest_status = QuestUnloaded; + _zone_quest_status = QuestUnloaded; + _global_zone_quest_status = QuestUnloaded; _spell_quest_status.clear(); _item_quest_status.clear(); @@ -426,6 +431,49 @@ bool QuestParserCollection::MercHasQuestSub(QuestEventID event_id) return MercHasQuestSubLocal(event_id) || MercHasQuestSubGlobal(event_id); } +bool QuestParserCollection::ZoneHasQuestSubLocal(QuestEventID event_id) +{ + if (_zone_quest_status == QuestUnloaded) { + std::string filename; + auto qi = GetQIByZoneQuest(filename); + + if (qi) { + _zone_quest_status = qi->GetIdentifier(); + qi->LoadZoneScript(filename); + return qi->ZoneHasQuestSub(event_id); + } + } else if (_zone_quest_status != QuestFailedToLoad) { + auto iter = _interfaces.find(_zone_quest_status); + return iter->second->ZoneHasQuestSub(event_id); + } + + return false; +} + +bool QuestParserCollection::ZoneHasQuestSubGlobal(QuestEventID event_id) +{ + if (_global_zone_quest_status == QuestUnloaded) { + std::string filename; + auto qi = GetQIByGlobalZoneQuest(filename); + + if (qi) { + _global_zone_quest_status = qi->GetIdentifier(); + qi->LoadGlobalZoneScript(filename); + return qi->GlobalZoneHasQuestSub(event_id); + } + } else if (_global_zone_quest_status != QuestFailedToLoad) { + auto iter = _interfaces.find(_global_zone_quest_status); + return iter->second->GlobalZoneHasQuestSub(event_id); + } + + return false; +} + +bool QuestParserCollection::ZoneHasQuestSub(QuestEventID event_id) +{ + return ZoneHasQuestSubLocal(event_id) || ZoneHasQuestSubGlobal(event_id); +} + int QuestParserCollection::EventNPC( QuestEventID event_id, NPC* npc, @@ -924,6 +972,83 @@ int QuestParserCollection::EventMercGlobal( return 0; } +int QuestParserCollection::EventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers +) +{ + const int local_return = EventZoneLocal(event_id, zone, data, extra_data, extra_pointers); + const int global_return = EventZoneGlobal(event_id, zone, data, extra_data, extra_pointers); + const int default_return = DispatchEventZone(event_id, zone, data, extra_data, extra_pointers); + + if (local_return != 0) { + return local_return; + } else if (global_return != 0) { + return global_return; + } else if (default_return != 0) { + return default_return; + } + + return 0; +} + +int QuestParserCollection::EventZoneLocal( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers +) +{ + if (_zone_quest_status == QuestUnloaded) { + std::string filename; + auto qi = GetQIByZoneQuest(filename); + + if (qi) { + _zone_quest_status = qi->GetIdentifier(); + qi->LoadZoneScript(filename); + return qi->EventZone(event_id, zone, data, extra_data, extra_pointers); + } + } else { + if (_zone_quest_status != QuestFailedToLoad) { + auto iter = _interfaces.find(_zone_quest_status); + return iter->second->EventZone(event_id, zone, data, extra_data, extra_pointers); + } + } + + return 0; +} + +int QuestParserCollection::EventZoneGlobal( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers +) +{ + if (_global_zone_quest_status == QuestUnloaded) { + std::string filename; + auto qi = GetQIByGlobalZoneQuest(filename); + + if (qi) { + _global_zone_quest_status = qi->GetIdentifier(); + qi->LoadGlobalZoneScript(filename); + return qi->EventGlobalZone(event_id, zone, data, extra_data, extra_pointers); + } + } else { + if (_global_zone_quest_status != QuestFailedToLoad) { + auto iter = _interfaces.find(_global_zone_quest_status); + return iter->second->EventGlobalZone(event_id, zone, data, extra_data, extra_pointers); + } + } + + return 0; +} + QuestInterface* QuestParserCollection::GetQIByNPCQuest(uint32 npc_id, std::string& filename) { if (!zone) { @@ -1425,6 +1550,86 @@ QuestInterface* QuestParserCollection::GetQIByGlobalMercQuest(std::string& filen return nullptr; } +QuestInterface* QuestParserCollection::GetQIByZoneQuest(std::string& filename) +{ + if (!zone || !zone->IsLoaded()) { + return nullptr; + } + + std::string file_name; + for (auto& dir: PathManager::Instance()->GetQuestPaths()) { + const std::string& global_path = fmt::format( + "{}/{}", + dir, + QUEST_GLOBAL_DIRECTORY + ); + + const std::string& zone_path = fmt::format( + "{}/{}", + dir, + zone->GetShortName() + ); + + const std::string& zone_versioned_path = fmt::format( + "{}/{}/v{}", + dir, + zone->GetShortName(), + zone->GetInstanceVersion() + ); + + std::vector file_names = { + fmt::format("{}/zone", zone_versioned_path), // Local versioned by Instance Version ./quests/zone/v0/zone.ext + fmt::format("{}/zone_v{}", zone_path, zone->GetInstanceVersion()), // Local by Instance Version + fmt::format("{}/zone", zone_path), // Local + fmt::format("{}/zone", global_path) // Global + }; + + for (auto& file: file_names) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}.{}", + file, + _extensions.find(e->GetIdentifier())->second + ); + + if (File::Exists(file_name)) { + filename = file_name; + return e; + } + } + } + } + + return nullptr; +} + +QuestInterface* QuestParserCollection::GetQIByGlobalZoneQuest(std::string& filename) +{ + if (!zone) { + return nullptr; + } + + std::string file_name; + + for (auto& dir: PathManager::Instance()->GetQuestPaths()) { + for (auto* e: _load_precedence) { + file_name = fmt::format( + "{}/{}/global_zone.{}", + dir, + QUEST_GLOBAL_DIRECTORY, + _extensions.find(e->GetIdentifier())->second + ); + + if (File::Exists(file_name)) { + filename = file_name; + return e; + } + } + } + + return nullptr; +} + void QuestParserCollection::GetErrors(std::list& quest_errors) { quest_errors.clear(); @@ -1561,6 +1766,26 @@ int QuestParserCollection::DispatchEventMerc( return ret; } +int QuestParserCollection::DispatchEventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers +) +{ + int ret = 0; + + for (const auto& e: _load_precedence) { + int i = e->DispatchEventZone(event_id, zone, data, extra_data, extra_pointers); + if (i != 0) { + ret = i; + } + } + + return ret; +} + void QuestParserCollection::LoadPerlEventExportSettings(PerlEventExportSettings* s) { for (int i = 0; i < _LargestEventID; i++) { diff --git a/zone/quest_parser_collection.h b/zone/quest_parser_collection.h index cb0a5e8d1..5d7d1d3c0 100644 --- a/zone/quest_parser_collection.h +++ b/zone/quest_parser_collection.h @@ -72,6 +72,7 @@ public: bool ItemHasQuestSub(EQ::ItemInstance* inst, QuestEventID event_id); bool BotHasQuestSub(QuestEventID event_id); bool MercHasQuestSub(QuestEventID event_id); + bool ZoneHasQuestSub(QuestEventID event_id); int EventNPC( QuestEventID event_id, @@ -172,6 +173,14 @@ public: std::vector* extra_pointers = nullptr ); + int EventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data = 0, + std::vector* extra_pointers = nullptr + ); + void GetErrors(std::list &quest_errors); /* @@ -209,6 +218,8 @@ private: bool BotHasQuestSubGlobal(QuestEventID event_id); bool MercHasQuestSubLocal(QuestEventID event_id); bool MercHasQuestSubGlobal(QuestEventID event_id); + bool ZoneHasQuestSubLocal(QuestEventID event_id); + bool ZoneHasQuestSubGlobal(QuestEventID event_id); int EventNPCLocal( QuestEventID event_id, @@ -280,6 +291,22 @@ private: std::vector* extra_pointers ); + int EventZoneLocal( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); + + int EventZoneGlobal( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); + QuestInterface* GetQIByNPCQuest(uint32 npc_id, std::string& filename); QuestInterface* GetQIByGlobalNPCQuest(std::string& filename); QuestInterface* GetQIByPlayerQuest(std::string& filename); @@ -291,6 +318,8 @@ private: QuestInterface* GetQIByGlobalBotQuest(std::string& filename); QuestInterface* GetQIByMercQuest(std::string& filename); QuestInterface* GetQIByGlobalMercQuest(std::string& filename); + QuestInterface* GetQIByZoneQuest(std::string& filename); + QuestInterface* GetQIByGlobalZoneQuest(std::string& filename); int DispatchEventNPC( QuestEventID event_id, @@ -347,6 +376,14 @@ private: std::vector* extra_pointers ); + int DispatchEventZone( + QuestEventID event_id, + Zone* zone, + std::string data, + uint32 extra_data, + std::vector* extra_pointers + ); + std::map _interfaces; std::map _extensions; std::list _load_precedence; @@ -359,6 +396,8 @@ private: uint32 _global_bot_quest_status; uint32 _merc_quest_status; uint32 _global_merc_quest_status; + uint32 _zone_quest_status; + uint32 _global_zone_quest_status; std::map _spell_quest_status; std::map _item_quest_status; std::map _encounter_quest_status; diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index ac17e68d3..342955fff 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -64,10 +64,10 @@ QuestManager quest_manager; EQ::ItemInstance* questitem = nullptr; \ const SPDat_Spell_Struct* questspell = nullptr; \ bool depop_npc = false; \ - std::string encounter; \ + std::string encounter = ""; \ do { \ - if(!quests_running_.empty()) { \ - running_quest e = quests_running_.top(); \ + if(!m_running_quests.empty()) { \ + RunningQuest e = m_running_quests.top(); \ owner = e.owner; \ initiator = e.initiator; \ questitem = e.questitem; \ @@ -124,33 +124,30 @@ void QuestManager::Process() { } } -void QuestManager::StartQuest(Mob *_owner, Client *_initiator, EQ::ItemInstance* _questitem, const SPDat_Spell_Struct* _questspell, std::string encounter) { - running_quest run; - run.owner = _owner; - run.initiator = _initiator; - run.questitem = _questitem; - run.questspell = _questspell; - run.depop_npc = false; - run.encounter = encounter; - quests_running_.push(run); +void QuestManager::StartQuest(const RunningQuest& q) +{ + m_running_quests.push(q); } void QuestManager::EndQuest() { - running_quest run = quests_running_.top(); - if(run.depop_npc && run.owner->IsNPC()) { + RunningQuest run = m_running_quests.top(); + + if (run.depop_npc && run.owner->IsNPC()) { //clear out any timers for them... std::list::iterator cur = QTimerList.begin(), end; end = QTimerList.end(); while (cur != end) { - if (cur->mob == run.owner) + if (cur->mob == run.owner) { cur = QTimerList.erase(cur); - else + } else { ++cur; + } } run.owner->Depop(); } - quests_running_.pop(); + + m_running_quests.pop(); } void QuestManager::ClearAllTimers() { @@ -1098,18 +1095,18 @@ void QuestManager::depop(int npc_type) { tmp->CastToNPC()->Depop(); } else { - running_quest e = quests_running_.top(); + RunningQuest e = m_running_quests.top(); e.depop_npc = true; - quests_running_.pop(); - quests_running_.push(e); + m_running_quests.pop(); + m_running_quests.push(e); } } } else { //depop self - running_quest e = quests_running_.top(); + RunningQuest e = m_running_quests.top(); e.depop_npc = true; - quests_running_.pop(); - quests_running_.push(e); + m_running_quests.pop(); + m_running_quests.push(e); } } } @@ -1606,7 +1603,7 @@ void QuestManager::save() { void QuestManager::faction(int faction_id, int faction_value, int temp) { QuestManagerCurrentQuestVars(); - running_quest run = quests_running_.top(); + RunningQuest run = m_running_quests.top(); if(run.owner->IsCharmed() == false && initiator) { if(faction_id != 0 && faction_value != 0) { initiator->SetFactionLevel2( @@ -2077,10 +2074,10 @@ void QuestManager::respawn(int npcTypeID, int grid) { if (!owner || !owner->IsNPC()) return; - running_quest e = quests_running_.top(); + RunningQuest e = m_running_quests.top(); e.depop_npc = true; - quests_running_.pop(); - quests_running_.push(e); + m_running_quests.pop(); + m_running_quests.push(e); const NPCType* npcType = nullptr; if ((npcType = content_db.LoadNPCTypesData(npcTypeID))) @@ -3980,81 +3977,90 @@ void QuestManager::ReloadZoneStaticData() } } -Client *QuestManager::GetInitiator() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Client* QuestManager::GetInitiator() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.initiator; } return nullptr; } -NPC *QuestManager::GetNPC() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +NPC* QuestManager::GetNPC() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return (e.owner && e.owner->IsNPC()) ? e.owner->CastToNPC() : nullptr; } return nullptr; } -Bot *QuestManager::GetBot() const { - if (!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Bot* QuestManager::GetBot() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return (e.owner && e.owner->IsBot()) ? e.owner->CastToBot() : nullptr; } return nullptr; } -Merc *QuestManager::GetMerc() const { - if (!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Merc* QuestManager::GetMerc() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return (e.owner && e.owner->IsMerc()) ? e.owner->CastToMerc() : nullptr; } return nullptr; } -Mob *QuestManager::GetOwner() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +Mob* QuestManager::GetOwner() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.owner; } return nullptr; } -EQ::InventoryProfile *QuestManager::GetInventory() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +EQ::InventoryProfile* QuestManager::GetInventory() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return &e.initiator->GetInv(); } return nullptr; } -EQ::ItemInstance *QuestManager::GetQuestItem() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +EQ::ItemInstance* QuestManager::GetQuestItem() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.questitem; } return nullptr; } -const SPDat_Spell_Struct *QuestManager::GetQuestSpell() { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +const SPDat_Spell_Struct* QuestManager::GetQuestSpell() +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.questspell; } return nullptr; } -std::string QuestManager::GetEncounter() const { - if(!quests_running_.empty()) { - running_quest e = quests_running_.top(); +std::string QuestManager::GetEncounter() const +{ + if (!m_running_quests.empty()) { + RunningQuest e = m_running_quests.top(); return e.encounter; } @@ -4661,3 +4667,33 @@ bool QuestManager::handin(std::map required) { return owner->CastToNPC()->CheckHandin(initiator, {}, required, {}); } + +std::vector QuestManager::GetPausedTimers(Mob* m) +{ + std::vector v; + + if (m && !PTimerList.empty()) { + for (auto e = PTimerList.begin(); e != PTimerList.end(); e++) { + if (e->owner == m) { + v.emplace_back(e->name); + } + } + } + + return v; +} + +std::vector QuestManager::GetTimers(Mob* m) +{ + std::vector v; + + if (m && !QTimerList.empty()) { + for (auto e = QTimerList.begin(); e != QTimerList.end(); e++) { + if (e->mob == m) { + v.emplace_back(e->name); + } + } + } + + return v; +} diff --git a/zone/questmgr.h b/zone/questmgr.h index 0e3cd4a4f..f58bb283a 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -33,15 +33,17 @@ namespace EQ class ItemInstance; } +struct RunningQuest { + Mob* owner = nullptr; + Client* initiator = nullptr; + EQ::ItemInstance* questitem = nullptr; + const SPDat_Spell_Struct* questspell = nullptr; + bool depop_npc = false; + std::string encounter = ""; + Zone* zone = nullptr; +}; + class QuestManager { - struct running_quest { - Mob *owner; - Client *initiator; - EQ::ItemInstance* questitem; - const SPDat_Spell_Struct* questspell; - bool depop_npc; - std::string encounter; - }; struct PausedTimer { Mob* owner; @@ -49,12 +51,13 @@ class QuestManager { uint32 time; }; public: + QuestManager(); virtual ~QuestManager(); - void StartQuest(Mob *_owner, Client *_initiator = nullptr, EQ::ItemInstance* _questitem = nullptr, const SPDat_Spell_Struct* _questspell = nullptr, std::string encounter = ""); + void StartQuest(const RunningQuest& q); void EndQuest(); - bool QuestsRunning() { return !quests_running_.empty(); } + bool QuestsRunning() { return !m_running_quests.empty(); } void Process(); @@ -361,6 +364,8 @@ public: bool SetAutoLoginCharacterNameByAccountID(uint32 account_id, const std::string& character_name); void SpawnCircle(uint32 npc_id, glm::vec4 position, float radius, uint32 points); void SpawnGrid(uint32 npc_id, glm::vec4 position, float spacing, uint32 spawn_count); + std::vector GetPausedTimers(Mob* m); + std::vector GetTimers(Mob* m); Bot *GetBot() const; Client *GetInitiator() const; @@ -381,7 +386,7 @@ public: bool handin(std::map required); private: - std::stack quests_running_; + std::stack m_running_quests; bool HaveProximitySays; diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4ce6bd150..b1101e9c6 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1907,7 +1907,7 @@ void NPC::DoClassAttacks(Mob *target) { target->GetBodyType() != BodyType::Undead && taunt_time && type_of_pet && - type_of_pet != petTargetLock && + type_of_pet != PetType::TargetLock && DistanceSquared(GetPosition(), target->GetPosition()) <= (RuleI(Pets, PetTauntRange) * RuleI(Pets, PetTauntRange)) ) { GetOwner()->MessageString(Chat::PetResponse, PET_TAUNTING); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index e99028737..71b3b2024 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -803,19 +803,19 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove caster->SetPet(this); SetOwnerID(caster->GetID()); - SetPetOrder(SPO_Follow); + SetPetOrder(PetOrder::Follow); SetAppearance(eaStanding); // Client has saved previous pet sit/stand - make all new pets // stand and follow on charm. if (caster->IsClient()) { Client *cpet = caster->CastToClient(); - cpet->SetPetCommandState(PET_BUTTON_SIT,0); - cpet->SetPetCommandState(PET_BUTTON_FOLLOW, 1); - cpet->SetPetCommandState(PET_BUTTON_GUARD, 0); - cpet->SetPetCommandState(PET_BUTTON_STOP, 0); + cpet->SetPetCommandState(PetButton::Sit, PetButtonState::Off); + cpet->SetPetCommandState(PetButton::Follow, PetButtonState::On); + cpet->SetPetCommandState(PetButton::Guard, PetButtonState::Off); + cpet->SetPetCommandState(PetButton::Stop, PetButtonState::Off); } - SetPetType(petCharmed); + SetPetType(PetType::Charmed); // This was done in AddBuff, but we were not a pet yet, so // the target windows didn't get updated. @@ -1308,18 +1308,18 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove if (IsClient() && pet) { auto c = CastToClient(); if (c->ClientVersionBit() & EQ::versions::maskUFAndLater) { - c->SetPetCommandState(PET_BUTTON_SIT, 0); - c->SetPetCommandState(PET_BUTTON_STOP, 0); - c->SetPetCommandState(PET_BUTTON_REGROUP, 0); - c->SetPetCommandState(PET_BUTTON_FOLLOW, 1); - c->SetPetCommandState(PET_BUTTON_GUARD, 0); + c->SetPetCommandState(PetButton::Sit, PetButtonState::Off); + c->SetPetCommandState(PetButton::Stop, PetButtonState::Off); + c->SetPetCommandState(PetButton::Regroup, PetButtonState::Off); + c->SetPetCommandState(PetButton::Follow, PetButtonState::On); + c->SetPetCommandState(PetButton::Guard, PetButtonState::Off); // Creating pet from spell - taunt always false // If suspended pet - that will be restore there // If logging in, client will send toggle - c->SetPetCommandState(PET_BUTTON_HOLD, 0); - c->SetPetCommandState(PET_BUTTON_GHOLD, 0); - c->SetPetCommandState(PET_BUTTON_FOCUS, 0); - c->SetPetCommandState(PET_BUTTON_SPELLHOLD, 0); + c->SetPetCommandState(PetButton::Hold, PetButtonState::Off); + c->SetPetCommandState(PetButton::GreaterHold, PetButtonState::Off); + c->SetPetCommandState(PetButton::Focus, PetButtonState::Off); + c->SetPetCommandState(PetButton::SpellHold, PetButtonState::Off); } } } @@ -1618,7 +1618,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove GetOwnerID() && // I'm a pet caster && // there's a caster caster->GetID() == GetOwnerID() && // and it's my master - GetPetType() != petCharmed + GetPetType() != PetType::Charmed ) { uint16 pet_spellid = CastToNPC()->GetPetSpellID(); @@ -4427,7 +4427,7 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) SendAppearancePacket(AppearanceType::Pet, 0, true, true); Mob* owner = GetOwner(); SetOwnerID(0); - SetPetType(petNone); + SetPetType(PetType::None); SetHeld(false); SetGHeld(false); SetNoCast(false); diff --git a/zone/task_client_state.cpp b/zone/task_client_state.cpp index 8690e05ef..af9525a60 100644 --- a/zone/task_client_state.cpp +++ b/zone/task_client_state.cpp @@ -1414,11 +1414,19 @@ void ClientTaskState::ShowClientTaskInfoMessage(ClientTaskInformation *task, Cli c->Message( Chat::White, fmt::format( - "Task {} | Title: {} ID: {} Type: {}", + "Task {} | Title: {} ID: {} Type: {} | {}", task->slot, task_data->title, task->task_id, - Tasks::GetTaskTypeDescription(task_data->type) + Tasks::GetTaskTypeDescription(task_data->type), + Saylink::Create( + fmt::format( + "#task complete {}", + task->task_id + ), + false, + "Complete" + ) ).c_str() ); c->Message(Chat::White, "------------------------------------------------"); diff --git a/zone/zone.cpp b/zone/zone.cpp index 37216b046..eea9d8a97 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1693,6 +1693,25 @@ bool Zone::Process() { } } + const bool has_timer_event = parse->ZoneHasQuestSub(EVENT_TIMER); + + for (auto e : zone_timers) { + if (e.timer_.Enabled() && e.timer_.Check()) { + if (has_timer_event) { + parse->EventZone(EVENT_TIMER, this, e.name); + } + } + } + + if (!m_zone_signals.empty()) { + int signal_id = m_zone_signals.front(); + m_zone_signals.pop_front(); + + if (parse->ZoneHasQuestSub(EVENT_SIGNAL)) { + parse->EventZone(EVENT_SIGNAL, this, std::to_string(signal_id), 0); + } + } + mMovementManager->Process(); return true; @@ -1935,6 +1954,8 @@ void Zone::Repop(bool is_forced) quest_manager.ClearAllTimers(); + StopAllTimers(); + LogInfo("Loading spawn groups"); if (!content_db.LoadSpawnGroups(short_name, GetInstanceVersion(), &spawn_group_list)) { LogError("Loading spawn groups failed"); @@ -3301,4 +3322,267 @@ void Zone::ReloadMaps() pathing = IPathfinder::Load(map_name); } +uint32 Zone::GetTimerDuration(std::string name) +{ + if (!IsLoaded() || zone_timers.empty()) { + return 0; + } + + const auto& e = std::find_if( + zone_timers.begin(), + zone_timers.end(), + [&name](ZoneTimer e) { + return e.name == name; + } + ); + + return e != zone_timers.end() ? e->timer_.GetDuration() : 0; +} + +uint32 Zone::GetTimerRemainingTime(std::string name) +{ + if (!IsLoaded() || zone_timers.empty()) { + return 0; + } + + const auto& e = std::find_if( + zone_timers.begin(), + zone_timers.end(), + [&name](ZoneTimer e) { + return e.name == name; + } + ); + + return e != zone_timers.end() ? e->timer_.GetRemainingTime() : 0; +} + +bool Zone::HasTimer(std::string name) +{ + if (!IsLoaded() || zone_timers.empty()) { + return false; + } + + const auto& e = std::find_if( + zone_timers.begin(), + zone_timers.end(), + [&name](ZoneTimer e) { + return e.name == name; + } + ); + + return e != zone_timers.end(); +} + +bool Zone::IsPausedTimer(std::string name) +{ + if (!IsLoaded() || paused_zone_timers.empty()) { + return false; + } + + const auto& e = std::find_if( + paused_zone_timers.begin(), + paused_zone_timers.end(), + [&name](PausedZoneTimer e) { + return e.name == name; + } + ); + + return e != paused_zone_timers.end(); +} + +void Zone::PauseTimer(std::string name) +{ + if ( + !IsLoaded() || + zone_timers.empty() || + !HasTimer(name) || + IsPausedTimer(name) + ) { + return; + } + + uint32 remaining_time = 0; + + const bool has_pause_event = parse->ZoneHasQuestSub(EVENT_TIMER_PAUSE); + + if (!zone_timers.empty()) { + for (auto e = zone_timers.begin(); e != zone_timers.end(); e++) { + if (e->name == name) { + remaining_time = e->timer_.GetRemainingTime(); + + zone_timers.erase(e); + + const std::string& export_string = fmt::format( + "{} {}", + name, + remaining_time + ); + + LogQuests( + "Pausing timer [{}] with [{}] ms remaining", + name, + remaining_time + ); + + paused_zone_timers.emplace_back( + PausedZoneTimer{ + .name = name, + .remaining_time = remaining_time + } + ); + + if (has_pause_event) { + parse->EventZone(EVENT_TIMER_PAUSE, this, export_string); + } + + break; + } + } + } +} + +void Zone::ResumeTimer(std::string name) +{ + if ( + !IsLoaded() || + paused_zone_timers.empty() || + !IsPausedTimer(name) + ) { + return; + } + + uint32 remaining_time = 0; + + if (!paused_zone_timers.empty()) { + for (auto e = paused_zone_timers.begin(); e != paused_zone_timers.end(); e++) { + if (e->name == name) { + remaining_time = e->remaining_time; + + paused_zone_timers.erase(e); + + if (!remaining_time) { + LogQuests("Paused timer [{}] not found or has expired.", name); + return; + } + + const std::string& export_string = fmt::format( + "{} {}", + name, + remaining_time + ); + + LogQuests( + "Creating a new timer and resuming [{}] with [{}] ms remaining", + name, + remaining_time + ); + + zone_timers.emplace_back(ZoneTimer(name, remaining_time)); + + if (parse->ZoneHasQuestSub(EVENT_TIMER_RESUME)) { + parse->EventZone(EVENT_TIMER_RESUME, this, export_string); + } + + break; + } + } + } +} + +void Zone::SetTimer(std::string name, uint32 duration) +{ + if (!IsLoaded() || HasTimer(name)) { + return; + } + + zone_timers.emplace_back(ZoneTimer(name, duration)); + + if (parse->ZoneHasQuestSub(EVENT_TIMER_START)) { + const std::string& export_string = fmt::format("{} {}", name, duration); + parse->EventZone(EVENT_TIMER_START, this, export_string); + } +} + +void Zone::StopTimer(std::string name) +{ + if ( + !IsLoaded() || + zone_timers.empty() || + !HasTimer(name) || + IsPausedTimer(name) + ) { + return; + } + + const bool has_stop_event = parse->ZoneHasQuestSub(EVENT_TIMER_STOP); + + for (auto e = zone_timers.begin(); e != zone_timers.end(); e++) { + if (e->name == name) { + if (has_stop_event) { + parse->EventZone(EVENT_TIMER_STOP, this, name); + } + + zone_timers.erase(e); + break; + } + } +} + +void Zone::StopAllTimers() +{ + if (!IsLoaded() || zone_timers.empty()) { + return; + } + + const bool has_stop_event = parse->ZoneHasQuestSub(EVENT_TIMER_STOP); + + for (auto e = zone_timers.begin(); e != zone_timers.end();) { + if (has_stop_event) { + parse->EventZone(EVENT_TIMER_STOP, this, e->name); + } + + e = zone_timers.erase(e); + } +} + +void Zone::Signal(int signal_id) +{ + m_zone_signals.push_back(signal_id); +} + +void Zone::SendPayload(int payload_id, std::string payload_value) +{ + if (parse->ZoneHasQuestSub(EVENT_PAYLOAD)) { + const auto& export_string = fmt::format("{} {}", payload_id, payload_value); + + parse->EventZone(EVENT_PAYLOAD, this, export_string, 0); + } +} + +std::vector Zone::GetPausedTimers() +{ + std::vector v; + + if (!paused_zone_timers.empty()) { + for (auto e = paused_zone_timers.begin(); e != paused_zone_timers.end(); e++) { + v.emplace_back(e->name); + } + } + + return v; +} + +std::vector Zone::GetTimers() +{ + std::vector v; + + if (!zone_timers.empty()) { + for (auto e = zone_timers.begin(); e != zone_timers.end(); e++) { + v.emplace_back(e->name); + } + } + + return v; +} + #include "zone_loot.cpp" diff --git a/zone/zone.h b/zone/zone.h index 237c7fdb0..fe9d39650 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -486,6 +486,26 @@ public: static void ClearZoneState(uint32 zone_id, uint32 instance_id); void ReloadMaps(); + void Signal(int signal_id); + void SendPayload(int payload_id, std::string payload_value); + + struct PausedZoneTimer { + std::string name; + uint32 remaining_time; + }; + + uint32 GetTimerDuration(std::string name); + uint32 GetTimerRemainingTime(std::string name); + bool HasTimer(std::string name); + bool IsPausedTimer(std::string name); + void PauseTimer(std::string name); + void ResumeTimer(std::string name); + void SetTimer(std::string name, uint32 duration); + void StopTimer(std::string name); + void StopAllTimers(); + std::vector GetPausedTimers(); + std::vector GetTimers(); + private: bool allow_mercs; bool can_bind; @@ -552,6 +572,18 @@ private: std::vector m_base_data = { }; uint32_t m_zone_server_id = 0; + + class ZoneTimer { + public: + inline ZoneTimer(std::string _name, uint32 duration) + : name(_name), timer_(duration) { timer_.Start(duration, false); } + std::string name; + Timer timer_; + }; + + std::vector zone_timers; + std::vector paused_zone_timers; + std::deque m_zone_signals; }; #endif diff --git a/zone/zoning.cpp b/zone/zoning.cpp index f857a6e20..96ad15dbc 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -709,7 +709,7 @@ void Client::ProcessMovePC(uint32 zoneID, uint32 instance_id, float x, float y, //if they have a pet and they are staying in zone, move with them Mob *p = GetPet(); if(p != nullptr){ - p->SetPetOrder(SPO_Follow); + p->SetPetOrder(PetOrder::Follow); p->GMMove(x+15, y, z); //so it dosent have to run across the map. } }