Refactor dialogue GUI to talk to the dialogue manager, not the other way around and not both ways.

- Fix memory leaks in DialogueWindow
- Fix Link objects being deleted from their own event handler
pull/303/head
scrawl 7 years ago
parent 476bec41c5
commit 2ce79e07a4

@ -2,6 +2,8 @@
#define GAME_MWBASE_DIALOGUEMANAGER_H
#include <string>
#include <vector>
#include <list>
#include <stdint.h>
@ -42,24 +44,29 @@ namespace MWBase
virtual bool isInChoice() const = 0;
virtual void startDialogue (const MWWorld::Ptr& actor) = 0;
typedef std::pair<std::string, std::string> Response; // title, text
virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response) = 0;
virtual void addTopic (const std::string& topic) = 0;
virtual void askQuestion (const std::string& question,int choice) = 0;
virtual void addChoice (const std::string& text,int choice) = 0;
virtual const std::vector<std::pair<std::string, int> >& getChoices() = 0;
virtual bool isGoodbye() = 0;
virtual void goodbye() = 0;
virtual void say(const MWWorld::Ptr &actor, const std::string &topic) = 0;
//calbacks for the GUI
virtual void keywordSelected (const std::string& keyword) = 0;
virtual Response keywordSelected (const std::string& keyword) = 0;
virtual void goodbyeSelected() = 0;
virtual void questionAnswered (int answer) = 0;
virtual Response questionAnswered (int answer) = 0;
virtual std::list<std::string> getAvailableTopics() = 0;
virtual bool checkServiceRefused () = 0;
virtual bool checkServiceRefused (Response& response) = 0;
virtual void persuade (int type) = 0;
virtual Response persuade (int type) = 0;
virtual int getTemporaryDispositionChange () const = 0;
/// @note This change is temporary and gets discarded when dialogue ends.

@ -140,7 +140,6 @@ namespace MWBase
virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0;
/// \todo investigate, if we really need to expose every single lousy UI element to the outside world
virtual MWGui::DialogueWindow* getDialogueWindow() = 0;
virtual MWGui::InventoryWindow* getInventoryWindow() = 0;
virtual MWGui::CountDialog* getCountDialog() = 0;
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;

@ -5,6 +5,7 @@
#include <algorithm>
#include <iterator>
#include <list>
#include <iostream>
#include <components/esm/loaddial.hpp>
#include <components/esm/loadinfo.hpp>
@ -33,8 +34,6 @@
#include "../mwworld/containerstore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwgui/dialogue.hpp"
#include "../mwscript/compilercontext.hpp"
#include "../mwscript/interpretercontext.hpp"
#include "../mwscript/extensions.hpp"
@ -59,6 +58,7 @@ namespace MWDialogue
{
mChoice = -1;
mIsInChoice = false;
mGoodbye = false;
mCompilerContext.setExtensions (&extensions);
}
@ -99,17 +99,15 @@ namespace MWDialogue
if (mActorKnownTopics.count( topicId ))
mKnownTopics.insert( topicId );
}
updateTopics();
}
void DialogueManager::startDialogue (const MWWorld::Ptr& actor)
bool DialogueManager::startDialogue (const MWWorld::Ptr& actor, Response& response)
{
updateGlobals();
// Dialogue with dead actor (e.g. through script) should not be allowed.
if (actor.getClass().getCreatureStats(actor).isDead())
return;
return false;
mLastTopic = "";
mPermanentDispositionChange = 0;
@ -117,6 +115,8 @@ namespace MWDialogue
mChoice = -1;
mIsInChoice = false;
mGoodbye = false;
mChoices.clear();
mActor = actor;
@ -125,8 +125,6 @@ namespace MWDialogue
mActorKnownTopics.clear();
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
//greeting
const MWWorld::Store<ESM::Dialogue> &dialogs =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
@ -140,10 +138,6 @@ namespace MWDialogue
// Search a response (we do not accept a fallback to "Info refusal" here)
if (const ESM::DialInfo *info = filter.search (*it, false))
{
//initialise the GUI
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue);
win->startDialogue(actor, actor.getClass().getName (actor));
creatureStats.talkedToPlayer();
if (!info->mSound.empty())
@ -152,29 +146,23 @@ namespace MWDialogue
}
// first topics update so that parseText knows the keywords to highlight
updateTopics();
updateActorKnownTopics();
parseText (info->mResponse);
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), "", false);
response = Response ("", Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
executeScript (info->mResultScript, mActor);
mLastTopic = it->mId;
// update topics again to accommodate changes resulting from executeScript
updateTopics();
updateActorKnownTopics();
return;
return true;
}
}
}
// No greetings found. The dialogue window should not be shown.
// If this is a companion, we must show the companion window directly (used by BM_bear_be_unique).
bool isCompanion = !mActor.getClass().getScript(mActor).empty()
&& mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion");
if (isCompanion)
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mActor);
return false;
}
bool DialogueManager::compile (const std::string& cmd, std::vector<Interpreter::Type_Code>& code, const MWWorld::Ptr& actor)
@ -252,8 +240,9 @@ namespace MWDialogue
}
}
void DialogueManager::executeTopic (const std::string& topic)
DialogueManager::Response DialogueManager::executeTopic (const std::string& topic)
{
DialogueManager::Response response;
Filter filter (mActor, mChoice, mTalkedTo);
const MWWorld::Store<ESM::Dialogue> &dialogues =
@ -261,8 +250,6 @@ namespace MWDialogue
const ESM::Dialogue& dialogue = *dialogues.find (topic);
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
const ESM::DialInfo* info = filter.search(dialogue, true);
if (info)
{
@ -287,7 +274,7 @@ namespace MWDialogue
title = topic;
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext), title);
response = Response(title, Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
if (dialogue.mType == ESM::Dialogue::Topic)
{
@ -308,11 +295,7 @@ namespace MWDialogue
mLastTopic = topic;
}
else
{
// no response found, print a fallback text
win->addResponse ("", topic);
}
return response;
}
const ESM::Dialogue *DialogueManager::searchDialogue(const std::string& id)
@ -325,11 +308,10 @@ namespace MWDialogue
MWBase::Environment::get().getWorld()->updateDialogueGlobals();
}
void DialogueManager::updateTopics()
void DialogueManager::updateActorKnownTopics()
{
updateGlobals();
std::list<std::string> keywordList;
mActorKnownTopics.clear();
const MWWorld::Store<ESM::Dialogue> &dialogs =
@ -345,35 +327,42 @@ namespace MWDialogue
{
std::string lower = Misc::StringUtils::lowerCase(iter->mId);
mActorKnownTopics.insert (lower);
//does the player know the topic?
if (mKnownTopics.count(lower))
{
keywordList.push_back (iter->mId);
}
}
}
}
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
}
std::list<std::string> DialogueManager::getAvailableTopics()
{
updateActorKnownTopics();
std::list<std::string> keywordList;
for (const std::string& topic : mActorKnownTopics)
{
//does the player know the topic?
if (mKnownTopics.count(Misc::StringUtils::lowerCase(topic)))
keywordList.push_back(topic);
}
// sort again, because the previous sort was case-sensitive
keywordList.sort(Misc::StringUtils::ciLess);
win->setKeywords(keywordList);
return keywordList;
}
void DialogueManager::keywordSelected (const std::string& keyword)
DialogueManager::Response DialogueManager::keywordSelected (const std::string& keyword)
{
Response response;
if(!mIsInChoice)
{
const ESM::Dialogue* dialogue = searchDialogue(keyword);
if (dialogue && dialogue->mType == ESM::Dialogue::Topic)
{
executeTopic (keyword);
response = executeTopic (keyword);
}
}
updateTopics();
return response;
}
bool DialogueManager::isInChoice() const
@ -383,8 +372,6 @@ namespace MWDialogue
void DialogueManager::goodbyeSelected()
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
// Apply disposition change to NPC's base disposition
if (mActor.getClass().isNpc())
{
@ -400,9 +387,10 @@ namespace MWDialogue
mTemporaryDispositionChange = 0;
}
void DialogueManager::questionAnswered (int answer)
DialogueManager::Response DialogueManager::questionAnswered (int answer)
{
mChoice = answer;
DialogueManager::Response response;
const ESM::Dialogue* dialogue = searchDialogue(mLastTopic);
if (dialogue)
@ -418,10 +406,10 @@ namespace MWDialogue
mChoice = -1;
mIsInChoice = false;
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices();
mChoices.clear();
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse (Interpreter::fixDefinesDialog(text, interpreterContext));
response = Response("", Interpreter::fixDefinesDialog(text, interpreterContext));
// Make sure the returned DialInfo is from the Dialogue we supplied. If could also be from the Info refusal group,
// in which case it should not be added to the journal.
@ -441,32 +429,39 @@ namespace MWDialogue
{
mChoice = -1;
mIsInChoice = false;
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->clearChoices();
mChoices.clear();
}
}
}
updateTopics();
updateActorKnownTopics();
return response;
}
void DialogueManager::askQuestion (const std::string& question, int choice)
void DialogueManager::addChoice (const std::string& text, int choice)
{
mIsInChoice = true;
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->addChoice(question, choice);
mChoices.push_back(std::make_pair(text, choice));
}
void DialogueManager::goodbye()
const std::vector<std::pair<std::string, int> >& DialogueManager::getChoices()
{
mIsInChoice = true;
return mChoices;
}
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
bool DialogueManager::isGoodbye()
{
return mGoodbye;
}
win->goodbye();
void DialogueManager::goodbye()
{
mIsInChoice = false;
mGoodbye = true;
}
void DialogueManager::persuade(int type)
DialogueManager::Response DialogueManager::persuade(int type)
{
bool success;
float temp, perm;
@ -515,7 +510,7 @@ namespace MWDialogue
text = "Bribe";
}
executeTopic (text + (success ? " Success" : " Fail"));
return executeTopic (text + (success ? " Success" : " Fail"));
}
int DialogueManager::getTemporaryDispositionChange() const
@ -528,7 +523,7 @@ namespace MWDialogue
mTemporaryDispositionChange += delta;
}
bool DialogueManager::checkServiceRefused()
bool DialogueManager::checkServiceRefused(Response& response)
{
Filter filter (mActor, mChoice, mTalkedTo);
@ -536,7 +531,6 @@ namespace MWDialogue
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal");
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, false, false, true);
if (!infos.empty())
@ -550,8 +544,7 @@ namespace MWDialogue
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext),
gmsts.find ("sServiceRefusal")->getString());
response = Response(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
executeScript (info->mResultScript, mActor);
return true;

@ -41,19 +41,22 @@ namespace MWDialogue
int mChoice;
std::string mLastTopic; // last topic ID, lowercase
bool mIsInChoice;
bool mGoodbye;
std::vector<std::pair<std::string, int> > mChoices;
float mTemporaryDispositionChange;
float mPermanentDispositionChange;
void parseText (const std::string& text);
void updateTopics();
void updateActorKnownTopics();
void updateGlobals();
bool compile (const std::string& cmd, std::vector<Interpreter::Type_Code>& code, const MWWorld::Ptr& actor);
void executeScript (const std::string& script, const MWWorld::Ptr& actor);
void executeTopic (const std::string& topic);
Response executeTopic (const std::string& topic);
const ESM::Dialogue* searchDialogue(const std::string& id);
@ -65,24 +68,29 @@ namespace MWDialogue
virtual bool isInChoice() const;
virtual void startDialogue (const MWWorld::Ptr& actor);
virtual bool startDialogue (const MWWorld::Ptr& actor, Response& response);
std::list<std::string> getAvailableTopics();
virtual void addTopic (const std::string& topic);
virtual void askQuestion (const std::string& question,int choice);
virtual void addChoice (const std::string& text,int choice);
const std::vector<std::pair<std::string, int> >& getChoices();
virtual bool isGoodbye();
virtual void goodbye();
virtual bool checkServiceRefused ();
virtual bool checkServiceRefused (Response& response);
virtual void say(const MWWorld::Ptr &actor, const std::string &topic);
//calbacks for the GUI
virtual void keywordSelected (const std::string& keyword);
virtual Response keywordSelected (const std::string& keyword);
virtual void goodbyeSelected();
virtual void questionAnswered (int answer);
virtual Response questionAnswered (int answer);
virtual void persuade (int type);
virtual Response persuade (int type);
virtual int getTemporaryDispositionChange () const;
/// @note This change is temporary and gets discarded when dialogue ends.

@ -68,7 +68,9 @@ namespace MWGui
else /*if (sender == mBribe1000Button)*/
type = MWBase::MechanicsManager::PT_Bribe1000;
MWBase::Environment::get().getDialogueManager()->persuade(type);
MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->persuade(type);
eventPersuadeMsg(response.first, response.second);
setVisible(false);
}
@ -214,30 +216,26 @@ namespace MWGui
void Choice::activated()
{
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId);
eventChoiceActivated(mChoiceId);
}
void Topic::activated()
{
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
MWBase::Environment::get().getDialogueManager()->keywordSelected(mTopicId);
eventTopicActivated(mTopicId);
}
void Goodbye::activated()
{
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
eventActivated();
}
// --------------------------------------------------------------------------------------------------
DialogueWindow::DialogueWindow()
: WindowBase("openmw_dialogue_window.layout")
, mEnabled(false)
, mGoodbye(false)
, mPersuasionDialog()
{
@ -245,13 +243,14 @@ namespace MWGui
center();
mPersuasionDialog.setVisible(false);
mPersuasionDialog.eventPersuadeMsg += MyGUI::newDelegate(this, &DialogueWindow::onPersuadeResult);
//History view
getWidget(mHistory, "History");
//Topics list
getWidget(mTopicsList, "TopicsList");
mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic);
mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectListItem);
getWidget(mGoodbyeButton, "ByeButton");
mGoodbyeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked);
@ -269,15 +268,27 @@ namespace MWGui
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize);
}
DialogueWindow::~DialogueWindow()
{
mPersuasionDialog.eventPersuadeMsg.clear();
deleteLater();
for (Link* link : mLinks)
delete link;
for (auto link : mTopicLinks)
delete link.second;
for (auto history : mHistoryContents)
delete history;
}
void DialogueWindow::onTradeComplete()
{
addResponse(MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}"));
addResponse("", MyGUI::LanguageManager::getInstance().replaceTags("#{sBarterDialog5}"));
}
bool DialogueWindow::exit()
{
if ((!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice())
&& !mGoodbye)
if ((MWBase::Environment::get().getDialogueManager()->isInChoice()))
{
return false;
}
@ -315,9 +326,9 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
}
void DialogueWindow::onSelectTopic(const std::string& topic, int id)
void DialogueWindow::onSelectListItem(const std::string& topic, int id)
{
if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice())
if (mGoodbye || MWBase::Environment::get().getDialogueManager()->isInChoice())
return;
int separatorPos = 0;
@ -328,17 +339,18 @@ namespace MWGui
}
if (id >= separatorPos)
MWBase::Environment::get().getDialogueManager()->keywordSelected(topic);
onTopicActivated(topic);
else
{
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
MWBase::DialogueManager::Response response;
if (topic == gmst.find("sPersuasion")->getString())
mPersuasionDialog.setVisible(true);
else if (topic == gmst.find("sCompanionShare")->getString())
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr);
else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused())
else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(response))
{
if (topic == gmst.find("sBarter")->getString())
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr);
@ -355,21 +367,30 @@ namespace MWGui
else if (topic == gmst.find("sRepair")->getString())
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr);
}
else
addResponse(response.first, response.second);
}
}
void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName)
void DialogueWindow::setPtr(const MWWorld::Ptr& actor)
{
MWBase::DialogueManager::Response response;
if (!MWBase::Environment::get().getDialogueManager()->startDialogue(actor, response))
{
// No greetings found. The dialogue window should not be shown.
// If this is a companion, we must show the companion window directly (used by BM_bear_be_unique).
if (isCompanion())
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion, mPtr);
return;
}
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
mGoodbye = false;
mEnabled = true;
bool sameActor = (mPtr == actor);
mPtr = actor;
mTopicsList->setEnabled(true);
setTitle(npcName);
clearChoices();
setTitle(mPtr.getClass().getName(mPtr));
mTopicsList->clear();
@ -381,12 +402,13 @@ namespace MWGui
}
for (std::vector<Link*>::iterator it = mLinks.begin(); it != mLinks.end(); ++it)
delete (*it);
mDeleteLater.push_back(*it); // Links are not deleted right away to prevent issues with event handlers
mLinks.clear();
updateDisposition();
restock();
addResponse(response.first, response.second, false);
}
void DialogueWindow::restock()
@ -403,11 +425,18 @@ namespace MWGui
}
}
void DialogueWindow::deleteLater()
{
for (Link* link : mDeleteLater)
delete link;
mDeleteLater.clear();
}
void DialogueWindow::setKeywords(std::list<std::string> keyWords)
{
mTopicsList->clear();
for (std::map<std::string, Link*>::iterator it = mTopicLinks.begin(); it != mTopicLinks.end(); ++it)
delete it->second;
mDeleteLater.push_back(it->second);
mTopicLinks.clear();
mKeywordSearch.clear();
@ -416,9 +445,6 @@ namespace MWGui
bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get<ESM::NPC>()->mBase->getTransport().empty())
|| (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get<ESM::Creature>()->mBase->getTransport().empty());
bool isCompanion = !mPtr.getClass().getScript(mPtr).empty()
&& mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion");
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
@ -446,7 +472,7 @@ namespace MWGui
if (services & ESM::NPC::Repair)
mTopicsList->addItem(gmst.find("sRepair")->getString());
if (isCompanion)
if (isCompanion())
mTopicsList->addItem(gmst.find("sCompanionShare")->getString());
if (mTopicsList->getItemCount() > 0)
@ -458,6 +484,7 @@ namespace MWGui
mTopicsList->addItem(*it);
Topic* t = new Topic(*it);
t->eventTopicActivated += MyGUI::newDelegate(this, &DialogueWindow::onTopicActivated);
mTopicLinks[Misc::StringUtils::lowerCase(*it)] = t;
mKeywordSearch.seed(Misc::StringUtils::lowerCase(*it), intptr_t(t));
@ -491,9 +518,11 @@ namespace MWGui
typesetter->sectionBreak(9);
// choices
const TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
for (std::vector<std::pair<std::string, int> >::iterator it = mChoices.begin(); it != mChoices.end(); ++it)
mChoices = MWBase::Environment::get().getDialogueManager()->getChoices();
for (std::vector<std::pair<std::string, int> >::const_iterator it = mChoices.begin(); it != mChoices.end(); ++it)
{
Choice* link = new Choice(it->second);
link->eventChoiceActivated += MyGUI::newDelegate(this, &DialogueWindow::onChoiceActivated);
mLinks.push_back(link);
typesetter->lineBreak();
@ -503,9 +532,11 @@ namespace MWGui
typesetter->write(questionStyle, to_utf8_span(it->first.c_str()));
}
mGoodbye = MWBase::Environment::get().getDialogueManager()->isGoodbye();
if (mGoodbye)
{
Goodbye* link = new Goodbye();
link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated);
mLinks.push_back(link);
std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->getString();
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver,
@ -550,32 +581,40 @@ namespace MWGui
reinterpret_cast<Link*>(link)->activated();
}
void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos)
void DialogueWindow::onTopicActivated(const std::string &topicId)
{
mHistory->setPosition(0, static_cast<int>(pos) * -1);
MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->keywordSelected(topicId);
addResponse(response.first, response.second);
}
void DialogueWindow::addResponse(const std::string &text, const std::string &title, bool needMargin)
void DialogueWindow::onChoiceActivated(int id)
{
mHistoryContents.push_back(new Response(text, title, needMargin));
updateHistory();
MWBase::DialogueManager::Response response = MWBase::Environment::get().getDialogueManager()->questionAnswered(id);
addResponse(response.first, response.second);
}
void DialogueWindow::addMessageBox(const std::string& text)
void DialogueWindow::onGoodbyeActivated()
{
mHistoryContents.push_back(new Message(text));
updateHistory();
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
resetReference();
}
void DialogueWindow::onScrollbarMoved(MyGUI::ScrollBar *sender, size_t pos)
{
mHistory->setPosition(0, static_cast<int>(pos) * -1);
}
void DialogueWindow::addChoice(const std::string& choice, int id)
void DialogueWindow::addResponse(const std::string &title, const std::string &text, bool needMargin)
{
mChoices.push_back(std::make_pair(choice, id));
mHistoryContents.push_back(new Response(text, title, needMargin));
updateHistory();
updateTopics();
}
void DialogueWindow::clearChoices()
void DialogueWindow::addMessageBox(const std::string& text)
{
mChoices.clear();
mHistoryContents.push_back(new Message(text));
updateHistory();
}
@ -608,13 +647,6 @@ namespace MWGui
}
}
void DialogueWindow::goodbye()
{
mGoodbye = true;
mEnabled = false;
updateHistory();
}
void DialogueWindow::onReferenceUnavailable()
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
@ -623,6 +655,30 @@ namespace MWGui
void DialogueWindow::onFrame(float dt)
{
checkReferenceAvailable();
if (mPtr.isEmpty())
return;
updateDisposition();
deleteLater();
if (mChoices != MWBase::Environment::get().getDialogueManager()->getChoices()
|| mGoodbye != MWBase::Environment::get().getDialogueManager()->isGoodbye())
updateHistory();
}
void DialogueWindow::updateTopics()
{
setKeywords(MWBase::Environment::get().getDialogueManager()->getAvailableTopics());
}
bool DialogueWindow::isCompanion()
{
return !mPtr.getClass().getScript(mPtr).empty()
&& mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion");
}
void DialogueWindow::onPersuadeResult(const std::string &title, const std::string &text)
{
addResponse(title, text);
}
}

@ -8,6 +8,8 @@
#include "../mwdialogue/keywordsearch.hpp"
#include <MyGUI_Delegate.h>
namespace Gui
{
class MWList;
@ -20,14 +22,14 @@ namespace MWGui
namespace MWGui
{
class DialogueHistoryViewModel;
class BookPage;
class PersuasionDialog : public WindowModal
{
public:
PersuasionDialog();
typedef MyGUI::delegates::CMultiDelegate2<const std::string&, const std::string&> EventHandle_Result;
EventHandle_Result eventPersuadeMsg;
virtual void onOpen();
private:
@ -53,6 +55,8 @@ namespace MWGui
struct Topic : Link
{
typedef MyGUI::delegates::CMultiDelegate1<const std::string&> EventHandle_TopicId;
EventHandle_TopicId eventTopicActivated;
Topic(const std::string& id) : mTopicId(id) {}
std::string mTopicId;
virtual void activated ();
@ -60,6 +64,8 @@ namespace MWGui
struct Choice : Link
{
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_ChoiceId;
EventHandle_ChoiceId eventChoiceActivated;
Choice(int id) : mChoiceId(id) {}
int mChoiceId;
virtual void activated ();
@ -67,6 +73,8 @@ namespace MWGui
struct Goodbye : Link
{
typedef MyGUI::delegates::CMultiDelegate0 Event_Activated;
Event_Activated eventActivated;
virtual void activated ();
};
@ -98,6 +106,7 @@ namespace MWGui
{
public:
DialogueWindow();
~DialogueWindow();
void onTradeComplete();
@ -108,25 +117,29 @@ namespace MWGui
void notifyLinkClicked (TypesetBook::InteractiveId link);
void startDialogue(MWWorld::Ptr actor, std::string npcName);
void setPtr(const MWWorld::Ptr& actor);
void setKeywords(std::list<std::string> keyWord);
void addResponse (const std::string& text, const std::string& title="", bool needMargin = true);
void addResponse (const std::string& title, const std::string& text, bool needMargin = true);
void addMessageBox(const std::string& text);
void addChoice(const std::string& choice, int id);
void clearChoices();
void goodbye();
void onFrame(float dt);
void clear() { resetReference(); }
protected:
void onSelectTopic(const std::string& topic, int id);
void updateTopics();
bool isCompanion();
void onPersuadeResult(const std::string& title, const std::string& text);
void onSelectListItem(const std::string& topic, int id);
void onByeClicked(MyGUI::Widget* _sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void onWindowResize(MyGUI::Window* _sender);
void onTopicActivated(const std::string& topicId);
void onChoiceActivated(int id);
void onGoodbyeActivated();
void onScrollbarMoved (MyGUI::ScrollBar* sender, size_t pos);
@ -137,17 +150,19 @@ namespace MWGui
private:
void updateDisposition();
void restock();
void deleteLater();
bool mEnabled;
bool mGoodbye;
std::vector<DialogueText*> mHistoryContents;
std::vector<std::pair<std::string, int> > mChoices;
bool mGoodbye;
std::vector<Link*> mLinks;
std::map<std::string, Link*> mTopicLinks;
std::vector<Link*> mDeleteLater;
KeywordSearchT mKeywordSearch;
BookPage* mHistory;

@ -353,6 +353,7 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting);
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
return;
}
}

@ -323,6 +323,7 @@ namespace MWGui
onCancelButtonClicked(mCancelButton);
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
return;
}
}

@ -197,6 +197,7 @@ namespace MWGui
// go back to game mode
MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training);
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
}
void TrainingWindow::onFrame(float dt)

@ -178,6 +178,7 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel);
MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
// Teleports any followers, too.
MWWorld::ActionTeleport action(interior ? cellname : "", pos, true);

@ -1288,7 +1288,6 @@ namespace MWGui
mConsole->executeFile (path);
}
MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; }
MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; }
MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; }
MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; }

@ -179,7 +179,6 @@ namespace MWGui
virtual bool isAllowed(GuiWindow wnd) const;
/// \todo investigate, if we really need to expose every single lousy UI element to the outside world
virtual MWGui::DialogueWindow* getDialogueWindow();
virtual MWGui::InventoryWindow* getInventoryWindow();
virtual MWGui::CountDialog* getCountDialog();
virtual MWGui::ConfirmationDialog* getConfirmationDialog();

@ -11,6 +11,7 @@
#include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/npcstats.hpp"
@ -116,7 +117,7 @@ namespace MWScript
runtime.pop();
arg0 = arg0 -1;
}
dialogue->askQuestion(question,choice);
dialogue->addChoice(question,choice);
}
}
};
@ -133,7 +134,7 @@ namespace MWScript
if (!ptr.getRefData().isEnabled())
return;
MWBase::Environment::get().getDialogueManager()->startDialogue (ptr);
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, ptr);
}
};

@ -1,7 +1,7 @@
#include "actiontalk.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/windowmanager.hpp"
namespace MWWorld
{
@ -9,6 +9,6 @@ namespace MWWorld
void ActionTalk::executeImp (const Ptr& actor)
{
MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget());
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget());
}
}

Loading…
Cancel
Save