diff --git a/README.md b/README.md index eb1f634..ac68a5b 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ This includes functions for: - Encrypted login helpers (EncryptPassword, EncryptedServerLogin) - Talent helpers (LearnTalentRank) - Spell lookups and utilities (GetUnitGUID, CombatLogFlush, etc.) +- Quest ID helpers (GetQuestLogQuestIds, GetQuestDialogQuestId) Detailed parameter, return-value, and behavior notes for individual functions are documented in [SCRIPTS.md](SCRIPTS.md). diff --git a/SCRIPTS.md b/SCRIPTS.md index 0fd2e87..850b006 100644 --- a/SCRIPTS.md +++ b/SCRIPTS.md @@ -77,6 +77,8 @@ For custom events, see [EVENTS.md](EVENTS.md). For installation, configuration, - [EncryptedServerLogin(username, encryptedPasswordBase64String)](#encryptedserverloginusername-encryptedpasswordbase64string) - [CombatLogFlush()](#combatlogflush) - [DisenchantAll](#disenchantallitemidorname-includesoulbound-or-disenchantallquality-includesoulbound) + - [GetQuestLogQuestIds()](#getquestlogquestids) + - [GetQuestDialogQuestId()](#getquestdialogquestid) --- ## Performance Optimization - Table References @@ -1700,3 +1702,33 @@ DisenchantAll("Glowing Brightwood Staff", 1) - The function will stop if you run out of matching items or if the disenchant spell fails - Displays chat messages: "Disenchanting [Item Link] move during cast to cancel.", "No more items to disenchant.", and "Disenchant interrupted or failed." - **REVIEW YOUR BAGS CAREFULLY BEFORE USE** - disenchanting cannot be undone! + +#### GetQuestLogQuestIds() +Returns a compact table of real quest IDs from the current quest log. + +**Returns:** +- A Lua table indexed `1..N` containing quest IDs only. + +**Examples:** +``` +/run local t=GetQuestLogQuestIds(); local i; for i=1,table.getn(t) do print(t[i]) end +``` + +--- + +#### GetQuestDialogQuestId() +Returns the real quest ID for the currently open quest dialog. + +This is mainly useful while handling: +- `QUEST_DETAIL` +- `QUEST_PROGRESS` +- `QUEST_COMPLETE` + +**Returns:** +- The current dialog quest ID as a number. +- `nil` when no valid quest dialog is active. + +**Examples:** +``` +/run print(GetQuestDialogQuestId()) +``` diff --git a/nampower/CMakeLists.txt b/nampower/CMakeLists.txt index ff51f58..3ffc974 100644 --- a/nampower/CMakeLists.txt +++ b/nampower/CMakeLists.txt @@ -59,6 +59,8 @@ set(SOURCE_FILES unit.cpp tooltip.hpp tooltip.cpp + quest.hpp + quest.cpp ) add_library(${DLL_NAME} SHARED ${SOURCE_FILES}) diff --git a/nampower/main.cpp b/nampower/main.cpp index 4d000dc..47f96c3 100644 --- a/nampower/main.cpp +++ b/nampower/main.cpp @@ -51,6 +51,7 @@ #include "unit.hpp" #include "pet.hpp" #include "tooltip.hpp" +#include "quest.hpp" #include #include @@ -2132,6 +2133,12 @@ namespace Nampower { char executeCustomLuaFile[] = "ExecuteCustomLuaFile"; RegisterLuaFunction(executeCustomLuaFile, reinterpret_cast(Script_ExecuteCustomLuaFile)); + + char getQuestLogQuestIds[] = "GetQuestLogQuestIds"; + RegisterLuaFunction(getQuestLogQuestIds, reinterpret_cast(Script_GetQuestLogQuestIds)); + + char getQuestDialogQuestId[] = "GetQuestDialogQuestId"; + RegisterLuaFunction(getQuestDialogQuestId, reinterpret_cast(Script_GetQuestDialogQuestId)); } void Glue_LoadScriptFunctionsHook(hadesmem::PatchDetourBase *detour) { diff --git a/nampower/offsets.hpp b/nampower/offsets.hpp index c0cb0e1..9ff5bfa 100644 --- a/nampower/offsets.hpp +++ b/nampower/offsets.hpp @@ -301,4 +301,9 @@ enum class Offsets : std::uint32_t { PetActionBarSlots = 0x00b71438, PetReactionMode = 0x00b71468, ActivePetGuid = 0x00b714a0, + + QuestLogEntries = 0x00BB71C0, + QuestLogEntryCount = 0x00BB7478, + QuestDialogState = 0x00BE0818, + QuestDialogCurrentQuestId = 0x00BE081C, }; diff --git a/nampower/quest.cpp b/nampower/quest.cpp new file mode 100644 index 0000000..6f4308c --- /dev/null +++ b/nampower/quest.cpp @@ -0,0 +1,89 @@ +// +// Quest log and dialog quest ID Lua APIs. +// + +#include "quest.hpp" + +#include "offsets.hpp" +#include "helper.hpp" + +namespace Nampower { + enum class QuestDialogKind : int32_t { + DETAIL = 1, + PROGRESS = 2, + COMPLETE = 3, + }; + + struct QuestLogEntryRaw { + int32_t questId; + int32_t questSortOrHeaderId; + int32_t headerToken; + int32_t flags; + }; + + static constexpr uint32_t kQuestLogMaxRows = 256; + + static uint32_t *GetQuestLogEntryCountPtr() { + return reinterpret_cast(Offsets::QuestLogEntryCount); + } + + static QuestLogEntryRaw *GetQuestLogEntriesPtr() { + return reinterpret_cast(Offsets::QuestLogEntries); + } + + static int32_t GetQuestDialogStateCode() { + return *reinterpret_cast(Offsets::QuestDialogState); + } + + static uint32_t GetQuestDialogQuestIdRaw() { + auto const state = GetQuestDialogStateCode(); + if (state < static_cast(QuestDialogKind::DETAIL) || + state > static_cast(QuestDialogKind::COMPLETE)) { + return 0; + } + + auto const questId = *reinterpret_cast(Offsets::QuestDialogCurrentQuestId); + return questId > 0 ? questId : 0; + } + + uint32_t Script_GetQuestLogQuestIds(uintptr_t *luaState) { + luaState = GetLuaStatePtr(); + + lua_newtable(luaState); + + auto const rowCount = *GetQuestLogEntryCountPtr(); + if (rowCount == 0 || rowCount > kQuestLogMaxRows) { + return 1; + } + + auto const *entries = GetQuestLogEntriesPtr(); + + int32_t outIndex = 1; + for (uint32_t i = 0; i < rowCount; ++i) { + auto const &entry = entries[i]; + if (entry.headerToken != 0 || entry.questId <= 0) { + continue; + } + + lua_pushnumber(luaState, static_cast(outIndex)); + lua_pushnumber(luaState, static_cast(entry.questId)); + lua_settable(luaState, -3); + ++outIndex; + } + + return 1; + } + + uint32_t Script_GetQuestDialogQuestId(uintptr_t *luaState) { + luaState = GetLuaStatePtr(); + + auto const questId = GetQuestDialogQuestIdRaw(); + if (questId == 0) { + lua_pushnil(luaState); + } else { + lua_pushnumber(luaState, static_cast(questId)); + } + + return 1; + } +} diff --git a/nampower/quest.hpp b/nampower/quest.hpp new file mode 100644 index 0000000..4adbec8 --- /dev/null +++ b/nampower/quest.hpp @@ -0,0 +1,12 @@ +// +// Quest ID helper APIs for quest log and quest dialog state. +// + +#pragma once + +#include "main.hpp" + +namespace Nampower { + uint32_t Script_GetQuestLogQuestIds(uintptr_t *luaState); + uint32_t Script_GetQuestDialogQuestId(uintptr_t *luaState); +}