diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 803c74325..06a142f0a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui ) add_openmw_dir (mwdialogue - dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper hypertextparser keywordsearch + dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper hypertextparser keywordsearch scripttest ) add_openmw_dir (mwscript diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d7b23c096..1b350d752 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -40,6 +40,7 @@ #include "mwdialogue/dialoguemanagerimp.hpp" #include "mwdialogue/journalimp.hpp" +#include "mwdialogue/scripttest.hpp" #include "mwmechanics/mechanicsmanagerimp.hpp" @@ -174,6 +175,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) + , mCompileAllDialogue (false) , mWarningsMode (1) , mScriptContext (0) , mFSStrict (false) @@ -425,7 +427,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) if (mCompileAll) { std::pair result = MWBase::Environment::get().getScriptManager()->compileAll(); - if (result.first) std::cout << "compiled " << result.second << " of " << result.first << " scripts (" @@ -433,6 +434,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) << "%)" << std::endl; } + if (mCompileAllDialogue) + { + std::pair result = MWDialogue::ScriptTest::compileAll(&mExtensions); + if (result.first) + std::cout + << "compiled " << result.second << " of " << result.first << " dialogue script/actor combinations a(" + << 100*static_cast (result.second)/result.first + << "%)" + << std::endl; + } } // Initialise and enter main loop. @@ -535,6 +546,11 @@ void OMW::Engine::setCompileAll (bool all) mCompileAll = all; } +void OMW::Engine::setCompileAllDialogue (bool all) +{ + mCompileAllDialogue = all; +} + void OMW::Engine::setSoundUsage(bool soundUsage) { mUseSound = soundUsage; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 0ee5a09c5..6cf31cba8 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -76,6 +76,7 @@ namespace OMW bool mSkipMenu; bool mUseSound; bool mCompileAll; + bool mCompileAllDialogue; int mWarningsMode; std::string mFocusName; std::map mFallbackMap; @@ -178,6 +179,9 @@ namespace OMW /// Compile all scripts (excludign dialogue scripts) at startup? void setCompileAll (bool all); + /// Compile all dialogue scripts at startup? + void setCompileAllDialogue (bool all); + /// Font encoding void setEncoding(const ToUTF8::FromType& encoding); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 744780b25..9382e2516 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -130,6 +130,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-all", bpo::value()->implicit_value(true) ->default_value(false), "compile all scripts (excluding dialogue scripts) at startup") + ("script-all-dialogue", bpo::value()->implicit_value(true) + ->default_value(false), "compile all dialogue scripts at startup") + ("script-console", bpo::value()->implicit_value(true) ->default_value(false), "enable console-only script functionality") @@ -264,6 +267,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // scripts engine.setCompileAll(variables["script-all"].as()); + engine.setCompileAllDialogue(variables["script-all-dialogue"].as()); engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as()); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index eff54fbc0..196df0039 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -47,7 +47,7 @@ namespace MWDialogue { DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage) : - mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), + mCompilerContext (MWScript::CompilerContext::Type_Dialogue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) , mTemporaryDispositionChange(0.f) , mPermanentDispositionChange(0.f), mScriptVerbose (scriptVerbose) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 629d99cc2..af8a5754f 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -603,6 +603,17 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, return suitableInfos[0]; } +std::vector MWDialogue::Filter::listAll (const ESM::Dialogue& dialogue) const +{ + std::vector infos; + for (ESM::Dialogue::InfoContainer::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) + { + if (testActor (*iter)) + infos.push_back(&*iter); + } + return infos; +} + std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition) const { diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 7e7f2b6f5..d41b7aa1e 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -55,7 +55,11 @@ namespace MWDialogue std::vector list (const ESM::Dialogue& dialogue, bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition=false) const; - ///< \note If fallbackToInfoRefusal is used, the returned DialInfo might not be from the supplied ESM::Dialogue. + ///< List all infos that could be used on the given actor, using the current runtime state of the actor. + /// \note If fallbackToInfoRefusal is used, the returned DialInfo might not be from the supplied ESM::Dialogue. + + std::vector listAll (const ESM::Dialogue& dialogue) const; + ///< List all infos that could possibly be used on the given actor, ignoring runtime state filters and ignoring player filters. const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. diff --git a/apps/openmw/mwdialogue/scripttest.cpp b/apps/openmw/mwdialogue/scripttest.cpp new file mode 100644 index 000000000..a8de21ef9 --- /dev/null +++ b/apps/openmw/mwdialogue/scripttest.cpp @@ -0,0 +1,124 @@ +#include "scripttest.hpp" + +#include "../mwworld/manualref.hpp" +#include "../mwworld/class.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" + +#include "../mwscript/compilercontext.hpp" + +#include +#include +#include +#include +#include +#include + +#include "filter.hpp" + +namespace +{ + +void test(const MWWorld::Ptr& actor, int &compiled, int &total, const Compiler::Extensions* extensions) +{ + MWDialogue::Filter filter(actor, 0, false); + + MWScript::CompilerContext compilerContext(MWScript::CompilerContext::Type_Dialogue); + compilerContext.setExtensions(extensions); + std::ostream errorStream(std::cout.rdbuf()); + Compiler::StreamErrorHandler errorHandler(errorStream); + + const MWWorld::Store& dialogues = MWBase::Environment::get().getWorld()->getStore().get(); + for (MWWorld::Store::iterator it = dialogues.begin(); it != dialogues.end(); ++it) + { + std::vector infos = filter.listAll(*it); + + for (std::vector::iterator it = infos.begin(); it != infos.end(); ++it) + { + const ESM::DialInfo* info = *it; + if (!info->mResultScript.empty()) + { + bool success = true; + ++total; + try + { + errorHandler.reset(); + + std::istringstream input (info->mResultScript + "\n"); + + Compiler::Scanner scanner (errorHandler, input, extensions); + + Compiler::Locals locals; + + std::string actorScript = actor.getClass().getScript(actor); + + if (!actorScript.empty()) + { + // grab local variables from actor's script, if available. + locals = MWBase::Environment::get().getScriptManager()->getLocals (actorScript); + } + + Compiler::ScriptParser parser(errorHandler, compilerContext, locals, false); + + scanner.scan (parser); + + if (!errorHandler.isGood()) + success = false; + + ++compiled; + } + catch (const Compiler::SourceException& /* error */) + { + // error has already been reported via error handler + success = false; + } + catch (const std::exception& error) + { + std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl; + success = false; + } + + if (!success) + { + std::cerr + << "compiling failed (dialogue script)" << std::endl + << info->mResultScript + << std::endl << std::endl; + } + } + } + } +} + +} + +namespace MWDialogue +{ + +namespace ScriptTest +{ + + std::pair compileAll(const Compiler::Extensions *extensions) + { + int compiled = 0, total = 0; + const MWWorld::Store& npcs = MWBase::Environment::get().getWorld()->getStore().get(); + for (MWWorld::Store::iterator it = npcs.begin(); it != npcs.end(); ++it) + { + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->mId); + test(ref.getPtr(), compiled, total, extensions); + } + + const MWWorld::Store& creatures = MWBase::Environment::get().getWorld()->getStore().get(); + for (MWWorld::Store::iterator it = creatures.begin(); it != creatures.end(); ++it) + { + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->mId); + test(ref.getPtr(), compiled, total, extensions); + } + return std::make_pair(total, compiled); + } + +} + +} diff --git a/apps/openmw/mwdialogue/scripttest.hpp b/apps/openmw/mwdialogue/scripttest.hpp new file mode 100644 index 000000000..1ed94c76a --- /dev/null +++ b/apps/openmw/mwdialogue/scripttest.hpp @@ -0,0 +1,20 @@ +#ifndef OPENMW_MWDIALOGUE_SCRIPTTEST_H +#define OPENMW_MWDIALOGUE_SCRIPTTEST_H + +#include + +namespace MWDialogue +{ + +namespace ScriptTest +{ + +/// Attempt to compile all dialogue scripts, use for verification purposes +/// @return A pair containing +std::pair compileAll(const Compiler::Extensions* extensions); + +} + +} + +#endif diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 95719ab69..010926f45 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -12,7 +12,7 @@ namespace MWScript enum Type { Type_Full, // global, local, targetted - Type_Dialgoue, + Type_Dialogue, Type_Console };