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:
parent
bce8e90ede
commit
eb979ef7cd
|
@ -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()
|
||||||
|
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue