From f29ebbdd71ba6eee1d72e239d91c29e5a8ceb535 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sun, 22 Mar 2026 15:36:25 -0700 Subject: [PATCH] feat: add quest watch/tracking and selection Lua API for WatchFrame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the quest tracking functions needed by WatchFrame.lua: - SelectQuestLogEntry/GetQuestLogSelection — quest log selection state - GetNumQuestWatches — count of tracked quests - GetQuestIndexForWatch(watchIdx) — map Nth watched quest to log index - AddQuestWatch/RemoveQuestWatch — toggle quest tracking by log index - IsQuestWatched — check if a quest log entry is tracked - GetQuestLink — generate colored quest link string Backed by existing trackedQuestIds_ set and questLog_ vector. Adds selectedQuestLogIndex_ state to GameHandler for quest selection. --- include/game/game_handler.hpp | 3 + src/addons/lua_engine.cpp | 105 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 033f8661..9eb2b867 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1674,6 +1674,8 @@ public: std::array rewardChoiceItems{}; // player picks one of these }; const std::vector& getQuestLog() const { return questLog_; } + int getSelectedQuestLogIndex() const { return selectedQuestLogIndex_; } + void setSelectedQuestLogIndex(int idx) { selectedQuestLogIndex_ = idx; } void abandonQuest(uint32_t questId); void shareQuestWithParty(uint32_t questId); // CMSG_PUSHQUESTTOPARTY bool requestQuestQuery(uint32_t questId, bool force = false); @@ -3187,6 +3189,7 @@ private: // Quest log std::vector questLog_; + int selectedQuestLogIndex_ = 0; std::unordered_set pendingQuestQueryIds_; std::unordered_set trackedQuestIds_; bool pendingLoginQuestResync_ = false; diff --git a/src/addons/lua_engine.cpp b/src/addons/lua_engine.cpp index fdaebadd..3ab3a3c9 100644 --- a/src/addons/lua_engine.cpp +++ b/src/addons/lua_engine.cpp @@ -2150,6 +2150,103 @@ static int lua_IsQuestComplete(lua_State* L) { return 1; } +// SelectQuestLogEntry(index) — select a quest in the quest log +static int lua_SelectQuestLogEntry(lua_State* L) { + auto* gh = getGameHandler(L); + int index = static_cast(luaL_checknumber(L, 1)); + if (gh) gh->setSelectedQuestLogIndex(index); + return 0; +} + +// GetQuestLogSelection() → index +static int lua_GetQuestLogSelection(lua_State* L) { + auto* gh = getGameHandler(L); + lua_pushnumber(L, gh ? gh->getSelectedQuestLogIndex() : 0); + return 1; +} + +// GetNumQuestWatches() → count +static int lua_GetNumQuestWatches(lua_State* L) { + auto* gh = getGameHandler(L); + lua_pushnumber(L, gh ? gh->getTrackedQuestIds().size() : 0); + return 1; +} + +// GetQuestIndexForWatch(watchIndex) → questLogIndex +// Maps the Nth watched quest to its quest log index (1-based) +static int lua_GetQuestIndexForWatch(lua_State* L) { + auto* gh = getGameHandler(L); + int watchIdx = static_cast(luaL_checknumber(L, 1)); + if (!gh || watchIdx < 1) { lua_pushnil(L); return 1; } + const auto& ql = gh->getQuestLog(); + const auto& tracked = gh->getTrackedQuestIds(); + int found = 0; + for (size_t i = 0; i < ql.size(); ++i) { + if (tracked.count(ql[i].questId)) { + found++; + if (found == watchIdx) { + lua_pushnumber(L, static_cast(i) + 1); // 1-based + return 1; + } + } + } + lua_pushnil(L); + return 1; +} + +// AddQuestWatch(questLogIndex) — add a quest to the watch list +static int lua_AddQuestWatch(lua_State* L) { + auto* gh = getGameHandler(L); + int index = static_cast(luaL_checknumber(L, 1)); + if (!gh || index < 1) return 0; + const auto& ql = gh->getQuestLog(); + if (index <= static_cast(ql.size())) { + gh->setQuestTracked(ql[index - 1].questId, true); + } + return 0; +} + +// RemoveQuestWatch(questLogIndex) — remove a quest from the watch list +static int lua_RemoveQuestWatch(lua_State* L) { + auto* gh = getGameHandler(L); + int index = static_cast(luaL_checknumber(L, 1)); + if (!gh || index < 1) return 0; + const auto& ql = gh->getQuestLog(); + if (index <= static_cast(ql.size())) { + gh->setQuestTracked(ql[index - 1].questId, false); + } + return 0; +} + +// IsQuestWatched(questLogIndex) → boolean +static int lua_IsQuestWatched(lua_State* L) { + auto* gh = getGameHandler(L); + int index = static_cast(luaL_checknumber(L, 1)); + if (!gh || index < 1) { lua_pushboolean(L, 0); return 1; } + const auto& ql = gh->getQuestLog(); + if (index <= static_cast(ql.size())) { + lua_pushboolean(L, gh->isQuestTracked(ql[index - 1].questId) ? 1 : 0); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +// GetQuestLink(questLogIndex) → "|cff...|Hquest:id:level|h[title]|h|r" +static int lua_GetQuestLink(lua_State* L) { + auto* gh = getGameHandler(L); + int index = static_cast(luaL_checknumber(L, 1)); + if (!gh || index < 1) { lua_pushnil(L); return 1; } + const auto& ql = gh->getQuestLog(); + if (index > static_cast(ql.size())) { lua_pushnil(L); return 1; } + const auto& q = ql[index - 1]; + // Yellow quest link format matching WoW + std::string link = "|cff808000|Hquest:" + std::to_string(q.questId) + + ":0|h[" + q.title + "]|h|r"; + lua_pushstring(L, link.c_str()); + return 1; +} + // --- Skill Line API --- // GetNumSkillLines() → count @@ -3906,6 +4003,14 @@ void LuaEngine::registerCoreAPI() { {"GetQuestLogTitle", lua_GetQuestLogTitle}, {"GetQuestLogQuestText", lua_GetQuestLogQuestText}, {"IsQuestComplete", lua_IsQuestComplete}, + {"SelectQuestLogEntry", lua_SelectQuestLogEntry}, + {"GetQuestLogSelection", lua_GetQuestLogSelection}, + {"GetNumQuestWatches", lua_GetNumQuestWatches}, + {"GetQuestIndexForWatch", lua_GetQuestIndexForWatch}, + {"AddQuestWatch", lua_AddQuestWatch}, + {"RemoveQuestWatch", lua_RemoveQuestWatch}, + {"IsQuestWatched", lua_IsQuestWatched}, + {"GetQuestLink", lua_GetQuestLink}, // Skill line API {"GetNumSkillLines", lua_GetNumSkillLines}, {"GetSkillLineInfo", lua_GetSkillLineInfo},