From d72ed1946004176fd7784d1cb79a016714c6697a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 20 Jul 2010 23:21:48 +0200 Subject: [PATCH 01/10] implemented script compiler for console --- apps/openmw/engine.cpp | 7 +-- apps/openmw/mwgui/console.hpp | 81 ++++++++++++++++++++++++---- apps/openmw/mwgui/window_manager.cpp | 5 +- apps/openmw/mwgui/window_manager.hpp | 13 ++++- libs/openengine | 2 +- 5 files changed, 90 insertions(+), 18 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0ea6c9040d..2a93561fec 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -206,11 +206,12 @@ void OMW::Engine::go() mOgre.getScene()); // Create window manager - this manages all the MW-specific GUI windows - mEnvironment.mWindowManager = new MWGui::WindowManager(mGuiManager->getGui()); + MWScript::registerExtensions (mExtensions); - mEnvironment.mSoundManager = new MWSound::SoundManager; + mEnvironment.mWindowManager = new MWGui::WindowManager(mGuiManager->getGui(), mEnvironment, + mExtensions); - MWScript::registerExtensions (mExtensions); + mEnvironment.mSoundManager = new MWSound::SoundManager; mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full, mEnvironment); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index c4597b3b7e..54ba503306 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -4,11 +4,70 @@ #include #include #include +#include + +#include +#include +#include +#include +#include +#include + +#include "../mwscript/compilercontext.hpp" namespace MWGui { - class Console : private OEngine::GUI::Layout + class Console : private OEngine::GUI::Layout, private Compiler::ErrorHandler { + private: + + MWScript::CompilerContext mCompilerContext; + + bool compile (const std::string& cmd) + { + try + { + std::istringstream input (cmd + '\n'); + + Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions()); + + Compiler::Locals locals; + Compiler::Literals literals; + std::vector code; + Compiler::LineParser parser (*this, mCompilerContext, locals, literals, code); + + scanner.scan (parser); + + return isGood(); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + + return false; + } + + /// Report error to the user. + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type) + { + std::ostringstream error; + error << "column " << loc.mColumn << " (" << loc.mLiteral << "):"; + + printError (error.str()); + printError ((type==ErrorMessage ? "error: " : "warning: ") + message); + } + + /// Report a file related error + virtual void report (const std::string& message, Type type) + { + printError ((type==ErrorMessage ? "error: " : "warning: ") + message); + } + public: MyGUI::EditPtr command; MyGUI::EditPtr history; @@ -20,8 +79,9 @@ namespace MWGui StringList::iterator current; std::string editString; - Console(int w, int h) - : Layout("openmw_console_layout.xml") + Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions) + : Layout("openmw_console_layout.xml"), + mCompilerContext (MWScript::CompilerContext::Type_Console, environment) { setCoord(10,10, w-10, h/2); @@ -38,6 +98,9 @@ namespace MWGui history->setOverflowToTheLeft(true); history->setEditStatic(true); history->setVisibleVScroll(true); + + // compiler + mCompilerContext.setExtensions (&extensions); } void enable() @@ -130,14 +193,10 @@ namespace MWGui // Log the command print("#FFFFFF> " + cm + "\n"); - /* NOTE: This is where the console command should be - handled. - - The console command is in the string 'cm'. Output from the - command should be put back into the console with the - printOK() or printError() functions. - */ - printOK("OK - echoing line " + cm); + if (compile (cm)) + { + // TODO execute command + } command->setCaption(""); } diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index d96c93e8eb..e83e096505 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -7,7 +7,8 @@ using namespace MWGui; -WindowManager::WindowManager(MyGUI::Gui *_gui) +WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment, + const Compiler::Extensions& extensions) : gui(_gui), mode(GM_Game), shown(GW_ALL), allowed(GW_ALL) { // Get size info from the Gui object @@ -19,7 +20,7 @@ WindowManager::WindowManager(MyGUI::Gui *_gui) menu = new MainMenu(w,h); map = new MapWindow(); stats = new StatsWindow(); - console = new Console(w,h); + console = new Console(w,h, environment, extensions); // The HUD is always on hud->setVisible(true); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index f95454aea5..2246dbd9f3 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -15,6 +15,16 @@ namespace MyGUI class Gui; } +namespace Compiler +{ + class Extensions; +} + +namespace MWWorld +{ + class Environment; +} + namespace MWGui { class HUD; @@ -91,7 +101,8 @@ namespace MWGui public: /// The constructor needs the main Gui object - WindowManager(MyGUI::Gui *_gui); + WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment, + const Compiler::Extensions& extensions); virtual ~WindowManager(); void setMode(GuiMode newMode) diff --git a/libs/openengine b/libs/openengine index c04d72cbe3..82a3c071e5 160000 --- a/libs/openengine +++ b/libs/openengine @@ -1 +1 @@ -Subproject commit c04d72cbe380217c2d1d60f8a2c6e4810fe4c050 +Subproject commit 82a3c071e56f2df451618e1371424c39aa299690 From 281f2d1136f4b7190515c5822cb529ef165b1bf8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 10:08:38 +0200 Subject: [PATCH 02/10] added script interpreter for console --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwgui/console.cpp | 217 ++++++++++++++++++++++++++++++++++ apps/openmw/mwgui/console.hpp | 171 ++++----------------------- 3 files changed, 240 insertions(+), 149 deletions(-) create mode 100644 apps/openmw/mwgui/console.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b05ca6eaa1..6833ce0690 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -37,6 +37,7 @@ set(GAMEGUI_HEADER ) set(GAMEGUI mwgui/window_manager.cpp + mwgui/console.cpp ) source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI}) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp new file mode 100644 index 0000000000..f624bfb036 --- /dev/null +++ b/apps/openmw/mwgui/console.cpp @@ -0,0 +1,217 @@ + +#include "console.hpp" + +#include + +#include "../mwscript/extensions.hpp" + +namespace MWGui +{ + class ConsoleInterpreterContext : public MWScript::InterpreterContext + { + Console& mConsole; + + public: + + ConsoleInterpreterContext (Console& console, MWWorld::Environment& environment, + MWWorld::Ptr reference); + + virtual void messageBox (const std::string& message, + const std::vector& buttons); + }; + + ConsoleInterpreterContext::ConsoleInterpreterContext (Console& console, + MWWorld::Environment& environment, MWWorld::Ptr reference) + : MWScript::InterpreterContext (environment, + reference.isEmpty() ? 0 : &reference.getRefData().getLocals(), reference), + mConsole (console) + {} + + void ConsoleInterpreterContext::messageBox (const std::string& message, + const std::vector& buttons) + { + if (!buttons.empty()) + mConsole.printError ("MessageBox doesn't support buttons while in console mode"); + else + mConsole.printOK (message); + } + + bool Console::compile (const std::string& cmd, Compiler::Output& output) + { + try + { + std::istringstream input (cmd + '\n'); + + Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions()); + + Compiler::LineParser parser (*this, mCompilerContext, output.getLocals(), + output.getLiterals(), output.getCode()); + + scanner.scan (parser); + + return isGood(); + } + catch (const Compiler::SourceException&) + { + // error has already been reported via error handler + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + + return false; + } + + void Console::report (const std::string& message, const Compiler::TokenLoc& loc, Type type) + { + std::ostringstream error; + error << "column " << loc.mColumn << " (" << loc.mLiteral << "):"; + + printError (error.str()); + printError ((type==ErrorMessage ? "error: " : "warning: ") + message); + } + + void Console::report (const std::string& message, Type type) + { + printError ((type==ErrorMessage ? "error: " : "warning: ") + message); + } + + Console::Console(int w, int h, MWWorld::Environment& environment, + const Compiler::Extensions& extensions) + : Layout("openmw_console_layout.xml"), + mCompilerContext (MWScript::CompilerContext::Type_Console, environment), + mEnvironment (environment) + { + setCoord(10,10, w-10, h/2); + + getWidget(command, "edit_Command"); + getWidget(history, "list_History"); + + // Set up the command line box + command->eventEditSelectAccept = + newDelegate(this, &Console::acceptCommand); + command->eventKeyButtonPressed = + newDelegate(this, &Console::keyPress); + + // Set up the log window + history->setOverflowToTheLeft(true); + history->setEditStatic(true); + history->setVisibleVScroll(true); + + // compiler + mCompilerContext.setExtensions (&extensions); + } + + void Console::enable() + { + setVisible(true); + + // Give keyboard focus to the combo box whenever the console is + // turned on + MyGUI::InputManager::getInstance().setKeyFocusWidget(command); + } + + void Console::disable() + { + setVisible(false); + } + + void Console::setFont(const std::string &fntName) + { + history->setFontName(fntName); + command->setFontName(fntName); + } + + void Console::clearHistory() + { + history->setCaption(""); + } + + void Console::print(const std::string &msg) + { + history->addText(msg); + } + + void Console::printOK(const std::string &msg) + { + print("#FF00FF" + msg + "\n"); + } + + void Console::printError(const std::string &msg) + { + print("#FF2222" + msg + "\n"); + } + + void Console::keyPress(MyGUI::WidgetPtr _sender, + MyGUI::KeyCode key, + MyGUI::Char _char) + { + if(command_history.empty()) return; + + // Traverse history with up and down arrows + if(key == MyGUI::KeyCode::ArrowUp) + { + // If the user was editing a string, store it for later + if(current == command_history.end()) + editString = command->getCaption(); + + if(current != command_history.begin()) + { + current--; + command->setCaption(*current); + } + } + else if(key == MyGUI::KeyCode::ArrowDown) + { + if(current != command_history.end()) + { + current++; + + if(current != command_history.end()) + command->setCaption(*current); + else + // Restore the edit string + command->setCaption(editString); + } + } + } + + void Console::acceptCommand(MyGUI::EditPtr _sender) + { + const std::string &cm = command->getCaption(); + if(cm.empty()) return; + + // Add the command to the history, and set the current pointer to + // the end of the list + command_history.push_back(cm); + current = command_history.end(); + editString.clear(); + + // Log the command + print("#FFFFFF> " + cm + "\n"); + + Compiler::Locals locals; + Compiler::Output output (locals); + + if (compile (cm, output)) + { + try + { + ConsoleInterpreterContext interpreterContext (*this, mEnvironment, MWWorld::Ptr()); + Interpreter::Interpreter interpreter (interpreterContext); + MWScript::installOpcodes (interpreter); + std::vector code; + output.getCode (code); + interpreter.run (&code[0], code.size()); + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + } + + command->setCaption(""); + } +} + diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 54ba503306..25212d627f 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -10,10 +10,11 @@ #include #include #include -#include -#include +#include +#include #include "../mwscript/compilercontext.hpp" +#include "../mwscript/interpretercontext.hpp" namespace MWGui { @@ -22,51 +23,15 @@ namespace MWGui private: MWScript::CompilerContext mCompilerContext; + MWWorld::Environment& mEnvironment; - bool compile (const std::string& cmd) - { - try - { - std::istringstream input (cmd + '\n'); - - Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions()); - - Compiler::Locals locals; - Compiler::Literals literals; - std::vector code; - Compiler::LineParser parser (*this, mCompilerContext, locals, literals, code); - - scanner.scan (parser); - - return isGood(); - } - catch (const Compiler::SourceException&) - { - // error has already been reported via error handler - } - catch (const std::exception& error) - { - printError (std::string ("An exception has been thrown: ") + error.what()); - } - - return false; - } + bool compile (const std::string& cmd, Compiler::Output& output); /// Report error to the user. - virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type) - { - std::ostringstream error; - error << "column " << loc.mColumn << " (" << loc.mLiteral << "):"; - - printError (error.str()); - printError ((type==ErrorMessage ? "error: " : "warning: ") + message); - } + virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); /// Report a file related error - virtual void report (const std::string& message, Type type) - { - printError ((type==ErrorMessage ? "error: " : "warning: ") + message); - } + virtual void report (const std::string& message, Type type); public: MyGUI::EditPtr command; @@ -79,127 +44,35 @@ namespace MWGui StringList::iterator current; std::string editString; - Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions) - : Layout("openmw_console_layout.xml"), - mCompilerContext (MWScript::CompilerContext::Type_Console, environment) - { - setCoord(10,10, w-10, h/2); - - getWidget(command, "edit_Command"); - getWidget(history, "list_History"); - - // Set up the command line box - command->eventEditSelectAccept = - newDelegate(this, &Console::acceptCommand); - command->eventKeyButtonPressed = - newDelegate(this, &Console::keyPress); - - // Set up the log window - history->setOverflowToTheLeft(true); - history->setEditStatic(true); - history->setVisibleVScroll(true); - - // compiler - mCompilerContext.setExtensions (&extensions); - } - - void enable() - { - setVisible(true); - - // Give keyboard focus to the combo box whenever the console is - // turned on - MyGUI::InputManager::getInstance().setKeyFocusWidget(command); - } - - void disable() - { - setVisible(false); - } - - void setFont(const std::string &fntName) - { - history->setFontName(fntName); - command->setFontName(fntName); - } - - void clearHistory() - { - history->setCaption(""); - } + Console(int w, int h, MWWorld::Environment& environment, const Compiler::Extensions& extensions); + + void enable(); + + void disable(); + + void setFont(const std::string &fntName); + + void clearHistory(); // Print a message to the console. Messages may contain color // code, eg. "#FFFFFF this is white". - void print(const std::string &msg) - { history->addText(msg); } + void print(const std::string &msg); // These are pre-colored versions that you should use. /// Output from successful console command - void printOK(const std::string &msg) - { print("#FF00FF" + msg + "\n"); } + void printOK(const std::string &msg); /// Error message - void printError(const std::string &msg) - { print("#FF2222" + msg + "\n"); } + void printError(const std::string &msg); private: void keyPress(MyGUI::WidgetPtr _sender, MyGUI::KeyCode key, - MyGUI::Char _char) - { - if(command_history.empty()) return; - - // Traverse history with up and down arrows - if(key == MyGUI::KeyCode::ArrowUp) - { - // If the user was editing a string, store it for later - if(current == command_history.end()) - editString = command->getCaption(); - - if(current != command_history.begin()) - { - current--; - command->setCaption(*current); - } - } - else if(key == MyGUI::KeyCode::ArrowDown) - { - if(current != command_history.end()) - { - current++; - - if(current != command_history.end()) - command->setCaption(*current); - else - // Restore the edit string - command->setCaption(editString); - } - } - } - - void acceptCommand(MyGUI::EditPtr _sender) - { - const std::string &cm = command->getCaption(); - if(cm.empty()) return; - - // Add the command to the history, and set the current pointer to - // the end of the list - command_history.push_back(cm); - current = command_history.end(); - editString.clear(); - - // Log the command - print("#FFFFFF> " + cm + "\n"); - - if (compile (cm)) - { - // TODO execute command - } - - command->setCaption(""); - } + MyGUI::Char _char); + + void acceptCommand(MyGUI::EditPtr _sender); }; } #endif From 6e3aacca086b46d3e5a8836341f326846465d96a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 10:10:59 +0200 Subject: [PATCH 03/10] CMakeLists fix --- apps/openmw/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 6833ce0690..b3d0649a8d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -88,9 +88,9 @@ set(GAMEWORLD_HEADER source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER}) -set(OPENMW_CPP ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT} ${GAMESOUND} ${GAMEGUI} ${GAMEWORLD} ${GAMEGUI}) +set(OPENMW_CPP ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT} ${GAMESOUND} ${GAMEGUI} ${GAMEWORLD}) set(OPENMW_HEADER ${GAME_HEADER} ${GAMEREND_HEADER} ${GAMEINPUT_HEADER} ${GAMESCRIPT_HEADER} - ${GAMESOUND_HEADER} ${GAMEGUI_HEADER} ${GAMEWORLD_HEADER} ${GAMEGUI_HEADER}) + ${GAMESOUND_HEADER} ${GAMEGUI_HEADER} ${GAMEWORLD_HEADER}) # Main executable add_executable(openmw From a87175446c084e305af382290a7593aa9cee5c6c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 10:28:58 +0200 Subject: [PATCH 04/10] disable windows on startup when --new-game is used --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwgui/window_manager.cpp | 4 ++-- apps/openmw/mwgui/window_manager.hpp | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2a93561fec..51d1f79b29 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -209,7 +209,7 @@ void OMW::Engine::go() MWScript::registerExtensions (mExtensions); mEnvironment.mWindowManager = new MWGui::WindowManager(mGuiManager->getGui(), mEnvironment, - mExtensions); + mExtensions, mNewGame); mEnvironment.mSoundManager = new MWSound::SoundManager; diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index e83e096505..1cd70ec088 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -8,8 +8,8 @@ using namespace MWGui; WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment, - const Compiler::Extensions& extensions) - : gui(_gui), mode(GM_Game), shown(GW_ALL), allowed(GW_ALL) + const Compiler::Extensions& extensions, bool newGame) + : gui(_gui), mode(GM_Game), shown(GW_ALL), allowed(newGame ? GW_None : GW_ALL) { // Get size info from the Gui object assert(gui); diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index 2246dbd9f3..24021a6c60 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -102,11 +102,14 @@ namespace MWGui public: /// The constructor needs the main Gui object WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment, - const Compiler::Extensions& extensions); + const Compiler::Extensions& extensions, bool newGame); virtual ~WindowManager(); void setMode(GuiMode newMode) { + if (newMode==GM_Inventory && allowed==GW_None) + return; + mode = newMode; updateVisible(); } From 01edd8deb5406d6d1f7eeedcb40abf61247e96de Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 10:57:21 +0200 Subject: [PATCH 05/10] compiler exception class fixes --- components/compiler/exception.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/compiler/exception.hpp b/components/compiler/exception.hpp index 9793158017..a286631158 100644 --- a/components/compiler/exception.hpp +++ b/components/compiler/exception.hpp @@ -9,6 +9,8 @@ namespace Compiler class SourceException : public std::exception { + public: + virtual const char *what() const throw() { return "compile error";} ///< Return error message }; @@ -17,6 +19,8 @@ namespace Compiler class FileException : public SourceException { + public: + virtual const char *what() const throw() { return "can't read file"; } ///< Return error message }; @@ -24,7 +28,10 @@ namespace Compiler /// \brief Exception: EOF condition encountered class EOFException : public SourceException - { virtual const char *what() const throw() { return "end of file"; } + { + public: + + virtual const char *what() const throw() { return "end of file"; } ///< Return error message }; } From cf7150e585f8d03c8787d86e48feb54f86a670da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 13:34:52 +0200 Subject: [PATCH 06/10] implemented naked expressions in lineparser (used in console; result is send through messagebox interface) --- apps/openmw/mwgui/console.cpp | 6 +- components/compiler/lineparser.cpp | 121 ++++++++++++++++++++++++++++- components/compiler/lineparser.hpp | 8 +- 3 files changed, 129 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index f624bfb036..d9148028f2 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -40,18 +40,20 @@ namespace MWGui { try { + ErrorHandler::reset(); + std::istringstream input (cmd + '\n'); Compiler::Scanner scanner (*this, input, mCompilerContext.getExtensions()); Compiler::LineParser parser (*this, mCompilerContext, output.getLocals(), - output.getLiterals(), output.getCode()); + output.getLiterals(), output.getCode(), true); scanner.scan (parser); return isGood(); } - catch (const Compiler::SourceException&) + catch (const Compiler::SourceException& error) { // error has already been reported via error handler } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 22f7f458d9..927990a328 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -11,19 +11,67 @@ namespace Compiler { + void LineParser::parseExpression (Scanner& scanner, const TokenLoc& loc) + { + mExprParser.reset(); + + if (!mExplicit.empty()) + { + mExprParser.parseName (mExplicit, loc, scanner); + mExprParser.parseSpecial (Scanner::S_ref, loc, scanner); + } + + scanner.scan (mExprParser); + + char type = mExprParser.append (mCode); + mState = EndState; + + switch (type) + { + case 'l': + + Generator::message (mCode, mLiterals, "%g", 0); + break; + + case 'f': + + Generator::message (mCode, mLiterals, "%f", 0); + break; + + default: + + throw std::runtime_error ("unknown expression result type"); + } + } + LineParser::LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, - Literals& literals, std::vector& code) + Literals& literals, std::vector& code, bool allowExpression) : Parser (errorHandler, context), mLocals (locals), mLiterals (literals), mCode (code), - mState (BeginState), mExprParser (errorHandler, context, locals, literals) + mState (BeginState), mExprParser (errorHandler, context, locals, literals), + mAllowExpression (allowExpression) {} bool LineParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner) { + if (mAllowExpression && mState==BeginState) + { + scanner.putbackInt (value, loc); + parseExpression (scanner, loc); + return true; + } + return Parser::parseInt (value, loc, scanner); } bool LineParser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner) { + if (mAllowExpression && mState==BeginState) + { + scanner.putbackFloat (value, loc); + parseExpression (scanner, loc); + return true; + } + return Parser::parseFloat (value, loc, scanner); } @@ -129,6 +177,29 @@ namespace Compiler return false; } + if (mState==BeginState && mAllowExpression) + { + std::string name2 = toLower (name); + + char type = mLocals.getType (name2); + + if (type!=' ') + { + scanner.putbackName (name, loc); + parseExpression (scanner, loc); + return true; + } + + type = getContext().getGlobalType (name2); + + if (type!=' ') + { + scanner.putbackName (name, loc); + parseExpression (scanner, loc); + return true; + } + } + if (mState==BeginState && getContext().isId (name)) { mState = PotentialExplicitState; @@ -172,6 +243,30 @@ namespace Compiler return true; } } + + if (mAllowExpression) + { + if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance) + { + scanner.putbackKeyword (keyword, loc); + parseExpression (scanner, loc); + return true; + } + + if (const Extensions *extensions = getContext().getExtensions()) + { + char returnType; + std::string argumentType; + + if (extensions->isFunction (keyword, returnType, argumentType, + !mExplicit.empty())) + { + scanner.putbackKeyword (keyword, loc); + parseExpression (scanner, loc); + return true; + } + } + } } if (mState==BeginState) @@ -232,13 +327,25 @@ namespace Compiler mState = EndState; return true; } + + if (mAllowExpression) + { + if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode || + keyword==Scanner::K_random || keyword==Scanner::K_scriptrunning || + keyword==Scanner::K_getsecondspassed) + { + scanner.putbackKeyword (keyword, loc); + parseExpression (scanner, loc); + return true; + } + } return Parser::parseKeyword (keyword, loc, scanner); } bool LineParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner) { - if (code==Scanner::S_newline && mState==EndState) + if (code==Scanner::S_newline && (mState==EndState || mState==BeginState)) return false; if (code==Scanner::S_comma && mState==MessageState) @@ -252,6 +359,14 @@ namespace Compiler mState = ExplicitState; return true; } + + if (mAllowExpression && mState==BeginState && + (code==Scanner::S_open || code==Scanner::S_minus)) + { + scanner.putbackSpecial (code, loc); + parseExpression (scanner, loc); + return true; + } return Parser::parseSpecial (code, loc, scanner); } diff --git a/components/compiler/lineparser.hpp b/components/compiler/lineparser.hpp index 717d734510..c407d3b6b8 100644 --- a/components/compiler/lineparser.hpp +++ b/components/compiler/lineparser.hpp @@ -35,11 +35,17 @@ namespace Compiler std::string mExplicit; char mType; ExprParser mExprParser; + bool mAllowExpression; + + void parseExpression (Scanner& scanner, const TokenLoc& loc); public: LineParser (ErrorHandler& errorHandler, Context& context, Locals& locals, - Literals& literals, std::vector& code); + Literals& literals, std::vector& code, + bool allowExpression = false); + ///< \param allowExpression Allow lines consisting of a naked expression + /// (result is send to the messagebox interface) virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner); ///< Handle an int token. From c8a18b7d70e70912d52aa759e517a12cadd593fc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 14:10:52 +0200 Subject: [PATCH 07/10] use global variable timescale instead of fixed factor --- apps/openmw/engine.cpp | 5 +++-- apps/openmw/mwworld/world.cpp | 5 +++++ apps/openmw/mwworld/world.hpp | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 51d1f79b29..b7480cc3cf 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -51,8 +51,9 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) // global scripts mEnvironment.mGlobalScripts->run (mEnvironment); - // passing of time (30 times as fast as RL time) - mEnvironment.mWorld->advanceTime ((mEnvironment.mFrameDuration*30)/3600); + // passing of time + mEnvironment.mWorld->advanceTime ( + mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600); return true; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index f93b81890e..301111d060 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -358,4 +358,9 @@ namespace MWWorld { mSkyManager->setMoonColour (red); } + + float World::getTimeScaleFactor() const + { + return mGlobalVariables->getInt ("timescale"); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 2873a69d14..d94e9d766d 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -103,6 +103,8 @@ namespace MWWorld int getSecundaPhase() const; void setMoonColour (bool red); + + float getTimeScaleFactor() const; }; } From 74f3eb6ad4245145ffe40bc715e503fccdaacc59 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 14:12:50 +0200 Subject: [PATCH 08/10] stop time while GUI is up --- apps/openmw/engine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b7480cc3cf..78e97c6ded 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -52,8 +52,9 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) mEnvironment.mGlobalScripts->run (mEnvironment); // passing of time - mEnvironment.mWorld->advanceTime ( - mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600); + if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game) + mEnvironment.mWorld->advanceTime ( + mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600); return true; } From e6707534978a9a153003a9cb3f94ba158552b0cd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 14:48:03 +0200 Subject: [PATCH 09/10] fixed handling of global variables of type short --- apps/openmw/mwworld/globals.cpp | 2 +- apps/openmw/mwworld/globals.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 6a45a51ece..acaa4243d9 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -40,7 +40,7 @@ namespace MWWorld case ESM::VT_Short: type = 's'; - value.mShort = *reinterpret_cast ( + value.mShort = *reinterpret_cast ( &iter->second.value); break; diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index 96ec3f3ce8..f946b8d14e 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -21,7 +21,7 @@ namespace MWWorld { Interpreter::Type_Float mFloat; Interpreter::Type_Float mLong; // Why Morrowind, why? :( - Interpreter::Type_Integer mShort; + Interpreter::Type_Float mShort; }; typedef std::map > Collection; From 77e03f0f31d1bb6705a1fe56090eb4517b2f65c2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Jul 2010 15:01:35 +0200 Subject: [PATCH 10/10] fixed global variable search to properly handle injected variables (DaysPassed) --- apps/openmw/mwscript/compilercontext.cpp | 14 +------------- apps/openmw/mwworld/globals.cpp | 10 ++++++++++ apps/openmw/mwworld/globals.hpp | 3 +++ apps/openmw/mwworld/world.cpp | 5 +++++ apps/openmw/mwworld/world.hpp | 3 +++ 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 5e4882f259..de00353caf 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -17,19 +17,7 @@ namespace MWScript char CompilerContext::getGlobalType (const std::string& name) const { - if (const ESM::Global *global = mEnvironment.mWorld->getStore().globals.find (name)) - { - switch (global->type) - { - case ESM::VT_Short: return 's'; - case ESM::VT_Int: return 'l'; - case ESM::VT_Float: return 'f'; - - default: return ' '; - } - } - - return ' '; + return mEnvironment.mWorld->getGlobalVariableType (name); } bool CompilerContext::isId (const std::string& name) const diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index acaa4243d9..b20a678bcb 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -145,5 +145,15 @@ namespace MWWorld default: throw std::runtime_error ("unsupported global variable type"); } } + + char Globals::getType (const std::string& name) const + { + Collection::const_iterator iter = mVariables.find (name); + + if (iter==mVariables.end()) + return ' '; + + return iter->second.first; + } } diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index f946b8d14e..6aa54ade29 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -53,6 +53,9 @@ namespace MWWorld float getFloat (const std::string& name) const; ///< Get value independently from real type. + + char getType (const std::string& name) const; + ///< If there is no global variable with this name, ' ' is returned. }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 301111d060..7c806230a5 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -228,6 +228,11 @@ namespace MWWorld return (*mGlobalVariables)[name]; } + char World::getGlobalVariableType (const std::string& name) const + { + return mGlobalVariables->getType (name); + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index d94e9d766d..dda80054a1 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -82,6 +82,9 @@ namespace MWWorld Globals::Data& getGlobalVariable (const std::string& name); + char getGlobalVariableType (const std::string& name) const; + ///< Return ' ', if there is no global variable with this name. + Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells.