feat(gameui): implement Set UI Binding scripts

This commit is contained in:
VDm 2025-08-09 16:37:01 +04:00
parent 7ca4c00a71
commit d59589550d
4 changed files with 162 additions and 23 deletions

View File

@ -13,6 +13,7 @@
#include "gameui/CGDressUpModelFrame.hpp"
#include "gameui/CGTabardModelFrame.hpp"
#include "gameui/CGQuestPOIFrame.hpp"
#include "gameui/CGUIBindings.hpp"
#include "gx/Coordinate.hpp"
#include "gx/Device.hpp"
#include "ui/FrameScript.hpp"
@ -84,8 +85,8 @@ void CGGameUI::Initialize() {
LoadScriptFunctions();
FrameScript_CreateEvents(g_scriptEvents, 722);
//CGGameUI::RegisterGameCVars();
//CGUIBindings::Initialize();
CGUIBindings::Initialize();
CGGameUI::RegisterFrameFactories();
// STORM_ASSERT(GetDataInterfaceVersion() == GetCodeInterfaceVersion())
@ -139,8 +140,9 @@ void CGGameUI::Initialize() {
FrameXML_FreeHashNodes();
FrameXML_CreateFrames("Interface\\FrameXML\\FrameXML.toc", 0, &md5, &status);
//if (SFile__FileExistsEx((void*)"Interface\\FrameXML\\Bindings.xml", 1))
// CGUIBindings::Load("Interface\\FrameXML\\Bindings.xml", &md5, &status);
if (SFile::FileExistsEx("Interface\\FrameXML\\Bindings.xml", 1)) {
CGUIBindings::s_bindings->Load("Interface\\FrameXML\\Bindings.xml", &md5, &status);
}
unsigned char digest2[16];
MD5Final(digest2, &md5);

View File

@ -7,10 +7,15 @@
#include <common/XML.hpp>
#include <common/Unicode.hpp>
#include <bc/Memory.hpp>
#include <utility>
static CStatus s_nullStatus;
static uint16_t s_initRound = 0;
CGUIBindings* CGUIBindings::s_bindings = nullptr;
static bool ValidateKeyString(const char* key) {
static std::pair<const char*, size_t> s_prefixes[3] = {
@ -113,6 +118,13 @@ void MODIFIEDCLICK::SetBinding(BINDING_SET a1, const char* binding) {
}
void CGUIBindings::Initialize() {
CGUIBindings::s_bindings = NEW(CGUIBindings);
while (!s_initRound) {
++s_initRound;
}
}
bool CGUIBindings::Load(const char* commandsFile, MD5_CTX* md5, CStatus* status) {
if (!status) {
status = &s_nullStatus;
@ -232,8 +244,8 @@ void CGUIBindings::LoadBinding(const char* commandsFile, XMLNode* node, CStatus*
const char* binding = node->GetAttributeByName("default");
if (binding && *binding) {
if (!this->m_bindings.Ptr(binding)) {
this->Bind(BINDING_SET_0, BINDING_MODE_0, binding, name);
if (!this->m_bindings[BINDING_DEFAULT].Ptr(binding)) {
this->Bind(BINDING_DEFAULT, BINDING_MODE_0, binding, name);
}
}
}
@ -255,7 +267,7 @@ void CGUIBindings::LoadModifiedClick(const char* commandsFile, XMLNode* node, CS
const char* binding = node->GetAttributeByName("default");
if (binding && *binding) {
modifiedClick->SetBinding(BINDING_SET_0, binding);
modifiedClick->SetBinding(BINDING_DEFAULT, binding);
}
}
@ -311,12 +323,12 @@ bool CGUIBindings::Bind(BINDING_SET set, BINDING_MODE mode, const char* keystrin
return false;
}
auto binding = this->m_bindings.Ptr(key);
auto binding = this->m_bindings[set].Ptr(key);
if (!binding) {
binding = this->m_bindings.New(key, 0, 0);
binding = this->m_bindings[set].New(key, 0, 0);
}
if (set != BINDING_SET_0) {
if (set != BINDING_DEFAULT) {
binding->flags &= ~1u;
} else {
binding->flags |= 1u;
@ -366,8 +378,7 @@ int32_t CGUIBindings::GetBindingIndex(KEYBINDING* binding, BINDING_MODE mode) co
}
int32_t CGUIBindings::GetNumCommandKeys(BINDING_SET set, BINDING_MODE mode, const char* command) {
// TODO: Check set argument
auto binding = this->m_bindings.Head();
auto binding = this->m_bindings[set].Head();
int32_t result = 0;
@ -377,15 +388,14 @@ int32_t CGUIBindings::GetNumCommandKeys(BINDING_SET set, BINDING_MODE mode, cons
++result;
}
binding = this->m_bindings.Next(binding);
binding = this->m_bindings[set].Next(binding);
}
return result;
}
void CGUIBindings::AdjustCommandKeyIndices(BINDING_SET set, BINDING_MODE mode, const char* command, int32_t index) {
// TODO: Check set argument
auto binding = this->m_bindings.Head();
auto binding = this->m_bindings[set].Head();
int32_t result = 0;
@ -398,6 +408,6 @@ void CGUIBindings::AdjustCommandKeyIndices(BINDING_SET set, BINDING_MODE mode, c
}
}
binding = this->m_bindings.Next(binding);
binding = this->m_bindings[set].Next(binding);
}
}

View File

@ -9,10 +9,10 @@ class CStatus;
class XMLNode;
enum BINDING_SET {
BINDING_SET_0 = 0,
BINDING_DEFAULT = 0,
BINDING_SET_1,
BINDING_SET_2,
BINDING_SET_3,
BINDING_SCRIPT,
};
enum BINDING_MODE {
@ -50,6 +50,11 @@ class MODIFIEDCLICK : public TSHashObject<MODIFIEDCLICK, HASHKEY_STRI> {
class CGUIBindings {
public:
static CGUIBindings* s_bindings;
static void Initialize();
CGUIBindings() = default;
bool Load(const char* commandsFile, MD5_CTX* md5, CStatus* status);
@ -64,7 +69,7 @@ class CGUIBindings {
int32_t m_numCommands;
int32_t m_numHiddenCommands;
int32_t m_numModifiedClicks;
TSHashTable<KEYBINDING, HASHKEY_STRI> m_bindings;
TSHashTable<KEYBINDING, HASHKEY_STRI> m_bindings[4];
TSHashTable<KEYCOMMAND, HASHKEY_STRI> m_commands;
TSHashTable<MODIFIEDCLICK, HASHKEY_STRI> m_modifiedClicks;
};

View File

@ -1,4 +1,5 @@
#include "gameui/GameScriptFunctions.hpp"
#include "gameui/CGUIBindings.hpp"
#include "ui/FrameScript.hpp"
#include "util/Lua.hpp"
#include "util/Unimplemented.hpp"
@ -13,23 +14,144 @@ static int32_t Script_GetBinding(lua_State* L) {
}
static int32_t Script_SetBinding(lua_State* L) {
WHOA_UNIMPLEMENTED(0);
if (!lua_isstring(L, 1)) {
return luaL_error(L, "Usage: SetBinding(\"KEY\"[, \"COMMAND\"][, mode])");
}
int32_t mode = BINDING_MODE_0;
if (lua_isnumber(L, 3)) {
mode = static_cast<int32_t>(lua_tonumber(L, 3)) - 1;
if (mode < BINDING_MODE_0 || mode > BINDING_MODE_3) {
mode = BINDING_MODE_0;
}
}
auto key = lua_tolstring(L, 1, 0);
auto command = lua_tolstring(L, 2, 0);
if (CGUIBindings::s_bindings->Bind(BINDING_SCRIPT, static_cast<BINDING_MODE>(mode), key, command)) {
FrameScript_SignalEvent(0x177u, 0);
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
}
static int32_t Script_SetBindingSpell(lua_State* L) {
WHOA_UNIMPLEMENTED(0);
if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) {
return luaL_error(L, "Usage: SetBindingSpell(\"KEY\", \"spellname\"[, mode])");
}
int32_t mode = BINDING_MODE_0;
if (lua_isnumber(L, 3)) {
mode = static_cast<int32_t>(lua_tonumber(L, 3)) - 1;
if (mode < BINDING_MODE_0 || mode > BINDING_MODE_3) {
mode = BINDING_MODE_0;
}
}
auto key = lua_tolstring(L, 1, 0);
auto spellName = lua_tolstring(L, 2, 0);
auto length = SStrLen(spellName) + 7;
auto command = static_cast<char*>(alloca(length));
SStrPrintf(command, length, "SPELL %s", spellName);
if (CGUIBindings::s_bindings->Bind(BINDING_SCRIPT, static_cast<BINDING_MODE>(mode), key, command)) {
FrameScript_SignalEvent(0x177u, 0);
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
}
static int32_t Script_SetBindingItem(lua_State* L) {
WHOA_UNIMPLEMENTED(0);
if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) {
return luaL_error(L, "Usage: SetBindingItem(\"KEY\", \"itemname\"[, mode])");
}
int32_t mode = BINDING_MODE_0;
if (lua_isnumber(L, 3)) {
mode = static_cast<int32_t>(lua_tonumber(L, 3)) - 1;
if (mode < BINDING_MODE_0 || mode > BINDING_MODE_3) {
mode = BINDING_MODE_0;
}
}
auto key = lua_tolstring(L, 1, 0);
auto itemName = lua_tolstring(L, 2, 0);
auto length = SStrLen(itemName) + 7;
auto command = static_cast<char*>(alloca(length));
SStrPrintf(command, length, "ITEM %s", itemName);
if (CGUIBindings::s_bindings->Bind(BINDING_SCRIPT, static_cast<BINDING_MODE>(mode), key, command)) {
FrameScript_SignalEvent(0x177u, 0);
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
}
static int32_t Script_SetBindingMacro(lua_State* L) {
WHOA_UNIMPLEMENTED(0);
if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) {
return luaL_error(L, "Usage: SetBindingMacro(\"KEY\", \"macroname\"|macroid[, mode])");
}
int32_t mode = BINDING_MODE_0;
if (lua_isnumber(L, 3)) {
mode = static_cast<int32_t>(lua_tonumber(L, 3)) - 1;
if (mode < BINDING_MODE_0 || mode > BINDING_MODE_3) {
mode = BINDING_MODE_0;
}
}
auto key = lua_tolstring(L, 1, 0);
auto macroName = lua_tolstring(L, 2, 0);
auto length = SStrLen(macroName) + 7;
auto command = static_cast<char*>(alloca(length));
SStrPrintf(command, length, "MACRO %s", macroName);
if (CGUIBindings::s_bindings->Bind(BINDING_SCRIPT, static_cast<BINDING_MODE>(mode), key, command)) {
FrameScript_SignalEvent(0x177u, 0);
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
}
static int32_t Script_SetBindingClick(lua_State* L) {
WHOA_UNIMPLEMENTED(0);
if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) {
return luaL_error(L, "Usage: SetBindingClick(\"KEY\", \"buttonName\"[, \"mouseButton\"][, mode])");
}
int32_t mode = BINDING_MODE_0;
if (lua_isnumber(L, 4)) {
mode = static_cast<int32_t>(lua_tonumber(L, 4)) - 1;
if (mode < BINDING_MODE_0 || mode > BINDING_MODE_3) {
mode = BINDING_MODE_0;
}
}
auto key = lua_tolstring(L, 1, 0);
auto buttonName = lua_tolstring(L, 2, 0);
auto mouseButton = lua_tolstring(L, 3, 0);
if (!mouseButton) {
mouseButton = "LeftButton";
}
auto length = SStrLen(buttonName) + SStrLen(mouseButton) + 8;
auto command = static_cast<char*>(alloca(length));
SStrPrintf(command, length, "CLICK %s:%s", buttonName, mouseButton);
if (CGUIBindings::s_bindings->Bind(BINDING_SCRIPT, static_cast<BINDING_MODE>(mode), key, command)) {
FrameScript_SignalEvent(0x177u, 0);
lua_pushnumber(L, 1.0);
} else {
lua_pushnil(L);
}
return 1;
}
static int32_t Script_SetOverrideBinding(lua_State* L) {