From eb979ef7cd333193986a0a1c7864acf1291fe084 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 27 Nov 2012 14:48:48 +0100 Subject: [PATCH] Modal Dialogs / Support for 9.70 OTC now supports showing and answering modal dialogs. addDialog(modaldialog, dialogId, cid, callback) TODO: -find out what the "popup" value does.. (Maybe someone knows) --- modules/game_interface/interface.otmod | 1 + modules/game_modaldialog/modaldialog.lua | 69 ++++++++++++++++++++++ modules/game_modaldialog/modaldialog.otmod | 10 ++++ modules/game_modaldialog/modaldialog.otui | 61 +++++++++++++++++++ modules/gamelib/game.lua | 2 +- src/otclient/game.cpp | 15 ++++- src/otclient/game.h | 7 +++ src/otclient/luafunctions.cpp | 1 + src/otclient/protocolgame.h | 1 + src/otclient/protocolgameparse.cpp | 51 +++++++++++++--- src/otclient/protocolgamesend.cpp | 10 ++++ 11 files changed, 217 insertions(+), 11 deletions(-) create mode 100644 modules/game_modaldialog/modaldialog.lua create mode 100644 modules/game_modaldialog/modaldialog.otmod create mode 100644 modules/game_modaldialog/modaldialog.otui diff --git a/modules/game_interface/interface.otmod b/modules/game_interface/interface.otmod index 7f9c772d..c3993fa6 100644 --- a/modules/game_interface/interface.otmod +++ b/modules/game_interface/interface.otmod @@ -30,5 +30,6 @@ Module - game_market - game_spelllist - game_cooldown + - game_modaldialog @onLoad: init() @onUnload: terminate() diff --git a/modules/game_modaldialog/modaldialog.lua b/modules/game_modaldialog/modaldialog.lua new file mode 100644 index 00000000..9c18eb77 --- /dev/null +++ b/modules/game_modaldialog/modaldialog.lua @@ -0,0 +1,69 @@ +function init() + g_ui.importStyle('modaldialog.otui') + + connect(g_game, { onModalDialog = onModalDialog, + onGameEnd = destroy }) +end + +function terminate() + disconnect(g_game, { onModalDialog = onModalDialog, + onGameEnd = destroy }) + + destroy() +end + +function destroy() + if modalDialog then + modalDialog:destroy() + modalDialog = nil + end +end + +function onModalDialog(id, title, message, enterId, enterText, escapeId, escapeText, choices) + if modalDialog then return end + + modalDialog = g_ui.createWidget('ModalDialog', rootWidget) + + local enterButton = modalDialog:getChildById('enterButton') + local escapeButton = modalDialog:getChildById('escapeButton') + local messageLabel = modalDialog:getChildById('messageLabel') + local choiceList = modalDialog:getChildById('choiceList') + + modalDialog:setText(title) + messageLabel:setText(message) + enterButton:setText(enterText) + escapeButton:setText(escapeText) + + local focusLabel = nil + for k, v in pairs(choices) do + local choiceId = v[1] + local choiceName = v[2] + + local label = g_ui.createWidget('ChoiceListLabel', choiceList) + label.choiceId = choiceId + label:setText(choiceName) + label:setPhantom(false) + + if not focusLabel then + focusLabel = label + end + end + choiceList:focusChild(focusLabel) + + local enterFunc = function() + g_game.answerModalDialog(id, enterId, choiceList:getFocusedChild().choiceId) + destroy() + end + + local escapeFunc = function() + g_game.answerModalDialog(id, escapeId, choiceList:getFocusedChild().choiceId) + destroy() + end + + enterButton.onClick = enterFunc + modalDialog.onEnter = enterFunc + + escapeButton.onClick = escapeFunc + modalDialog.onEscape = escapeFunc + return +end \ No newline at end of file diff --git a/modules/game_modaldialog/modaldialog.otmod b/modules/game_modaldialog/modaldialog.otmod new file mode 100644 index 00000000..948e2924 --- /dev/null +++ b/modules/game_modaldialog/modaldialog.otmod @@ -0,0 +1,10 @@ +Module + name: game_modaldialog + description: Show and process modal dialogs + author: Summ + website: www.otclient.info + sandboxed: true + dependencies: [ game_interface ] + scripts: [ modaldialog.lua ] + @onLoad: init() + @onUnload: terminate() diff --git a/modules/game_modaldialog/modaldialog.otui b/modules/game_modaldialog/modaldialog.otui new file mode 100644 index 00000000..9090f8e9 --- /dev/null +++ b/modules/game_modaldialog/modaldialog.otui @@ -0,0 +1,61 @@ +TextScrollbar < VerticalScrollBar + +ChoiceListLabel < Label + font: verdana-11px-monochrome + background-color: alpha + text-offset: 2 0 + focusable: true + + $focus: + background-color: #ffffff22 + color: #ffffff + +ModalDialog < MainWindow + id: modalDialog + !text: tr('Title') + size: 280 230 + @onEscape: self:destroy() + + Label + id: messageLabel + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + text-align: left + text: Message + height: 60 + + TextList + id: choiceList + vertical-scrollbar: choiceScrollBar + anchors.fill: parent + anchors.top: prev.bottom + anchors.bottom: next.top + margin-bottom: 10 + margin-top: 10 + padding: 1 + focusable: false + + Button + id: enterButton + !text: tr('Ok') + anchors.top: next.top + anchors.right: next.left + margin-right: 8 + width: 60 + + Button + id: escapeButton + !text: tr('Cancel') + anchors.bottom: parent.bottom + anchors.right: parent.right + margin-top: 10 + width: 60 + + VerticalScrollBar + id: choiceScrollBar + anchors.top: choiceList.top + anchors.bottom: choiceList.bottom + anchors.right: choiceList.right + step: 14 + pixels-scroll: true \ No newline at end of file diff --git a/modules/gamelib/game.lua b/modules/gamelib/game.lua index 809a935f..8d50bb0c 100644 --- a/modules/gamelib/game.lua +++ b/modules/gamelib/game.lua @@ -50,7 +50,7 @@ function g_game.getSupportedProtocols() return { 810, 853, 854, 860, 861, 862, 870, 910, 940, 944, 953, 954, 960, 961, - 963 + 963, 970 } end diff --git a/src/otclient/game.cpp b/src/otclient/game.cpp index 3a11321e..e4f2f411 100644 --- a/src/otclient/game.cpp +++ b/src/otclient/game.cpp @@ -408,6 +408,11 @@ void Game::processQuestLine(int questId, const std::vector > choiceList) +{ + g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, enterId, enterText, escapeId, escapeText, choiceList); +} + void Game::processAttackCancel(uint seq) { if(isAttacking() && (seq == 0 || m_seq == seq)) @@ -1125,6 +1130,14 @@ void Game::requestItemInfo(const ItemPtr& item, int index) m_protocolGame->sendRequestItemInfo(item->getId(), item->getSubType(), index); } +void Game::answerModalDialog(int dialog, int button, int choice) +{ + if(!canPerformGameAction()) + return; + + m_protocolGame->sendAnswerModalDialog(dialog, button, choice); +} + void Game::ping() { if(!m_protocolGame || !m_protocolGame->isConnected()) @@ -1168,7 +1181,7 @@ void Game::setClientVersion(int version) if(isOnline()) stdext::throw_exception("Unable to change client version while online"); - if(version != 0 && (version < 810 || version > 963)) + if(version != 0 && (version < 810 || version > 970)) stdext::throw_exception(stdext::format("Protocol version %d not supported", version)); m_features.reset(); diff --git a/src/otclient/game.h b/src/otclient/game.h index 6edc8184..71260ca3 100644 --- a/src/otclient/game.h +++ b/src/otclient/game.h @@ -122,6 +122,9 @@ protected: void processQuestLog(const std::vector >& questList); void processQuestLine(int questId, const std::vector >& questMissions); + // modal dialogs >= 970 + void processModalDialog(uint32 id, std::string title, std::string message, int enterId, std::string enterText, int escapeId, std::string escapeText, std::vector > choiceList); + friend class ProtocolGame; friend class Map; @@ -232,6 +235,10 @@ public: // 910 only void requestItemInfo(const ItemPtr& item, int index); + + // >= 970 modal dialog + void answerModalDialog(int dialog, int button, int choice); + //void reportRuleViolation2(); void ping(); diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index f0e56b00..1cb9d4e1 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -228,6 +228,7 @@ void OTClient::registerLuaFunctions() g_lua.bindSingletonFunction("g_game", "getFeature", &Game::getFeature, &g_game); g_lua.bindSingletonFunction("g_game", "setFeature", &Game::setFeature, &g_game); g_lua.bindSingletonFunction("g_game", "enableFeature", &Game::enableFeature, &g_game); + g_lua.bindSingletonFunction("g_game", "answerModalDialog", &Game::answerModalDialog, &g_game); g_lua.registerSingletonClass("g_shaders"); g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders); diff --git a/src/otclient/protocolgame.h b/src/otclient/protocolgame.h index 31996282..2496caa5 100644 --- a/src/otclient/protocolgame.h +++ b/src/otclient/protocolgame.h @@ -105,6 +105,7 @@ public: void sendRequestQuestLine(int questId); void sendNewNewRuleViolation(int reason, int action, const std::string& characterName, const std::string& comment, const std::string& translation); void sendRequestItemInfo(int itemId, int subType, int index); + void sendAnswerModalDialog(int dialog, int button, int choice); protected: void onConnect(); diff --git a/src/otclient/protocolgameparse.cpp b/src/otclient/protocolgameparse.cpp index b85977f4..833f4306 100644 --- a/src/otclient/protocolgameparse.cpp +++ b/src/otclient/protocolgameparse.cpp @@ -308,6 +308,10 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) case Proto::GameServerExtendedOpcode: parseExtendedOpcode(msg); break; + // PROTOCOL>=970 + case Proto::GameServerShowModalDialog: + parseShowModalDialog(msg); + break; default: stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode)); break; @@ -1358,16 +1362,45 @@ void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg) void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg) { - msg->getU32(); // id - msg->getString(); // title - msg->getString(); // message - int size = msg->getU8(); - for(int i=0;igetString(); // button name - msg->getU8(); // button value + uint32 id = msg->getU32(); + std::string title = msg->getString(); + std::string message = msg->getString(); + + int sizeButtons = msg->getU8(); + std::map buttonList; + for(int i = 0; i < sizeButtons; ++i) { + std::string name = msg->getString(); + int value = msg->getU8(); + buttonList[value] = name; + } + + int sizeChoices = msg->getU8(); + std::vector > choiceList; + for(int i = 0; i < sizeChoices; ++i) { + std::string name = msg->getString(); + int value = msg->getU8(); + choiceList.push_back(std::make_tuple(value, name)); } - msg->getU8(); // default escape button - msg->getU8(); // default enter button + + int enterButton = msg->getU8(); + int escapeButton = msg->getU8(); + msg->getU8(); // popup value (no clue what it is for) + + std::map::iterator itEnter = buttonList.find(enterButton); + if(itEnter == buttonList.end()) + { + g_logger.info(stdext::format("Enter button does not exist for dialog id: %d", id)); + return; + } + + std::map::iterator itEscape = buttonList.find(escapeButton); + if(itEscape == buttonList.end()) + { + g_logger.info(stdext::format("Escape button does not exist for dialog id: %d", id)); + return; + } + + g_game.processModalDialog(id, title, message, itEnter->first, itEnter->second, itEscape->first, itEscape->second, choiceList); } void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg) diff --git a/src/otclient/protocolgamesend.cpp b/src/otclient/protocolgamesend.cpp index 642ab2d1..5d82abb9 100644 --- a/src/otclient/protocolgamesend.cpp +++ b/src/otclient/protocolgamesend.cpp @@ -751,6 +751,16 @@ void ProtocolGame::sendRequestItemInfo(int itemId, int subType, int index) send(msg); } +void ProtocolGame::sendAnswerModalDialog(int dialog, int button, int choice) +{ + OutputMessagePtr msg(new OutputMessage); + msg->addU8(Proto::ClientAnswerModalDialog); + msg->addU32(dialog); + msg->addU8(button); + msg->addU8(choice); + send(msg); +} + void ProtocolGame::addPosition(const OutputMessagePtr& msg, const Position& position) { msg->addU16(position.x);