From 5d46fc869ce984bfb6856f8edef2929a0e9921ab Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 3 Jul 2010 20:35:59 +0200 Subject: [PATCH] added missing sound script functionality; various script-related bug-fixes --- apps/openmw/engine.cpp | 3 +- apps/openmw/mwscript/scriptmanager.cpp | 9 +- apps/openmw/mwsound/extensions.cpp | 175 +++++++++++++++++++++++-- apps/openmw/mwsound/soundmanager.cpp | 2 +- apps/openmw/mwsound/soundmanager.hpp | 2 +- components/compiler/extensions.cpp | 43 +++++- components/compiler/extensions.hpp | 21 +++ components/compiler/lineparser.cpp | 16 +++ components/interpreter/interpreter.cpp | 4 +- 9 files changed, 258 insertions(+), 17 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e801850978..f3a68b8c50 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -57,7 +57,8 @@ void OMW::Engine::processCommands() } OMW::Engine::Engine() -: mWorld(NULL), mDebug (false), mSoundManager (0), mScriptManager (0), mScriptContext (0) +: mWorld(NULL), mDebug (false), mVerboseScripts (false), mSoundManager (0), mScriptManager (0), + mScriptContext (0) { mspCommandServer.reset( new OMW::CommandServer::Server(&mCommandQueue, kCommandServerPort)); diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index cb72a439aa..7aea55693c 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -17,6 +17,8 @@ #include "../mwsound/extensions.hpp" +#include "cellextensions.hpp" + namespace MWScript { ScriptManager::ScriptManager (const ESMS::ESMStore& store, bool verbose, @@ -104,9 +106,13 @@ namespace MWScript installOpcodes (interpreter); interpreter.run (&iter->second[0], iter->second.size()); } - catch (...) + catch (const std::exception& e) { std::cerr << "exeution of script " << name << " failed." << std::endl; + + if (mVerbose) + std::cerr << "(" << e.what() << ")" << std::endl; + iter->second.clear(); // don't execute again. } } @@ -114,6 +120,7 @@ namespace MWScript void ScriptManager::installOpcodes (Interpreter::Interpreter& interpreter) { Interpreter::installOpcodes (interpreter); + Cell::installOpcodes (interpreter); MWSound::installOpcodes (interpreter); } } diff --git a/apps/openmw/mwsound/extensions.cpp b/apps/openmw/mwsound/extensions.cpp index 9ec5b38c61..fe9bf9d374 100644 --- a/apps/openmw/mwsound/extensions.cpp +++ b/apps/openmw/mwsound/extensions.cpp @@ -17,6 +17,26 @@ namespace MWSound { namespace Script { + class OpSay : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string file = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + std::string text = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + context.getSoundManager().say (context.getReference(), file, text, + context); + } + }; + class OpSayDone : public Interpreter::Opcode0 { public: @@ -31,6 +51,125 @@ namespace MWSound } }; + class OpStreamMusic : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string sound = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + context.getSoundManager().streamMusic (sound, context); + } + }; + + class OpPlaySound : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string sound = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + context.getSoundManager().playSound (sound, 1.0, 1.0, context); + } + }; + + class OpPlaySoundVP : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string sound = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + float volume = *reinterpret_cast (&runtime[0]); + runtime.pop(); + + float pitch = *reinterpret_cast (&runtime[0]); + runtime.pop(); + + context.getSoundManager().playSound (sound, volume, pitch, context); + } + }; + + class OpPlaySound3D : public Interpreter::Opcode0 + { + bool mLoop; + + public: + + OpPlaySound3D (bool loop) : mLoop (loop) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string sound = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + context.getSoundManager().playSound3D (context.getReference(), sound, + 1.0, 1.0, mLoop, context); + } + }; + + class OpPlaySoundVP3D : public Interpreter::Opcode0 + { + bool mLoop; + + public: + + OpPlaySoundVP3D (bool loop) : mLoop (loop) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string sound = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + float volume = *reinterpret_cast (&runtime[0]); + runtime.pop(); + + float pitch = *reinterpret_cast (&runtime[0]); + runtime.pop(); + + context.getSoundManager().playSound3D (context.getReference(), sound, volume, + pitch, mLoop, context); + + } + }; + + class OpStopSound : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string sound = runtime.getStringLiteral (runtime[0]); + runtime.pop(); + + context.getSoundManager().stopSound3D (context.getReference(), sound, context); + } + }; + class OpGetSoundPlaying : public Interpreter::Opcode0 { public: @@ -55,25 +194,43 @@ namespace MWSound const int opcodePlaySoundVP = 0x2000005; const int opcodePlaySound3D = 0x2000006; const int opcodePlaySound3DVP = 0x2000007; - const int opcodeStopSound = 0x2000008; - const int opcodeGetSoundPlaying = 0x2000009; + const int opcodePlayLoopSound3D = 0x2000008; + const int opcodePlayLoopSound3DVP = 0x2000009; + const int opcodeStopSound = 0x200000a; + const int opcodeGetSoundPlaying = 0x200000b; } - // TODO opcodeSay, opcodeStreamMusic, opcodePlaySound, opcodePlaySoundVP, - // opcodePlaySound, opcodePlaySound, opcodeStopSound - void registerExtensions (Compiler::Extensions& extensions) { + extensions.registerInstruction ("say", "SS", Script::opcodeSay); extensions.registerFunction ("saydone", 'l', "", Script::opcodeSayDone); - - extensions.registerFunction ("getsoundplaying", 'l', "S", Script::opcodeGetSoundPlaying); - + extensions.registerInstruction ("streammusic", "S", Script::opcodeStreamMusic); + extensions.registerInstruction ("playsound", "S", Script::opcodePlaySound); + extensions.registerInstruction ("playsoundvp", "Sll", Script::opcodePlaySoundVP); + extensions.registerInstruction ("playsound3d", "S", Script::opcodePlaySound3D); + extensions.registerInstruction ("playsound3dvp", "Sll", Script::opcodePlaySound3DVP); + extensions.registerInstruction ("playloopsound3d", "S", Script::opcodePlayLoopSound3D); + extensions.registerInstruction ("playloopsound3dvp", "Sll", + Script::opcodePlayLoopSound3DVP); + extensions.registerInstruction ("stopsound", "S", Script::opcodeStopSound); + extensions.registerFunction ("getsoundplaying", 'l', "S", Script::opcodeGetSoundPlaying); } void installOpcodes (Interpreter::Interpreter& interpreter) { + interpreter.installSegment5 (Script::opcodeSay, new Script::OpSay); interpreter.installSegment5 (Script::opcodeSayDone, new Script::OpSayDone); - + interpreter.installSegment5 (Script::opcodeStreamMusic, new Script::OpStreamMusic); + interpreter.installSegment5 (Script::opcodePlaySound, new Script::OpPlaySound); + interpreter.installSegment5 (Script::opcodePlaySoundVP, new Script::OpPlaySoundVP); + interpreter.installSegment5 (Script::opcodePlaySound3D, new Script::OpPlaySound3D (false)); + interpreter.installSegment5 (Script::opcodePlaySound3DVP, + new Script::OpPlaySoundVP3D (false)); + interpreter.installSegment5 (Script::opcodePlayLoopSound3D, + new Script::OpPlaySound3D (true)); + interpreter.installSegment5 (Script::opcodePlayLoopSound3DVP, + new Script::OpPlaySoundVP3D (true)); + interpreter.installSegment5 (Script::opcodeStopSound, new Script::OpStopSound); interpreter.installSegment5 (Script::opcodeGetSoundPlaying, new Script::OpGetSoundPlaying); } } diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 6878ba9eab..bfe51686ba 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -35,7 +35,7 @@ namespace MWSound } void SoundManager::playSound3D (MWWorld::Ptr reference, const std::string& soundId, - float volume, float pitch, Interpreter::Context& context) + float volume, float pitch, bool loop, Interpreter::Context& context) { std::cout << "sound effect: playing sound " << soundId diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index db39e0666b..5a79c0c27b 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -50,7 +50,7 @@ namespace MWSound ///< Play a sound, independently of 3D-position void playSound3D (MWWorld::Ptr reference, const std::string& soundId, - float volume, float pitch, Interpreter::Context& context); + float volume, float pitch, bool loop, Interpreter::Context& context); ///< Play a sound from an object void stopSound3D (MWWorld::Ptr reference, const std::string& soundId, diff --git a/components/compiler/extensions.cpp b/components/compiler/extensions.cpp index d83f368482..ff05208dee 100644 --- a/components/compiler/extensions.cpp +++ b/components/compiler/extensions.cpp @@ -31,7 +31,18 @@ namespace Compiler argumentType = iter->second.mArguments; return true; } - + + bool Extensions::isInstruction (int keyword, std::string& argumentType) const + { + std::map::const_iterator iter = mInstructions.find (keyword); + + if (iter==mInstructions.end()) + return false; + + argumentType = iter->second.mArguments; + return true; + } + void Extensions::registerFunction (const std::string& keyword, char returnType, const std::string& argumentType, int segment5code) { @@ -48,7 +59,23 @@ namespace Compiler mFunctions.insert (std::make_pair (code, function)); } + + void Extensions::registerInstruction (const std::string& keyword, + const std::string& argumentType, int segment5code) + { + assert (segment5code>=33554432 && segment5code<=67108863); + int code = mNextKeywordIndex--; + + mKeywords.insert (std::make_pair (keyword, code)); + + Instruction instruction; + instruction.mArguments = argumentType; + instruction.mCode = segment5code; + + mInstructions.insert (std::make_pair (code, instruction)); + } + void Extensions::generateFunctionCode (int keyword, std::vector& code) const { @@ -57,6 +84,18 @@ namespace Compiler if (iter==mFunctions.end()) throw std::logic_error ("unknown custom function keyword"); - Generator::segment5 (iter->second.mCode); + code.push_back (Generator::segment5 (iter->second.mCode)); } + + void Extensions::generateInstructionCode (int keyword, + std::vector& code) + const + { + std::map::const_iterator iter = mInstructions.find (keyword); + + if (iter==mInstructions.end()) + throw std::logic_error ("unknown custom instruction keyword"); + + code.push_back (Generator::segment5 (iter->second.mCode)); + } } diff --git a/components/compiler/extensions.hpp b/components/compiler/extensions.hpp index 975abcef61..f864daf1b7 100644 --- a/components/compiler/extensions.hpp +++ b/components/compiler/extensions.hpp @@ -19,10 +19,17 @@ namespace Compiler std::string mArguments; int mCode; }; + + struct Instruction + { + std::string mArguments; + int mCode; + }; int mNextKeywordIndex; std::map mKeywords; std::map mFunctions; + std::map mInstructions; public: @@ -36,6 +43,9 @@ namespace Compiler bool isFunction (int keyword, char& returnType, std::string& argumentType) const; ///< Is this keyword registered with a function? If yes, return return and argument /// types. + + bool isInstruction (int keyword, std::string& argumentType) const; + ///< Is this keyword registered with a function? If yes, return argument types. void registerFunction (const std::string& keyword, char returnType, const std::string& argumentType, int segment5code); @@ -44,9 +54,20 @@ namespace Compiler /// - keyword must be unique /// \note Currently only segment 5 opcodes are supported. + void registerInstruction (const std::string& keyword, + const std::string& argumentType, int segment5code); + ///< Register a custom instruction + /// - keyword must be all lower case. + /// - keyword must be unique + /// \note Currently only segment 5 opcodes are supported. + void generateFunctionCode (int keyword, std::vector& code) const; ///< Append code for function to \a code. + + void generateInstructionCode (int keyword, std::vector& code) + const; + ///< Append code for function to \a code. }; } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 50f89ab7f8..347ba2deb2 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -7,6 +7,7 @@ #include "skipparser.hpp" #include "locals.hpp" #include "generator.hpp" +#include "extensions.hpp" namespace Compiler { @@ -135,6 +136,21 @@ namespace Compiler mState = EndState; return true; } + + // check for custom extensions + if (const Extensions *extensions = getContext().getExtensions()) + { + std::string argumentType; + + if (extensions->isInstruction (keyword, argumentType)) + { + mExprParser.parseArguments (argumentType, scanner, mCode, true); + + extensions->generateInstructionCode (keyword, mCode); + mState = EndState; + return true; + } + } } else if (mState==SetLocalVarState && keyword==Scanner::K_to) { diff --git a/components/interpreter/interpreter.cpp b/components/interpreter/interpreter.cpp index d0f8107db9..f3ebd97a7a 100644 --- a/components/interpreter/interpreter.cpp +++ b/components/interpreter/interpreter.cpp @@ -76,7 +76,7 @@ namespace Interpreter if (iter==mSegment3.end()) abortUnknownCode (3, opcode); - + iter->second->execute (mRuntime, arg0); return; @@ -106,7 +106,7 @@ namespace Interpreter if (iter==mSegment5.end()) abortUnknownCode (5, opcode); - + iter->second->execute (mRuntime); return;