Merge pull request 'add quest log ID and quest dialog ID' (#64) from YourNameVanilla/nampower:master into master

Reviewed-on: https://gitea.com/avitasia/nampower/pulls/64
This commit is contained in:
avitasia
2026-04-13 15:41:14 +00:00
7 changed files with 148 additions and 0 deletions
+1
View File
@@ -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).
+32
View File
@@ -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())
```
+2
View File
@@ -59,6 +59,8 @@ set(SOURCE_FILES
unit.cpp
tooltip.hpp
tooltip.cpp
quest.hpp
quest.cpp
)
add_library(${DLL_NAME} SHARED ${SOURCE_FILES})
+7
View File
@@ -51,6 +51,7 @@
#include "unit.hpp"
#include "pet.hpp"
#include "tooltip.hpp"
#include "quest.hpp"
#include <cstdint>
#include <memory>
@@ -2132,6 +2133,12 @@ namespace Nampower {
char executeCustomLuaFile[] = "ExecuteCustomLuaFile";
RegisterLuaFunction(executeCustomLuaFile, reinterpret_cast<uintptr_t *>(Script_ExecuteCustomLuaFile));
char getQuestLogQuestIds[] = "GetQuestLogQuestIds";
RegisterLuaFunction(getQuestLogQuestIds, reinterpret_cast<uintptr_t *>(Script_GetQuestLogQuestIds));
char getQuestDialogQuestId[] = "GetQuestDialogQuestId";
RegisterLuaFunction(getQuestDialogQuestId, reinterpret_cast<uintptr_t *>(Script_GetQuestDialogQuestId));
}
void Glue_LoadScriptFunctionsHook(hadesmem::PatchDetourBase *detour) {
+5
View File
@@ -301,4 +301,9 @@ enum class Offsets : std::uint32_t {
PetActionBarSlots = 0x00b71438,
PetReactionMode = 0x00b71468,
ActivePetGuid = 0x00b714a0,
QuestLogEntries = 0x00BB71C0,
QuestLogEntryCount = 0x00BB7478,
QuestDialogState = 0x00BE0818,
QuestDialogCurrentQuestId = 0x00BE081C,
};
+89
View File
@@ -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<uint32_t *>(Offsets::QuestLogEntryCount);
}
static QuestLogEntryRaw *GetQuestLogEntriesPtr() {
return reinterpret_cast<QuestLogEntryRaw *>(Offsets::QuestLogEntries);
}
static int32_t GetQuestDialogStateCode() {
return *reinterpret_cast<int32_t *>(Offsets::QuestDialogState);
}
static uint32_t GetQuestDialogQuestIdRaw() {
auto const state = GetQuestDialogStateCode();
if (state < static_cast<int32_t>(QuestDialogKind::DETAIL) ||
state > static_cast<int32_t>(QuestDialogKind::COMPLETE)) {
return 0;
}
auto const questId = *reinterpret_cast<uint32_t *>(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<double>(outIndex));
lua_pushnumber(luaState, static_cast<double>(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<double>(questId));
}
return 1;
}
}
+12
View File
@@ -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);
}