From 15113f4056e1d26e547e35955426f2536560c1e0 Mon Sep 17 00:00:00 2001 From: Kinglykrab <89047260+Kinglykrab@users.noreply.github.com> Date: Wed, 29 Jun 2022 15:29:02 -0400 Subject: [PATCH] [Quest API] Add TrackNPC to Perl/Lua. (#2272) * [Quest API] Add TrackNPC to Perl/Lua. - Add quest::tracknpc(entity_id) to Perl. - Add eq.track_npc(entity_id) to Lua. - This will allow server operators to arbitrarily Track NPCs for clients with scripts. - Modified tracking to auto turn off and tell you that you discovered your target if within 10 units, this is to allow scripted Tracking to turn off without the need for the Tracking skill. * Remove unnecessary DoTracking() call. * Update client.cpp --- zone/client.cpp | 18 +++++++++++++++ zone/client.h | 2 ++ zone/client_packet.cpp | 10 ++++---- zone/client_process.cpp | 43 +++++++++++++++++++++++----------- zone/embparser_api.cpp | 13 +++++++++++ zone/entity.cpp | 51 +++++++++++++++++++++++------------------ zone/lua_general.cpp | 11 +++++---- zone/questmgr.cpp | 9 ++++++++ zone/questmgr.h | 1 + zone/string_ids.h | 1 + 10 files changed, 113 insertions(+), 46 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index bc42c3db0..5b88e3e43 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -11753,3 +11753,21 @@ void Client::Undye() database.DeleteCharacterDye(CharacterID()); } + +void Client::SetTrackingID(uint32 entity_id) +{ + if (!entity_id) { + TrackingID = 0; + return; + } + + auto *m = entity_list.GetMob(entity_id); + if (!m) { + TrackingID = 0; + return; + } + + TrackingID = entity_id; + + MessageString(Chat::Skills, TRACKING_BEGIN, m->GetCleanName()); +} diff --git a/zone/client.h b/zone/client.h index 180e30464..b73ae9a02 100644 --- a/zone/client.h +++ b/zone/client.h @@ -409,6 +409,8 @@ public: inline void SetBaseRace(uint32 i) { m_pp.race=i; } inline void SetBaseGender(uint32 i) { m_pp.gender=i; } inline void SetDeity(uint32 i) {m_pp.deity=i;deity=i;} + + void SetTrackingID(uint32 entity_id); inline uint8 GetLevel2() const { return m_pp.level2; } inline uint16 GetBaseRace() const { return m_pp.race; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 85ccd9b81..87bcd8da8 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -14165,16 +14165,14 @@ void Client::Handle_OP_TrackTarget(const EQApplicationPacket *app) return; } - if (app->size != sizeof(TrackTarget_Struct)) - { - LogError("Invalid size for OP_TrackTarget: Expected: [{}], Got: [{}]", - sizeof(TrackTarget_Struct), app->size); + if (app->size != sizeof(TrackTarget_Struct)) { + LogError("Invalid size for OP_TrackTarget: Expected: [{}], Got: [{}]", sizeof(TrackTarget_Struct), app->size); return; } - TrackTarget_Struct *tts = (TrackTarget_Struct*)app->pBuffer; + auto *t = (TrackTarget_Struct*) app->pBuffer; - TrackingID = tts->EntityID; + SetTrackingID(t->EntityID); } void Client::Handle_OP_TrackUnknown(const EQApplicationPacket *app) diff --git a/zone/client_process.cpp b/zone/client_process.cpp index e0aac03e4..6dedfc0ca 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -1946,10 +1946,11 @@ void Client::CalcRestState() void Client::DoTracking() { - if (TrackingID == 0) + if (!TrackingID) { return; + } - Mob *m = entity_list.GetMob(TrackingID); + auto *m = entity_list.GetMob(TrackingID); if (!m || m->IsCorpse()) { MessageString(Chat::Skills, TRACK_LOST_TARGET); @@ -1957,29 +1958,43 @@ void Client::DoTracking() return; } - float RelativeHeading = GetHeading() - CalculateHeadingToTarget(m->GetX(), m->GetY()); + if (DistanceNoZ(m->GetPosition(), GetPosition()) < 10) { + Message( + Chat::Skills, + fmt::format( + "You have found {}.", + m->GetCleanName() + ).c_str() + ); + TrackingID = 0; + return; + } - if (RelativeHeading < 0) - RelativeHeading += 512; + float relative_heading = GetHeading() - CalculateHeadingToTarget(m->GetX(), m->GetY()); - if (RelativeHeading > 480) + if (relative_heading < 0) { + relative_heading += 512; + } + + if (relative_heading > 480) { MessageString(Chat::Skills, TRACK_STRAIGHT_AHEAD, m->GetCleanName()); - else if (RelativeHeading > 416) + } else if (relative_heading > 416) { MessageString(Chat::Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "left"); - else if (RelativeHeading > 352) + } else if (relative_heading > 352) { MessageString(Chat::Skills, TRACK_TO_THE, m->GetCleanName(), "left"); - else if (RelativeHeading > 288) + } else if (relative_heading > 288) { MessageString(Chat::Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "left"); - else if (RelativeHeading > 224) + } else if (relative_heading > 224) { MessageString(Chat::Skills, TRACK_BEHIND_YOU, m->GetCleanName()); - else if (RelativeHeading > 160) + } else if (relative_heading > 160) { MessageString(Chat::Skills, TRACK_BEHIND_AND_TO, m->GetCleanName(), "right"); - else if (RelativeHeading > 96) + } else if (relative_heading > 96) { MessageString(Chat::Skills, TRACK_TO_THE, m->GetCleanName(), "right"); - else if (RelativeHeading > 32) + } else if (relative_heading > 32) { MessageString(Chat::Skills, TRACK_AHEAD_AND_TO, m->GetCleanName(), "right"); - else if (RelativeHeading >= 0) + } else if (relative_heading >= 0) { MessageString(Chat::Skills, TRACK_STRAIGHT_AHEAD, m->GetCleanName()); + } } void Client::HandleRespawnFromHover(uint32 Option) diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index e4f2ee15f..9ad63ae53 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -8454,6 +8454,18 @@ XS(XS__discordsend) { XSRETURN_EMPTY; } +XS(XS__tracknpc); +XS(XS__tracknpc) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::tracknpc(uint32 entity_id)"); + { + uint32 entity_id = (uint32) SvUV(ST(0)); + quest_manager.TrackNPC(entity_id); + } + XSRETURN_EMPTY; +} + /* This is the callback perl will look for to setup the quest package's XSUBs @@ -8893,6 +8905,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "tasktimeleft"), XS__tasktimeleft, file); newXS(strcpy(buf, "toggle_spawn_event"), XS__toggle_spawn_event, file); newXS(strcpy(buf, "toggledoorstate"), XS__toggledoorstate, file); + newXS(strcpy(buf, "tracknpc"), XS__tracknpc, file); newXS(strcpy(buf, "traindisc"), XS__traindisc, file); newXS(strcpy(buf, "traindiscs"), XS__traindiscs, file); newXS(strcpy(buf, "unique_spawn"), XS__unique_spawn, file); diff --git a/zone/entity.cpp b/zone/entity.cpp index 918b1ec2a..16b3e6dc8 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3668,46 +3668,53 @@ void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id) bool EntityList::MakeTrackPacket(Client *client) { std::list > tracking_list; - uint32 distance = 0; - float MobDistance; + auto distance = static_cast(client->GetSkill(EQ::skills::SkillTracking) * client->GetClassTrackingDistanceMultiplier(client->GetClass())); - distance = (client->GetSkill(EQ::skills::SkillTracking) * client->GetClassTrackingDistanceMultiplier(client->GetClass())); - - if (distance <= 0) + if (distance <= 0.0f) { return false; - if (distance < 300) - distance = 300; + } + + if (distance < 300.0f) { + distance = 300.0f; + } for (auto it = mob_list.cbegin(); it != mob_list.cend(); ++it) { - if (!it->second || it->second == client || !it->second->IsTrackable() || - it->second->IsInvisible(client)) + if ( + !it->second || + it->second == client || + !it->second->IsTrackable() || + it->second->IsInvisible(client) + ) { continue; + } - MobDistance = DistanceNoZ(it->second->GetPosition(), client->GetPosition()); - if (MobDistance > distance) + const auto mob_distance = DistanceNoZ(it->second->GetPosition(), client->GetPosition()); + if (mob_distance > distance) { continue; + } - tracking_list.push_back(std::make_pair(it->second, MobDistance)); + tracking_list.push_back(std::make_pair(it->second, mob_distance)); } tracking_list.sort( [](const std::pair &a, const std::pair &b) { return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp(); - }); + } + ); + auto outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size()); - Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer; + auto pack = (Tracking_Struct *) outapp->pBuffer; outapp->priority = 6; int index = 0; for (auto it = tracking_list.cbegin(); it != tracking_list.cend(); ++it, ++index) { - Mob *cur_entity = it->first; - outtrack->Entrys[index].entityid = (uint32)cur_entity->GetID(); - outtrack->Entrys[index].distance = it->second; - outtrack->Entrys[index].level = cur_entity->GetLevel(); - outtrack->Entrys[index].is_npc = !cur_entity->IsClient(); - strn0cpy(outtrack->Entrys[index].name, cur_entity->GetName(), sizeof(outtrack->Entrys[index].name)); - outtrack->Entrys[index].is_pet = cur_entity->IsPet(); - outtrack->Entrys[index].is_merc = cur_entity->IsMerc(); + pack->Entrys[index].entityid = static_cast(it->first->GetID()); + pack->Entrys[index].distance = it->second; + pack->Entrys[index].level = it->first->GetLevel(); + pack->Entrys[index].is_npc = !it->first->IsClient(); + strn0cpy(pack->Entrys[index].name, it->first->GetName(), sizeof(pack->Entrys[index].name)); + pack->Entrys[index].is_pet = it->first->IsPet(); + pack->Entrys[index].is_merc = it->first->IsMerc(); } client->QueuePacket(outapp); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index a13ed4c77..21c8306d8 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -3392,16 +3392,18 @@ std::string lua_commify(std::string number) { return commify(number); } -bool lua_check_name_filter(std::string name) -{ +bool lua_check_name_filter(std::string name) { return database.CheckNameFilter(name); } -void lua_discord_send(std::string webhook_name, std::string message) -{ +void lua_discord_send(std::string webhook_name, std::string message) { zone->SendDiscordMessage(webhook_name, message); } +void lua_track_npc(uint32 entity_id) { + quest_manager.TrackNPC(entity_id); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ @@ -3857,6 +3859,7 @@ luabind::scope lua_register_general() { luabind::def("commify", &lua_commify), luabind::def("check_name_filter", &lua_check_name_filter), luabind::def("discord_send", &lua_discord_send), + luabind::def("track_npc", &lua_track_npc), /* Cross Zone diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 53e23533b..7ce6aec2d 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -3688,3 +3688,12 @@ std::string QuestManager::getenvironmentaldamagename(uint8 damage_type) { std::string environmental_damage_name = EQ::constants::GetEnvironmentalDamageName(damage_type); return environmental_damage_name; } + +void QuestManager::TrackNPC(uint32 entity_id) { + QuestManagerCurrentQuestVars(); + if (!initiator) { + return; + } + + initiator->SetTrackingID(entity_id); +} diff --git a/zone/questmgr.h b/zone/questmgr.h index 1e8ab19a7..0183a4098 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -336,6 +336,7 @@ public: int getspellstat(uint32 spell_id, std::string stat_identifier, uint8 slot = 0); const SPDat_Spell_Struct *getspell(uint32 spell_id); std::string getenvironmentaldamagename(uint8 damage_type); + void TrackNPC(uint32 entity_id); Client *GetInitiator() const; NPC *GetNPC() const; diff --git a/zone/string_ids.h b/zone/string_ids.h index 24fd2d22e..7c94bd8b6 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -454,6 +454,7 @@ #define NO_ABILITY_OUT_OF_COMBAT 9194 //You can not use this ability while out of combat. #define AE_RAMPAGE 11015 //%1 goes on a WILD RAMPAGE! #define FACE_ACCEPTED 12028 //Facial features accepted. +#define TRACKING_BEGIN 12040 //You begin tracking %1. #define SPELL_LEVEL_TO_LOW 12048 //You will have to achieve level %1 before you can scribe the %2. #define YOU_RECEIVE_AS_SPLIT 12071 //You receive %1 as your split. #define ATTACKFAILED 12158 //%1 try to %2 %3, but %4!