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)
This commit is contained in:
Samuel 2012-11-27 14:48:48 +01:00
parent bce8e90ede
commit eb979ef7cd
11 changed files with 217 additions and 11 deletions

View File

@ -30,5 +30,6 @@ Module
- game_market - game_market
- game_spelllist - game_spelllist
- game_cooldown - game_cooldown
- game_modaldialog
@onLoad: init() @onLoad: init()
@onUnload: terminate() @onUnload: terminate()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -50,7 +50,7 @@ function g_game.getSupportedProtocols()
return { return {
810, 853, 854, 860, 861, 862, 870, 810, 853, 854, 860, 861, 862, 870,
910, 940, 944, 953, 954, 960, 961, 910, 940, 944, 953, 954, 960, 961,
963 963, 970
} }
end end

View File

@ -408,6 +408,11 @@ void Game::processQuestLine(int questId, const std::vector<std::tuple<std::strin
g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions); g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
} }
void Game::processModalDialog(uint32 id, std::string title, std::string message, int enterId, std::string enterText, int escapeId, std::string escapeText, std::vector<std::tuple<int, std::string> > choiceList)
{
g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, enterId, enterText, escapeId, escapeText, choiceList);
}
void Game::processAttackCancel(uint seq) void Game::processAttackCancel(uint seq)
{ {
if(isAttacking() && (seq == 0 || m_seq == 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); 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() void Game::ping()
{ {
if(!m_protocolGame || !m_protocolGame->isConnected()) if(!m_protocolGame || !m_protocolGame->isConnected())
@ -1168,7 +1181,7 @@ void Game::setClientVersion(int version)
if(isOnline()) if(isOnline())
stdext::throw_exception("Unable to change client version while online"); 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)); stdext::throw_exception(stdext::format("Protocol version %d not supported", version));
m_features.reset(); m_features.reset();

View File

@ -122,6 +122,9 @@ protected:
void processQuestLog(const std::vector<std::tuple<int, std::string, bool> >& questList); void processQuestLog(const std::vector<std::tuple<int, std::string, bool> >& questList);
void processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string> >& questMissions); void processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string> >& 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<std::tuple<int, std::string> > choiceList);
friend class ProtocolGame; friend class ProtocolGame;
friend class Map; friend class Map;
@ -232,6 +235,10 @@ public:
// 910 only // 910 only
void requestItemInfo(const ItemPtr& item, int index); void requestItemInfo(const ItemPtr& item, int index);
// >= 970 modal dialog
void answerModalDialog(int dialog, int button, int choice);
//void reportRuleViolation2(); //void reportRuleViolation2();
void ping(); void ping();

View File

@ -228,6 +228,7 @@ void OTClient::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "getFeature", &Game::getFeature, &g_game); 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", "setFeature", &Game::setFeature, &g_game);
g_lua.bindSingletonFunction("g_game", "enableFeature", &Game::enableFeature, &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.registerSingletonClass("g_shaders");
g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders); g_lua.bindSingletonFunction("g_shaders", "createShader", &ShaderManager::createShader, &g_shaders);

View File

@ -105,6 +105,7 @@ public:
void sendRequestQuestLine(int questId); void sendRequestQuestLine(int questId);
void sendNewNewRuleViolation(int reason, int action, const std::string& characterName, const std::string& comment, const std::string& translation); 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 sendRequestItemInfo(int itemId, int subType, int index);
void sendAnswerModalDialog(int dialog, int button, int choice);
protected: protected:
void onConnect(); void onConnect();

View File

@ -308,6 +308,10 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
case Proto::GameServerExtendedOpcode: case Proto::GameServerExtendedOpcode:
parseExtendedOpcode(msg); parseExtendedOpcode(msg);
break; break;
// PROTOCOL>=970
case Proto::GameServerShowModalDialog:
parseShowModalDialog(msg);
break;
default: default:
stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode)); stdext::throw_exception(stdext::format("unhandled opcode %d", (int)opcode));
break; break;
@ -1358,16 +1362,45 @@ void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg)
void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg) void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg)
{ {
msg->getU32(); // id uint32 id = msg->getU32();
msg->getString(); // title std::string title = msg->getString();
msg->getString(); // message std::string message = msg->getString();
int size = msg->getU8();
for(int i=0;i<size;++i) { int sizeButtons = msg->getU8();
msg->getString(); // button name std::map<int, std::string > buttonList;
msg->getU8(); // button value for(int i = 0; i < sizeButtons; ++i) {
std::string name = msg->getString();
int value = msg->getU8();
buttonList[value] = name;
} }
msg->getU8(); // default escape button
msg->getU8(); // default enter button int sizeChoices = msg->getU8();
std::vector<std::tuple<int, std::string> > 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));
}
int enterButton = msg->getU8();
int escapeButton = msg->getU8();
msg->getU8(); // popup value (no clue what it is for)
std::map<int, std::string >::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<int, std::string >::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) void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)

View File

@ -751,6 +751,16 @@ void ProtocolGame::sendRequestItemInfo(int itemId, int subType, int index)
send(msg); 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) void ProtocolGame::addPosition(const OutputMessagePtr& msg, const Position& position)
{ {
msg->addU16(position.x); msg->addU16(position.x);