mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-13 12:09:41 +00:00
Use all topics to search for keywords in dialogues (Fixes #2013)
Move KeywordSearch to MWDialogue Move hypertext parsing functions to a new file
This commit is contained in:
parent
9213067aee
commit
ed6bdc0bde
9 changed files with 150 additions and 106 deletions
|
@ -38,13 +38,13 @@ add_openmw_dir (mwgui
|
|||
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
|
||||
enchantingdialog trainingwindow travelwindow exposedwindow cursor spellicons
|
||||
merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks
|
||||
keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
|
||||
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
|
||||
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow
|
||||
)
|
||||
|
||||
add_openmw_dir (mwdialogue
|
||||
dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper
|
||||
dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper hypertextparser keywordsearch
|
||||
)
|
||||
|
||||
add_openmw_dir (mwscript
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "../mwmechanics/npcstats.hpp"
|
||||
|
||||
#include "filter.hpp"
|
||||
#include "hypertextparser.hpp"
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
|
@ -82,42 +83,27 @@ namespace MWDialogue
|
|||
|
||||
void DialogueManager::parseText (const std::string& text)
|
||||
{
|
||||
std::vector<HyperTextToken> hypertext = ParseHyperText(text);
|
||||
std::vector<HyperTextParser::Token> hypertext = HyperTextParser::parseHyperText(text);
|
||||
|
||||
//calculation of standard form fir all hyperlinks
|
||||
for (size_t i = 0; i < hypertext.size(); ++i)
|
||||
for (std::vector<HyperTextParser::Token>::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok)
|
||||
{
|
||||
if (hypertext[i].mLink)
|
||||
Misc::StringUtils::toLower(tok->mText);
|
||||
|
||||
if (tok->isExplicitLink())
|
||||
{
|
||||
size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText);
|
||||
// calculation of standard form for all hyperlinks
|
||||
size_t asterisk_count = HyperTextParser::removePseudoAsterisks(tok->mText);
|
||||
for(; asterisk_count > 0; --asterisk_count)
|
||||
hypertext[i].mText.append("*");
|
||||
tok->mText.append("*");
|
||||
|
||||
hypertext[i].mText = mTranslationDataStorage.topicStandardForm(hypertext[i].mText);
|
||||
tok->mText = mTranslationDataStorage.topicStandardForm(tok->mText);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < hypertext.size(); ++i)
|
||||
{
|
||||
std::list<std::string>::iterator it;
|
||||
for(it = mActorKnownTopics.begin(); it != mActorKnownTopics.end(); ++it)
|
||||
{
|
||||
if (hypertext[i].mLink)
|
||||
{
|
||||
if( hypertext[i].mText == *it )
|
||||
{
|
||||
mKnownTopics[hypertext[i].mText] = true;
|
||||
}
|
||||
}
|
||||
else if( !mTranslationDataStorage.hasTranslation() )
|
||||
{
|
||||
size_t pos = Misc::StringUtils::lowerCase(hypertext[i].mText).find(*it, 0);
|
||||
if(pos !=std::string::npos)
|
||||
{
|
||||
mKnownTopics[*it] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tok->isImplicitKeyword() && mTranslationDataStorage.hasTranslation())
|
||||
continue;
|
||||
|
||||
if (std::find(mActorKnownTopics.begin(), mActorKnownTopics.end(), tok->mText) != mActorKnownTopics.end())
|
||||
mKnownTopics[tok->mText] = true;
|
||||
}
|
||||
|
||||
updateTopics();
|
||||
|
@ -724,55 +710,4 @@ namespace MWDialogue
|
|||
mLastTopic, actor.getClass().getName(actor));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
|
||||
{
|
||||
std::vector<HyperTextToken> result;
|
||||
MyGUI::UString utext(text);
|
||||
size_t pos_end, iteration_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
size_t pos_begin = utext.find('@', iteration_pos);
|
||||
if (pos_begin != std::string::npos)
|
||||
pos_end = utext.find('#', pos_begin);
|
||||
|
||||
if (pos_begin != std::string::npos && pos_end != std::string::npos)
|
||||
{
|
||||
result.push_back( HyperTextToken(utext.substr(iteration_pos, pos_begin - iteration_pos), false) );
|
||||
|
||||
std::string link = utext.substr(pos_begin + 1, pos_end - pos_begin - 1);
|
||||
result.push_back( HyperTextToken(link, true) );
|
||||
|
||||
iteration_pos = pos_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back( HyperTextToken(utext.substr(iteration_pos), false) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t RemovePseudoAsterisks(std::string& phrase)
|
||||
{
|
||||
size_t pseudoAsterisksCount = 0;
|
||||
|
||||
if( !phrase.empty() )
|
||||
{
|
||||
std::string::reverse_iterator rit = phrase.rbegin();
|
||||
|
||||
const char specialPseudoAsteriskCharacter = 127;
|
||||
while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter )
|
||||
{
|
||||
pseudoAsterisksCount++;
|
||||
++rit;
|
||||
}
|
||||
}
|
||||
|
||||
phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount);
|
||||
|
||||
return pseudoAsterisksCount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,21 +103,6 @@ namespace MWDialogue
|
|||
/// Removes the last added topic response for the given actor from the journal
|
||||
virtual void clearInfoActor (const MWWorld::Ptr& actor) const;
|
||||
};
|
||||
|
||||
|
||||
struct HyperTextToken
|
||||
{
|
||||
HyperTextToken(const std::string& text, bool link) : mText(text), mLink(link) {}
|
||||
|
||||
std::string mText;
|
||||
bool mLink;
|
||||
};
|
||||
|
||||
// In translations (at least Russian) the links are marked with @#, so
|
||||
// it should be a function to parse it
|
||||
std::vector<HyperTextToken> ParseHyperText(const std::string& text);
|
||||
|
||||
size_t RemovePseudoAsterisks(std::string& phrase);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
89
apps/openmw/mwdialogue/hypertextparser.cpp
Normal file
89
apps/openmw/mwdialogue/hypertextparser.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwworld/store.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "keywordsearch.hpp"
|
||||
|
||||
#include "hypertextparser.hpp"
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
namespace HyperTextParser
|
||||
{
|
||||
std::vector<Token> parseHyperText(const std::string & text)
|
||||
{
|
||||
std::vector<Token> result;
|
||||
size_t pos_end, iteration_pos = 0;
|
||||
for(;;)
|
||||
{
|
||||
size_t pos_begin = text.find('@', iteration_pos);
|
||||
if (pos_begin != std::string::npos)
|
||||
pos_end = text.find('#', pos_begin);
|
||||
|
||||
if (pos_begin != std::string::npos && pos_end != std::string::npos)
|
||||
{
|
||||
if (pos_begin != iteration_pos)
|
||||
tokenizeKeywords(text.substr(iteration_pos, pos_begin - iteration_pos), result);
|
||||
|
||||
std::string link = text.substr(pos_begin + 1, pos_end - pos_begin - 1);
|
||||
result.push_back(Token(link, Token::ExplicitLink));
|
||||
|
||||
iteration_pos = pos_end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iteration_pos != text.size())
|
||||
tokenizeKeywords(text.substr(iteration_pos), result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void tokenizeKeywords(const std::string & text, std::vector<Token> & tokens)
|
||||
{
|
||||
const MWWorld::Store<ESM::Dialogue> & dialogs =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||
|
||||
std::list<std::string> keywordList;
|
||||
for (MWWorld::Store<ESM::Dialogue>::iterator it = dialogs.begin(); it != dialogs.end(); ++it)
|
||||
keywordList.push_back(Misc::StringUtils::lowerCase(it->mId));
|
||||
keywordList.sort(Misc::StringUtils::ciLess);
|
||||
|
||||
KeywordSearch<std::string, int /*unused*/> keywordSearch;
|
||||
KeywordSearch<std::string, int /*unused*/>::Match match;
|
||||
|
||||
for (std::list<std::string>::const_iterator it = keywordList.begin(); it != keywordList.end(); ++it)
|
||||
keywordSearch.seed(*it, 0 /*unused*/);
|
||||
|
||||
for (std::string::const_iterator it = text.begin(); it != text.end() && keywordSearch.search(it, text.end(), match, text.begin()); it = match.mEnd)
|
||||
tokens.push_back(Token(std::string(match.mBeg, match.mEnd), Token::ImplicitKeyword));
|
||||
}
|
||||
|
||||
size_t removePseudoAsterisks(std::string & phrase)
|
||||
{
|
||||
size_t pseudoAsterisksCount = 0;
|
||||
|
||||
if( !phrase.empty() )
|
||||
{
|
||||
std::string::reverse_iterator rit = phrase.rbegin();
|
||||
|
||||
const char specialPseudoAsteriskCharacter = 127;
|
||||
while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter )
|
||||
{
|
||||
pseudoAsterisksCount++;
|
||||
++rit;
|
||||
}
|
||||
}
|
||||
|
||||
phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount);
|
||||
|
||||
return pseudoAsterisksCount;
|
||||
}
|
||||
}
|
||||
}
|
36
apps/openmw/mwdialogue/hypertextparser.hpp
Normal file
36
apps/openmw/mwdialogue/hypertextparser.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef GAME_MWDIALOGUE_HYPERTEXTPARSER_H
|
||||
#define GAME_MWDIALOGUE_HYPERTEXTPARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace MWDialogue
|
||||
{
|
||||
namespace HyperTextParser
|
||||
{
|
||||
struct Token
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
ExplicitLink, // enclosed in @#
|
||||
ImplicitKeyword
|
||||
};
|
||||
|
||||
Token(const std::string & text, Type type) : mText(text), mType(type) {}
|
||||
|
||||
bool isExplicitLink() { return mType == ExplicitLink; }
|
||||
bool isImplicitKeyword() { return mType == ImplicitKeyword; }
|
||||
|
||||
std::string mText;
|
||||
Type mType;
|
||||
};
|
||||
|
||||
// In translations (at least Russian) the links are marked with @#, so
|
||||
// it should be a function to parse it
|
||||
std::vector<Token> parseHyperText(const std::string & text);
|
||||
void tokenizeKeywords(const std::string & text, std::vector<Token> & tokens);
|
||||
size_t removePseudoAsterisks(std::string & phrase);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef MWGUI_KEYWORDSEARCH_H
|
||||
#define MWGUI_KEYWORDSEARCH_H
|
||||
#ifndef GAME_MWDIALOGUE_KEYWORDSEARCH_H
|
||||
#define GAME_MWDIALOGUE_KEYWORDSEARCH_H
|
||||
|
||||
#include <map>
|
||||
#include <locale>
|
||||
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
namespace MWGui
|
||||
namespace MWDialogue
|
||||
{
|
||||
|
||||
template <typename string_t, typename value_t>
|
||||
|
@ -141,7 +141,6 @@ public:
|
|||
match.mValue = candidate->second.mValue;
|
||||
match.mBeg = i;
|
||||
match.mEnd = k;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "bookpage.hpp"
|
||||
|
||||
#include "keywordsearch.hpp"
|
||||
#include "../mwdialogue/keywordsearch.hpp"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
|
@ -76,7 +76,7 @@ namespace MWGui
|
|||
virtual void activated ();
|
||||
};
|
||||
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
typedef MWDialogue::KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
struct DialogueText
|
||||
{
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include "../mwbase/journal.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
|
||||
#include "keywordsearch.hpp"
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
#include "../mwdialogue/keywordsearch.hpp"
|
||||
|
||||
namespace MWGui {
|
||||
|
||||
|
@ -22,7 +22,7 @@ struct JournalViewModelImpl;
|
|||
|
||||
struct JournalViewModelImpl : JournalViewModel
|
||||
{
|
||||
typedef KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
typedef MWDialogue::KeywordSearch <std::string, intptr_t> KeywordSearchT;
|
||||
|
||||
mutable bool mKeywordSearchLoaded;
|
||||
mutable KeywordSearchT mKeywordSearch;
|
||||
|
|
Loading…
Reference in a new issue