From d9c12c733db99b59e9f6482971a97196adbe6cc1 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 23 Mar 2026 03:53:54 -0700 Subject: [PATCH] feat: add gossip/NPC dialog API for quest and vendor addons GetNumGossipOptions() returns option count for current NPC dialog. GetGossipOptions() returns pairs of (text, type) for each option where type is "gossip", "vendor", "taxi", "trainer", etc. SelectGossipOption(index) selects a dialog option. GetNumGossipAvailableQuests() / GetNumGossipActiveQuests() return quest counts in the gossip dialog. CloseGossip() closes the NPC dialog. Uses existing GossipMessageData from SMSG_GOSSIP_MESSAGE handler. Enables gossip addons and quest helper dialog interaction. --- src/addons/lua_engine.cpp | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/addons/lua_engine.cpp b/src/addons/lua_engine.cpp index f27a8518..b46face7 100644 --- a/src/addons/lua_engine.cpp +++ b/src/addons/lua_engine.cpp @@ -5182,6 +5182,58 @@ void LuaEngine::registerCoreAPI() { if (gh) gh->requestPvpLog(); return 0; }}, + // --- Gossip --- + {"GetNumGossipOptions", [](lua_State* L) -> int { + auto* gh = getGameHandler(L); + lua_pushnumber(L, gh ? gh->getCurrentGossip().options.size() : 0); + return 1; + }}, + {"GetGossipOptions", [](lua_State* L) -> int { + // Returns pairs of (text, type) for each option + auto* gh = getGameHandler(L); + if (!gh) return 0; + const auto& opts = gh->getCurrentGossip().options; + int n = 0; + static const char* kIcons[] = {"gossip","vendor","taxi","trainer","spiritguide","innkeeper","banker","petition","tabard","battlemaster","auctioneer"}; + for (const auto& o : opts) { + lua_pushstring(L, o.text.c_str()); + lua_pushstring(L, o.icon < 11 ? kIcons[o.icon] : "gossip"); + n += 2; + } + return n; + }}, + {"SelectGossipOption", [](lua_State* L) -> int { + auto* gh = getGameHandler(L); + int index = static_cast(luaL_checknumber(L, 1)); + if (!gh || index < 1) return 0; + const auto& opts = gh->getCurrentGossip().options; + if (index <= static_cast(opts.size())) + gh->selectGossipOption(opts[index - 1].id); + return 0; + }}, + {"GetNumGossipAvailableQuests", [](lua_State* L) -> int { + auto* gh = getGameHandler(L); + if (!gh) { lua_pushnumber(L, 0); return 1; } + int count = 0; + for (const auto& q : gh->getCurrentGossip().quests) + if (q.questIcon != 4) ++count; // 4 = active/in-progress + lua_pushnumber(L, count); + return 1; + }}, + {"GetNumGossipActiveQuests", [](lua_State* L) -> int { + auto* gh = getGameHandler(L); + if (!gh) { lua_pushnumber(L, 0); return 1; } + int count = 0; + for (const auto& q : gh->getCurrentGossip().quests) + if (q.questIcon == 4) ++count; + lua_pushnumber(L, count); + return 1; + }}, + {"CloseGossip", [](lua_State* L) -> int { + auto* gh = getGameHandler(L); + if (gh) gh->closeGossip(); + return 0; + }}, // --- Connection & Equipment --- {"IsConnectedToServer", [](lua_State* L) -> int { auto* gh = getGameHandler(L);