forked from mirror/openmw-tes3mp
added missing sound script functionality; various script-related bug-fixes
This commit is contained in:
parent
eeeb9b09f8
commit
5d46fc869c
9 changed files with 258 additions and 17 deletions
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MWScript::InterpreterContext&> (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<MWScript::InterpreterContext&> (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<MWScript::InterpreterContext&> (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<MWScript::InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string sound = runtime.getStringLiteral (runtime[0]);
|
||||
runtime.pop();
|
||||
|
||||
float volume = *reinterpret_cast<float *> (&runtime[0]);
|
||||
runtime.pop();
|
||||
|
||||
float pitch = *reinterpret_cast<float *> (&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<MWScript::InterpreterContext&> (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<MWScript::InterpreterContext&> (runtime.getContext());
|
||||
|
||||
std::string sound = runtime.getStringLiteral (runtime[0]);
|
||||
runtime.pop();
|
||||
|
||||
float volume = *reinterpret_cast<float *> (&runtime[0]);
|
||||
runtime.pop();
|
||||
|
||||
float pitch = *reinterpret_cast<float *> (&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<MWScript::InterpreterContext&> (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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -31,7 +31,18 @@ namespace Compiler
|
|||
argumentType = iter->second.mArguments;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Extensions::isInstruction (int keyword, std::string& argumentType) const
|
||||
{
|
||||
std::map<int, Instruction>::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<Interpreter::Type_Code>& 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<Interpreter::Type_Code>& code)
|
||||
const
|
||||
{
|
||||
std::map<int, Instruction>::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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,17 @@ namespace Compiler
|
|||
std::string mArguments;
|
||||
int mCode;
|
||||
};
|
||||
|
||||
struct Instruction
|
||||
{
|
||||
std::string mArguments;
|
||||
int mCode;
|
||||
};
|
||||
|
||||
int mNextKeywordIndex;
|
||||
std::map<std::string, int> mKeywords;
|
||||
std::map<int, Function> mFunctions;
|
||||
std::map<int, Instruction> 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<Interpreter::Type_Code>& code)
|
||||
const;
|
||||
///< Append code for function to \a code.
|
||||
|
||||
void generateInstructionCode (int keyword, std::vector<Interpreter::Type_Code>& code)
|
||||
const;
|
||||
///< Append code for function to \a code.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue