diff --git a/apps/mwinterpreter/context.cpp b/apps/mwinterpreter/context.cpp index abe7c26112..9119521fb5 100644 --- a/apps/mwinterpreter/context.cpp +++ b/apps/mwinterpreter/context.cpp @@ -101,6 +101,15 @@ namespace SAInterpreter void Context::setGlobalFloat (const std::string& name, float value) {} + bool Context::isScriptRunning (const std::string& name) + { + return false; + } + + void Context::startScript (const std::string& name) {} + + void Context::stopScript (const std::string& name) {} + void Context::report() { std::size_t i = 0; diff --git a/apps/mwinterpreter/context.hpp b/apps/mwinterpreter/context.hpp index e02d84b703..217b2a1d4f 100644 --- a/apps/mwinterpreter/context.hpp +++ b/apps/mwinterpreter/context.hpp @@ -52,6 +52,12 @@ namespace SAInterpreter virtual void setGlobalFloat (const std::string& name, float value); + virtual bool isScriptRunning (const std::string& name); + + virtual void startScript (const std::string& name); + + virtual void stopScript (const std::string& name); + void report(); ///< Write state to std::cout }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e93bd95872..30cae5897b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -42,7 +42,7 @@ bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt) executeLocalScripts(); // global scripts - mGlobalScripts->run (mEnvironment); + mEnvironment.mGlobalScripts->run (mEnvironment); return true; } @@ -63,7 +63,7 @@ void OMW::Engine::processCommands() } OMW::Engine::Engine() -: mDebug (false), mVerboseScripts (false), mScriptManager (0), mGlobalScripts (0), +: mDebug (false), mVerboseScripts (false), mNewGame (false), mScriptManager (0), mScriptContext (0) { mspCommandServer.reset( @@ -75,7 +75,7 @@ OMW::Engine::~Engine() // mspCommandServer->stop(); delete mEnvironment.mWorld; delete mEnvironment.mSoundManager; - delete mGlobalScripts; + delete mEnvironment.mGlobalScripts; delete mScriptManager; delete mScriptContext; } @@ -146,6 +146,11 @@ void OMW::Engine::enableVerboseScripts() mVerboseScripts = true; } +void OMW::Engine::setNewGame() +{ + mNewGame = true; +} + // Initialise and enter main loop. void OMW::Engine::go() @@ -174,7 +179,7 @@ void OMW::Engine::go() loadBSA(); // Create the world - mEnvironment.mWorld = new MWWorld::World (mOgre, mDataDir, mMaster, mCellName); + mEnvironment.mWorld = new MWWorld::World (mOgre, mDataDir, mMaster, mCellName, mNewGame); mEnvironment.mSoundManager = new MWSound::SoundManager; @@ -187,7 +192,8 @@ void OMW::Engine::go() mScriptManager = new MWScript::ScriptManager (mEnvironment.mWorld->getStore(), mVerboseScripts, *mScriptContext); - mGlobalScripts = new MWScript::GlobalScripts (mEnvironment.mWorld->getStore(), *mScriptManager); + mEnvironment.mGlobalScripts = new MWScript::GlobalScripts (mEnvironment.mWorld->getStore(), + *mScriptManager); std::cout << "Setting up input system\n"; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index a56dca156b..f0b46c6ab3 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -23,7 +23,6 @@ namespace Compiler namespace MWScript { class ScriptManager; - class GlobalScripts; } namespace MWSound @@ -50,13 +49,13 @@ namespace OMW std::string mMaster; bool mDebug; bool mVerboseScripts; + bool mNewGame; TsDeque mCommandQueue; std::auto_ptr mspCommandServer; MWWorld::Environment mEnvironment; MWScript::ScriptManager *mScriptManager; - MWScript::GlobalScripts *mGlobalScripts; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; @@ -101,6 +100,9 @@ namespace OMW /// Enable verbose script output void enableVerboseScripts(); + + /// Start as a new game. + void setNewGame(); /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 0908c972cb..70530c2ef9 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -31,6 +31,7 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) "master file") ( "debug", "debug mode" ) ( "script-verbose", "verbose script output" ) + ( "new-game", "activate char gen/new game mechanics" ) ; bpo::variables_map variables; @@ -59,6 +60,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) if (variables.count ("script-verbose")) engine.enableVerboseScripts(); + if (variables.count ("new-game")) + engine.setNewGame(); + return true; } diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 8512eaaad5..14930b8280 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -1,5 +1,8 @@ #include "globalscripts.hpp" + +#include + #include "interpretercontext.hpp" #include "scriptmanager.hpp" @@ -25,22 +28,42 @@ namespace MWScript locals.configure (*script); - mScripts.insert (std::make_pair (name, locals)); + mScripts.insert (std::make_pair (name, std::make_pair (true, locals))); } } + void GlobalScripts::removeScript (const std::string& name) + { + std::map >::iterator iter = mScripts.find (name); + + if (iter!=mScripts.end()) + iter->second.first = false; + } + + bool GlobalScripts::isRunning (const std::string& name) const + { + std::map >::const_iterator iter = + mScripts.find (name); + + if (iter==mScripts.end()) + return false; + + return iter->second.first; + } + void GlobalScripts::run (MWWorld::Environment& environment) { - std::map::iterator iter = mScripts.begin(); - - while (iter!=mScripts.end()) + for (std::map >::iterator iter (mScripts.begin()); + iter!=mScripts.end(); ++iter) { - MWScript::InterpreterContext interpreterContext (environment, - &iter->second, MWWorld::Ptr()); - mScriptManager.run (iter->first, interpreterContext); - - ++iter; + if (iter->second.first) + { + MWScript::InterpreterContext interpreterContext (environment, + &iter->second.second, MWWorld::Ptr()); + mScriptManager.run (iter->first, interpreterContext); + } } + } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 9407050a6d..741968fcdc 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -24,7 +24,7 @@ namespace MWScript { const ESMS::ESMStore& mStore; ScriptManager& mScriptManager; - std::map mScripts; + std::map > mScripts; // running, local variables public: @@ -32,7 +32,12 @@ namespace MWScript void addScript (const std::string& name); + void removeScript (const std::string& name); + + bool isRunning (const std::string& name) const; + void run (MWWorld::Environment& environment); + ///< run all active global scripts }; } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 8bcbbe5c7a..525aef1836 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -6,12 +6,14 @@ #include -#include "locals.hpp" #include "../mwworld/world.hpp" +#include "locals.hpp" +#include "globalscripts.hpp" + namespace MWScript { - InterpreterContext::InterpreterContext (const MWWorld::Environment& environment, + InterpreterContext::InterpreterContext (MWWorld::Environment& environment, MWScript::Locals *locals, MWWorld::Ptr reference) : mEnvironment (environment), mLocals (locals), mReference (reference) {} @@ -119,7 +121,22 @@ namespace MWScript mEnvironment.mWorld->getGlobalVariable (name) = *reinterpret_cast (&value); } - + + bool InterpreterContext::isScriptRunning (const std::string& name) + { + return mEnvironment.mGlobalScripts->isRunning (name); + } + + void InterpreterContext::startScript (const std::string& name) + { + mEnvironment.mGlobalScripts->addScript (name); + } + + void InterpreterContext::stopScript (const std::string& name) + { + mEnvironment.mGlobalScripts->removeScript (name); + } + MWWorld::World& InterpreterContext::getWorld() { return *mEnvironment.mWorld; diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 2cb8b3bce5..f0efae65c8 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -22,13 +22,13 @@ namespace MWScript class InterpreterContext : public Interpreter::Context { - MWWorld::Environment mEnvironment; + MWWorld::Environment& mEnvironment; Locals *mLocals; MWWorld::Ptr mReference; public: - InterpreterContext (const MWWorld::Environment& environment, + InterpreterContext (MWWorld::Environment& environment, MWScript::Locals *locals, MWWorld::Ptr reference); ///< The ownership of \a locals is not transferred. 0-pointer allowed. @@ -61,6 +61,12 @@ namespace MWScript virtual void setGlobalFloat (const std::string& name, float value); + virtual bool isScriptRunning (const std::string& name); + + virtual void startScript (const std::string& name); + + virtual void stopScript (const std::string& name); + MWWorld::World& getWorld(); MWSound::SoundManager& getSoundManager(); diff --git a/apps/openmw/mwsound/extensions.cpp b/apps/openmw/mwsound/extensions.cpp index ba3a8352c2..4aee9827c0 100644 --- a/apps/openmw/mwsound/extensions.cpp +++ b/apps/openmw/mwsound/extensions.cpp @@ -205,15 +205,15 @@ namespace MWSound extensions.registerInstruction ("say", "SS", Script::opcodeSay); extensions.registerFunction ("saydone", 'l', "", Script::opcodeSayDone); extensions.registerInstruction ("streammusic", "S", Script::opcodeStreamMusic); - extensions.registerInstruction ("playsound", "S", Script::opcodePlaySound); - extensions.registerInstruction ("playsoundvp", "Sff", Script::opcodePlaySoundVP); - extensions.registerInstruction ("playsound3d", "S", Script::opcodePlaySound3D); - extensions.registerInstruction ("playsound3dvp", "Sff", Script::opcodePlaySound3DVP); - extensions.registerInstruction ("playloopsound3d", "S", Script::opcodePlayLoopSound3D); - extensions.registerInstruction ("playloopsound3dvp", "Sff", + extensions.registerInstruction ("playsound", "c", Script::opcodePlaySound); + extensions.registerInstruction ("playsoundvp", "cff", Script::opcodePlaySoundVP); + extensions.registerInstruction ("playsound3d", "c", Script::opcodePlaySound3D); + extensions.registerInstruction ("playsound3dvp", "cff", Script::opcodePlaySound3DVP); + extensions.registerInstruction ("playloopsound3d", "c", Script::opcodePlayLoopSound3D); + extensions.registerInstruction ("playloopsound3dvp", "cff", Script::opcodePlayLoopSound3DVP); - extensions.registerInstruction ("stopsound", "S", Script::opcodeStopSound); - extensions.registerFunction ("getsoundplaying", 'l', "S", Script::opcodeGetSoundPlaying); + extensions.registerInstruction ("stopsound", "c", Script::opcodeStopSound); + extensions.registerFunction ("getsoundplaying", 'l', "c", Script::opcodeGetSoundPlaying); } void installOpcodes (Interpreter::Interpreter& interpreter) diff --git a/apps/openmw/mwworld/environment.hpp b/apps/openmw/mwworld/environment.hpp index 4decbf9600..b208d95a24 100644 --- a/apps/openmw/mwworld/environment.hpp +++ b/apps/openmw/mwworld/environment.hpp @@ -6,6 +6,11 @@ namespace MWSound class SoundManager; } +namespace MWScript +{ + class GlobalScripts; +} + namespace MWWorld { class World; @@ -13,10 +18,11 @@ namespace MWWorld ///< Collection of script-accessable sub-systems struct Environment { - Environment() : mWorld (0), mSoundManager (0) {} + Environment() : mWorld (0), mSoundManager (0), mGlobalScripts (0) {} World *mWorld; - MWSound::SoundManager *mSoundManager; + MWSound::SoundManager *mSoundManager; + MWScript::GlobalScripts *mGlobalScripts; }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 0381fa159a..217bff7daf 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -57,7 +57,7 @@ namespace MWWorld } World::World (Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir, - const std::string& master, const std::string& startCell) + const std::string& master, const std::string& startCell, bool newGame) : mSkyManager (0), mScene (renderer), mPlayerPos (mScene.getCamera()) { boost::filesystem::path masterPath (dataDir); @@ -79,6 +79,14 @@ namespace MWWorld iter != mStore.globals.list.end(); ++iter) mGlobalVariables.insert (std::make_pair (iter->first, iter->second.value)); + if (newGame) + { + // set new game mark + float newGameState = 1; + mGlobalVariables["chargenstate"] = + *reinterpret_cast (&newGameState); + } + std::cout << "\nSetting up cell rendering\n"; // This connects the cell data with the rendering scene. diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 98f22963ab..d39c457d20 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -62,7 +62,7 @@ namespace MWWorld public: World (Render::OgreRenderer& renderer, const boost::filesystem::path& master, - const std::string& dataDir, const std::string& startCell); + const std::string& dataDir, const std::string& startCell, bool newGame); ~World(); diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 6eee56e8df..fd44c5e41a 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -315,6 +315,17 @@ namespace Compiler mNextOperand = false; return true; } + else if (keyword==Scanner::K_scriptrunning) + { + mTokenLoc = loc; + parseArguments ("c", scanner); + + Generator::scriptRunning (mCode); + mOperands.push_back ('l'); + + mNextOperand = false; + return true; + } else { // check for custom extensions @@ -492,9 +503,10 @@ namespace Compiler for (std::string::const_iterator iter (arguments.begin()); iter!=arguments.end(); ++iter) { - if (*iter=='S') + if (*iter=='S' || *iter=='c') { stringParser.reset(); + if (*iter=='c') stringParser.smashCase(); scanner.scan (stringParser); if (invert) diff --git a/components/compiler/exprparser.hpp b/components/compiler/exprparser.hpp index 4ac74075cc..b8f295b5c1 100644 --- a/components/compiler/exprparser.hpp +++ b/components/compiler/exprparser.hpp @@ -94,7 +94,7 @@ namespace Compiler std::vector& code, bool invert = false); ///< Parse sequence of arguments specified by \a arguments. /// \param arguments Each character represents one arguments ('l': integer, - /// 'f': float, 'S': string) + /// 'f': float, 'S': string, 'c': string (case smashed)) /// \param invert Store arguments in reverted order. }; } diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 692a943480..f9893ad9a5 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -259,6 +259,21 @@ namespace { code.push_back (Compiler::Generator::segment5 (45)); } + + void opScriptRunning (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (46)); + } + + void opStartScript (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (47)); + } + + void opStopScript (Compiler::Generator::CodeContainer& code) + { + code.push_back (Compiler::Generator::segment5 (48)); + } } namespace Compiler @@ -635,6 +650,21 @@ namespace Compiler { opRandom (code); } + + void scriptRunning (CodeContainer& code) + { + opScriptRunning (code); + } + + void startScript (CodeContainer& code) + { + opStartScript (code); + } + + void stopScript (CodeContainer& code) + { + opStopScript (code); + } } } diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index 5115d71342..cebb5b00f6 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -100,6 +100,12 @@ namespace Compiler const std::string& name); void random (CodeContainer& code); + + void scriptRunning (CodeContainer& code); + + void startScript (CodeContainer& code); + + void stopScript (CodeContainer& code); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 699c07815c..8ce37b4148 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -145,6 +145,20 @@ namespace Compiler Generator::exit (mCode); mState = EndState; return true; + + case Scanner::K_startscript: + + mExprParser.parseArguments ("c", scanner, mCode, true); + Generator::startScript (mCode); + mState = EndState; + return true; + + case Scanner::K_stopscript: + + mExprParser.parseArguments ("c", scanner, mCode, true); + Generator::stopScript (mCode); + mState = EndState; + return true; } // check for custom extensions diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 7370e5c291..092d8074ae 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -244,6 +244,7 @@ namespace Compiler "getsquareroot", "menumode", "random", + "startscript", "stopscript", "scriptrunning", 0 }; diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 1af4547409..88e0706736 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -50,7 +50,8 @@ namespace Compiler K_set, K_to, K_getsquareroot, K_menumode, - K_random + K_random, + K_startscript, K_stopscript, K_scriptrunning }; enum special diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 4d3e6935bf..0e2e38be56 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -10,7 +10,7 @@ namespace Compiler { StringParser::StringParser (ErrorHandler& errorHandler, Context& context, Literals& literals) - : Parser (errorHandler, context), mLiterals (literals), mState (StartState) + : Parser (errorHandler, context), mLiterals (literals), mState (StartState), mSmashCase (false) { } @@ -20,7 +20,11 @@ namespace Compiler { if (mState==StartState || mState==CommaState) { - Generator::pushString (mCode, mLiterals, name); + if (mSmashCase) + Generator::pushString (mCode, mLiterals, toLower (name)); + else + Generator::pushString (mCode, mLiterals, name); + return false; } @@ -47,6 +51,12 @@ namespace Compiler { mState = StartState; mCode.clear(); + mSmashCase = false; + } + + void StringParser::smashCase() + { + mSmashCase = false; } } diff --git a/components/compiler/stringparser.hpp b/components/compiler/stringparser.hpp index 9d128e2d38..f692c650b8 100644 --- a/components/compiler/stringparser.hpp +++ b/components/compiler/stringparser.hpp @@ -21,6 +21,7 @@ namespace Compiler Literals& mLiterals; State mState; std::vector mCode; + bool mSmashCase; public: @@ -38,8 +39,11 @@ namespace Compiler void append (std::vector& code); ///< Append code for parsed string. + void smashCase(); + ///< Transform all scanned strings to lower case + void reset(); - ///< Reset parser to clean state. + ///< Reset parser to clean state (this includes the smashCase function). }; } diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 42af70b6cb..3373d33039 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -45,7 +45,13 @@ namespace Interpreter virtual void setGlobalLong (const std::string& name, int value) = 0; - virtual void setGlobalFloat (const std::string& name, float value) = 0; + virtual void setGlobalFloat (const std::string& name, float value) = 0; + + virtual bool isScriptRunning (const std::string& name) = 0; + + virtual void startScript (const std::string& name) = 0; + + virtual void stopScript (const std::string& name) = 0; }; } diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 458268e105..2812cd3801 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -104,6 +104,9 @@ op 42: replace stack[0] with global short stack[0] op 43: replace stack[0] with global long stack[0] op 44: replace stack[0] with global float stack[0] op 45: replace stack[0] with a random integer value in the range [0, stack[0]-1] -opcodes 46-33554431 unused +op 46: replace stack[0] with 1, if global script stack[0] is running, 0 else +op 47: start script stack[0] and pop +op 48: stop script stack[0] and pop +opcodes 49-33554431 unused opcodes 33554432-67108863 reserved for extensions diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 46740a9977..36fd01f013 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -9,6 +9,7 @@ #include "mathopcodes.hpp" #include "controlopcodes.hpp" #include "miscopcodes.hpp" +#include "scriptopcodes.hpp" namespace Interpreter { @@ -86,6 +87,11 @@ namespace Interpreter interpreter.installSegment3 (0, new OpMessageBox); interpreter.installSegment5 (38, new OpMenuMode); interpreter.installSegment5 (45, new OpRandom); + + // script control + interpreter.installSegment5 (46, new OpScriptRunning); + interpreter.installSegment5 (47, new OpStartScript); + interpreter.installSegment5 (48, new OpStopScript); } } diff --git a/components/interpreter/scriptopcodes.hpp b/components/interpreter/scriptopcodes.hpp new file mode 100644 index 0000000000..84fd546fb2 --- /dev/null +++ b/components/interpreter/scriptopcodes.hpp @@ -0,0 +1,47 @@ +#ifndef INTERPRETER_SCRIPTOPCODES_H_INCLUDED +#define INTERPRETER_SCRIPTOPCODES_H_INCLUDED + +#include "opcodes.hpp" +#include "runtime.hpp" +#include "context.hpp" + +namespace Interpreter +{ + class OpScriptRunning : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0]); + runtime[0] = runtime.getContext().isScriptRunning (name); + } + }; + + class OpStartScript : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + runtime.getContext().startScript (name); + } + }; + + class OpStopScript : public Opcode0 + { + public: + + virtual void execute (Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + runtime.getContext().stopScript (name); + } + }; +} + +#endif +