diff --git a/src/gameui/CGGameUI.cpp b/src/gameui/CGGameUI.cpp index 9728515..b539816 100644 --- a/src/gameui/CGGameUI.cpp +++ b/src/gameui/CGGameUI.cpp @@ -206,3 +206,8 @@ void CGGameUI::Reload() { int32_t CGGameUI::HandleDisplaySizeChanged(const CSizeEvent& event) { return 0; } + +bool CGGameUI::CanPerformAction(int32_t action) { + // TODO + return true; +} diff --git a/src/gameui/CGGameUI.hpp b/src/gameui/CGGameUI.hpp index f10ac86..afec605 100644 --- a/src/gameui/CGGameUI.hpp +++ b/src/gameui/CGGameUI.hpp @@ -13,6 +13,7 @@ class CGGameUI { static void RegisterFrameFactories(); static void Reload(); static int32_t HandleDisplaySizeChanged(const CSizeEvent& event); + static bool CanPerformAction(int32_t action); public: static CSimpleTop* m_simpleTop; diff --git a/src/gameui/CGUIBindings.cpp b/src/gameui/CGUIBindings.cpp index 41bda41..a5e6404 100644 --- a/src/gameui/CGUIBindings.cpp +++ b/src/gameui/CGUIBindings.cpp @@ -1,4 +1,5 @@ #include "gameui/CGUIBindings.hpp" +#include "gameui/CGGameUI.hpp" #include "ui/FrameScript.hpp" #include "util/CStatus.hpp" #include "util/SFile.hpp" @@ -6,9 +7,14 @@ #include + static CStatus s_nullStatus; +void MODIFIEDCLICK::SetBinding(BINDING_SET a1, const char* binding) { +} + + bool CGUIBindings::Load(const char* commandsFile, MD5_CTX* md5, CStatus* status) { if (!status) { status = &s_nullStatus; @@ -126,13 +132,97 @@ void CGUIBindings::LoadBinding(const char* commandsFile, XMLNode* node, CStatus* const char* angle = node->GetAttributeByName("angle"); command->angle = StringToBOOL(angle); - const char* defaultValue = node->GetAttributeByName("default"); - if (defaultValue && *defaultValue) { - if (!this->m_commands.Ptr(defaultValue)) { - // TODO: CGUIBindings::Bind(0, 0, defaultValue, name); + 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); } } } void CGUIBindings::LoadModifiedClick(const char* commandsFile, XMLNode* node, CStatus* status) { + const char* action = node->GetAttributeByName("action"); + if (!action || !*action) { + status->Add(STATUS_WARNING, "Found modified click with no action in %s", commandsFile); + return; + } + + if (this->m_modifiedClicks.Ptr(action)) { + status->Add(STATUS_WARNING, "Modified click %s is defined more than once in %s", action, commandsFile); + return; + } + + auto modifiedClick = this->m_modifiedClicks.New(action, 0, 0); + this->m_numModifiedClicks++; + + const char* binding = node->GetAttributeByName("default"); + if (binding && *binding) { + modifiedClick->SetBinding(BINDING_SET_0, binding); + } +} + +bool CGUIBindings::Bind(BINDING_SET set, BINDING_MODE mode, const char* keystring, const char* command) { + if (!CGGameUI::CanPerformAction(13) || !keystring) { + return false; + } + + if (!command || !*command) { + command = "NONE"; + } + + static char s_character[2] = {}; + + const char* key = keystring; + + if (!SStrCmpI(keystring, "LEFTBRACKET", STORM_MAX_STR)) { + s_character[0] = '['; + key = s_character; + } else if (!SStrCmpI(keystring, "RIGHTBRACKET", STORM_MAX_STR)) { + s_character[0] = ']'; + key = s_character; + } else if (!SStrCmpI(keystring, "SLASH", STORM_MAX_STR)) { + s_character[0] = '/'; + key = s_character; + } else if (!SStrCmpI(keystring, "BACKSLASH", STORM_MAX_STR)) { + s_character[0] = '\\'; + key = s_character; + } else if (!SStrCmpI(keystring, "SEMICOLON", STORM_MAX_STR)) { + s_character[0] = ';'; + key = s_character; + } else if (!SStrCmpI(keystring, "APOSTROPHE", STORM_MAX_STR)) { + s_character[0] = '\''; + key = s_character; + } else if (!SStrCmpI(keystring, "COMMA", STORM_MAX_STR)) { + s_character[0] = ','; + key = s_character; + } else if (!SStrCmpI(keystring, "PERIOD", STORM_MAX_STR)) { + s_character[0] = '.'; + key = s_character; + } else if (!SStrCmpI(keystring, "TILDE", STORM_MAX_STR)) { + s_character[0] = '`'; + key = s_character; + } else if (!SStrCmpI(keystring, "PLUS", STORM_MAX_STR)) { + s_character[0] = '='; + key = s_character; + } else if (!SStrCmpI(keystring, "MINUS", STORM_MAX_STR)) { + s_character[0] = '-'; + key = s_character; + } + + // TODO: if (!sub_55DAB0) + + auto binding = this->m_bindings.Ptr(key); + if (!binding) { + binding = this->m_bindings.New(key, 0, 0); + } + + if (set != BINDING_SET_0) { + binding->flags &= ~1u; + } else { + binding->flags |= 1u; + } + + // TODO + + return true; } diff --git a/src/gameui/CGUIBindings.hpp b/src/gameui/CGUIBindings.hpp index 28f5272..839cfc2 100644 --- a/src/gameui/CGUIBindings.hpp +++ b/src/gameui/CGUIBindings.hpp @@ -7,9 +7,23 @@ class CStatus; class XMLNode; +enum BINDING_SET { + BINDING_SET_0 = 0, + BINDING_SET_1, + BINDING_SET_2, + BINDING_SET_3, +}; + +enum BINDING_MODE { + BINDING_MODE_0 = 0, + BINDING_MODE_1, + BINDING_MODE_2, + BINDING_MODE_3 +}; + class KEYBINDING : public TSHashObject { public: - int32_t index; + uint32_t flags; char* command; }; @@ -22,6 +36,13 @@ class KEYCOMMAND : public TSHashObject { int32_t angle; }; +class MODIFIEDCLICK : public TSHashObject { + public: + void SetBinding(BINDING_SET a1, const char* binding); + + int32_t index; +}; + class CGUIBindings { public: CGUIBindings() = default; @@ -29,11 +50,14 @@ class CGUIBindings { bool Load(const char* commandsFile, MD5_CTX* md5, CStatus* status); void LoadBinding(const char* commandsFile, XMLNode* node, CStatus* status); void LoadModifiedClick(const char* commandsFile, XMLNode* node, CStatus* status); + bool Bind(BINDING_SET set, BINDING_MODE mode, const char* keystring, const char* command); int32_t m_numCommands; int32_t m_numHiddenCommands; + int32_t m_numModifiedClicks; TSHashTable m_bindings; TSHashTable m_commands; + TSHashTable m_modifiedClicks; }; #endif // GAME_UI_CGUIBINDINGS_HPP