diff options
133 files changed, 4912 insertions, 1994 deletions
diff --git a/.gitignore b/.gitignore index 270fb560fe..faec15b3de 100644 --- a/.gitignore +++ b/.gitignore @@ -199,3 +199,7 @@ dists/msvc*/** #Ignore bison debug output *.output + +#Ignore Xcode output/project files +out/ +scummvm.xcodeproj @@ -44,8 +44,7 @@ For a more comprehensive changelog of the latest experimental code, see: interacting with the armor in room 37 (main house, downstairs). This bug is also present in the original game. - Fixed auto-saving in the fan-made Cascade Quest. - - Fixed a bug in Conquests of the Longbow: The Adventures of Robin Hood that caused - the game to crash while wandering through the Sherwood Forest. + - Fixed a game bug in the Conquests of Longbow scripts that could cause crashes in Sherwood Forest. - Added a detection entry for the ImagiNation Network (INN) demo. SCUMM: diff --git a/backends/graphics/opengl/opengl-sys.h b/backends/graphics/opengl/opengl-sys.h index 4495128f32..7b531cc140 100644 --- a/backends/graphics/opengl/opengl-sys.h +++ b/backends/graphics/opengl/opengl-sys.h @@ -48,9 +48,15 @@ // 0 - Force OpenGL context // 1 - Force OpenGL ES context // 2 - Force OpenGL ES 2.0 context -#define USE_FORCED_GL (defined(USE_GLES_MODE) && USE_GLES_MODE == 0) -#define USE_FORCED_GLES (defined(USE_GLES_MODE) && USE_GLES_MODE == 1) -#define USE_FORCED_GLES2 (defined(USE_GLES_MODE) && USE_GLES_MODE == 2) +#ifdef USE_GLES_MODE + #define USE_FORCED_GL (USE_GLES_MODE == 0) + #define USE_FORCED_GLES (USE_GLES_MODE == 1) + #define USE_FORCED_GLES2 (USE_GLES_MODE == 2) +#else + #define USE_FORCED_GL 0 + #define USE_FORCED_GLES 0 + #define USE_FORCED_GLES2 0 +#endif // On Tizen we include the toolchain's OpenGL file. This is something we // actually want to avoid. However, since Tizen uses eglGetProcAddress which diff --git a/base/plugins.h b/base/plugins.h index 6037fc2d71..2793ff3ffd 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -79,8 +79,12 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; #define PLUGIN_ENABLED_STATIC(ID) \ (ENABLE_##ID && !PLUGIN_ENABLED_DYNAMIC(ID)) -#define PLUGIN_ENABLED_DYNAMIC(ID) \ - (ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN) && defined(DYNAMIC_MODULES)) +#ifdef DYNAMIC_MODULES + #define PLUGIN_ENABLED_DYNAMIC(ID) \ + (ENABLE_##ID && (ENABLE_##ID == DYNAMIC_PLUGIN)) +#else + #define PLUGIN_ENABLED_DYNAMIC(ID) 0 +#endif // see comments in backends/plugins/elf/elf-provider.cpp #if defined(USE_ELF_LOADER) && defined(ELF_LOADER_CXA_ATEXIT) diff --git a/common/gui_options.h b/common/gui_options.h index ec3eccd161..d17f45cac1 100644 --- a/common/gui_options.h +++ b/common/gui_options.h @@ -68,7 +68,7 @@ #define GUIO_GAMEOPTIONS6 "\055" #define GUIO_GAMEOPTIONS7 "\056" #define GUIO_GAMEOPTIONS8 "\057" -#define GUIO_GAMEOPTIONS9 "\058" +#define GUIO_GAMEOPTIONS9 "\060" #define GUIO0() (GUIO_NONE) #define GUIO1(a) (a) diff --git a/common/scummsys.h b/common/scummsys.h index 5e1069fb46..959c67a404 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -29,7 +29,11 @@ // This is a convenience macro to test whether the compiler used is a GCC // version, which is at least major.minor. -#define GCC_ATLEAST(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) +#ifdef __GNUC__ + #define GCC_ATLEAST(major, minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) +#else + #define GCC_ATLEAST(major, minor) 0 +#endif #if defined(_WIN32_WCE) && _WIN32_WCE < 300 #define NONSTANDARD_PORT diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp index 7e2cad0901..8841eaa73d 100644 --- a/devtools/create_project/create_project.cpp +++ b/devtools/create_project/create_project.cpp @@ -524,6 +524,8 @@ int main(int argc, char *argv[]) { // 4355 ('this' : used in base member initializer list) // only disabled for specific engines where it is used in a safe way // + // 4373 (previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers) + // // 4510 ('class' : default constructor could not be generated) // // 4511 ('class' : copy constructor could not be generated) @@ -573,6 +575,8 @@ int main(int argc, char *argv[]) { projectWarnings["m4"].push_back("4355"); + projectWarnings["sci"].push_back("4373"); + if (msvcVersion == 9) provider = new CreateProjectTool::VisualStudioProvider(globalWarnings, projectWarnings, msvcVersion); else diff --git a/engines/adl/display.cpp b/engines/adl/display.cpp index 858d3ac20b..d05257792c 100644 --- a/engines/adl/display.cpp +++ b/engines/adl/display.cpp @@ -133,6 +133,8 @@ Display::Display() : _textBufSurface->create(DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2, Graphics::PixelFormat::createFormatCLUT8()); createFont(); + + _startMillis = g_system->getMillis(); } Display::~Display() { @@ -487,7 +489,11 @@ void Display::updateTextSurface() { r.translate(((c & 0x3f) % 16) * 7 * 2, (c & 0x3f) / 16 * 8 * 2); if (!(c & 0x80)) { - if (!(c & 0x40) || ((g_system->getMillis() / 270) & 1)) + // Blink text. We subtract _startMillis to make this compatible + // with the event recorder, which returns offsetted values on + // playback. + const uint32 millisPassed = g_system->getMillis() - _startMillis; + if (!(c & 0x40) || ((millisPassed / 270) & 1)) r.translate(0, 4 * 8 * 2); } diff --git a/engines/adl/display.h b/engines/adl/display.h index bc27b7cb6b..e761e63f2e 100644 --- a/engines/adl/display.h +++ b/engines/adl/display.h @@ -102,6 +102,7 @@ private: Graphics::Surface *_font; uint _cursorPos; bool _showCursor; + uint32 _startMillis; }; } // End of namespace Adl diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp index 8b1d48f5a1..d3545a7d3b 100644 --- a/engines/director/lingo/lingo-builtins.cpp +++ b/engines/director/lingo/lingo-builtins.cpp @@ -26,7 +26,7 @@ namespace Director { static struct BuiltinProto { const char *name; - void (*func)(void); + void (*func)(int); int minArgs; int maxArgs; bool parens; @@ -38,6 +38,7 @@ static struct BuiltinProto { { "exp", Lingo::b_exp, 1, 1, true }, // D4 { "float", Lingo::b_float, 1, 1, true }, // D4 { "integer",Lingo::b_integer, 1, 1, true }, + { "integerp",Lingo::b_integerp, 1, 1, true }, { "log", Lingo::b_log, 1, 1, true }, // D4 { "pi", Lingo::b_pi, 0, 0, true }, // D4 { "power", Lingo::b_power, 2, 2, true }, // D4 @@ -46,9 +47,10 @@ static struct BuiltinProto { { "sqrt", Lingo::b_sqrt, 1, 1, true }, // D2 { "tan", Lingo::b_tan, 1, 1, true }, // D4 // String - { "chars", Lingo::b_chars, 3, 3, true }, // D2 - { "length", Lingo::b_length, 1, 1, true }, // D2 - { "string", Lingo::b_string, 1, 1, true }, // D2 + { "chars", Lingo::b_chars, 3, 3, true }, // D2 + { "charToNum", Lingo::b_charToNum, 1, 1, true }, // D2 + { "length", Lingo::b_length, 1, 1, true }, // D2 + { "string", Lingo::b_string, 1, 1, true }, // D2 // Files { "closeDA", Lingo::b_closeDA, 0, 0, false }, // D2 { "closeResFile", Lingo::b_closeResFile, 0, 1, false }, // D2 @@ -87,9 +89,12 @@ static struct BuiltinProto { { "showGlobals", Lingo::b_showGlobals, 0, 0, false }, // D2 { "showLocals", Lingo::b_showLocals, 0, 0, false }, // D2 // Score + { "constrainH", Lingo::b_constrainH, 2, 2, true }, // D2 + { "constrainV", Lingo::b_constrainV, 2, 2, true }, // D2 { "editableText", Lingo::b_editableText, 0, 0, false }, // D2 // go // D2 { "installMenu", Lingo::b_installMenu, 1, 1, false }, // D2 + { "label", Lingo::b_label, 1, 1, true }, // D2 { "moveableSprite", Lingo::b_moveableSprite,0, 0, false }, // D2 { "puppetPalette", Lingo::b_puppetPalette, -1,0, false }, // D2 { "puppetSound", Lingo::b_puppetSound, -1,0, false }, // D2 @@ -103,6 +108,18 @@ static struct BuiltinProto { { "point", Lingo::b_point, 2, 2, true }, // Sound { "beep", Lingo::b_beep, 0, 1, false }, // D2 + { "mci", Lingo::b_mci, 1, 1, false }, + { "mciwait", Lingo::b_mciwait, 1, 1, false }, + // Constants + { "backspace", Lingo::b_backspace, 0, 0, false }, // D2 + { "empty", Lingo::b_empty, 0, 0, false }, // D2 + { "enter", Lingo::b_enter, 0, 0, false }, // D2 + { "false", Lingo::b_false, 0, 0, false }, // D2 + { "quote", Lingo::b_quote, 0, 0, false }, // D2 + { "return", Lingo::b_return, 0, 0, false }, // D2 + { "tab", Lingo::b_tab, 0, 0, false }, // D2 + { "true", Lingo::b_true, 0, 0, false }, // D2 + { 0, 0, 0, 0, false } }; @@ -116,16 +133,51 @@ void Lingo::initBuiltIns() { sym->nargs = blt->minArgs; sym->maxArgs = blt->maxArgs; sym->parens = blt->parens; - sym->u.func = blt->func; + sym->u.bltin = blt->func; _handlers[blt->name] = sym; } } +void Lingo::printStubWithArglist(const char *funcname, int nargs) { + Common::String s(funcname); + + s += '('; + + for (int i = 0; i < nargs; i++) { + Datum d = _stack[_stack.size() - nargs + i]; + + d.toString(); + s += *d.u.s; + + if (i != nargs - 1) + s += ", "; + } + + s += ")"; + + warning("STUB: %s", s.c_str()); +} + +void Lingo::convertVOIDtoString(int arg, int nargs) { + if (_stack[_stack.size() - nargs + arg].type == VOID) { + if (_stack[_stack.size() - nargs + arg].u.s != NULL) + g_lingo->_stack[_stack.size() - nargs + arg].type = STRING; + else + warning("Incorrect convertVOIDtoString for arg %d of %d", arg, nargs); + } +} + +void Lingo::dropStack(int nargs) { + for (int i = 0; i < nargs; i++) + pop(); +} + + /////////////////// // Math /////////////////// -void Lingo::b_abs() { +void Lingo::b_abs(int nargs) { Datum d = g_lingo->pop(); if (d.type == INT) @@ -136,21 +188,21 @@ void Lingo::b_abs() { g_lingo->push(d); } -void Lingo::b_atan() { +void Lingo::b_atan(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); d.u.f = atan(d.u.f); g_lingo->push(d); } -void Lingo::b_cos() { +void Lingo::b_cos(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); d.u.f = cos(d.u.f); g_lingo->push(d); } -void Lingo::b_exp() { +void Lingo::b_exp(int nargs) { Datum d = g_lingo->pop(); d.toInt(); // Lingo uses int, so we're enforcing it d.toFloat(); @@ -158,33 +210,41 @@ void Lingo::b_exp() { g_lingo->push(d); } -void Lingo::b_float() { +void Lingo::b_float(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); g_lingo->push(d); } -void Lingo::b_integer() { +void Lingo::b_integer(int nargs) { Datum d = g_lingo->pop(); d.toInt(); g_lingo->push(d); } -void Lingo::b_log() { +void Lingo::b_integerp(int nargs) { + Datum d = g_lingo->pop(); + int res = (d.type == INT) ? 1 : 0; + d.toInt(); + d.u.i = res; + g_lingo->push(d); +} + +void Lingo::b_log(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); d.u.f = log(d.u.f); g_lingo->push(d); } -void Lingo::b_pi() { +void Lingo::b_pi(int nargs) { Datum d; d.toFloat(); d.u.f = M_PI; g_lingo->push(d); } -void Lingo::b_power() { +void Lingo::b_power(int nargs) { Datum d1 = g_lingo->pop(); Datum d2 = g_lingo->pop(); d1.toFloat(); @@ -193,7 +253,7 @@ void Lingo::b_power() { g_lingo->push(d1); } -void Lingo::b_random() { +void Lingo::b_random(int nargs) { Datum max = g_lingo->pop(); Datum res; @@ -205,21 +265,21 @@ void Lingo::b_random() { g_lingo->push(res); } -void Lingo::b_sin() { +void Lingo::b_sin(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); d.u.f = sin(d.u.f); g_lingo->push(d); } -void Lingo::b_sqrt() { +void Lingo::b_sqrt(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); d.u.f = sqrt(d.u.f); g_lingo->push(d); } -void Lingo::b_tan() { +void Lingo::b_tan(int nargs) { Datum d = g_lingo->pop(); d.toFloat(); d.u.f = tan(d.u.f); @@ -229,7 +289,7 @@ void Lingo::b_tan() { /////////////////// // String /////////////////// -void Lingo::b_chars() { +void Lingo::b_chars(int nargs) { Datum to = g_lingo->pop(); Datum from = g_lingo->pop(); Datum s = g_lingo->pop(); @@ -253,7 +313,21 @@ void Lingo::b_chars() { g_lingo->push(s); } -void Lingo::b_length() { +void Lingo::b_charToNum(int nargs) { + Datum d = g_lingo->pop(); + + if (d.type != STRING) + error("Incorrect type for 'charToNum' function: %s", d.type2str()); + + byte chr = d.u.s->c_str()[0]; + delete d.u.s; + + d.u.i = chr; + d.type = INT; + g_lingo->push(d); +} + +void Lingo::b_length(int nargs) { Datum d = g_lingo->pop(); if (d.type != STRING) @@ -267,7 +341,7 @@ void Lingo::b_length() { g_lingo->push(d); } -void Lingo::b_string() { +void Lingo::b_string(int nargs) { Datum d = g_lingo->pop(); d.toString(); g_lingo->push(d); @@ -276,11 +350,11 @@ void Lingo::b_string() { /////////////////// // Files /////////////////// -void Lingo::b_closeDA() { +void Lingo::b_closeDA(int nargs) { warning("STUB: b_closeDA"); } -void Lingo::b_closeResFile() { +void Lingo::b_closeResFile(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -290,7 +364,7 @@ void Lingo::b_closeResFile() { delete d.u.s; } -void Lingo::b_closeXlib() { +void Lingo::b_closeXlib(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -300,7 +374,7 @@ void Lingo::b_closeXlib() { delete d.u.s; } -void Lingo::b_openDA() { +void Lingo::b_openDA(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -310,7 +384,7 @@ void Lingo::b_openDA() { delete d.u.s; } -void Lingo::b_openResFile() { +void Lingo::b_openResFile(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -320,7 +394,7 @@ void Lingo::b_openResFile() { delete d.u.s; } -void Lingo::b_openXlib() { +void Lingo::b_openXlib(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -330,7 +404,7 @@ void Lingo::b_openXlib() { delete d.u.s; } -void Lingo::b_showResFile() { +void Lingo::b_showResFile(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -340,7 +414,7 @@ void Lingo::b_showResFile() { delete d.u.s; } -void Lingo::b_showXlib() { +void Lingo::b_showXlib(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -353,55 +427,59 @@ void Lingo::b_showXlib() { /////////////////// // Control /////////////////// -void Lingo::b_dontPassEvent() { +void Lingo::b_dontPassEvent(int nargs) { warning("STUB: b_dontPassEvent"); } -void Lingo::b_continue() { +void Lingo::b_continue(int nargs) { warning("STUB: b_continue"); } -void Lingo::b_nothing() { +void Lingo::b_nothing(int nargs) { warning("STUB: b_nothing"); } -void Lingo::b_delay() { +void Lingo::b_delay(int nargs) { Datum d = g_lingo->pop(); d.toInt(); warning("STUB: b_delay(%d)", d.u.i); } -void Lingo::b_do() { +void Lingo::b_do(int nargs) { Datum d = g_lingo->pop(); d.toString(); warning("STUB: b_do(%s)", d.u.s->c_str()); } -void Lingo::b_pause() { +void Lingo::b_pause(int nargs) { warning("STUB: b_pause"); } -void Lingo::b_playAccel() { - warning("STUB: b_playAccel"); +void Lingo::b_playAccel(int nargs) { + g_lingo->printStubWithArglist("b_playAccel", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_printFrom() { - warning("STUB: b_printFrom"); +void Lingo::b_printFrom(int nargs) { + g_lingo->printStubWithArglist("b_printFrom", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_quit() { +void Lingo::b_quit(int nargs) { warning("STUB: b_quit"); } -void Lingo::b_restart() { +void Lingo::b_restart(int nargs) { warning("STUB: b_restart"); } -void Lingo::b_shutDown() { +void Lingo::b_shutDown(int nargs) { warning("STUB: b_shutDown"); } -void Lingo::b_startTimer() { +void Lingo::b_startTimer(int nargs) { warning("STUB: b_startTimer"); } @@ -409,14 +487,14 @@ void Lingo::b_startTimer() { /////////////////// // Misc /////////////////// -void Lingo::b_ilk() { +void Lingo::b_ilk(int nargs) { Datum d = g_lingo->pop(); d.u.i = d.type; d.type = SYMBOL; g_lingo->push(d); } -void Lingo::b_alert() { +void Lingo::b_alert(int nargs) { Datum d = g_lingo->pop(); d.toString(); @@ -426,17 +504,17 @@ void Lingo::b_alert() { delete d.u.s; } -void Lingo::b_cursor() { +void Lingo::b_cursor(int nargs) { Datum d = g_lingo->pop(); d.toInt(); warning("STUB: b_cursor(%d)", d.u.i); } -void Lingo::b_showGlobals() { +void Lingo::b_showGlobals(int nargs) { warning("STUB: b_showGlobals"); } -void Lingo::b_showLocals() { +void Lingo::b_showLocals(int nargs) { warning("STUB: b_showLocals"); } @@ -445,51 +523,99 @@ void Lingo::b_showLocals() { /////////////////// // Score /////////////////// -void Lingo::b_updateStage() { - warning("STUB: b_updateStage"); +void Lingo::b_constrainH(int nargs) { + Datum num = g_lingo->pop(); + Datum sprite = g_lingo->pop(); + + num.toInt(); + sprite.toInt(); + + warning("STUB: b_constrainH(%d, %d)", sprite.u.i, num.u.i); + + g_lingo->push(Datum(0)); } -void Lingo::b_editableText() { +void Lingo::b_constrainV(int nargs) { + Datum num = g_lingo->pop(); + Datum sprite = g_lingo->pop(); + + num.toInt(); + sprite.toInt(); + + warning("STUB: b_constrainV(%d, %d)", sprite.u.i, num.u.i); + + g_lingo->push(Datum(0)); +} + +void Lingo::b_editableText(int nargs) { warning("STUB: b_editableText"); } -void Lingo::b_installMenu() { +void Lingo::b_installMenu(int nargs) { Datum d = g_lingo->pop(); warning("STUB: b_installMenu(%d)", d.u.i); } -void Lingo::b_moveableSprite() { +void Lingo::b_label(int nargs) { + Datum d = g_lingo->pop(); + d.toInt(); + warning("STUB: b_label(%d)", d.u.i); + + g_lingo->push(Datum(0)); +} + +void Lingo::b_moveableSprite(int nargs) { Datum d = g_lingo->pop(); warning("STUB: b_moveableSprite(%d)", d.u.i); } -void Lingo::b_puppetPalette() { - warning("STUB: b_puppetPalette"); +void Lingo::b_puppetPalette(int nargs) { + g_lingo->convertVOIDtoString(0, nargs); + + g_lingo->printStubWithArglist("b_puppetPalette", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_puppetSound() { - warning("STUB: b_puppetSound"); +void Lingo::b_puppetSound(int nargs) { + g_lingo->convertVOIDtoString(0, nargs); + + g_lingo->printStubWithArglist("b_puppetSound", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_puppetSprite() { - warning("STUB: b_puppetSprite"); +void Lingo::b_puppetSprite(int nargs) { + g_lingo->printStubWithArglist("b_puppetSprite", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_puppetTempo() { +void Lingo::b_puppetTempo(int nargs) { Datum d = g_lingo->pop(); warning("STUB: b_puppetTempo(%d)", d.u.i); } -void Lingo::b_puppetTransition() { - warning("STUB: b_puppetTransition"); +void Lingo::b_puppetTransition(int nargs) { + g_lingo->printStubWithArglist("b_puppetTransition", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_spriteBox() { - warning("STUB: b_spriteBox"); +void Lingo::b_spriteBox(int nargs) { + g_lingo->printStubWithArglist("b_spriteBox", nargs); + + g_lingo->dropStack(nargs); } -void Lingo::b_zoomBox() { - warning("STUB: b_zoomBox"); +void Lingo::b_zoomBox(int nargs) { + g_lingo->printStubWithArglist("b_zoomBox", nargs); + + g_lingo->dropStack(nargs); +} + +void Lingo::b_updateStage(int nargs) { + warning("STUB: b_updateStage"); } @@ -497,7 +623,7 @@ void Lingo::b_zoomBox() { /////////////////// // Point /////////////////// -void Lingo::b_point() { +void Lingo::b_point(int nargs) { Datum y = g_lingo->pop(); Datum x = g_lingo->pop(); Datum d; @@ -518,11 +644,93 @@ void Lingo::b_point() { /////////////////// // Sound /////////////////// -void Lingo::b_beep() { +void Lingo::b_beep(int nargs) { Datum d = g_lingo->pop(); warning("STUB: b_beep(%d)", d.u.i); } +void Lingo::b_mci(int nargs) { + Datum d = g_lingo->pop(); + + d.toString(); + + g_lingo->func_mci(*d.u.s); +} + +void Lingo::b_mciwait(int nargs) { + Datum d = g_lingo->pop(); + + d.toString(); + + g_lingo->func_mciwait(*d.u.s); +} + +/////////////////// +// Constants +/////////////////// +void Lingo::b_backspace(int nargs) { + g_lingo->push(Datum(new Common::String("\b"))); +} + +void Lingo::b_empty(int nargs) { + g_lingo->push(Datum(new Common::String(""))); +} + +void Lingo::b_enter(int nargs) { + g_lingo->push(Datum(new Common::String("\n"))); +} +void Lingo::b_false(int nargs) { + g_lingo->push(Datum(0)); +} + +void Lingo::b_quote(int nargs) { + g_lingo->push(Datum(new Common::String("\""))); +} + +void Lingo::b_return(int nargs) { + g_lingo->push(Datum(new Common::String("\r"))); +} + +void Lingo::b_tab(int nargs) { + g_lingo->push(Datum(new Common::String("\t"))); +} + +void Lingo::b_true(int nargs) { + g_lingo->push(Datum(1)); +} + +/////////////////// +// Factory +/////////////////// +void Lingo::b_factory(int nargs) { + // This is intentionally empty +} + +void Lingo::factoryCall(Common::String &name, int nargs) { + Common::String s("factoryCall: "); + + s += name; + + convertVOIDtoString(0, nargs); + + printStubWithArglist(s.c_str(), nargs); + + Datum method = _stack[_stack.size() - nargs + 0]; + + s = name + "-" + *method.u.s; + + call(s, nargs); + + if (method.u.s->compareToIgnoreCase("mNew")) { + warning("Got mNew method"); + Datum d; + + d.type = OBJECT; + d.u.s = new Common::String(name); + + g_lingo->push(d); + } +} } // End of namespace Director diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp index 8d2b663b1b..6072977d07 100644 --- a/engines/director/lingo/lingo-code.cpp +++ b/engines/director/lingo/lingo-code.cpp @@ -57,7 +57,7 @@ void Lingo::push(Datum d) { void Lingo::pushVoid() { Datum d; - d.u.i = 0; + d.u.s = NULL; d.type = VOID; push(d); } @@ -81,7 +81,7 @@ void Lingo::c_printtop(void) { switch (d.type) { case VOID: - warning("Void"); + warning("Void, came from %s", d.u.s ? d.u.s->c_str() : "<>"); break; case INT: warning("%d", d.u.i); @@ -123,7 +123,7 @@ void Lingo::c_constpush() { void Lingo::c_voidpush() { Datum d; - d.u.i = 0; + d.u.s = NULL; d.type = VOID; g_lingo->push(d); } @@ -140,13 +140,10 @@ void Lingo::c_fconstpush() { } void Lingo::c_stringpush() { - Datum d; char *s = (char *)&(*g_lingo->_currentScript)[g_lingo->_pc]; g_lingo->_pc += g_lingo->calcStringAlignment(s); - d.u.s = new Common::String(s); - d.type = STRING; - g_lingo->push(d); + g_lingo->push(Datum(new Common::String(s))); } void Lingo::c_varpush() { @@ -186,7 +183,7 @@ void Lingo::c_assign() { return; } - if (d1.u.sym->type == STRING) // Free memory if needed + if ((d1.u.sym->type == STRING || d1.u.sym->type == VOID) && d1.u.sym->u.s) // Free memory if needed delete d1.u.sym->u.s; if (d1.u.sym->type == POINT || d1.u.sym->type == RECT || d1.u.sym->type == ARRAY) @@ -252,6 +249,8 @@ void Lingo::c_eval() { d.u.arr = d.u.sym->u.arr; else if (d.u.sym->type == SYMBOL) d.u.i = d.u.sym->u.i; + else if (d.u.sym->type == VOID) + d.u.s = new Common::String(d.u.sym->name); else warning("c_eval: unhandled type: %s", d.type2str()); @@ -657,22 +656,6 @@ void Lingo::c_ifcode() { //************************ // Built-in functions //************************ -void Lingo::c_mci() { - Common::String s((char *)&(*g_lingo->_currentScript)[g_lingo->_pc]); - - g_lingo->func_mci(s); - - g_lingo->_pc += g_lingo->calcStringAlignment(s.c_str()); -} - -void Lingo::c_mciwait() { - Common::String s((char *)&(*g_lingo->_currentScript)[g_lingo->_pc]); - - g_lingo->func_mciwait(s); - - g_lingo->_pc += g_lingo->calcStringAlignment(s.c_str()); -} - void Lingo::c_goto() { Datum mode = g_lingo->pop(); Datum frame, movie; @@ -732,11 +715,24 @@ void Lingo::c_call() { g_lingo->_pc += g_lingo->calcStringAlignment(name.c_str()); int nargs = READ_UINT32(&(*g_lingo->_currentScript)[g_lingo->_pc++]); + + g_lingo->call(name, nargs); +} + +void Lingo::call(Common::String &name, int nargs) { bool drop = false; Symbol *sym; if (!g_lingo->_handlers.contains(name)) { + Symbol *s = g_lingo->lookupVar(name.c_str(), false); + if (s && s->type == OBJECT) { + debug(3, "Dereferencing object reference: %s to %s", name.c_str(), s->u.s->c_str()); + name = *s->u.s; + } + } + + if (!g_lingo->_handlers.contains(name)) { warning("Call to undefined handler '%s'. Dropping %d stack items", name.c_str(), nargs); drop = true; } else { @@ -769,9 +765,10 @@ void Lingo::c_call() { } if (sym->type == BLTIN) { - // FIXME. TODO. Pass nargs - - (*sym->u.func)(); + if (sym->u.bltin == b_factory) + g_lingo->factoryCall(name, nargs); + else + (*sym->u.bltin)(nargs); return; } @@ -779,7 +776,7 @@ void Lingo::c_call() { for (int i = nargs; i < sym->nargs; i++) { Datum d; - d.u.i = 0; + d.u.s = NULL; d.type = VOID; g_lingo->push(d); } diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp index 4284fa7452..bf96802bb7 100644 --- a/engines/director/lingo/lingo-codegen.cpp +++ b/engines/director/lingo/lingo-codegen.cpp @@ -270,6 +270,18 @@ void Lingo::processIf(int elselabel, int endlabel) { void Lingo::codeFactory(Common::String &name) { _currentFactory = name; + + Symbol *sym = new Symbol; + + sym->name = (char *)calloc(name.size() + 1, 1); + Common::strlcpy(sym->name, name.c_str(), name.size()); + sym->type = BLTIN; + sym->nargs = -1; + sym->maxArgs = 0; + sym->parens = true; + sym->u.bltin = g_lingo->b_factory; + + _handlers[name] = sym; } } diff --git a/engines/director/lingo/lingo-gr.cpp b/engines/director/lingo/lingo-gr.cpp index 2fc8fb9bf8..63128058ed 100644 --- a/engines/director/lingo/lingo-gr.cpp +++ b/engines/director/lingo/lingo-gr.cpp @@ -74,66 +74,65 @@ RECT = 263, ARRAY = 264, SYMBOL = 265, - INT = 266, - THEENTITY = 267, - THEENTITYWITHID = 268, - FLOAT = 269, - BLTIN = 270, - BLTINNOARGS = 271, - BLTINNOARGSORONE = 272, - BLTINONEARG = 273, - BLTINARGLIST = 274, - ID = 275, - STRING = 276, - HANDLER = 277, - tDOWN = 278, - tELSE = 279, - tNLELSIF = 280, - tEND = 281, - tEXIT = 282, - tFRAME = 283, - tGLOBAL = 284, - tGO = 285, - tIF = 286, - tINTO = 287, - tLOOP = 288, - tMACRO = 289, - tMCI = 290, - tMCIWAIT = 291, - tMOVIE = 292, - tNEXT = 293, - tOF = 294, - tPREVIOUS = 295, - tPUT = 296, - tREPEAT = 297, - tSET = 298, - tTHEN = 299, - tTO = 300, - tWHEN = 301, - tWITH = 302, - tWHILE = 303, - tNLELSE = 304, - tFACTORY = 305, - tMETHOD = 306, - tOPEN = 307, - tPLAY = 308, - tDONE = 309, - tPLAYACCEL = 310, - tGE = 311, - tLE = 312, - tGT = 313, - tLT = 314, - tEQ = 315, - tNEQ = 316, - tAND = 317, - tOR = 318, - tNOT = 319, - tCONCAT = 320, - tCONTAINS = 321, - tSTARTS = 322, - tSPRITE = 323, - tINTERSECTS = 324, - tWITHIN = 325 + OBJECT = 266, + INT = 267, + THEENTITY = 268, + THEENTITYWITHID = 269, + FLOAT = 270, + BLTIN = 271, + BLTINNOARGS = 272, + BLTINNOARGSORONE = 273, + BLTINONEARG = 274, + BLTINARGLIST = 275, + ID = 276, + STRING = 277, + HANDLER = 278, + tDOWN = 279, + tELSE = 280, + tNLELSIF = 281, + tEND = 282, + tEXIT = 283, + tFRAME = 284, + tGLOBAL = 285, + tGO = 286, + tIF = 287, + tINTO = 288, + tLOOP = 289, + tMACRO = 290, + tMOVIE = 291, + tNEXT = 292, + tOF = 293, + tPREVIOUS = 294, + tPUT = 295, + tREPEAT = 296, + tSET = 297, + tTHEN = 298, + tTO = 299, + tWHEN = 300, + tWITH = 301, + tWHILE = 302, + tNLELSE = 303, + tFACTORY = 304, + tMETHOD = 305, + tOPEN = 306, + tPLAY = 307, + tDONE = 308, + tPLAYACCEL = 309, + tGE = 310, + tLE = 311, + tGT = 312, + tLT = 313, + tEQ = 314, + tNEQ = 315, + tAND = 316, + tOR = 317, + tNOT = 318, + tCONCAT = 319, + tCONTAINS = 320, + tSTARTS = 321, + tSPRITE = 322, + tINTERSECTS = 323, + tWITHIN = 324 }; #endif /* Tokens. */ @@ -145,66 +144,65 @@ #define RECT 263 #define ARRAY 264 #define SYMBOL 265 -#define INT 266 -#define THEENTITY 267 -#define THEENTITYWITHID 268 -#define FLOAT 269 -#define BLTIN 270 -#define BLTINNOARGS 271 -#define BLTINNOARGSORONE 272 -#define BLTINONEARG 273 -#define BLTINARGLIST 274 -#define ID 275 -#define STRING 276 -#define HANDLER 277 -#define tDOWN 278 -#define tELSE 279 -#define tNLELSIF 280 -#define tEND 281 -#define tEXIT 282 -#define tFRAME 283 -#define tGLOBAL 284 -#define tGO 285 -#define tIF 286 -#define tINTO 287 -#define tLOOP 288 -#define tMACRO 289 -#define tMCI 290 -#define tMCIWAIT 291 -#define tMOVIE 292 -#define tNEXT 293 -#define tOF 294 -#define tPREVIOUS 295 -#define tPUT 296 -#define tREPEAT 297 -#define tSET 298 -#define tTHEN 299 -#define tTO 300 -#define tWHEN 301 -#define tWITH 302 -#define tWHILE 303 -#define tNLELSE 304 -#define tFACTORY 305 -#define tMETHOD 306 -#define tOPEN 307 -#define tPLAY 308 -#define tDONE 309 -#define tPLAYACCEL 310 -#define tGE 311 -#define tLE 312 -#define tGT 313 -#define tLT 314 -#define tEQ 315 -#define tNEQ 316 -#define tAND 317 -#define tOR 318 -#define tNOT 319 -#define tCONCAT 320 -#define tCONTAINS 321 -#define tSTARTS 322 -#define tSPRITE 323 -#define tINTERSECTS 324 -#define tWITHIN 325 +#define OBJECT 266 +#define INT 267 +#define THEENTITY 268 +#define THEENTITYWITHID 269 +#define FLOAT 270 +#define BLTIN 271 +#define BLTINNOARGS 272 +#define BLTINNOARGSORONE 273 +#define BLTINONEARG 274 +#define BLTINARGLIST 275 +#define ID 276 +#define STRING 277 +#define HANDLER 278 +#define tDOWN 279 +#define tELSE 280 +#define tNLELSIF 281 +#define tEND 282 +#define tEXIT 283 +#define tFRAME 284 +#define tGLOBAL 285 +#define tGO 286 +#define tIF 287 +#define tINTO 288 +#define tLOOP 289 +#define tMACRO 290 +#define tMOVIE 291 +#define tNEXT 292 +#define tOF 293 +#define tPREVIOUS 294 +#define tPUT 295 +#define tREPEAT 296 +#define tSET 297 +#define tTHEN 298 +#define tTO 299 +#define tWHEN 300 +#define tWITH 301 +#define tWHILE 302 +#define tNLELSE 303 +#define tFACTORY 304 +#define tMETHOD 305 +#define tOPEN 306 +#define tPLAY 307 +#define tDONE 308 +#define tPLAYACCEL 309 +#define tGE 310 +#define tLE 311 +#define tGT 312 +#define tLT 313 +#define tEQ 314 +#define tNEQ 315 +#define tAND 316 +#define tOR 317 +#define tNOT 318 +#define tCONCAT 319 +#define tCONTAINS 320 +#define tSTARTS 321 +#define tSPRITE 322 +#define tINTERSECTS 323 +#define tWITHIN 324 @@ -262,7 +260,7 @@ typedef union YYSTYPE Common::Array<double> *arr; } /* Line 193 of yacc.c. */ -#line 266 "engines/director/lingo/lingo-gr.cpp" +#line 264 "engines/director/lingo/lingo-gr.cpp" YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 @@ -275,7 +273,7 @@ typedef union YYSTYPE /* Line 216 of yacc.c. */ -#line 279 "engines/director/lingo/lingo-gr.cpp" +#line 277 "engines/director/lingo/lingo-gr.cpp" #ifdef short # undef short @@ -488,22 +486,22 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 91 +#define YYFINAL 87 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 939 +#define YYLAST 921 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 84 +#define YYNTOKENS 83 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 35 /* YYNRULES -- Number of rules. */ -#define YYNRULES 126 +#define YYNRULES 124 /* YYNRULES -- Number of states. */ -#define YYNSTATES 263 +#define YYNSTATES 259 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 325 +#define YYMAXUTOK 324 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -512,12 +510,12 @@ union yyalloc static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 77, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 76, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 76, 82, 2, - 78, 79, 74, 72, 83, 73, 2, 75, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 75, 81, 2, + 77, 78, 73, 71, 82, 72, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 81, 71, 80, 2, 2, 2, 2, 2, 2, 2, + 80, 70, 79, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -543,7 +541,7 @@ static const yytype_uint8 yytranslate[] = 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70 + 65, 66, 67, 68, 69 }; #if YYDEBUG @@ -559,63 +557,63 @@ static const yytype_uint16 yyprhs[] = 223, 224, 225, 228, 231, 233, 235, 237, 239, 244, 246, 248, 251, 253, 257, 261, 265, 269, 273, 277, 281, 285, 289, 293, 297, 300, 304, 308, 312, 316, - 319, 322, 326, 331, 336, 339, 342, 345, 347, 349, - 351, 354, 357, 360, 362, 365, 370, 373, 375, 379, - 382, 385, 388, 391, 395, 398, 401, 403, 407, 410, - 413, 416, 420, 423, 424, 433, 436, 437, 446, 447, - 449, 453, 458, 459, 463, 464, 466 + 319, 322, 326, 331, 336, 339, 341, 343, 345, 348, + 351, 354, 356, 359, 364, 367, 369, 373, 376, 379, + 382, 385, 389, 392, 395, 397, 401, 404, 407, 410, + 414, 417, 418, 427, 430, 431, 440, 441, 443, 447, + 452, 453, 457, 458, 460 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 85, 0, -1, 85, 86, 87, -1, 87, -1, 1, - 86, -1, 77, -1, -1, 112, -1, 106, -1, 117, - -1, 88, -1, 90, -1, 41, 105, 32, 20, -1, - 43, 20, 71, 105, -1, 43, 12, 71, 105, -1, - 43, 13, 105, 71, 105, -1, 43, 20, 45, 105, - -1, 43, 12, 45, 105, -1, 43, 13, 105, 45, - 105, -1, 105, -1, 106, -1, 89, -1, 91, -1, - 98, 78, 97, 79, 104, 103, 26, 42, -1, 99, - 71, 105, 103, 45, 105, 103, 104, 103, 26, 42, - -1, 99, 71, 105, 103, 23, 45, 105, 103, 104, - 103, 26, 42, -1, 46, 20, 44, 105, -1, 100, - 97, 44, 86, 104, 103, 26, 31, -1, 100, 97, - 44, 86, 104, 103, 49, 104, 103, 26, 31, -1, - 100, 97, 44, 86, 104, 103, 102, 93, 103, 26, - 31, -1, 100, 97, 44, 102, 89, 103, -1, 100, - 97, 44, 102, 89, 103, 49, 102, 89, 103, -1, - 100, 97, 44, 102, 89, 103, 94, 103, 92, 103, - -1, -1, 49, 102, 89, -1, 93, 96, -1, 96, - -1, 94, 95, -1, 95, -1, 101, 97, 44, 102, - 90, 103, -1, 94, -1, 101, 97, 44, 104, 103, - -1, 105, -1, 105, 71, 105, -1, 78, 97, 79, - -1, 42, 48, -1, 42, 47, 20, -1, 31, -1, - 25, -1, -1, -1, -1, 104, 86, -1, 104, 90, - -1, 11, -1, 14, -1, 21, -1, 16, -1, 20, - 78, 118, 79, -1, 20, -1, 12, -1, 13, 105, - -1, 88, -1, 105, 72, 105, -1, 105, 73, 105, - -1, 105, 74, 105, -1, 105, 75, 105, -1, 105, - 80, 105, -1, 105, 81, 105, -1, 105, 61, 105, - -1, 105, 56, 105, -1, 105, 57, 105, -1, 105, - 62, 105, -1, 105, 63, 105, -1, 64, 105, -1, - 105, 82, 105, -1, 105, 65, 105, -1, 105, 66, - 105, -1, 105, 67, 105, -1, 72, 105, -1, 73, - 105, -1, 78, 105, 79, -1, 68, 105, 69, 105, - -1, 68, 105, 70, 105, -1, 35, 21, -1, 36, - 20, -1, 41, 105, -1, 108, -1, 111, -1, 27, - -1, 29, 107, -1, 18, 105, -1, 17, 105, -1, - 17, -1, 19, 118, -1, 52, 105, 47, 105, -1, - 52, 105, -1, 20, -1, 107, 83, 20, -1, 30, - 33, -1, 30, 38, -1, 30, 40, -1, 30, 109, - -1, 30, 109, 110, -1, 30, 110, -1, 28, 105, - -1, 105, -1, 39, 37, 105, -1, 37, 105, -1, - 53, 54, -1, 53, 109, -1, 53, 109, 110, -1, - 53, 110, -1, -1, 34, 20, 113, 102, 115, 86, - 116, 104, -1, 50, 20, -1, -1, 51, 20, 114, - 102, 115, 86, 116, 104, -1, -1, 20, -1, 115, - 83, 20, -1, 115, 86, 83, 20, -1, -1, 20, - 102, 118, -1, -1, 105, -1, 118, 83, 105, -1 + 84, 0, -1, 84, 85, 86, -1, 86, -1, 1, + 85, -1, 76, -1, -1, 111, -1, 105, -1, 116, + -1, 87, -1, 89, -1, 40, 104, 33, 21, -1, + 42, 21, 70, 104, -1, 42, 13, 70, 104, -1, + 42, 14, 104, 70, 104, -1, 42, 21, 44, 104, + -1, 42, 13, 44, 104, -1, 42, 14, 104, 44, + 104, -1, 104, -1, 105, -1, 88, -1, 90, -1, + 97, 77, 96, 78, 103, 102, 27, 41, -1, 98, + 70, 104, 102, 44, 104, 102, 103, 102, 27, 41, + -1, 98, 70, 104, 102, 24, 44, 104, 102, 103, + 102, 27, 41, -1, 45, 21, 43, 104, -1, 99, + 96, 43, 85, 103, 102, 27, 32, -1, 99, 96, + 43, 85, 103, 102, 48, 103, 102, 27, 32, -1, + 99, 96, 43, 85, 103, 102, 101, 92, 102, 27, + 32, -1, 99, 96, 43, 101, 88, 102, -1, 99, + 96, 43, 101, 88, 102, 48, 101, 88, 102, -1, + 99, 96, 43, 101, 88, 102, 93, 102, 91, 102, + -1, -1, 48, 101, 88, -1, 92, 95, -1, 95, + -1, 93, 94, -1, 94, -1, 100, 96, 43, 101, + 89, 102, -1, 93, -1, 100, 96, 43, 103, 102, + -1, 104, -1, 104, 70, 104, -1, 77, 96, 78, + -1, 41, 47, -1, 41, 46, 21, -1, 32, -1, + 26, -1, -1, -1, -1, 103, 85, -1, 103, 89, + -1, 12, -1, 15, -1, 22, -1, 17, -1, 21, + 77, 117, 78, -1, 21, -1, 13, -1, 14, 104, + -1, 87, -1, 104, 71, 104, -1, 104, 72, 104, + -1, 104, 73, 104, -1, 104, 74, 104, -1, 104, + 79, 104, -1, 104, 80, 104, -1, 104, 60, 104, + -1, 104, 55, 104, -1, 104, 56, 104, -1, 104, + 61, 104, -1, 104, 62, 104, -1, 63, 104, -1, + 104, 81, 104, -1, 104, 64, 104, -1, 104, 65, + 104, -1, 104, 66, 104, -1, 71, 104, -1, 72, + 104, -1, 77, 104, 78, -1, 67, 104, 68, 104, + -1, 67, 104, 69, 104, -1, 40, 104, -1, 107, + -1, 110, -1, 28, -1, 30, 106, -1, 19, 104, + -1, 18, 104, -1, 18, -1, 20, 117, -1, 51, + 104, 46, 104, -1, 51, 104, -1, 21, -1, 106, + 82, 21, -1, 31, 34, -1, 31, 37, -1, 31, + 39, -1, 31, 108, -1, 31, 108, 109, -1, 31, + 109, -1, 29, 104, -1, 104, -1, 38, 36, 104, + -1, 36, 104, -1, 52, 53, -1, 52, 108, -1, + 52, 108, 109, -1, 52, 109, -1, -1, 35, 21, + 112, 101, 114, 85, 115, 103, -1, 49, 21, -1, + -1, 50, 21, 113, 101, 114, 85, 115, 103, -1, + -1, 21, -1, 114, 82, 21, -1, 114, 85, 82, + 21, -1, -1, 21, 101, 117, -1, -1, 104, -1, + 117, 82, 104, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -629,11 +627,11 @@ static const yytype_uint16 yyrline[] = 337, 339, 340, 341, 344, 345, 348, 351, 355, 358, 362, 369, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 399, 400, 401, 402, 403, 404, - 406, 407, 410, 413, 416, 417, 418, 421, 422, 433, - 434, 435, 436, 439, 442, 447, 448, 451, 452, 455, - 456, 459, 462, 492, 492, 498, 501, 501, 507, 508, - 509, 510, 512, 516, 524, 525, 526 + 393, 394, 395, 396, 399, 400, 401, 402, 404, 405, + 408, 411, 414, 415, 416, 419, 420, 431, 432, 433, + 434, 437, 440, 445, 446, 449, 450, 453, 454, 457, + 460, 490, 490, 496, 499, 499, 504, 505, 506, 507, + 509, 513, 521, 522, 523 }; #endif @@ -643,13 +641,13 @@ static const yytype_uint16 yyrline[] = static const char *const yytname[] = { "$end", "error", "$undefined", "UNARY", "CASTREF", "VOID", "VAR", - "POINT", "RECT", "ARRAY", "SYMBOL", "INT", "THEENTITY", + "POINT", "RECT", "ARRAY", "SYMBOL", "OBJECT", "INT", "THEENTITY", "THEENTITYWITHID", "FLOAT", "BLTIN", "BLTINNOARGS", "BLTINNOARGSORONE", "BLTINONEARG", "BLTINARGLIST", "ID", "STRING", "HANDLER", "tDOWN", "tELSE", "tNLELSIF", "tEND", "tEXIT", "tFRAME", "tGLOBAL", "tGO", "tIF", - "tINTO", "tLOOP", "tMACRO", "tMCI", "tMCIWAIT", "tMOVIE", "tNEXT", "tOF", - "tPREVIOUS", "tPUT", "tREPEAT", "tSET", "tTHEN", "tTO", "tWHEN", "tWITH", - "tWHILE", "tNLELSE", "tFACTORY", "tMETHOD", "tOPEN", "tPLAY", "tDONE", + "tINTO", "tLOOP", "tMACRO", "tMOVIE", "tNEXT", "tOF", "tPREVIOUS", + "tPUT", "tREPEAT", "tSET", "tTHEN", "tTO", "tWHEN", "tWITH", "tWHILE", + "tNLELSE", "tFACTORY", "tMETHOD", "tOPEN", "tPLAY", "tDONE", "tPLAYACCEL", "tGE", "tLE", "tGT", "tLT", "tEQ", "tNEQ", "tAND", "tOR", "tNOT", "tCONCAT", "tCONTAINS", "tSTARTS", "tSPRITE", "tINTERSECTS", "tWITHIN", "'='", "'+'", "'-'", "'*'", "'/'", "'%'", "'\\n'", "'('", @@ -675,27 +673,27 @@ static const yytype_uint16 yytoknum[] = 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 61, 43, 45, 42, 47, 37, 10, 40, 41, - 62, 60, 38, 44 + 61, 43, 45, 42, 47, 37, 10, 40, 41, 62, + 60, 38, 44 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 84, 85, 85, 85, 86, 87, 87, 87, 87, - 87, 87, 88, 88, 88, 88, 88, 88, 88, 89, - 89, 90, 90, 90, 90, 90, 90, 91, 91, 91, - 91, 91, 91, 92, 92, 93, 93, 94, 94, 95, - 96, 96, 97, 97, 97, 98, 99, 100, 101, 102, - 103, 104, 104, 104, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 107, 107, 108, - 108, 108, 108, 108, 108, 109, 109, 110, 110, 111, - 111, 111, 111, 113, 112, 112, 114, 112, 115, 115, - 115, 115, 116, 117, 118, 118, 118 + 0, 83, 84, 84, 84, 85, 86, 86, 86, 86, + 86, 86, 87, 87, 87, 87, 87, 87, 87, 88, + 88, 89, 89, 89, 89, 89, 89, 90, 90, 90, + 90, 90, 90, 91, 91, 92, 92, 93, 93, 94, + 95, 95, 96, 96, 96, 97, 98, 99, 100, 101, + 102, 103, 103, 103, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 106, 106, 107, 107, 107, + 107, 107, 107, 108, 108, 109, 109, 110, 110, 110, + 110, 112, 111, 111, 113, 111, 114, 114, 114, 114, + 115, 116, 117, 117, 117 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -709,11 +707,11 @@ static const yytype_uint8 yyr2[] = 0, 0, 2, 2, 1, 1, 1, 1, 4, 1, 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, - 2, 3, 4, 4, 2, 2, 2, 1, 1, 1, - 2, 2, 2, 1, 2, 4, 2, 1, 3, 2, - 2, 2, 2, 3, 2, 2, 1, 3, 2, 2, - 2, 3, 2, 0, 8, 2, 0, 8, 0, 1, - 3, 4, 0, 3, 0, 1, 3 + 2, 3, 4, 4, 2, 1, 1, 1, 2, 2, + 2, 1, 2, 4, 2, 1, 3, 2, 2, 2, + 2, 3, 2, 2, 1, 3, 2, 2, 2, 3, + 2, 0, 8, 2, 0, 8, 0, 1, 3, 4, + 0, 3, 0, 1, 3 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -721,85 +719,83 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 0, 54, 60, 0, 55, 57, 93, 0, 124, - 49, 56, 89, 0, 0, 47, 0, 0, 0, 0, + 0, 0, 54, 60, 0, 55, 57, 91, 0, 122, + 49, 56, 87, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 62, 21, 11, 22, 0, 0, - 0, 19, 8, 87, 88, 7, 9, 5, 4, 59, - 0, 62, 61, 92, 91, 125, 94, 124, 124, 97, - 90, 0, 99, 0, 100, 0, 101, 106, 102, 104, - 113, 84, 85, 86, 0, 45, 0, 0, 0, 0, - 115, 116, 96, 109, 110, 112, 74, 0, 79, 80, - 0, 1, 6, 0, 0, 0, 0, 42, 0, 0, + 0, 3, 62, 21, 11, 22, 0, 0, 0, 19, + 8, 85, 86, 7, 9, 5, 4, 59, 0, 62, + 61, 90, 89, 123, 92, 122, 122, 95, 88, 0, + 97, 0, 98, 0, 99, 104, 100, 102, 111, 84, + 0, 45, 0, 0, 0, 0, 113, 114, 94, 107, + 108, 110, 74, 0, 79, 80, 0, 1, 6, 0, + 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 123, 0, 105, 108, - 0, 103, 49, 0, 46, 0, 0, 0, 0, 0, - 0, 49, 0, 111, 0, 0, 81, 2, 0, 50, - 0, 0, 49, 0, 70, 71, 69, 72, 73, 76, - 77, 78, 63, 64, 65, 66, 67, 68, 75, 126, - 58, 98, 107, 118, 12, 17, 14, 0, 0, 16, - 13, 26, 118, 95, 82, 83, 51, 0, 44, 51, - 0, 43, 119, 0, 18, 15, 0, 50, 0, 0, - 50, 50, 20, 0, 122, 122, 52, 53, 0, 0, - 50, 49, 30, 120, 0, 51, 51, 0, 50, 51, - 0, 51, 0, 48, 49, 50, 38, 0, 121, 114, - 117, 23, 51, 50, 27, 50, 50, 40, 36, 0, - 0, 37, 33, 0, 50, 0, 0, 35, 0, 0, - 50, 49, 50, 49, 0, 0, 0, 0, 49, 31, - 0, 32, 0, 0, 24, 28, 29, 50, 34, 50, - 25, 41, 39 + 0, 0, 121, 0, 103, 106, 0, 101, 49, 0, + 46, 0, 0, 0, 0, 0, 0, 49, 0, 109, + 0, 0, 81, 2, 0, 50, 0, 0, 49, 0, + 70, 71, 69, 72, 73, 76, 77, 78, 63, 64, + 65, 66, 67, 68, 75, 124, 58, 96, 105, 116, + 12, 17, 14, 0, 0, 16, 13, 26, 116, 93, + 82, 83, 51, 0, 44, 51, 0, 43, 117, 0, + 18, 15, 0, 50, 0, 0, 50, 50, 20, 0, + 120, 120, 52, 53, 0, 0, 50, 49, 30, 118, + 0, 51, 51, 0, 50, 51, 0, 51, 0, 48, + 49, 50, 38, 0, 119, 112, 115, 23, 51, 50, + 27, 50, 50, 40, 36, 0, 0, 37, 33, 0, + 50, 0, 0, 35, 0, 0, 50, 49, 50, 49, + 0, 0, 0, 0, 49, 31, 0, 32, 0, 0, + 24, 28, 29, 50, 34, 50, 25, 41, 39 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 32, 196, 33, 51, 35, 197, 37, 242, 226, - 227, 216, 228, 96, 38, 39, 40, 217, 252, 177, - 187, 41, 192, 60, 43, 68, 69, 44, 45, 122, - 131, 183, 205, 46, 56 + -1, 30, 192, 31, 49, 33, 193, 35, 238, 222, + 223, 212, 224, 92, 36, 37, 38, 213, 248, 173, + 183, 39, 188, 58, 41, 66, 67, 42, 43, 118, + 127, 179, 201, 44, 54 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -199 +#define YYPACT_NINF -198 static const yytype_int16 yypact[] = { - 248, -50, -199, -199, 169, -199, -199, 169, 169, 169, - 49, -199, -199, 9, 588, -199, 13, 26, 18, 169, - 4, 11, 34, 36, 39, 169, 626, 169, 169, 169, - 169, 169, 6, -199, 7, -199, -199, -199, -17, -7, - 394, 813, -199, -199, -199, -199, -199, -199, -199, -16, - 169, -199, 813, 813, 813, 813, -18, 169, 169, -199, - -6, 169, -199, 169, -199, 43, -199, 813, -5, -199, - -199, -199, -199, 640, 56, -199, -36, 169, -28, 38, - -199, -199, 693, -199, -5, -199, 857, 715, 857, 857, - 764, -199, 348, 394, 169, 394, 42, 791, 169, 169, - 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, - 169, 169, 169, 640, 169, -58, -18, 65, 813, 813, - 169, -199, -199, 67, -199, 169, 169, 671, 169, 169, - 169, -199, 169, -199, 169, 169, -199, -199, 10, 813, - 14, 737, -50, 169, 813, 813, 813, 813, 813, 813, - 813, 813, 835, 835, 857, 857, 813, 813, 813, 813, - -199, -199, 813, 68, -199, 813, 813, 169, 169, 813, - 813, 813, 68, 813, 813, 813, -199, -4, -199, -199, - 542, 813, -199, -57, 813, 813, -57, 411, 45, 169, - 411, -199, -199, 74, 20, 20, -199, -199, 70, 169, - 813, -10, -3, -199, 80, -199, -199, 59, 813, -199, - 76, -199, 83, -199, -199, 83, -199, 394, -199, 411, - 411, -199, -199, 411, -199, 411, 83, 83, -199, 394, - 542, -199, 60, 73, 411, 93, 94, -199, 95, 81, - -199, -199, -199, -199, 102, 90, 106, 125, -14, -199, - 542, -199, 479, 116, -199, -199, -199, 411, -199, -199, - -199, -199, -199 + 243, -53, -198, -198, 385, -198, -198, 385, 385, 385, + 791, -198, -198, 18, 573, -198, 22, 385, 7, 6, + 26, 31, 36, 385, 613, 385, 385, 385, 385, 385, + 4, -198, 5, -198, -198, -198, -48, -8, 512, 769, + -198, -198, -198, -198, -198, -198, -198, -14, 385, -198, + 769, 769, 769, 769, -21, 385, 385, -198, -4, 385, + -198, 385, -198, 38, -198, 769, 8, -198, -198, 151, + 54, -198, -37, 385, -29, 39, -198, -198, 649, -198, + 8, -198, 840, 671, 840, 840, 720, -198, 341, 512, + 385, 512, 40, 747, 385, 385, 385, 385, 385, 385, + 385, 385, 385, 385, 385, 385, 385, 385, 385, 151, + 385, -57, -21, 63, 769, 769, 385, -198, -198, 64, + -198, 385, 385, 627, 385, 385, 385, -198, 385, -198, + 385, 385, -198, -198, 9, 769, 14, 693, -53, 385, + 769, 769, 769, 769, 769, 769, 769, 769, 818, 818, + 840, 840, 769, 769, 769, 769, -198, -198, 769, 65, + -198, 769, 769, 385, 385, 769, 769, 769, 65, 769, + 769, 769, -198, -12, -198, -198, 529, 769, -198, -58, + 769, 769, -58, 402, 49, 385, 402, -198, -198, 73, + 13, 13, -198, -198, 71, 385, 769, -11, -17, -198, + 78, -198, -198, 60, 769, -198, 72, -198, 77, -198, + -198, 77, -198, 512, -198, 402, 402, -198, -198, 402, + -198, 402, 77, 77, -198, 512, 529, -198, 57, 67, + 402, 79, 80, -198, 81, 68, -198, -198, -198, -198, + 85, 74, 84, 87, -16, -198, 529, -198, 468, 76, + -198, -198, -198, 402, -198, -198, -198, -198, -198 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -199, -199, 12, 71, 3, -172, 0, -199, -199, -199, - -45, -197, -67, -91, -199, -199, -199, -198, -9, 115, - -169, 41, 5, -199, -199, 134, -11, -199, -199, -199, - -199, -8, -33, -199, 17 + -198, -198, 12, 25, 2, -170, 0, -198, -198, -198, + -78, -197, -101, -61, -198, -198, -198, -186, -9, 113, + -167, 41, 3, -198, -198, 98, -7, -198, -198, -198, + -198, -45, -67, -198, 16 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -809,231 +805,228 @@ static const yytype_int16 yypgoto[] = #define YYTABLE_NINF -60 static const yytype_int16 yytable[] = { - 36, 58, 138, 34, 140, 42, 91, -10, 191, 125, - 190, -51, -51, 48, 229, 85, 210, 128, 231, 188, - 47, 160, 213, 76, 77, 114, 193, 47, 229, 59, - 231, 78, 63, 70, 65, 126, 219, 220, 72, 211, - 223, 189, 225, 129, 92, 52, 214, 71, 53, 54, - 55, 74, 75, 234, 79, 67, 80, 121, 240, 81, - 73, 93, 57, -51, 94, 114, 82, 67, 86, 87, - 88, 89, 90, 133, 115, 116, 124, 117, 258, 257, - 120, 97, 130, 47, -10, 161, 142, 164, 182, 176, - 199, 113, 36, 178, 203, 34, 207, 42, 55, 55, - 218, 221, 118, 204, 119, -59, -59, 224, 213, 241, - -59, -59, -59, 163, -59, -59, -59, 243, 127, 245, - 246, 247, 172, -59, -59, 248, 233, 57, 253, -59, - -59, -59, 254, 180, 97, 139, 141, 255, 239, 144, + 34, 56, 32, 40, 87, -10, 187, 121, 186, 209, + -51, -51, 184, 46, 227, 124, 206, 81, 45, 72, + 73, 156, 225, 45, 189, 110, 227, 74, 134, 89, + 136, 210, 185, 122, 215, 216, 225, 207, 219, 57, + 221, 125, 88, 68, 61, 50, 63, 75, 51, 52, + 53, 230, 76, 70, 71, 65, 236, 77, 69, 117, + -51, 110, 90, 55, 78, 65, 82, 83, 84, 85, + 86, 111, 112, 129, 116, 120, 254, 253, 113, 93, + 45, -10, 126, 138, 157, 160, 178, 172, 34, 109, + 32, 40, 174, 195, 199, 200, 53, 53, 203, 214, + 114, 217, 115, 209, 220, 237, 241, 242, 243, 159, + 239, 244, 249, 133, 123, 250, 251, 256, 168, 252, + 211, 233, 80, 182, 202, 0, 0, 0, 0, 176, + 93, 135, 137, 0, 0, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 179, 159, 256, 215, 260, 237, - 84, 162, 206, 137, 186, 0, 165, 166, 0, 169, - 170, 171, 0, 173, 0, 174, 175, 0, 0, 0, - 2, 3, 4, 5, 181, 6, 0, 0, 0, 49, - 11, 0, 212, 0, 0, 194, 0, 0, 195, 0, - 0, 0, 0, 0, 0, 230, 0, 0, 184, 185, - 50, 0, 21, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 200, 0, 250, 27, 0, 0, 0, 28, 0, 0, - 208, 29, 30, 0, 0, 0, 0, 31, -6, 1, - 0, 0, 259, 0, 0, 0, 0, 0, 97, 2, - 3, 4, 5, 0, 6, 7, 8, 9, 10, 11, - 97, 0, 0, 0, 0, 12, 0, 13, 14, 15, - 0, 0, 16, 17, 18, 0, 0, 0, 0, 19, - 20, 21, 0, 0, 22, 0, 0, 0, 23, 24, - 25, 26, 198, 0, 0, 201, 202, 0, 0, 0, - 0, 0, 27, 0, 0, 209, 28, 0, 0, 0, - 29, 30, 0, 222, 0, -6, 31, 0, 0, 0, - 232, 0, 0, 0, 0, 0, 0, 0, 235, 0, - 236, 238, 0, 0, 0, 0, 0, 0, 0, 244, - 0, 0, 0, 0, 0, 249, 0, 251, 0, 2, - 3, 4, 5, 0, 6, 7, 8, 9, 10, 11, - 0, 0, 261, 0, 262, 12, 0, 13, 14, 15, - 0, 0, 16, 17, 18, 0, 0, 0, 0, 19, - 20, 21, 0, 0, 22, 0, 0, 0, 23, 24, - 25, 26, 0, 0, 0, 2, 3, 4, 5, 0, - 6, 0, 27, 0, 49, 11, 28, 0, 0, 0, - 29, 30, 2, 3, 4, 5, 31, 6, 7, 8, - 9, 49, 11, 0, 0, 50, 0, 21, 12, 0, - 13, 14, 15, 0, 0, 0, 17, 18, 0, 0, - 0, 0, 19, 20, 21, 0, 0, 22, 27, 0, - 0, 0, 28, 25, 26, 0, 29, 30, 0, 0, - 0, 0, 95, 0, 0, 27, 0, 0, 0, 28, - 0, 0, 0, 29, 30, 0, 0, 0, 47, 31, - 2, 3, 4, 5, 0, 6, 7, 8, 9, 49, + 175, 155, 229, 0, 0, 0, 0, 158, 0, 0, + 0, 0, 161, 162, 235, 165, 166, 167, 0, 169, + 0, 170, 171, 0, 0, 0, 0, 0, 0, 0, + 177, 0, 0, 0, 119, 0, 0, 0, 208, 0, + 0, 190, 0, 0, 191, 0, 0, 0, 0, 0, + 0, 226, 0, 0, 180, 181, 94, 95, 0, 0, + 0, 96, 97, 98, 0, 99, 100, 101, 0, 0, + 0, 0, 102, 103, 104, 105, 196, 0, 246, 0, + 106, 107, 108, 0, 0, 0, 204, 0, 0, 0, + 0, 0, 0, -6, 1, 0, 0, 0, 255, 0, + 0, 0, 0, 0, 93, 2, 3, 4, 5, 0, + 6, 7, 8, 9, 10, 11, 93, 0, 0, 0, + 0, 12, 0, 13, 14, 15, 0, 0, 16, 0, + 0, 0, 0, 17, 18, 19, 0, 0, 20, 0, + 0, 0, 21, 22, 23, 24, 194, 0, 0, 197, + 198, 0, 0, 0, 0, 0, 25, 0, 0, 205, + 26, 0, 0, 0, 27, 28, 0, 218, 0, -6, + 29, 0, 0, 0, 228, 0, 0, 0, 0, 0, + 0, 0, 231, 0, 232, 234, 0, 0, 0, 0, + 0, 0, 0, 240, 0, 0, 0, 0, 0, 245, + 0, 247, 0, 2, 3, 4, 5, 0, 6, 7, + 8, 9, 10, 11, 0, 0, 257, 0, 258, 12, + 0, 13, 14, 15, 0, 0, 16, 0, 0, 0, + 0, 17, 18, 19, 0, 0, 20, 0, 0, 0, + 21, 22, 23, 24, 0, 0, 0, 2, 3, 4, + 5, 0, 6, 0, 25, 0, 47, 11, 26, 0, + 0, 0, 27, 28, 2, 3, 4, 5, 29, 6, + 7, 8, 9, 47, 11, 48, 0, 19, 0, 0, + 12, 0, 13, 14, 15, 0, 0, 0, 0, 0, + 0, 0, 17, 18, 19, 0, 0, 20, 25, 0, + 0, 0, 26, 23, 24, 0, 27, 28, 0, 0, + 0, 0, 29, 0, 0, 25, 0, 0, 0, 26, + 0, 0, 0, 27, 28, 0, 0, 0, 45, 29, + 2, 3, 4, 5, 0, 6, 7, 8, 9, 47, 11, 0, 0, 0, 0, 0, 12, 0, 13, 14, - 15, 0, 0, 0, 17, 18, 0, 0, 0, 0, - 19, 20, 21, 0, 0, 22, 0, 0, 0, 0, - 0, 25, 26, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 27, 0, 0, 0, 28, 0, 0, - 0, 29, 30, 2, 3, 4, 5, 31, 6, 7, - 8, 9, 49, 11, 0, 0, 0, 0, 0, 12, - 0, 13, 14, 0, 0, 0, 0, 17, 18, 0, - 0, 0, 0, 19, 0, 21, 0, 0, 0, 0, - 0, 0, 0, 0, 25, 26, 0, 0, 0, 2, - 3, 4, 5, 0, 6, 0, 27, 0, 49, 11, - 28, 0, 0, 0, 29, 30, 61, 0, 0, 0, - 31, 62, 0, 0, 0, 63, 64, 65, 66, 50, - 0, 21, 0, 0, 0, 0, 0, 2, 3, 4, - 5, 0, 6, 0, 0, 0, 49, 11, 0, 0, - 0, 0, 27, 0, 61, 0, 28, 0, 0, 0, - 29, 30, 0, 63, 0, 65, 31, 50, 0, 21, - 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, - 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 27, 0, 0, 0, 28, 0, 98, 99, 29, 30, - 0, 100, 101, 102, 31, 103, 104, 105, 0, 0, - 0, 0, 106, 107, 108, 109, 167, 0, 0, 0, - 110, 111, 112, 0, 0, 0, 0, 98, 99, 0, - 0, 0, 100, 101, 102, 0, 103, 104, 105, 0, - 132, 0, 168, 106, 107, 108, 109, 0, 0, 98, - 99, 110, 111, 112, 100, 101, 102, 0, 103, 104, - 105, 0, 0, 0, 0, 106, 107, 108, 109, 0, - 0, 98, 99, 110, 111, 112, 100, 101, 102, 0, - 103, 104, 105, 0, 134, 135, 0, 106, 107, 108, - 109, 0, 0, 98, 99, 110, 111, 112, 100, 101, - 102, 0, 103, 104, 105, 0, 0, 0, 143, 106, - 107, 108, 109, 0, 0, 0, 136, 110, 111, 112, - 98, 99, 0, 0, 0, 100, 101, 102, 0, 103, - 104, 105, 0, 0, 0, 0, 106, 107, 108, 109, - 0, 0, 0, 136, 110, 111, 112, 98, 99, 0, - 0, 0, 100, 101, 102, 0, 103, 104, 105, 0, - 0, 0, 143, 106, 107, 108, 109, 0, 0, 98, - 99, 110, 111, 112, 100, 101, 102, 0, 103, 104, - 105, 0, 0, 0, 0, 106, 107, 108, 109, 0, - 0, 98, 99, 110, 111, 112, 100, 101, 102, 0, - 103, 104, 105, 0, 0, 0, 0, 0, 0, 108, - 109, 0, 0, 98, 99, 110, 111, 112, 100, 101, - 102, 0, 103, 104, 105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 110, 111, 112 + 15, 0, 0, 0, 0, 0, 0, 0, 17, 18, + 19, 0, 0, 20, 0, 0, 0, 0, 0, 23, + 24, 0, 0, 0, 2, 3, 4, 5, 0, 6, + 0, 25, 0, 47, 11, 26, 0, 0, 0, 27, + 28, 2, 3, 4, 5, 29, 6, 7, 8, 9, + 47, 11, 48, 0, 19, 0, 0, 12, 0, 13, + 14, 0, 0, 0, 0, 0, 0, 0, 0, 17, + 0, 19, 0, 0, 0, 25, 0, 0, 0, 26, + 23, 24, 0, 27, 28, 2, 3, 4, 5, 91, + 6, 0, 25, 0, 47, 11, 26, 0, 0, 0, + 27, 28, 59, 0, 0, 0, 29, 60, 0, 61, + 62, 63, 64, 48, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 3, 4, 5, 0, + 6, 0, 0, 0, 47, 11, 25, 0, 0, 0, + 26, 0, 59, 0, 27, 28, 0, 0, 0, 61, + 29, 63, 0, 48, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, + 0, 163, 0, 0, 0, 0, 25, 0, 0, 0, + 26, 0, 94, 95, 27, 28, 0, 96, 97, 98, + 29, 99, 100, 101, 0, 128, 0, 164, 102, 103, + 104, 105, 0, 0, 94, 95, 106, 107, 108, 96, + 97, 98, 0, 99, 100, 101, 0, 0, 0, 0, + 102, 103, 104, 105, 0, 0, 94, 95, 106, 107, + 108, 96, 97, 98, 0, 99, 100, 101, 0, 130, + 131, 0, 102, 103, 104, 105, 0, 0, 94, 95, + 106, 107, 108, 96, 97, 98, 0, 99, 100, 101, + 0, 0, 0, 139, 102, 103, 104, 105, 0, 0, + 0, 132, 106, 107, 108, 94, 95, 0, 0, 0, + 96, 97, 98, 0, 99, 100, 101, 0, 0, 0, + 0, 102, 103, 104, 105, 0, 0, 0, 132, 106, + 107, 108, 94, 95, 0, 0, 0, 96, 97, 98, + 0, 99, 100, 101, 0, 0, 0, 139, 102, 103, + 104, 105, 0, 0, 94, 95, 106, 107, 108, 96, + 97, 98, 0, 99, 100, 101, 0, 0, 0, 0, + 102, 103, 104, 105, 0, 0, -59, -59, 106, 107, + 108, -59, -59, -59, 0, -59, -59, -59, 0, 0, + 0, 0, 0, 0, -59, -59, 0, 0, 55, 0, + -59, -59, -59, 94, 95, 0, 0, 0, 96, 97, + 98, 0, 99, 100, 101, 0, 0, 0, 0, 0, + 0, 104, 105, 0, 0, 94, 95, 106, 107, 108, + 96, 97, 98, 0, 99, 100, 101, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, + 107, 108 }; static const yytype_int16 yycheck[] = { - 0, 10, 93, 0, 95, 0, 0, 0, 180, 45, - 179, 25, 26, 1, 212, 26, 26, 45, 215, 23, - 77, 79, 25, 12, 13, 83, 83, 77, 226, 20, - 227, 20, 37, 20, 39, 71, 205, 206, 20, 49, - 209, 45, 211, 71, 32, 4, 49, 21, 7, 8, - 9, 47, 48, 222, 20, 14, 20, 68, 230, 20, - 19, 78, 78, 77, 71, 83, 25, 26, 27, 28, - 29, 30, 31, 84, 57, 58, 20, 83, 250, 248, - 37, 40, 44, 77, 77, 20, 44, 20, 20, 79, - 45, 50, 92, 79, 20, 92, 26, 92, 57, 58, - 20, 42, 61, 83, 63, 56, 57, 31, 25, 49, - 61, 62, 63, 122, 65, 66, 67, 44, 77, 26, - 26, 26, 131, 74, 75, 44, 217, 78, 26, 80, - 81, 82, 42, 142, 93, 94, 95, 31, 229, 98, + 0, 10, 0, 0, 0, 0, 176, 44, 175, 26, + 26, 27, 24, 1, 211, 44, 27, 24, 76, 13, + 14, 78, 208, 76, 82, 82, 223, 21, 89, 77, + 91, 48, 44, 70, 201, 202, 222, 48, 205, 21, + 207, 70, 30, 21, 36, 4, 38, 21, 7, 8, + 9, 218, 21, 46, 47, 14, 226, 21, 17, 66, + 76, 82, 70, 77, 23, 24, 25, 26, 27, 28, + 29, 55, 56, 80, 36, 21, 246, 244, 82, 38, + 76, 76, 43, 43, 21, 21, 21, 78, 88, 48, + 88, 88, 78, 44, 21, 82, 55, 56, 27, 21, + 59, 41, 61, 26, 32, 48, 27, 27, 27, 118, + 43, 43, 27, 88, 73, 41, 32, 41, 127, 32, + 198, 222, 24, 168, 191, -1, -1, -1, -1, 138, + 89, 90, 91, -1, -1, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 142, 114, 31, 202, 42, 226, - 26, 120, 195, 92, 172, -1, 125, 126, -1, 128, - 129, 130, -1, 132, -1, 134, 135, -1, -1, -1, - 11, 12, 13, 14, 143, 16, -1, -1, -1, 20, - 21, -1, 201, -1, -1, 183, -1, -1, 186, -1, - -1, -1, -1, -1, -1, 214, -1, -1, 167, 168, - 41, -1, 43, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 189, -1, 241, 64, -1, -1, -1, 68, -1, -1, - 199, 72, 73, -1, -1, -1, -1, 78, 0, 1, - -1, -1, 252, -1, -1, -1, -1, -1, 217, 11, - 12, 13, 14, -1, 16, 17, 18, 19, 20, 21, - 229, -1, -1, -1, -1, 27, -1, 29, 30, 31, - -1, -1, 34, 35, 36, -1, -1, -1, -1, 41, - 42, 43, -1, -1, 46, -1, -1, -1, 50, 51, - 52, 53, 187, -1, -1, 190, 191, -1, -1, -1, - -1, -1, 64, -1, -1, 200, 68, -1, -1, -1, - 72, 73, -1, 208, -1, 77, 78, -1, -1, -1, - 215, -1, -1, -1, -1, -1, -1, -1, 223, -1, - 225, 226, -1, -1, -1, -1, -1, -1, -1, 234, - -1, -1, -1, -1, -1, 240, -1, 242, -1, 11, - 12, 13, 14, -1, 16, 17, 18, 19, 20, 21, - -1, -1, 257, -1, 259, 27, -1, 29, 30, 31, - -1, -1, 34, 35, 36, -1, -1, -1, -1, 41, - 42, 43, -1, -1, 46, -1, -1, -1, 50, 51, - 52, 53, -1, -1, -1, 11, 12, 13, 14, -1, - 16, -1, 64, -1, 20, 21, 68, -1, -1, -1, - 72, 73, 11, 12, 13, 14, 78, 16, 17, 18, - 19, 20, 21, -1, -1, 41, -1, 43, 27, -1, - 29, 30, 31, -1, -1, -1, 35, 36, -1, -1, - -1, -1, 41, 42, 43, -1, -1, 46, 64, -1, - -1, -1, 68, 52, 53, -1, 72, 73, -1, -1, - -1, -1, 78, -1, -1, 64, -1, -1, -1, 68, - -1, -1, -1, 72, 73, -1, -1, -1, 77, 78, - 11, 12, 13, 14, -1, 16, 17, 18, 19, 20, - 21, -1, -1, -1, -1, -1, 27, -1, 29, 30, - 31, -1, -1, -1, 35, 36, -1, -1, -1, -1, - 41, 42, 43, -1, -1, 46, -1, -1, -1, -1, - -1, 52, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 64, -1, -1, -1, 68, -1, -1, - -1, 72, 73, 11, 12, 13, 14, 78, 16, 17, - 18, 19, 20, 21, -1, -1, -1, -1, -1, 27, - -1, 29, 30, -1, -1, -1, -1, 35, 36, -1, - -1, -1, -1, 41, -1, 43, -1, -1, -1, -1, - -1, -1, -1, -1, 52, 53, -1, -1, -1, 11, - 12, 13, 14, -1, 16, -1, 64, -1, 20, 21, - 68, -1, -1, -1, 72, 73, 28, -1, -1, -1, - 78, 33, -1, -1, -1, 37, 38, 39, 40, 41, - -1, 43, -1, -1, -1, -1, -1, 11, 12, 13, - 14, -1, 16, -1, -1, -1, 20, 21, -1, -1, - -1, -1, 64, -1, 28, -1, 68, -1, -1, -1, - 72, 73, -1, 37, -1, 39, 78, 41, -1, 43, - -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, - 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 64, -1, -1, -1, 68, -1, 56, 57, 72, 73, - -1, 61, 62, 63, 78, 65, 66, 67, -1, -1, - -1, -1, 72, 73, 74, 75, 45, -1, -1, -1, - 80, 81, 82, -1, -1, -1, -1, 56, 57, -1, - -1, -1, 61, 62, 63, -1, 65, 66, 67, -1, - 47, -1, 71, 72, 73, 74, 75, -1, -1, 56, - 57, 80, 81, 82, 61, 62, 63, -1, 65, 66, - 67, -1, -1, -1, -1, 72, 73, 74, 75, -1, - -1, 56, 57, 80, 81, 82, 61, 62, 63, -1, - 65, 66, 67, -1, 69, 70, -1, 72, 73, 74, - 75, -1, -1, 56, 57, 80, 81, 82, 61, 62, - 63, -1, 65, 66, 67, -1, -1, -1, 71, 72, - 73, 74, 75, -1, -1, -1, 79, 80, 81, 82, - 56, 57, -1, -1, -1, 61, 62, 63, -1, 65, - 66, 67, -1, -1, -1, -1, 72, 73, 74, 75, - -1, -1, -1, 79, 80, 81, 82, 56, 57, -1, - -1, -1, 61, 62, 63, -1, 65, 66, 67, -1, - -1, -1, 71, 72, 73, 74, 75, -1, -1, 56, - 57, 80, 81, 82, 61, 62, 63, -1, 65, 66, - 67, -1, -1, -1, -1, 72, 73, 74, 75, -1, - -1, 56, 57, 80, 81, 82, 61, 62, 63, -1, - 65, 66, 67, -1, -1, -1, -1, -1, -1, 74, - 75, -1, -1, 56, 57, 80, 81, 82, 61, 62, - 63, -1, 65, 66, 67, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 80, 81, 82 + 138, 110, 213, -1, -1, -1, -1, 116, -1, -1, + -1, -1, 121, 122, 225, 124, 125, 126, -1, 128, + -1, 130, 131, -1, -1, -1, -1, -1, -1, -1, + 139, -1, -1, -1, 33, -1, -1, -1, 197, -1, + -1, 179, -1, -1, 182, -1, -1, -1, -1, -1, + -1, 210, -1, -1, 163, 164, 55, 56, -1, -1, + -1, 60, 61, 62, -1, 64, 65, 66, -1, -1, + -1, -1, 71, 72, 73, 74, 185, -1, 237, -1, + 79, 80, 81, -1, -1, -1, 195, -1, -1, -1, + -1, -1, -1, 0, 1, -1, -1, -1, 248, -1, + -1, -1, -1, -1, 213, 12, 13, 14, 15, -1, + 17, 18, 19, 20, 21, 22, 225, -1, -1, -1, + -1, 28, -1, 30, 31, 32, -1, -1, 35, -1, + -1, -1, -1, 40, 41, 42, -1, -1, 45, -1, + -1, -1, 49, 50, 51, 52, 183, -1, -1, 186, + 187, -1, -1, -1, -1, -1, 63, -1, -1, 196, + 67, -1, -1, -1, 71, 72, -1, 204, -1, 76, + 77, -1, -1, -1, 211, -1, -1, -1, -1, -1, + -1, -1, 219, -1, 221, 222, -1, -1, -1, -1, + -1, -1, -1, 230, -1, -1, -1, -1, -1, 236, + -1, 238, -1, 12, 13, 14, 15, -1, 17, 18, + 19, 20, 21, 22, -1, -1, 253, -1, 255, 28, + -1, 30, 31, 32, -1, -1, 35, -1, -1, -1, + -1, 40, 41, 42, -1, -1, 45, -1, -1, -1, + 49, 50, 51, 52, -1, -1, -1, 12, 13, 14, + 15, -1, 17, -1, 63, -1, 21, 22, 67, -1, + -1, -1, 71, 72, 12, 13, 14, 15, 77, 17, + 18, 19, 20, 21, 22, 40, -1, 42, -1, -1, + 28, -1, 30, 31, 32, -1, -1, -1, -1, -1, + -1, -1, 40, 41, 42, -1, -1, 45, 63, -1, + -1, -1, 67, 51, 52, -1, 71, 72, -1, -1, + -1, -1, 77, -1, -1, 63, -1, -1, -1, 67, + -1, -1, -1, 71, 72, -1, -1, -1, 76, 77, + 12, 13, 14, 15, -1, 17, 18, 19, 20, 21, + 22, -1, -1, -1, -1, -1, 28, -1, 30, 31, + 32, -1, -1, -1, -1, -1, -1, -1, 40, 41, + 42, -1, -1, 45, -1, -1, -1, -1, -1, 51, + 52, -1, -1, -1, 12, 13, 14, 15, -1, 17, + -1, 63, -1, 21, 22, 67, -1, -1, -1, 71, + 72, 12, 13, 14, 15, 77, 17, 18, 19, 20, + 21, 22, 40, -1, 42, -1, -1, 28, -1, 30, + 31, -1, -1, -1, -1, -1, -1, -1, -1, 40, + -1, 42, -1, -1, -1, 63, -1, -1, -1, 67, + 51, 52, -1, 71, 72, 12, 13, 14, 15, 77, + 17, -1, 63, -1, 21, 22, 67, -1, -1, -1, + 71, 72, 29, -1, -1, -1, 77, 34, -1, 36, + 37, 38, 39, 40, -1, 42, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12, 13, 14, 15, -1, + 17, -1, -1, -1, 21, 22, 63, -1, -1, -1, + 67, -1, 29, -1, 71, 72, -1, -1, -1, 36, + 77, 38, -1, 40, -1, 42, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, + -1, 44, -1, -1, -1, -1, 63, -1, -1, -1, + 67, -1, 55, 56, 71, 72, -1, 60, 61, 62, + 77, 64, 65, 66, -1, 46, -1, 70, 71, 72, + 73, 74, -1, -1, 55, 56, 79, 80, 81, 60, + 61, 62, -1, 64, 65, 66, -1, -1, -1, -1, + 71, 72, 73, 74, -1, -1, 55, 56, 79, 80, + 81, 60, 61, 62, -1, 64, 65, 66, -1, 68, + 69, -1, 71, 72, 73, 74, -1, -1, 55, 56, + 79, 80, 81, 60, 61, 62, -1, 64, 65, 66, + -1, -1, -1, 70, 71, 72, 73, 74, -1, -1, + -1, 78, 79, 80, 81, 55, 56, -1, -1, -1, + 60, 61, 62, -1, 64, 65, 66, -1, -1, -1, + -1, 71, 72, 73, 74, -1, -1, -1, 78, 79, + 80, 81, 55, 56, -1, -1, -1, 60, 61, 62, + -1, 64, 65, 66, -1, -1, -1, 70, 71, 72, + 73, 74, -1, -1, 55, 56, 79, 80, 81, 60, + 61, 62, -1, 64, 65, 66, -1, -1, -1, -1, + 71, 72, 73, 74, -1, -1, 55, 56, 79, 80, + 81, 60, 61, 62, -1, 64, 65, 66, -1, -1, + -1, -1, -1, -1, 73, 74, -1, -1, 77, -1, + 79, 80, 81, 55, 56, -1, -1, -1, 60, 61, + 62, -1, 64, 65, 66, -1, -1, -1, -1, -1, + -1, 73, 74, -1, -1, 55, 56, 79, 80, 81, + 60, 61, 62, -1, 64, 65, 66, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, + 80, 81 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 1, 11, 12, 13, 14, 16, 17, 18, 19, - 20, 21, 27, 29, 30, 31, 34, 35, 36, 41, - 42, 43, 46, 50, 51, 52, 53, 64, 68, 72, - 73, 78, 85, 87, 88, 89, 90, 91, 98, 99, - 100, 105, 106, 108, 111, 112, 117, 77, 86, 20, - 41, 88, 105, 105, 105, 105, 118, 78, 102, 20, - 107, 28, 33, 37, 38, 39, 40, 105, 109, 110, - 20, 21, 20, 105, 47, 48, 12, 13, 20, 20, - 20, 20, 105, 54, 109, 110, 105, 105, 105, 105, - 105, 0, 86, 78, 71, 78, 97, 105, 56, 57, - 61, 62, 63, 65, 66, 67, 72, 73, 74, 75, - 80, 81, 82, 105, 83, 118, 118, 83, 105, 105, - 37, 110, 113, 32, 20, 45, 71, 105, 45, 71, - 44, 114, 47, 110, 69, 70, 79, 87, 97, 105, - 97, 105, 44, 71, 105, 105, 105, 105, 105, 105, - 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, - 79, 20, 105, 102, 20, 105, 105, 45, 71, 105, - 105, 105, 102, 105, 105, 105, 79, 103, 79, 86, - 102, 105, 20, 115, 105, 105, 115, 104, 23, 45, - 104, 89, 106, 83, 86, 86, 86, 90, 103, 45, - 105, 103, 103, 20, 83, 116, 116, 26, 105, 103, - 26, 49, 102, 25, 49, 94, 95, 101, 20, 104, - 104, 42, 103, 104, 31, 104, 93, 94, 96, 101, - 102, 95, 103, 97, 104, 103, 103, 96, 103, 97, - 89, 49, 92, 44, 103, 26, 26, 26, 44, 103, - 102, 103, 102, 26, 42, 31, 31, 104, 89, 90, - 42, 103, 103 + 0, 1, 12, 13, 14, 15, 17, 18, 19, 20, + 21, 22, 28, 30, 31, 32, 35, 40, 41, 42, + 45, 49, 50, 51, 52, 63, 67, 71, 72, 77, + 84, 86, 87, 88, 89, 90, 97, 98, 99, 104, + 105, 107, 110, 111, 116, 76, 85, 21, 40, 87, + 104, 104, 104, 104, 117, 77, 101, 21, 106, 29, + 34, 36, 37, 38, 39, 104, 108, 109, 21, 104, + 46, 47, 13, 14, 21, 21, 21, 21, 104, 53, + 108, 109, 104, 104, 104, 104, 104, 0, 85, 77, + 70, 77, 96, 104, 55, 56, 60, 61, 62, 64, + 65, 66, 71, 72, 73, 74, 79, 80, 81, 104, + 82, 117, 117, 82, 104, 104, 36, 109, 112, 33, + 21, 44, 70, 104, 44, 70, 43, 113, 46, 109, + 68, 69, 78, 86, 96, 104, 96, 104, 43, 70, + 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 78, 21, 104, 101, + 21, 104, 104, 44, 70, 104, 104, 104, 101, 104, + 104, 104, 78, 102, 78, 85, 101, 104, 21, 114, + 104, 104, 114, 103, 24, 44, 103, 88, 105, 82, + 85, 85, 85, 89, 102, 44, 104, 102, 102, 21, + 82, 115, 115, 27, 104, 102, 27, 48, 101, 26, + 48, 93, 94, 100, 21, 103, 103, 41, 102, 103, + 32, 103, 92, 93, 95, 100, 101, 94, 102, 96, + 103, 102, 102, 95, 102, 96, 88, 48, 91, 43, + 102, 27, 27, 27, 43, 102, 101, 102, 101, 27, + 41, 32, 32, 103, 88, 89, 41, 102, 102 }; #define yyerrok (yyerrstatus = 0) @@ -2334,140 +2327,130 @@ yyreduce: case 84: #line 399 "engines/director/lingo/lingo-gr.y" - { g_lingo->code1(g_lingo->c_mci); g_lingo->codeString((yyvsp[(2) - (2)].s)->c_str()); delete (yyvsp[(2) - (2)].s); ;} - break; - - case 85: -#line 400 "engines/director/lingo/lingo-gr.y" - { g_lingo->code1(g_lingo->c_mciwait); g_lingo->codeString((yyvsp[(2) - (2)].s)->c_str()); delete (yyvsp[(2) - (2)].s); ;} - break; - - case 86: -#line 401 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_printtop); ;} break; - case 89: -#line 404 "engines/director/lingo/lingo-gr.y" + case 87: +#line 402 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(0); // Push fake value on stack g_lingo->code1(g_lingo->c_procret); ;} break; - case 91: -#line 407 "engines/director/lingo/lingo-gr.y" + case 89: +#line 405 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->_handlers[*(yyvsp[(1) - (2)].s)]->u.func); delete (yyvsp[(1) - (2)].s); ;} break; - case 92: -#line 410 "engines/director/lingo/lingo-gr.y" + case 90: +#line 408 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->_handlers[*(yyvsp[(1) - (2)].s)]->u.func); delete (yyvsp[(1) - (2)].s); ;} break; - case 93: -#line 413 "engines/director/lingo/lingo-gr.y" + case 91: +#line 411 "engines/director/lingo/lingo-gr.y" { g_lingo->code2(g_lingo->c_voidpush, g_lingo->_handlers[*(yyvsp[(1) - (1)].s)]->u.func); delete (yyvsp[(1) - (1)].s); ;} break; - case 94: -#line 416 "engines/director/lingo/lingo-gr.y" + case 92: +#line 414 "engines/director/lingo/lingo-gr.y" { g_lingo->codeFunc((yyvsp[(1) - (2)].s), (yyvsp[(2) - (2)].narg)); ;} break; - case 95: -#line 417 "engines/director/lingo/lingo-gr.y" + case 93: +#line 415 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_open); ;} break; - case 96: -#line 418 "engines/director/lingo/lingo-gr.y" + case 94: +#line 416 "engines/director/lingo/lingo-gr.y" { g_lingo->code2(g_lingo->c_voidpush, g_lingo->c_open); ;} break; - case 97: -#line 421 "engines/director/lingo/lingo-gr.y" + case 95: +#line 419 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_global); g_lingo->codeString((yyvsp[(1) - (1)].s)->c_str()); delete (yyvsp[(1) - (1)].s); ;} break; - case 98: -#line 422 "engines/director/lingo/lingo-gr.y" + case 96: +#line 420 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_global); g_lingo->codeString((yyvsp[(3) - (3)].s)->c_str()); delete (yyvsp[(3) - (3)].s); ;} break; - case 99: -#line 433 "engines/director/lingo/lingo-gr.y" + case 97: +#line 431 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_gotoloop); ;} break; - case 100: -#line 434 "engines/director/lingo/lingo-gr.y" + case 98: +#line 432 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_gotonext); ;} break; - case 101: -#line 435 "engines/director/lingo/lingo-gr.y" + case 99: +#line 433 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_gotoprevious); ;} break; - case 102: -#line 436 "engines/director/lingo/lingo-gr.y" + case 100: +#line 434 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(1); g_lingo->code1(g_lingo->c_goto); ;} break; - case 103: -#line 439 "engines/director/lingo/lingo-gr.y" + case 101: +#line 437 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(3); g_lingo->code1(g_lingo->c_goto); ;} break; - case 104: -#line 442 "engines/director/lingo/lingo-gr.y" + case 102: +#line 440 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(2); g_lingo->code1(g_lingo->c_goto); ;} break; - case 109: -#line 455 "engines/director/lingo/lingo-gr.y" + case 107: +#line 453 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_playdone); ;} break; - case 110: -#line 456 "engines/director/lingo/lingo-gr.y" + case 108: +#line 454 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(1); g_lingo->code1(g_lingo->c_play); ;} break; - case 111: -#line 459 "engines/director/lingo/lingo-gr.y" + case 109: +#line 457 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(3); g_lingo->code1(g_lingo->c_play); ;} break; - case 112: -#line 462 "engines/director/lingo/lingo-gr.y" + case 110: +#line 460 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(2); g_lingo->code1(g_lingo->c_play); ;} break; - case 113: -#line 492 "engines/director/lingo/lingo-gr.y" + case 111: +#line 490 "engines/director/lingo/lingo-gr.y" { g_lingo->_indef = true; g_lingo->_currentFactory.clear(); ;} break; - case 114: -#line 493 "engines/director/lingo/lingo-gr.y" + case 112: +#line 491 "engines/director/lingo/lingo-gr.y" { g_lingo->codeConst(0); // Push fake value on stack g_lingo->code1(g_lingo->c_procret); @@ -2475,54 +2458,53 @@ yyreduce: g_lingo->_indef = false; ;} break; - case 115: -#line 498 "engines/director/lingo/lingo-gr.y" + case 113: +#line 496 "engines/director/lingo/lingo-gr.y" { g_lingo->codeFactory(*(yyvsp[(2) - (2)].s)); ;} break; - case 116: -#line 501 "engines/director/lingo/lingo-gr.y" + case 114: +#line 499 "engines/director/lingo/lingo-gr.y" { g_lingo->_indef = true; ;} break; - case 117: -#line 502 "engines/director/lingo/lingo-gr.y" + case 115: +#line 500 "engines/director/lingo/lingo-gr.y" { - g_lingo->codeConst(0); // Push fake value on stack - g_lingo->code1(g_lingo->c_procret); - g_lingo->define(*(yyvsp[(2) - (8)].s), (yyvsp[(4) - (8)].code), (yyvsp[(5) - (8)].narg), &g_lingo->_currentFactory); + g_lingo->code1(STOP); + g_lingo->define(*(yyvsp[(2) - (8)].s), (yyvsp[(4) - (8)].code), (yyvsp[(5) - (8)].narg) + 1, &g_lingo->_currentFactory); g_lingo->_indef = false; ;} break; - case 118: -#line 507 "engines/director/lingo/lingo-gr.y" + case 116: +#line 504 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = 0; ;} break; - case 119: -#line 508 "engines/director/lingo/lingo-gr.y" + case 117: +#line 505 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArg((yyvsp[(1) - (1)].s)); (yyval.narg) = 1; ;} break; - case 120: -#line 509 "engines/director/lingo/lingo-gr.y" + case 118: +#line 506 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArg((yyvsp[(3) - (3)].s)); (yyval.narg) = (yyvsp[(1) - (3)].narg) + 1; ;} break; - case 121: -#line 510 "engines/director/lingo/lingo-gr.y" + case 119: +#line 507 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArg((yyvsp[(4) - (4)].s)); (yyval.narg) = (yyvsp[(1) - (4)].narg) + 1; ;} break; - case 122: -#line 512 "engines/director/lingo/lingo-gr.y" + case 120: +#line 509 "engines/director/lingo/lingo-gr.y" { g_lingo->codeArgStore(); ;} break; - case 123: -#line 516 "engines/director/lingo/lingo-gr.y" + case 121: +#line 513 "engines/director/lingo/lingo-gr.y" { g_lingo->code1(g_lingo->c_call); g_lingo->codeString((yyvsp[(1) - (3)].s)->c_str()); @@ -2531,24 +2513,24 @@ yyreduce: g_lingo->code1(numpar); ;} break; - case 124: -#line 524 "engines/director/lingo/lingo-gr.y" + case 122: +#line 521 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = 0; ;} break; - case 125: -#line 525 "engines/director/lingo/lingo-gr.y" + case 123: +#line 522 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = 1; ;} break; - case 126: -#line 526 "engines/director/lingo/lingo-gr.y" + case 124: +#line 523 "engines/director/lingo/lingo-gr.y" { (yyval.narg) = (yyvsp[(1) - (3)].narg) + 1; ;} break; /* Line 1267 of yacc.c. */ -#line 2552 "engines/director/lingo/lingo-gr.cpp" +#line 2534 "engines/director/lingo/lingo-gr.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -2762,6 +2744,6 @@ yyreturn: } -#line 529 "engines/director/lingo/lingo-gr.y" +#line 526 "engines/director/lingo/lingo-gr.y" diff --git a/engines/director/lingo/lingo-gr.h b/engines/director/lingo/lingo-gr.h index d7ab8924cf..49bd8b5c08 100644 --- a/engines/director/lingo/lingo-gr.h +++ b/engines/director/lingo/lingo-gr.h @@ -47,66 +47,65 @@ RECT = 263, ARRAY = 264, SYMBOL = 265, - INT = 266, - THEENTITY = 267, - THEENTITYWITHID = 268, - FLOAT = 269, - BLTIN = 270, - BLTINNOARGS = 271, - BLTINNOARGSORONE = 272, - BLTINONEARG = 273, - BLTINARGLIST = 274, - ID = 275, - STRING = 276, - HANDLER = 277, - tDOWN = 278, - tELSE = 279, - tNLELSIF = 280, - tEND = 281, - tEXIT = 282, - tFRAME = 283, - tGLOBAL = 284, - tGO = 285, - tIF = 286, - tINTO = 287, - tLOOP = 288, - tMACRO = 289, - tMCI = 290, - tMCIWAIT = 291, - tMOVIE = 292, - tNEXT = 293, - tOF = 294, - tPREVIOUS = 295, - tPUT = 296, - tREPEAT = 297, - tSET = 298, - tTHEN = 299, - tTO = 300, - tWHEN = 301, - tWITH = 302, - tWHILE = 303, - tNLELSE = 304, - tFACTORY = 305, - tMETHOD = 306, - tOPEN = 307, - tPLAY = 308, - tDONE = 309, - tPLAYACCEL = 310, - tGE = 311, - tLE = 312, - tGT = 313, - tLT = 314, - tEQ = 315, - tNEQ = 316, - tAND = 317, - tOR = 318, - tNOT = 319, - tCONCAT = 320, - tCONTAINS = 321, - tSTARTS = 322, - tSPRITE = 323, - tINTERSECTS = 324, - tWITHIN = 325 + OBJECT = 266, + INT = 267, + THEENTITY = 268, + THEENTITYWITHID = 269, + FLOAT = 270, + BLTIN = 271, + BLTINNOARGS = 272, + BLTINNOARGSORONE = 273, + BLTINONEARG = 274, + BLTINARGLIST = 275, + ID = 276, + STRING = 277, + HANDLER = 278, + tDOWN = 279, + tELSE = 280, + tNLELSIF = 281, + tEND = 282, + tEXIT = 283, + tFRAME = 284, + tGLOBAL = 285, + tGO = 286, + tIF = 287, + tINTO = 288, + tLOOP = 289, + tMACRO = 290, + tMOVIE = 291, + tNEXT = 292, + tOF = 293, + tPREVIOUS = 294, + tPUT = 295, + tREPEAT = 296, + tSET = 297, + tTHEN = 298, + tTO = 299, + tWHEN = 300, + tWITH = 301, + tWHILE = 302, + tNLELSE = 303, + tFACTORY = 304, + tMETHOD = 305, + tOPEN = 306, + tPLAY = 307, + tDONE = 308, + tPLAYACCEL = 309, + tGE = 310, + tLE = 311, + tGT = 312, + tLT = 313, + tEQ = 314, + tNEQ = 315, + tAND = 316, + tOR = 317, + tNOT = 318, + tCONCAT = 319, + tCONTAINS = 320, + tSTARTS = 321, + tSPRITE = 322, + tINTERSECTS = 323, + tWITHIN = 324 }; #endif /* Tokens. */ @@ -118,66 +117,65 @@ #define RECT 263 #define ARRAY 264 #define SYMBOL 265 -#define INT 266 -#define THEENTITY 267 -#define THEENTITYWITHID 268 -#define FLOAT 269 -#define BLTIN 270 -#define BLTINNOARGS 271 -#define BLTINNOARGSORONE 272 -#define BLTINONEARG 273 -#define BLTINARGLIST 274 -#define ID 275 -#define STRING 276 -#define HANDLER 277 -#define tDOWN 278 -#define tELSE 279 -#define tNLELSIF 280 -#define tEND 281 -#define tEXIT 282 -#define tFRAME 283 -#define tGLOBAL 284 -#define tGO 285 -#define tIF 286 -#define tINTO 287 -#define tLOOP 288 -#define tMACRO 289 -#define tMCI 290 -#define tMCIWAIT 291 -#define tMOVIE 292 -#define tNEXT 293 -#define tOF 294 -#define tPREVIOUS 295 -#define tPUT 296 -#define tREPEAT 297 -#define tSET 298 -#define tTHEN 299 -#define tTO 300 -#define tWHEN 301 -#define tWITH 302 -#define tWHILE 303 -#define tNLELSE 304 -#define tFACTORY 305 -#define tMETHOD 306 -#define tOPEN 307 -#define tPLAY 308 -#define tDONE 309 -#define tPLAYACCEL 310 -#define tGE 311 -#define tLE 312 -#define tGT 313 -#define tLT 314 -#define tEQ 315 -#define tNEQ 316 -#define tAND 317 -#define tOR 318 -#define tNOT 319 -#define tCONCAT 320 -#define tCONTAINS 321 -#define tSTARTS 322 -#define tSPRITE 323 -#define tINTERSECTS 324 -#define tWITHIN 325 +#define OBJECT 266 +#define INT 267 +#define THEENTITY 268 +#define THEENTITYWITHID 269 +#define FLOAT 270 +#define BLTIN 271 +#define BLTINNOARGS 272 +#define BLTINNOARGSORONE 273 +#define BLTINONEARG 274 +#define BLTINARGLIST 275 +#define ID 276 +#define STRING 277 +#define HANDLER 278 +#define tDOWN 279 +#define tELSE 280 +#define tNLELSIF 281 +#define tEND 282 +#define tEXIT 283 +#define tFRAME 284 +#define tGLOBAL 285 +#define tGO 286 +#define tIF 287 +#define tINTO 288 +#define tLOOP 289 +#define tMACRO 290 +#define tMOVIE 291 +#define tNEXT 292 +#define tOF 293 +#define tPREVIOUS 294 +#define tPUT 295 +#define tREPEAT 296 +#define tSET 297 +#define tTHEN 298 +#define tTO 299 +#define tWHEN 300 +#define tWITH 301 +#define tWHILE 302 +#define tNLELSE 303 +#define tFACTORY 304 +#define tMETHOD 305 +#define tOPEN 306 +#define tPLAY 307 +#define tDONE 308 +#define tPLAYACCEL 309 +#define tGE 310 +#define tLE 311 +#define tGT 312 +#define tLT 313 +#define tEQ 314 +#define tNEQ 315 +#define tAND 316 +#define tOR 317 +#define tNOT 318 +#define tCONCAT 319 +#define tCONTAINS 320 +#define tSTARTS 321 +#define tSPRITE 322 +#define tINTERSECTS 323 +#define tWITHIN 324 @@ -195,7 +193,7 @@ typedef union YYSTYPE Common::Array<double> *arr; } /* Line 1529 of yacc.c. */ -#line 199 "engines/director/lingo/lingo-gr.hpp" +#line 197 "engines/director/lingo/lingo-gr.hpp" YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 diff --git a/engines/director/lingo/lingo-gr.y b/engines/director/lingo/lingo-gr.y index 0e25ec5361..ea66bc6fd9 100644 --- a/engines/director/lingo/lingo-gr.y +++ b/engines/director/lingo/lingo-gr.y @@ -77,14 +77,14 @@ void yyerror(char *s) { } %token UNARY -%token CASTREF VOID VAR POINT RECT ARRAY SYMBOL +%token CASTREF VOID VAR POINT RECT ARRAY SYMBOL OBJECT %token<i> INT %token<e> THEENTITY THEENTITYWITHID %token<f> FLOAT %token<s> BLTIN BLTINNOARGS BLTINNOARGSORONE BLTINONEARG BLTINARGLIST %token<s> ID STRING HANDLER %token tDOWN tELSE tNLELSIF tEND tEXIT tFRAME tGLOBAL tGO tIF tINTO tLOOP tMACRO -%token tMCI tMCIWAIT tMOVIE tNEXT tOF tPREVIOUS tPUT tREPEAT tSET tTHEN tTO tWHEN +%token tMOVIE tNEXT tOF tPREVIOUS tPUT tREPEAT tSET tTHEN tTO tWHEN %token tWITH tWHILE tNLELSE tFACTORY tMETHOD tOPEN tPLAY tDONE tPLAYACCEL %token tGE tLE tGT tLT tEQ tNEQ tAND tOR tNOT %token tCONCAT tCONTAINS tSTARTS @@ -396,9 +396,7 @@ expr: INT { $$ = g_lingo->codeConst($1); } | tSPRITE expr tWITHIN expr { g_lingo->code1(g_lingo->c_within); } ; -func: tMCI STRING { g_lingo->code1(g_lingo->c_mci); g_lingo->codeString($2->c_str()); delete $2; } - | tMCIWAIT ID { g_lingo->code1(g_lingo->c_mciwait); g_lingo->codeString($2->c_str()); delete $2; } - | tPUT expr { g_lingo->code1(g_lingo->c_printtop); } +func: tPUT expr { g_lingo->code1(g_lingo->c_printtop); } | gotofunc | playfunc | tEXIT { g_lingo->codeConst(0); // Push fake value on stack @@ -500,9 +498,8 @@ defn: tMACRO ID { g_lingo->_indef = true; g_lingo->_currentFactory.clear(); } } | tMETHOD ID { g_lingo->_indef = true; } begin argdef nl argstore stmtlist { - g_lingo->codeConst(0); // Push fake value on stack - g_lingo->code1(g_lingo->c_procret); - g_lingo->define(*$2, $4, $5, &g_lingo->_currentFactory); + g_lingo->code1(STOP); + g_lingo->define(*$2, $4, $5 + 1, &g_lingo->_currentFactory); g_lingo->_indef = false; } ; argdef: /* nothing */ { $$ = 0; } | ID { g_lingo->codeArg($1); $$ = 1; } diff --git a/engines/director/lingo/lingo-lex.cpp b/engines/director/lingo/lingo-lex.cpp index 69c8745a86..5fbd8d8653 100644 --- a/engines/director/lingo/lingo-lex.cpp +++ b/engines/director/lingo/lingo-lex.cpp @@ -364,8 +364,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 58 -#define YY_END_OF_BUFFER 59 +#define YY_NUM_RULES 56 +#define YY_END_OF_BUFFER 57 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -373,30 +373,28 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[197] = +static yyconst flex_int16_t yy_accept[191] = { 0, - 0, 0, 59, 57, 3, 55, 55, 57, 57, 54, - 54, 54, 53, 54, 54, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, - 51, 51, 2, 2, 3, 55, 0, 0, 0, 0, - 0, 56, 50, 1, 52, 53, 49, 47, 48, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 18, - 8, 51, 51, 51, 51, 51, 51, 51, 51, 29, - 51, 31, 51, 51, 51, 51, 51, 51, 51, 51, - 41, 51, 51, 2, 2, 0, 1, 52, 4, 51, - 51, 51, 51, 12, 51, 51, 51, 51, 0, 51, - - 51, 51, 23, 51, 51, 51, 28, 51, 51, 51, - 34, 51, 36, 51, 51, 51, 51, 51, 51, 0, - 51, 6, 7, 11, 14, 51, 51, 51, 0, 51, - 20, 21, 51, 51, 51, 51, 27, 30, 32, 51, - 51, 51, 51, 0, 40, 45, 51, 43, 10, 51, - 51, 15, 51, 17, 51, 22, 51, 51, 26, 51, - 51, 51, 51, 39, 46, 51, 0, 51, 51, 16, - 51, 51, 25, 51, 35, 42, 37, 0, 44, 0, - 51, 13, 51, 24, 51, 0, 9, 5, 51, 33, - 0, 51, 0, 19, 38, 0 - + 0, 0, 57, 55, 3, 53, 53, 55, 55, 52, + 52, 52, 51, 52, 52, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 2, 2, 3, 53, 0, 0, 0, 0, + 0, 54, 48, 1, 50, 51, 47, 45, 46, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 18, + 8, 49, 49, 49, 49, 49, 49, 49, 27, 49, + 29, 49, 49, 49, 49, 49, 49, 49, 49, 39, + 49, 49, 2, 2, 0, 1, 50, 4, 49, 49, + 49, 49, 12, 49, 49, 49, 49, 0, 49, 49, + + 49, 49, 49, 49, 26, 49, 49, 49, 32, 49, + 34, 49, 49, 49, 49, 49, 49, 0, 49, 6, + 7, 11, 14, 49, 49, 49, 0, 49, 20, 21, + 49, 49, 49, 25, 28, 30, 49, 49, 49, 49, + 0, 38, 43, 49, 41, 10, 49, 49, 15, 49, + 17, 49, 22, 49, 24, 49, 49, 49, 49, 37, + 44, 49, 0, 49, 49, 16, 49, 23, 49, 33, + 40, 35, 0, 42, 0, 49, 13, 49, 49, 0, + 9, 5, 49, 31, 0, 49, 0, 19, 36, 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -441,61 +439,59 @@ static yyconst flex_int32_t yy_meta[61] = 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 } ; -static yyconst flex_int16_t yy_base[202] = +static yyconst flex_int16_t yy_base[196] = { 0, - 0, 59, 187, 465, 63, 67, 71, 75, 169, 465, - 152, 140, 52, 68, 130, 56, 0, 56, 57, 67, - 72, 68, 68, 69, 112, 70, 104, 111, 80, 118, - 130, 143, 175, 180, 189, 465, 193, 167, 197, 80, - 136, 465, 465, 0, 93, 90, 465, 465, 465, 0, - 104, 82, 176, 108, 112, 165, 187, 190, 117, 133, - 0, 175, 180, 192, 190, 183, 184, 183, 188, 0, - 202, 0, 207, 204, 193, 198, 200, 205, 221, 220, - 0, 230, 212, 266, 276, 220, 0, 80, 0, 220, - 240, 234, 243, 0, 232, 233, 240, 256, 280, 271, - - 263, 263, 259, 254, 272, 265, 0, 271, 264, 268, - 0, 284, 0, 281, 276, 303, 282, 285, 285, 294, - 303, 0, 0, 0, 0, 283, 304, 311, 308, 308, - 0, 0, 311, 325, 315, 322, 0, 0, 0, 321, - 330, 316, 317, 169, 0, 0, 327, 328, 212, 329, - 324, 0, 330, 465, 325, 0, 334, 340, 0, 332, - 331, 348, 342, 252, 0, 347, 382, 353, 348, 0, - 369, 358, 0, 359, 0, 0, 0, 393, 0, 373, - 368, 0, 377, 0, 369, 381, 465, 0, 372, 0, - 404, 376, 409, 0, 414, 465, 444, 446, 451, 455, - - 459 + 0, 59, 203, 452, 63, 67, 71, 75, 167, 452, + 157, 154, 52, 68, 143, 56, 0, 56, 57, 67, + 72, 68, 68, 69, 85, 102, 102, 104, 80, 119, + 113, 120, 173, 177, 181, 452, 185, 189, 193, 102, + 99, 452, 452, 0, 80, 129, 452, 452, 452, 0, + 91, 120, 165, 118, 126, 146, 184, 187, 171, 96, + 0, 172, 177, 189, 178, 177, 178, 184, 0, 188, + 0, 202, 199, 188, 192, 192, 199, 220, 219, 0, + 226, 208, 251, 262, 217, 0, 78, 0, 219, 227, + 230, 239, 0, 228, 229, 242, 256, 273, 257, 250, + + 251, 255, 263, 256, 0, 262, 253, 258, 0, 274, + 0, 271, 267, 304, 271, 274, 273, 284, 299, 0, + 0, 0, 0, 279, 297, 308, 297, 296, 0, 0, + 301, 304, 314, 0, 0, 0, 311, 320, 305, 307, + 156, 0, 0, 322, 319, 341, 321, 320, 0, 326, + 452, 322, 0, 327, 0, 328, 329, 344, 336, 370, + 0, 343, 375, 344, 341, 0, 345, 0, 348, 0, + 0, 0, 380, 0, 363, 355, 0, 372, 360, 372, + 452, 0, 363, 0, 394, 366, 398, 0, 400, 452, + 431, 433, 438, 442, 446 + } ; -static yyconst flex_int16_t yy_def[202] = +static yyconst flex_int16_t yy_def[196] = { 0, - 196, 1, 196, 196, 196, 196, 196, 196, 197, 196, - 196, 196, 196, 196, 196, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 196, 196, 196, 196, 196, 196, 196, 196, - 197, 196, 196, 199, 196, 196, 196, 196, 196, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 196, 196, 196, 199, 196, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 196, 198, - - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 196, - 198, 198, 198, 198, 198, 198, 198, 198, 196, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 200, 198, 198, 198, 198, 196, 198, - 198, 198, 198, 196, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 200, 198, 198, 196, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 196, 198, 196, - 198, 198, 198, 198, 198, 196, 196, 198, 198, 198, - 196, 198, 201, 198, 201, 0, 196, 196, 196, 196, - - 196 + 190, 1, 190, 190, 190, 190, 190, 190, 191, 190, + 190, 190, 190, 190, 190, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 190, 190, 190, 190, 190, 190, 190, 190, + 191, 190, 190, 193, 190, 190, 190, 190, 190, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 190, 190, 190, 193, 190, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 190, 192, 192, + + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 190, 192, 192, + 192, 192, 192, 192, 192, 192, 190, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 194, 192, 192, 192, 192, 190, 192, 192, 192, 192, + 190, 192, 192, 192, 192, 192, 192, 192, 192, 194, + 192, 192, 190, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 190, 192, 190, 192, 192, 192, 192, 190, + 190, 192, 192, 192, 190, 192, 195, 192, 195, 0, + 190, 190, 190, 190, 190 + } ; -static yyconst flex_int16_t yy_nxt[526] = +static yyconst flex_int16_t yy_nxt[513] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 4, 13, 14, 10, 15, 16, 17, 18, 19, 20, 21, @@ -505,59 +501,58 @@ static yyconst flex_int16_t yy_nxt[526] = 27, 28, 29, 30, 31, 17, 17, 32, 17, 17, 33, 45, 46, 34, 35, 36, 36, 37, 38, 39, 39, 38, 38, 39, 39, 38, 37, 36, 36, 37, - 47, 48, 51, 52, 53, 40, 57, 61, 68, 40, - 88, 54, 59, 55, 62, 60, 63, 69, 76, 45, - - 46, 58, 56, 88, 86, 51, 52, 53, 90, 40, - 57, 61, 68, 40, 54, 59, 55, 62, 60, 63, - 69, 89, 76, 70, 58, 56, 64, 86, 65, 94, - 66, 90, 71, 72, 99, 73, 77, 99, 93, 67, - 74, 42, 49, 75, 98, 89, 78, 70, 44, 79, - 64, 80, 65, 94, 66, 71, 72, 81, 73, 43, - 77, 93, 67, 74, 82, 83, 75, 98, 38, 78, - 144, 38, 79, 144, 42, 80, 84, 36, 36, 85, - 81, 85, 36, 36, 85, 40, 196, 95, 82, 83, - 35, 36, 36, 37, 37, 36, 36, 37, 38, 39, - - 39, 38, 91, 96, 97, 196, 100, 101, 102, 40, - 92, 95, 103, 167, 104, 40, 167, 105, 106, 107, - 108, 109, 110, 196, 111, 91, 112, 96, 97, 100, - 101, 113, 102, 92, 114, 115, 103, 104, 116, 40, - 105, 106, 107, 119, 108, 109, 110, 111, 117, 112, - 120, 121, 118, 178, 113, 196, 178, 114, 122, 115, - 123, 124, 116, 125, 126, 127, 119, 84, 36, 36, - 85, 128, 117, 120, 121, 135, 118, 85, 36, 36, - 85, 99, 122, 123, 99, 124, 125, 126, 127, 130, - 196, 132, 133, 134, 136, 128, 137, 138, 131, 135, - - 139, 140, 141, 142, 144, 143, 148, 144, 146, 147, - 151, 129, 149, 130, 132, 133, 134, 150, 136, 137, - 138, 131, 152, 139, 140, 153, 141, 142, 143, 145, - 148, 146, 147, 151, 129, 154, 149, 155, 156, 157, - 159, 150, 158, 160, 161, 165, 152, 162, 163, 153, - 166, 168, 145, 169, 170, 171, 172, 173, 154, 174, - 155, 156, 175, 157, 159, 158, 176, 160, 161, 165, - 162, 163, 177, 179, 166, 168, 169, 170, 171, 181, - 172, 173, 174, 167, 182, 175, 167, 183, 196, 184, - 176, 185, 187, 189, 178, 177, 179, 178, 188, 190, - - 191, 196, 181, 192, 180, 193, 194, 182, 193, 196, - 193, 183, 184, 193, 185, 196, 187, 189, 196, 196, - 186, 188, 190, 196, 191, 196, 192, 196, 180, 194, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 186, 41, 41, 196, 41, 41, 50, - 50, 87, 87, 196, 87, 87, 164, 196, 196, 164, - 195, 196, 196, 195, 3, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196 + 47, 48, 51, 52, 53, 40, 57, 61, 87, 40, + 87, 54, 59, 55, 62, 60, 63, 98, 75, 64, + + 98, 58, 56, 65, 42, 51, 52, 53, 88, 40, + 57, 61, 66, 40, 54, 59, 55, 62, 60, 63, + 67, 69, 75, 64, 58, 56, 85, 65, 72, 68, + 70, 71, 88, 73, 79, 66, 74, 76, 45, 46, + 80, 81, 82, 93, 67, 69, 89, 77, 92, 85, + 78, 72, 68, 70, 71, 49, 73, 141, 79, 74, + 141, 76, 44, 80, 43, 81, 82, 93, 94, 89, + 77, 92, 42, 78, 83, 36, 36, 84, 84, 36, + 36, 84, 35, 36, 36, 37, 37, 36, 36, 37, + 38, 90, 94, 38, 38, 39, 39, 38, 97, 91, + + 95, 96, 190, 99, 100, 101, 106, 40, 190, 102, + 103, 40, 190, 104, 90, 105, 107, 108, 190, 109, + 110, 97, 91, 111, 95, 96, 99, 100, 112, 101, + 106, 40, 102, 103, 113, 40, 104, 114, 105, 117, + 107, 108, 109, 110, 115, 120, 111, 118, 116, 190, + 119, 112, 83, 36, 36, 84, 121, 122, 113, 123, + 124, 114, 117, 84, 36, 36, 84, 125, 115, 120, + 118, 126, 116, 119, 98, 128, 132, 98, 130, 121, + 131, 122, 123, 124, 129, 133, 190, 134, 135, 136, + 125, 137, 138, 139, 145, 126, 140, 143, 144, 128, + + 132, 130, 146, 131, 127, 141, 148, 129, 141, 133, + 134, 135, 136, 147, 137, 149, 138, 139, 145, 140, + 143, 144, 150, 190, 151, 152, 146, 127, 153, 148, + 142, 154, 155, 156, 157, 190, 158, 147, 159, 149, + 161, 162, 163, 164, 168, 163, 150, 151, 152, 165, + 166, 153, 167, 142, 154, 169, 155, 156, 157, 158, + 170, 159, 171, 178, 161, 162, 172, 164, 168, 174, + 176, 173, 165, 166, 173, 167, 163, 177, 169, 163, + 179, 173, 181, 170, 173, 182, 171, 178, 183, 172, + 184, 185, 174, 176, 186, 187, 188, 175, 187, 187, + + 177, 190, 187, 179, 190, 190, 181, 180, 182, 190, + 190, 190, 183, 184, 190, 185, 190, 186, 190, 188, + 190, 175, 190, 190, 190, 190, 190, 190, 190, 190, + 180, 41, 41, 190, 41, 41, 50, 50, 86, 86, + 190, 86, 86, 160, 190, 190, 160, 189, 190, 190, + 189, 3, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190 } ; -static yyconst flex_int16_t yy_chk[526] = +static yyconst flex_int16_t yy_chk[513] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -567,56 +562,55 @@ static yyconst flex_int16_t yy_chk[526] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 13, 13, 2, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 14, 14, 16, 18, 19, 6, 21, 23, 26, 7, - 88, 20, 22, 20, 23, 22, 24, 26, 29, 46, - - 46, 21, 20, 45, 40, 16, 18, 19, 52, 6, - 21, 23, 26, 7, 20, 22, 20, 23, 22, 24, - 26, 51, 29, 27, 21, 20, 25, 40, 25, 55, - 25, 52, 27, 27, 60, 28, 30, 60, 54, 25, - 28, 41, 15, 28, 59, 51, 30, 27, 12, 30, - 25, 31, 25, 55, 25, 27, 27, 31, 28, 11, - 30, 54, 25, 28, 32, 32, 28, 59, 38, 30, - 144, 38, 30, 144, 9, 31, 33, 33, 33, 33, - 31, 34, 34, 34, 34, 38, 3, 56, 32, 32, - 35, 35, 35, 35, 37, 37, 37, 37, 39, 39, - - 39, 39, 53, 57, 58, 0, 62, 63, 64, 38, - 53, 56, 65, 149, 66, 39, 149, 67, 68, 69, - 71, 73, 74, 0, 75, 53, 76, 57, 58, 62, - 63, 77, 64, 53, 78, 79, 65, 66, 80, 39, - 67, 68, 69, 83, 71, 73, 74, 75, 82, 76, - 86, 90, 82, 164, 77, 0, 164, 78, 91, 79, - 92, 93, 80, 95, 96, 97, 83, 84, 84, 84, - 84, 98, 82, 86, 90, 104, 82, 85, 85, 85, - 85, 99, 91, 92, 99, 93, 95, 96, 97, 100, - 0, 101, 102, 103, 105, 98, 106, 108, 100, 104, - - 109, 110, 112, 114, 116, 115, 119, 116, 117, 118, - 126, 99, 120, 100, 101, 102, 103, 121, 105, 106, - 108, 100, 127, 109, 110, 128, 112, 114, 115, 116, - 119, 117, 118, 126, 99, 129, 120, 130, 133, 134, - 136, 121, 135, 140, 141, 147, 127, 142, 143, 128, - 148, 150, 116, 151, 153, 155, 157, 158, 129, 160, - 130, 133, 161, 134, 136, 135, 162, 140, 141, 147, - 142, 143, 163, 166, 148, 150, 151, 153, 155, 168, - 157, 158, 160, 167, 169, 161, 167, 171, 0, 172, - 162, 174, 180, 183, 178, 163, 166, 178, 181, 185, - - 186, 0, 168, 189, 167, 191, 192, 169, 191, 0, - 193, 171, 172, 193, 174, 195, 180, 183, 195, 0, - 178, 181, 185, 0, 186, 0, 189, 0, 167, 192, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 178, 197, 197, 0, 197, 197, 198, - 198, 199, 199, 0, 199, 199, 200, 0, 0, 200, - 201, 0, 0, 201, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, - 196, 196, 196, 196, 196 + 14, 14, 16, 18, 19, 6, 21, 23, 87, 7, + 45, 20, 22, 20, 23, 22, 24, 60, 29, 25, + + 60, 21, 20, 25, 41, 16, 18, 19, 51, 6, + 21, 23, 25, 7, 20, 22, 20, 23, 22, 24, + 26, 27, 29, 25, 21, 20, 40, 25, 28, 26, + 27, 27, 51, 28, 31, 25, 28, 30, 46, 46, + 31, 32, 32, 55, 26, 27, 52, 30, 54, 40, + 30, 28, 26, 27, 27, 15, 28, 141, 31, 28, + 141, 30, 12, 31, 11, 32, 32, 55, 56, 52, + 30, 54, 9, 30, 33, 33, 33, 33, 34, 34, + 34, 34, 35, 35, 35, 35, 37, 37, 37, 37, + 38, 53, 56, 38, 39, 39, 39, 39, 59, 53, + + 57, 58, 3, 62, 63, 64, 70, 38, 0, 65, + 66, 39, 0, 67, 53, 68, 72, 73, 0, 74, + 75, 59, 53, 76, 57, 58, 62, 63, 77, 64, + 70, 38, 65, 66, 78, 39, 67, 79, 68, 82, + 72, 73, 74, 75, 81, 90, 76, 85, 81, 0, + 89, 77, 83, 83, 83, 83, 91, 92, 78, 94, + 95, 79, 82, 84, 84, 84, 84, 96, 81, 90, + 85, 97, 81, 89, 98, 99, 102, 98, 100, 91, + 101, 92, 94, 95, 99, 103, 0, 104, 106, 107, + 96, 108, 110, 112, 117, 97, 113, 115, 116, 99, + + 102, 100, 118, 101, 98, 114, 124, 99, 114, 103, + 104, 106, 107, 119, 108, 125, 110, 112, 117, 113, + 115, 116, 126, 0, 127, 128, 118, 98, 131, 124, + 114, 132, 133, 137, 138, 0, 139, 119, 140, 125, + 144, 145, 146, 147, 154, 146, 126, 127, 128, 148, + 150, 131, 152, 114, 132, 156, 133, 137, 138, 139, + 157, 140, 158, 167, 144, 145, 159, 147, 154, 162, + 164, 160, 148, 150, 160, 152, 163, 165, 156, 163, + 169, 173, 175, 157, 173, 176, 158, 167, 178, 159, + 179, 180, 162, 164, 183, 185, 186, 163, 185, 187, + + 165, 189, 187, 169, 189, 0, 175, 173, 176, 0, + 0, 0, 178, 179, 0, 180, 0, 183, 0, 186, + 0, 163, 0, 0, 0, 0, 0, 0, 0, 0, + 173, 191, 191, 0, 191, 191, 192, 192, 193, 193, + 0, 193, 193, 194, 0, 0, 194, 195, 0, 0, + 195, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + + 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, + 190, 190 } ; static yy_state_type yy_last_accepting_state; @@ -690,7 +684,7 @@ static void countnl() { g_lingo->_colnumber = strlen(p); } -#line 694 "engines/director/lingo/lingo-lex.cpp" +#line 688 "engines/director/lingo/lingo-lex.cpp" #define INITIAL 0 @@ -878,7 +872,7 @@ YY_DECL #line 69 "engines/director/lingo/lingo-lex.l" -#line 882 "engines/director/lingo/lingo-lex.cpp" +#line 876 "engines/director/lingo/lingo-lex.cpp" if ( !(yy_init) ) { @@ -932,13 +926,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 197 ) + if ( yy_current_state >= 191 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 465 ); + while ( yy_base[yy_current_state] != 452 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -1077,81 +1071,71 @@ YY_RULE_SETUP case 23: YY_RULE_SETUP #line 94 "engines/director/lingo/lingo-lex.l" -{ count(); return tMCI; } +{ count(); return tMETHOD; } YY_BREAK case 24: YY_RULE_SETUP #line 95 "engines/director/lingo/lingo-lex.l" -{ count(); return tMCIWAIT; } +{ count(); return tMOVIE; } YY_BREAK case 25: YY_RULE_SETUP #line 96 "engines/director/lingo/lingo-lex.l" -{ count(); return tMETHOD; } +{ count(); return tNEXT; } YY_BREAK case 26: YY_RULE_SETUP #line 97 "engines/director/lingo/lingo-lex.l" -{ count(); return tMOVIE; } +{ count(); return tNOT; } YY_BREAK case 27: YY_RULE_SETUP #line 98 "engines/director/lingo/lingo-lex.l" -{ count(); return tNEXT; } +{ count(); return tOF; } YY_BREAK case 28: YY_RULE_SETUP #line 99 "engines/director/lingo/lingo-lex.l" -{ count(); return tNOT; } +{ count(); return tOPEN; } YY_BREAK case 29: YY_RULE_SETUP #line 100 "engines/director/lingo/lingo-lex.l" -{ count(); return tOF; } +{ count(); return tOR; } YY_BREAK case 30: YY_RULE_SETUP #line 101 "engines/director/lingo/lingo-lex.l" -{ count(); return tOPEN; } +{ count(); return tPLAY; } YY_BREAK case 31: YY_RULE_SETUP #line 102 "engines/director/lingo/lingo-lex.l" -{ count(); return tOR; } +{ count(); return tPREVIOUS; } YY_BREAK case 32: YY_RULE_SETUP #line 103 "engines/director/lingo/lingo-lex.l" -{ count(); return tPLAY; } +{ count(); return tPUT; } YY_BREAK case 33: YY_RULE_SETUP #line 104 "engines/director/lingo/lingo-lex.l" -{ count(); return tPREVIOUS; } +{ count(); return tREPEAT; } YY_BREAK case 34: YY_RULE_SETUP #line 105 "engines/director/lingo/lingo-lex.l" -{ count(); return tPUT; } +{ count(); return tSET; } YY_BREAK case 35: YY_RULE_SETUP #line 106 "engines/director/lingo/lingo-lex.l" -{ count(); return tREPEAT; } +{ count(); return tSTARTS; } YY_BREAK case 36: YY_RULE_SETUP #line 107 "engines/director/lingo/lingo-lex.l" -{ count(); return tSET; } - YY_BREAK -case 37: -YY_RULE_SETUP -#line 108 "engines/director/lingo/lingo-lex.l" -{ count(); return tSTARTS; } - YY_BREAK -case 38: -YY_RULE_SETUP -#line 109 "engines/director/lingo/lingo-lex.l" { count(); @@ -1193,9 +1177,9 @@ YY_RULE_SETUP warning("Unhandled the entity %s", ptr); } YY_BREAK -case 39: +case 37: YY_RULE_SETUP -#line 149 "engines/director/lingo/lingo-lex.l" +#line 147 "engines/director/lingo/lingo-lex.l" { count(); @@ -1216,64 +1200,64 @@ YY_RULE_SETUP warning("Unhandled the entity %s", ptr); } YY_BREAK +case 38: +YY_RULE_SETUP +#line 166 "engines/director/lingo/lingo-lex.l" +{ count(); return tTHEN; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 167 "engines/director/lingo/lingo-lex.l" +{ count(); return tTO; } + YY_BREAK case 40: YY_RULE_SETUP #line 168 "engines/director/lingo/lingo-lex.l" -{ count(); return tTHEN; } +{ count(); return tSPRITE; } YY_BREAK case 41: YY_RULE_SETUP #line 169 "engines/director/lingo/lingo-lex.l" -{ count(); return tTO; } +{ count(); return tWITH; } YY_BREAK case 42: YY_RULE_SETUP #line 170 "engines/director/lingo/lingo-lex.l" -{ count(); return tSPRITE; } +{ count(); return tWITHIN; } YY_BREAK case 43: YY_RULE_SETUP #line 171 "engines/director/lingo/lingo-lex.l" -{ count(); return tWITH; } +{ count(); return tWHEN; } YY_BREAK case 44: YY_RULE_SETUP #line 172 "engines/director/lingo/lingo-lex.l" -{ count(); return tWITHIN; } +{ count(); return tWHILE; } YY_BREAK case 45: YY_RULE_SETUP -#line 173 "engines/director/lingo/lingo-lex.l" -{ count(); return tWHEN; } +#line 174 "engines/director/lingo/lingo-lex.l" +{ count(); return tNEQ; } YY_BREAK case 46: YY_RULE_SETUP -#line 174 "engines/director/lingo/lingo-lex.l" -{ count(); return tWHILE; } +#line 175 "engines/director/lingo/lingo-lex.l" +{ count(); return tGE; } YY_BREAK case 47: YY_RULE_SETUP #line 176 "engines/director/lingo/lingo-lex.l" -{ count(); return tNEQ; } +{ count(); return tLE; } YY_BREAK case 48: YY_RULE_SETUP #line 177 "engines/director/lingo/lingo-lex.l" -{ count(); return tGE; } +{ count(); return tCONCAT; } YY_BREAK case 49: YY_RULE_SETUP -#line 178 "engines/director/lingo/lingo-lex.l" -{ count(); return tLE; } - YY_BREAK -case 50: -YY_RULE_SETUP #line 179 "engines/director/lingo/lingo-lex.l" -{ count(); return tCONCAT; } - YY_BREAK -case 51: -YY_RULE_SETUP -#line 181 "engines/director/lingo/lingo-lex.l" { count(); yylval.s = new Common::String(yytext); @@ -1301,43 +1285,43 @@ YY_RULE_SETUP return ID; } YY_BREAK -case 52: +case 50: YY_RULE_SETUP -#line 207 "engines/director/lingo/lingo-lex.l" +#line 205 "engines/director/lingo/lingo-lex.l" { count(); yylval.f = atof(yytext); return FLOAT; } YY_BREAK -case 53: +case 51: YY_RULE_SETUP -#line 208 "engines/director/lingo/lingo-lex.l" +#line 206 "engines/director/lingo/lingo-lex.l" { count(); yylval.i = strtol(yytext, NULL, 10); return INT; } YY_BREAK -case 54: +case 52: YY_RULE_SETUP -#line 209 "engines/director/lingo/lingo-lex.l" +#line 207 "engines/director/lingo/lingo-lex.l" { count(); return *yytext; } YY_BREAK -case 55: -/* rule 55 can match eol */ +case 53: +/* rule 53 can match eol */ YY_RULE_SETUP -#line 210 "engines/director/lingo/lingo-lex.l" +#line 208 "engines/director/lingo/lingo-lex.l" { return '\n'; } YY_BREAK -case 56: +case 54: YY_RULE_SETUP -#line 211 "engines/director/lingo/lingo-lex.l" +#line 209 "engines/director/lingo/lingo-lex.l" { count(); yylval.s = new Common::String(&yytext[1]); yylval.s->deleteLastChar(); return STRING; } YY_BREAK -case 57: +case 55: YY_RULE_SETUP -#line 212 "engines/director/lingo/lingo-lex.l" +#line 210 "engines/director/lingo/lingo-lex.l" YY_BREAK -case 58: +case 56: YY_RULE_SETUP -#line 214 "engines/director/lingo/lingo-lex.l" +#line 212 "engines/director/lingo/lingo-lex.l" ECHO; YY_BREAK -#line 1341 "engines/director/lingo/lingo-lex.cpp" +#line 1325 "engines/director/lingo/lingo-lex.cpp" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1630,7 +1614,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 197 ) + if ( yy_current_state >= 191 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -1658,11 +1642,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 197 ) + if ( yy_current_state >= 191 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 196); + yy_is_jam = (yy_current_state == 190); return yy_is_jam ? 0 : yy_current_state; } @@ -2337,7 +2321,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 214 "engines/director/lingo/lingo-lex.l" +#line 212 "engines/director/lingo/lingo-lex.l" diff --git a/engines/director/lingo/lingo-lex.l b/engines/director/lingo/lingo-lex.l index 0693399fec..8c89a99764 100644 --- a/engines/director/lingo/lingo-lex.l +++ b/engines/director/lingo/lingo-lex.l @@ -91,8 +91,6 @@ whitespace [\t ] (?i:into) { count(); return tINTO; } (?i:loop) { count(); return tLOOP; } (?i:macro) { count(); return tMACRO; } -(?i:mci) { count(); return tMCI; } -(?i:mciwait) { count(); return tMCIWAIT; } (?i:method) { count(); return tMETHOD; } (?i:movie) { count(); return tMOVIE; } (?i:next) { count(); return tNEXT; } diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp index 3f4f9cc432..3b00c092ec 100644 --- a/engines/director/lingo/lingo-the.cpp +++ b/engines/director/lingo/lingo-the.cpp @@ -37,9 +37,11 @@ TheEntity entities[] = { { kTheExitLock, "exitlock", false }, { kTheFloatPrecision, "floatPrecision", false }, { kTheFrame, "frame", false }, + { kTheFreeBlock, "freeBlock", false }, + { kTheFreeBytes, "freeBytes", false }, { kTheItemDelimiter, "itemDelimiter", false }, { kTheKey, "key", false }, - { kTheKeyCode, "keycode", false }, + { kTheKeyCode, "keyCode", false }, { kTheLastClick, "lastClick", false }, { kTheLastEvent, "lastEvent", false }, { kTheLastFrame, "lastFrame", false }, diff --git a/engines/director/lingo/lingo-the.h b/engines/director/lingo/lingo-the.h index 5fea4ba009..7a27c0ad84 100644 --- a/engines/director/lingo/lingo-the.h +++ b/engines/director/lingo/lingo-the.h @@ -28,6 +28,8 @@ namespace Director { enum TheEntityType { kTheNOEntity = 0, kTheFrame = 1, + kTheFreeBlock, + kTheFreeBytes, kThePathName, kTheMenu, kTheMenuItem, diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp index 7076ac2bc3..f3faf975fe 100644 --- a/engines/director/lingo/lingo.cpp +++ b/engines/director/lingo/lingo.cpp @@ -20,6 +20,8 @@ * */ +#include "common/str-array.h" + #include "director/lingo/lingo.h" #include "director/lingo/lingo-gr.h" @@ -360,14 +362,19 @@ Common::String *Lingo::toLowercaseMac(Common::String *s) { void Lingo::runTests() { Common::File inFile; - Common::ArchiveMemberList fileList; - SearchMan.listMatchingMembers(fileList, "*.lingo"); + Common::ArchiveMemberList fsList; + SearchMan.listMatchingMembers(fsList, "*.lingo"); + Common::StringArray fileList; int counter = 1; - for (Common::ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) { - Common::ArchiveMember const &m = **it; - Common::SeekableReadStream *const stream = m.createReadStream(); + for (Common::ArchiveMemberList::iterator it = fsList.begin(); it != fsList.end(); ++it) + fileList.push_back((*it)->getName()); + + Common::sort(fileList.begin(), fileList.end()); + + for (int i = 0; i < fileList.size(); i++) { + Common::SeekableReadStream *const stream = SearchMan.createReadStreamForMember(fileList[i]); if (stream) { uint size = stream->size(); @@ -375,7 +382,7 @@ void Lingo::runTests() { stream->read(script, size); - warning("Compiling file %s of size %d, id: %d", m.getName().c_str(), size, counter); + warning("Compiling file %s of size %d, id: %d", fileList[i].c_str(), size, counter); _hadError = false; addCode(script, kMovieScript, counter); diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h index ad706401a4..8af20f2a15 100644 --- a/engines/director/lingo/lingo.h +++ b/engines/director/lingo/lingo.h @@ -85,7 +85,8 @@ struct Symbol { /* symbol table entry */ int i; /* VAR */ double f; /* FLOAT */ ScriptData *defn; /* FUNCTION, PROCEDURE */ - void (*func)(void); /* BUILTIN */ + void (*func)(); /* OPCODE */ + void (*bltin)(int); /* BUILTIN */ Common::String *s; /* STRING */ FloatArray *arr; /* ARRAY, POINT, RECT */ } u; @@ -110,6 +111,9 @@ struct Datum { /* interpreter stack type */ } u; Datum() { u.sym = NULL; type = VOID; } + Datum(int val) { u.i = val; type = INT; } + Datum(double val) { u.f = val; type = FLOAT; } + Datum(Common::String *val) { u.s = val; type = STRING; } double toFloat(); int toInt(); @@ -239,6 +243,9 @@ public: static void c_ge(); static void c_le(); static void c_call(); + + void call(Common::String &name, int nargs); + static void c_procret(); static void c_mci(); @@ -254,66 +261,90 @@ public: static void c_open(); - static void b_abs(); - static void b_atan(); - static void b_chars(); - static void b_cos(); - static void b_exp(); - static void b_float(); - static void b_integer(); - static void b_length(); - static void b_log(); - static void b_pi(); - static void b_power(); - static void b_random(); - static void b_sin(); - static void b_sqrt(); - static void b_string(); - static void b_tan(); - - static void b_ilk(); - static void b_alert(); - static void b_cursor(); - static void b_printFrom(); - static void b_showGlobals(); - static void b_showLocals(); - - static void b_editableText(); - static void b_installMenu(); - static void b_updateStage(); - static void b_moveableSprite(); - static void b_puppetPalette(); - static void b_puppetSound(); - static void b_puppetSprite(); - static void b_puppetTempo(); - static void b_puppetTransition(); - static void b_spriteBox(); - static void b_zoomBox(); - - static void b_continue(); - static void b_dontPassEvent(); - static void b_delay(); - static void b_do(); - static void b_nothing(); - static void b_pause(); - static void b_playAccel(); - static void b_quit(); - static void b_restart(); - static void b_shutDown(); - static void b_startTimer(); - - static void b_closeDA(); - static void b_closeResFile(); - static void b_closeXlib(); - static void b_openDA(); - static void b_openResFile(); - static void b_openXlib(); - static void b_showResFile(); - static void b_showXlib(); - - static void b_point(); - - static void b_beep(); + void printStubWithArglist(const char *funcname, int nargs); + void convertVOIDtoString(int arg, int nargs); + void dropStack(int nargs); + + static void b_abs(int nargs); + static void b_atan(int nargs); + static void b_cos(int nargs); + static void b_exp(int nargs); + static void b_float(int nargs); + static void b_integer(int nargs); + static void b_integerp(int nargs); + static void b_log(int nargs); + static void b_pi(int nargs); + static void b_power(int nargs); + static void b_random(int nargs); + static void b_sin(int nargs); + static void b_sqrt(int nargs); + static void b_tan(int nargs); + + static void b_chars(int nargs); + static void b_charToNum(int nargs); + static void b_length(int nargs); + static void b_string(int nargs); + + static void b_ilk(int nargs); + static void b_alert(int nargs); + static void b_cursor(int nargs); + static void b_printFrom(int nargs); + static void b_showGlobals(int nargs); + static void b_showLocals(int nargs); + + static void b_constrainH(int nargs); + static void b_constrainV(int nargs); + static void b_editableText(int nargs); + static void b_installMenu(int nargs); + static void b_label(int nargs); + static void b_moveableSprite(int nargs); + static void b_puppetPalette(int nargs); + static void b_puppetSound(int nargs); + static void b_puppetSprite(int nargs); + static void b_puppetTempo(int nargs); + static void b_puppetTransition(int nargs); + static void b_spriteBox(int nargs); + static void b_updateStage(int nargs); + static void b_zoomBox(int nargs); + + static void b_continue(int nargs); + static void b_dontPassEvent(int nargs); + static void b_delay(int nargs); + static void b_do(int nargs); + static void b_nothing(int nargs); + static void b_pause(int nargs); + static void b_playAccel(int nargs); + static void b_quit(int nargs); + static void b_restart(int nargs); + static void b_shutDown(int nargs); + static void b_startTimer(int nargs); + + static void b_closeDA(int nargs); + static void b_closeResFile(int nargs); + static void b_closeXlib(int nargs); + static void b_openDA(int nargs); + static void b_openResFile(int nargs); + static void b_openXlib(int nargs); + static void b_showResFile(int nargs); + static void b_showXlib(int nargs); + + static void b_point(int nargs); + + static void b_beep(int nargs); + static void b_mci(int nargs); + static void b_mciwait(int nargs); + + static void b_backspace(int nargs); + static void b_empty(int nargs); + static void b_enter(int nargs); + static void b_false(int nargs); + static void b_quote(int nargs); + static void b_return(int nargs); + static void b_tab(int nargs); + static void b_true(int nargs); + + static void b_factory(int nargs); + void factoryCall(Common::String &name, int nargs); void func_mci(Common::String &s); void func_mciwait(Common::String &s); diff --git a/engines/director/lingo/tests/factory2.lingo b/engines/director/lingo/tests/factory2.lingo new file mode 100644 index 0000000000..a7b2317e17 --- /dev/null +++ b/engines/director/lingo/tests/factory2.lingo @@ -0,0 +1,4 @@ +global aim1 +AimGun2 + +aim1(mDispose) diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp index dcd5c33740..dd8d8b246d 100644 --- a/engines/fullpipe/gfx.cpp +++ b/engines/fullpipe/gfx.cpp @@ -806,7 +806,7 @@ bool Bitmap::isPixelHitAtPos(int x, int y) { if (!_surface) return false; - return ((*((int32 *)_surface->getBasePtr(x, y)) & 0xff000000) != 0); + return ((*((int32 *)_surface->getBasePtr(x - _x, y - _y)) & 0xff000000) != 0); } void Bitmap::decode(int32 *palette) { diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp index 484b1e150e..78920ed9a6 100644 --- a/engines/fullpipe/interaction.cpp +++ b/engines/fullpipe/interaction.cpp @@ -305,7 +305,7 @@ LABEL_38: ani->changeStatics2(inter->_staticsId1); } - int xpos = inter->_yOffs + obj->_ox; + int xpos = inter->_xOffs + obj->_ox; int ypos = inter->_yOffs + obj->_oy; obj->setPicAniInfo(&aniInfo); diff --git a/engines/fullpipe/mgm.cpp b/engines/fullpipe/mgm.cpp index c9eeebb224..62fbb1ff6d 100644 --- a/engines/fullpipe/mgm.cpp +++ b/engines/fullpipe/mgm.cpp @@ -528,7 +528,7 @@ int MGM::recalcOffsets(int idx, int st1idx, int st2idx, bool flip, bool flop) { debugC(2, kDebugPathfinding, "MGM::recalcOffsets(%d, %d, %d, %d, %d)", idx, st1idx, st2idx, flip, flop); if (st1idx == st2idx) { - memset(&item->subItems[subIdx], 0, sizeof(item->subItems[subIdx])); + memset(item->subItems[subIdx], 0, sizeof(*(item->subItems[subIdx]))); return 0; } diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index fd79e53b07..f08eee9677 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -42,6 +42,7 @@ #ifdef ENABLE_RIVEN #include "mohawk/riven.h" #include "mohawk/riven_external.h" +#include "mohawk/riven_sound.h" #endif namespace Mohawk { diff --git a/engines/mohawk/cstime.cpp b/engines/mohawk/cstime.cpp index 3b26378819..b2889be714 100644 --- a/engines/mohawk/cstime.cpp +++ b/engines/mohawk/cstime.cpp @@ -54,6 +54,7 @@ MohawkEngine_CSTime::MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescript _console = 0; _gfx = 0; + _sound = 0; _cursor = 0; _interface = 0; _view = 0; @@ -66,6 +67,7 @@ MohawkEngine_CSTime::~MohawkEngine_CSTime() { delete _interface; delete _view; delete _console; + delete _sound; delete _gfx; delete _rnd; } @@ -75,6 +77,7 @@ Common::Error MohawkEngine_CSTime::run() { _console = new CSTimeConsole(this); _gfx = new CSTimeGraphics(this); + _sound = new Sound(this); _cursor = new DefaultCursorManager(this, ID_CURS); _interface = new CSTimeInterface(this); diff --git a/engines/mohawk/cstime.h b/engines/mohawk/cstime.h index bfb7daf945..393032aaa9 100644 --- a/engines/mohawk/cstime.h +++ b/engines/mohawk/cstime.h @@ -136,6 +136,7 @@ public: Common::RandomSource *_rnd; + Sound *_sound; CSTimeGraphics *_gfx; bool _needsUpdate; diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index 5af8fac901..579e3792b3 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -144,6 +144,7 @@ MohawkEngine_LivingBooks::MohawkEngine_LivingBooks(OSystem *syst, const MohawkGa _rnd = new Common::RandomSource("livingbooks"); + _sound = NULL; _page = NULL; const Common::FSNode gameDataDir(ConfMan.get("path")); @@ -158,6 +159,7 @@ MohawkEngine_LivingBooks::~MohawkEngine_LivingBooks() { destroyPage(); delete _console; + delete _sound; delete _gfx; delete _rnd; _bookInfoFile.clear(); @@ -182,6 +184,7 @@ Common::Error MohawkEngine_LivingBooks::run() { error("Could not find xRes/yRes variables"); _gfx = new LBGraphics(this, _screenWidth, _screenHeight); + _sound = new Sound(this); if (getGameType() != GType_LIVINGBOOKSV1) _cursor = new LivingBooksCursorManager_v2(); diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index 1a265a1a02..cf67c1ee8e 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -714,6 +714,7 @@ public: Common::RandomSource *_rnd; + Sound *_sound; LBGraphics *_gfx; bool _needsRedraw, _needsUpdate; diff --git a/engines/mohawk/module.mk b/engines/mohawk/module.mk index 83e541e3e4..3fc118d2b6 100644 --- a/engines/mohawk/module.mk +++ b/engines/mohawk/module.mk @@ -57,6 +57,7 @@ MODULE_OBJS += \ riven_graphics.o \ riven_saveload.o \ riven_scripts.o \ + riven_sound.o \ riven_vars.o endif diff --git a/engines/mohawk/mohawk.cpp b/engines/mohawk/mohawk.cpp index d740d9479a..b38409f9f1 100644 --- a/engines/mohawk/mohawk.cpp +++ b/engines/mohawk/mohawk.cpp @@ -40,14 +40,12 @@ MohawkEngine::MohawkEngine(OSystem *syst, const MohawkGameDescription *gamedesc) // Setup mixer syncSoundSettings(); - _sound = 0; _video = 0; _pauseDialog = 0; _cursor = 0; } MohawkEngine::~MohawkEngine() { - delete _sound; delete _video; delete _pauseDialog; delete _cursor; @@ -58,7 +56,6 @@ MohawkEngine::~MohawkEngine() { } Common::Error MohawkEngine::run() { - _sound = new Sound(this); _video = new VideoManager(this); _pauseDialog = new PauseDialog(this, "The game is paused. Press any key to continue."); @@ -66,14 +63,12 @@ Common::Error MohawkEngine::run() { } void MohawkEngine::pauseEngineIntern(bool pause) { + Engine::pauseEngineIntern(pause); + if (pause) { _video->pauseVideos(); - _sound->pauseSound(); - _sound->pauseSLST(); } else { _video->resumeVideos(); - _sound->resumeSound(); - _sound->resumeSLST(); _system->updateScreen(); } } diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h index ac91dca971..bc0d642bce 100644 --- a/engines/mohawk/mohawk.h +++ b/engines/mohawk/mohawk.h @@ -100,7 +100,6 @@ public: bool hasFeature(EngineFeature f) const; - Sound *_sound; VideoManager *_video; CursorManager *_cursor; diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index a1c6d0e748..3c00c1e11b 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -75,6 +75,7 @@ MohawkEngine_Myst::MohawkEngine_Myst(OSystem *syst, const MohawkGameDescription _curResource = -1; _hoverResource = nullptr; + _sound = nullptr; _gfx = nullptr; _console = nullptr; _scriptParser = nullptr; @@ -88,6 +89,7 @@ MohawkEngine_Myst::~MohawkEngine_Myst() { DebugMan.clearAllDebugChannels(); delete _gfx; + delete _sound; delete _console; delete _scriptParser; delete _gameState; @@ -220,6 +222,7 @@ Common::Error MohawkEngine_Myst::run() { MohawkEngine::run(); _gfx = new MystGraphics(this); + _sound = new Sound(this); _console = new MystConsole(this); _gameState = new MystGameState(this, _saveFileMan); _optionsDialog = new MystOptionsDialog(this); diff --git a/engines/mohawk/myst.h b/engines/mohawk/myst.h index 0b249e5499..0491e853b6 100644 --- a/engines/mohawk/myst.h +++ b/engines/mohawk/myst.h @@ -200,6 +200,7 @@ public: bool _showResourceRects; + Sound *_sound; MystGraphics *_gfx; MystGameState *_gameState; MystScriptParser *_scriptParser; diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp index b05b76da30..b7c83c0ff8 100644 --- a/engines/mohawk/riven.cpp +++ b/engines/mohawk/riven.cpp @@ -34,8 +34,8 @@ #include "mohawk/riven_external.h" #include "mohawk/riven_graphics.h" #include "mohawk/riven_saveload.h" +#include "mohawk/riven_sound.h" #include "mohawk/dialogs.h" -#include "mohawk/sound.h" #include "mohawk/video.h" #include "mohawk/console.h" @@ -59,6 +59,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio _curStack = kStackUnknown; _hotspots = nullptr; _gfx = nullptr; + _sound = nullptr; _externalScriptHandler = nullptr; _rnd = nullptr; _scriptMan = nullptr; @@ -92,6 +93,7 @@ MohawkEngine_Riven::MohawkEngine_Riven(OSystem *syst, const MohawkGameDescriptio } MohawkEngine_Riven::~MohawkEngine_Riven() { + delete _sound; delete _gfx; delete _console; delete _externalScriptHandler; @@ -123,6 +125,7 @@ Common::Error MohawkEngine_Riven::run() { SearchMan.add("arcriven.z", &_installerArchive, 0, false); _gfx = new RivenGraphics(this); + _sound = new RivenSoundManager(this); _console = new RivenConsole(this); _saveLoad = new RivenSaveLoad(this, _saveFileMan); _externalScriptHandler = new RivenExternal(this); @@ -199,6 +202,7 @@ Common::Error MohawkEngine_Riven::run() { void MohawkEngine_Riven::handleEvents() { // Update background running things checkTimer(); + _sound->updateSLST(); bool needsUpdate = _gfx->runScheduledWaterEffects(); needsUpdate |= _video->updateMovies(); @@ -710,6 +714,7 @@ void MohawkEngine_Riven::delayAndUpdate(uint32 ms) { uint32 startTime = _system->getMillis(); while (_system->getMillis() < startTime + ms && !shouldQuit()) { + _sound->updateSLST(); bool needsUpdate = _gfx->runScheduledWaterEffects(); needsUpdate |= _video->updateMovies(); diff --git a/engines/mohawk/riven.h b/engines/mohawk/riven.h index 3ea50bb38d..ce819ac970 100644 --- a/engines/mohawk/riven.h +++ b/engines/mohawk/riven.h @@ -41,6 +41,7 @@ class RivenExternal; class RivenConsole; class RivenSaveLoad; class RivenOptionsDialog; +class RivenSoundManager; // Riven Stack Types enum { @@ -121,6 +122,7 @@ public: MohawkEngine_Riven(OSystem *syst, const MohawkGameDescription *gamedesc); virtual ~MohawkEngine_Riven(); + RivenSoundManager *_sound; RivenGraphics *_gfx; RivenExternal *_externalScriptHandler; Common::RandomSource *_rnd; diff --git a/engines/mohawk/riven_external.cpp b/engines/mohawk/riven_external.cpp index 00075039fe..125630445e 100644 --- a/engines/mohawk/riven_external.cpp +++ b/engines/mohawk/riven_external.cpp @@ -24,7 +24,7 @@ #include "mohawk/riven.h" #include "mohawk/riven_external.h" #include "mohawk/riven_graphics.h" -#include "mohawk/sound.h" +#include "mohawk/riven_sound.h" #include "mohawk/video.h" #include "gui/message.h" @@ -2429,7 +2429,7 @@ void RivenExternal::xtexterior300_telescopedown(uint16 argc, uint16 *argv) { // Play the sound of not being able to move _vm->_cursor->setCursor(kRivenHideCursor); _vm->_system->updateScreen(); - _vm->_sound->playSoundBlocking(13); + _vm->_sound->playSound(13); } } else { // We're not at the bottom, and we can move down again @@ -2463,7 +2463,7 @@ void RivenExternal::xtexterior300_telescopeup(uint16 argc, uint16 *argv) { // Play the sound of not being able to move _vm->_cursor->setCursor(kRivenHideCursor); _vm->_system->updateScreen(); - _vm->_sound->playSoundBlocking(13); + _vm->_sound->playSound(13); return; } diff --git a/engines/mohawk/riven_graphics.cpp b/engines/mohawk/riven_graphics.cpp index db22dde22d..b583bc9710 100644 --- a/engines/mohawk/riven_graphics.cpp +++ b/engines/mohawk/riven_graphics.cpp @@ -23,6 +23,7 @@ #include "mohawk/resource.h" #include "mohawk/riven.h" #include "mohawk/riven_graphics.h" +#include "mohawk/riven_sound.h" #include "common/system.h" #include "engines/util.h" @@ -111,6 +112,7 @@ void RivenGraphics::drawPLST(uint16 x) { void RivenGraphics::updateScreen(Common::Rect updateRect) { if (_updatesEnabled) { _vm->runUpdateScreenScript(); + _vm->_sound->triggerDrawSound(); if (_dirtyScreen) { _activatedPLSTs.clear(); diff --git a/engines/mohawk/riven_scripts.cpp b/engines/mohawk/riven_scripts.cpp index caa235ec8b..3655452603 100644 --- a/engines/mohawk/riven_scripts.cpp +++ b/engines/mohawk/riven_scripts.cpp @@ -25,7 +25,7 @@ #include "mohawk/riven_external.h" #include "mohawk/riven_graphics.h" #include "mohawk/riven_scripts.h" -#include "mohawk/sound.h" +#include "mohawk/riven_sound.h" #include "mohawk/video.h" #include "common/memstream.h" @@ -309,54 +309,44 @@ void RivenScript::switchCard(uint16 op, uint16 argc, uint16 *argv) { // Command 3: play an SLST from the script void RivenScript::playScriptSLST(uint16 op, uint16 argc, uint16 *argv) { - SLSTRecord slstRecord; int offset = 0, j = 0; + uint16 soundCount = argv[offset++]; + SLSTRecord slstRecord; slstRecord.index = 0; // not set by the scripts, so we set it to 0 - slstRecord.sound_count = argv[0]; - slstRecord.sound_ids = new uint16[slstRecord.sound_count]; - - offset = slstRecord.sound_count; + slstRecord.soundIds.resize(soundCount); - for (j = 0; j < slstRecord.sound_count; j++) - slstRecord.sound_ids[j] = argv[offset++]; - slstRecord.fade_flags = argv[offset++]; + for (j = 0; j < soundCount; j++) + slstRecord.soundIds[j] = argv[offset++]; + slstRecord.fadeFlags = argv[offset++]; slstRecord.loop = argv[offset++]; - slstRecord.global_volume = argv[offset++]; + slstRecord.globalVolume = argv[offset++]; slstRecord.u0 = argv[offset++]; - slstRecord.u1 = argv[offset++]; + slstRecord.suspend = argv[offset++]; - slstRecord.volumes = new uint16[slstRecord.sound_count]; - slstRecord.balances = new int16[slstRecord.sound_count]; - slstRecord.u2 = new uint16[slstRecord.sound_count]; + slstRecord.volumes.resize(soundCount); + slstRecord.balances.resize(soundCount); + slstRecord.u2.resize(soundCount); - for (j = 0; j < slstRecord.sound_count; j++) + for (j = 0; j < soundCount; j++) slstRecord.volumes[j] = argv[offset++]; - for (j = 0; j < slstRecord.sound_count; j++) + for (j = 0; j < soundCount; j++) slstRecord.balances[j] = argv[offset++]; // negative = left, 0 = center, positive = right - for (j = 0; j < slstRecord.sound_count; j++) + for (j = 0; j < soundCount; j++) slstRecord.u2[j] = argv[offset++]; // Unknown // Play the requested sound list _vm->_sound->playSLST(slstRecord); - _vm->_activatedSLST = true; - - delete[] slstRecord.sound_ids; - delete[] slstRecord.volumes; - delete[] slstRecord.balances; - delete[] slstRecord.u2; } // Command 4: play local tWAV resource (twav_id, volume, block) void RivenScript::playSound(uint16 op, uint16 argc, uint16 *argv) { - byte volume = Sound::convertRivenVolume(argv[1]); + uint16 volume = argv[1]; + bool playOnDraw = argv[2] == 1; - if (argv[2] == 1) - _vm->_sound->playSoundBlocking(argv[0], volume); - else - _vm->_sound->playSound(argv[0], volume); + _vm->_sound->playSound(argv[0], volume, playOnDraw); } // Command 7: set variable value (variable, value) diff --git a/engines/mohawk/riven_sound.cpp b/engines/mohawk/riven_sound.cpp new file mode 100644 index 0000000000..dd45f94ad3 --- /dev/null +++ b/engines/mohawk/riven_sound.cpp @@ -0,0 +1,459 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/debug.h" +#include "common/system.h" + +#include "audio/audiostream.h" + +#include "mohawk/riven_sound.h" +#include "mohawk/sound.h" + +namespace Mohawk { + +RivenSoundManager::RivenSoundManager(MohawkEngine *vm) : + _vm(vm), + _effect(nullptr), + _mainAmbientSoundId(-1), + _effectPlayOnDraw(false), + _nextFadeUpdate(0) { + +} + +RivenSoundManager::~RivenSoundManager() { + stopSound(); + stopAllSLST(false); +} + +Audio::RewindableAudioStream *RivenSoundManager::makeAudioStream(uint16 id) { + return makeMohawkWaveStream(_vm->getResource(ID_TWAV, id)); +} + +void RivenSoundManager::playSound(uint16 id, uint16 volume, bool playOnDraw) { + debug (0, "Playing sound %d", id); + + stopSound(); + + Audio::RewindableAudioStream *rewindStream = makeAudioStream(id); + if (!rewindStream) { + warning("Unable to play sound with id %d", id); + return; + } + + _effect = new RivenSound(_vm, rewindStream); + _effect->setVolume(volume); + + _effectPlayOnDraw = playOnDraw; + if (!playOnDraw) { + _effect->play(); + } +} + +void RivenSoundManager::playSLST(uint16 index, uint16 card) { + Common::SeekableReadStream *slstStream = _vm->getResource(ID_SLST, card); + + uint16 recordCount = slstStream->readUint16BE(); + + for (uint16 i = 0; i < recordCount; i++) { + SLSTRecord slstRecord; + slstRecord.index = slstStream->readUint16BE(); + + uint16 soundCount = slstStream->readUint16BE(); + slstRecord.soundIds.resize(soundCount); + + for (uint16 j = 0; j < soundCount; j++) + slstRecord.soundIds[j] = slstStream->readUint16BE(); + + slstRecord.fadeFlags = slstStream->readUint16BE(); + slstRecord.loop = slstStream->readUint16BE(); + slstRecord.globalVolume = slstStream->readUint16BE(); + slstRecord.u0 = slstStream->readUint16BE(); // Unknown + + if (slstRecord.u0 > 1) + warning("slstRecord.u0: %d non-boolean", slstRecord.u0); + + slstRecord.suspend = slstStream->readUint16BE(); + + if (slstRecord.suspend != 0) + warning("slstRecord.u1: %d non-zero", slstRecord.suspend); + + slstRecord.volumes.resize(soundCount); + slstRecord.balances.resize(soundCount); + slstRecord.u2.resize(soundCount); + + for (uint16 j = 0; j < soundCount; j++) + slstRecord.volumes[j] = slstStream->readUint16BE(); + + for (uint16 j = 0; j < soundCount; j++) + slstRecord.balances[j] = slstStream->readSint16BE(); // negative = left, 0 = center, positive = right + + for (uint16 j = 0; j < soundCount; j++) { + slstRecord.u2[j] = slstStream->readUint16BE(); // Unknown + + if (slstRecord.u2[j] != 255 && slstRecord.u2[j] != 256) + warning("slstRecord.u2[%d]: %d not 255 or 256", j, slstRecord.u2[j]); + } + + if (slstRecord.index == index) { + playSLST(slstRecord); + delete slstStream; + return; + } + } + + delete slstStream; + + // If we have no matching entries, we do nothing and just let + // the previous ambient sounds continue. +} + +void RivenSoundManager::playSLST(const SLSTRecord &slstRecord) { + if (slstRecord.soundIds.empty()) { + return; + } + + if (slstRecord.soundIds[0] == _mainAmbientSoundId) { + if (slstRecord.soundIds.size() > _ambientSounds.sounds.size()) { + addAmbientSounds(slstRecord); + } + setAmbientLooping(slstRecord.loop); + setTargetVolumes(slstRecord); + _ambientSounds.suspend = slstRecord.suspend; + if (slstRecord.suspend) { + freePreviousAmbientSounds(); + pauseAmbientSounds(); + applyTargetVolumes(); + } else { + playAmbientSounds(); + } + } else { + _mainAmbientSoundId = slstRecord.soundIds[0]; + freePreviousAmbientSounds(); + moveAmbientSoundsToPreviousSounds(); + addAmbientSounds(slstRecord); + setAmbientLooping(slstRecord.loop); + setTargetVolumes(slstRecord); + _ambientSounds.suspend = slstRecord.suspend; + if (slstRecord.suspend) { + freePreviousAmbientSounds(); + applyTargetVolumes(); + } else { + startFadingAmbientSounds(slstRecord.fadeFlags); + } + } +} + +void RivenSoundManager::stopAllSLST(bool fade) { + _mainAmbientSoundId = -1; + freePreviousAmbientSounds(); + moveAmbientSoundsToPreviousSounds(); + startFadingAmbientSounds(fade ? kFadeOutPreviousSounds : 0); +} + +void RivenSoundManager::stopSound() { + if (_effect) { + delete _effect; + } + _effect = nullptr; + _effectPlayOnDraw = false; +} + +void RivenSoundManager::addAmbientSounds(const SLSTRecord &record) { + if (record.soundIds.size() > _ambientSounds.sounds.size()) { + uint oldSize = _ambientSounds.sounds.size(); + + // Resize the list to the new size + _ambientSounds.sounds.resize(record.soundIds.size()); + + // Add new elements to the list + for (uint i = oldSize; i < _ambientSounds.sounds.size(); i++) { + Audio::RewindableAudioStream *stream = makeAudioStream(record.soundIds[i]); + + RivenSound *sound = new RivenSound(_vm, stream); + sound->setVolume(record.volumes[i]); + sound->setBalance(record.balances[i]); + + _ambientSounds.sounds[i].sound = sound; + _ambientSounds.sounds[i].targetVolume = record.volumes[i]; + _ambientSounds.sounds[i].targetBalance = record.balances[i]; + } + } +} + +void RivenSoundManager::setTargetVolumes(const SLSTRecord &record) { + for (uint i = 0; i < _ambientSounds.sounds.size(); i++) { + _ambientSounds.sounds[i].targetVolume = record.volumes[i] * record.globalVolume / 256; + _ambientSounds.sounds[i].targetBalance = record.balances[i]; + } + _ambientSounds.fading = true; +} + +void RivenSoundManager::freePreviousAmbientSounds() { + for (uint i = 0; i < _previousAmbientSounds.sounds.size(); i++) { + delete _previousAmbientSounds.sounds[i].sound; + } + _previousAmbientSounds = AmbientSoundList(); +} + +void RivenSoundManager::moveAmbientSoundsToPreviousSounds() { + _previousAmbientSounds = _ambientSounds; + _ambientSounds = AmbientSoundList(); +} + +void RivenSoundManager::applyTargetVolumes() { + for (uint i = 0; i < _ambientSounds.sounds.size(); i++) { + AmbientSound &ambientSound = _ambientSounds.sounds[i]; + RivenSound *sound = ambientSound.sound; + sound->setVolume(ambientSound.targetVolume); + sound->setBalance(ambientSound.targetBalance); + } + _ambientSounds.fading = false; +} + +void RivenSoundManager::startFadingAmbientSounds(uint16 flags) { + for (uint i = 0; i < _ambientSounds.sounds.size(); i++) { + AmbientSound &ambientSound = _ambientSounds.sounds[i]; + uint16 volume; + if (flags & kFadeInNewSounds) { + volume = 0; + } else { + volume = ambientSound.targetVolume; + } + ambientSound.sound->setVolume(volume); + } + _ambientSounds.fading = true; + playAmbientSounds(); + + if (!_previousAmbientSounds.sounds.empty()) { + if (flags) { + _previousAmbientSounds.fading = true; + } else { + freePreviousAmbientSounds(); + } + + for (uint i = 0; i < _previousAmbientSounds.sounds.size(); i++) { + AmbientSound &ambientSound = _previousAmbientSounds.sounds[i]; + if (flags & kFadeOutPreviousSounds) { + ambientSound.targetVolume = 0; + } else { + ambientSound.sound->setVolume(ambientSound.targetVolume); + } + } + } +} + +void RivenSoundManager::playAmbientSounds() { + for (uint i = 0; i < _ambientSounds.sounds.size(); i++) { + _ambientSounds.sounds[i].sound->play(); + } +} + +void RivenSoundManager::setAmbientLooping(bool loop) { + for (uint i = 0; i < _ambientSounds.sounds.size(); i++) { + _ambientSounds.sounds[i].sound->setLooping(loop); + } +} + +void RivenSoundManager::triggerDrawSound() { + if (_effectPlayOnDraw && _effect) { + _effect->play(); + } + _effectPlayOnDraw = false; +} + +void RivenSoundManager::pauseAmbientSounds() { + for (uint i = 0; i < _ambientSounds.sounds.size(); i++) { + _ambientSounds.sounds[i].sound->pause(); + } +} + +void RivenSoundManager::updateSLST() { + uint32 time = _vm->_system->getMillis(); + int32 delta = CLIP<int32>(time - _nextFadeUpdate, -50, 50); + if (_nextFadeUpdate == 0 || delta > 0) { + _nextFadeUpdate = time + 50 - delta; + + if (_ambientSounds.fading) { + fadeAmbientSoundList(_ambientSounds); + } + + if (_previousAmbientSounds.fading) { + fadeAmbientSoundList(_previousAmbientSounds); + } + + if (!_previousAmbientSounds.sounds.empty() && !_ambientSounds.fading && !_previousAmbientSounds.fading) { + freePreviousAmbientSounds(); + } + } +} + +void RivenSoundManager::fadeAmbientSoundList(AmbientSoundList &list) { + list.fading = false; + + for (uint i = 0; i < list.sounds.size(); i++) { + AmbientSound &ambientSound = list.sounds[i]; + list.fading |= fadeVolume(ambientSound); + list.fading |= fadeBalance(ambientSound); + } +} + +bool RivenSoundManager::fadeVolume(AmbientSound &ambientSound) { + uint16 volume = ambientSound.sound->getVolume(); + float delta = (ambientSound.targetVolume - volume) / 30.0f; + + if (ABS<float>(delta) < 0.01f) { + ambientSound.sound->setVolume(ambientSound.targetVolume); + return false; + } else { + // Make sure the increment is not zero once converted to an integer + if (delta > 0 && delta < 1) { + delta = 1; + } else if (delta < 0 && delta > -1) { + delta = -1; + } + + ambientSound.sound->setVolume(volume + delta); + return true; + } +} + +bool RivenSoundManager::fadeBalance(RivenSoundManager::AmbientSound &ambientSound) { + int16 balance = ambientSound.sound->getBalance(); + float delta = (ambientSound.targetBalance - balance) / 10.0f; + + if (ABS<float>(delta) < 0.01) { + ambientSound.sound->setBalance(ambientSound.targetBalance); + return false; + } else { + // Make sure the increment is not zero once converted to an integer + if (delta > 0 && delta < 1) { + delta = 1; + } else if (delta < 0 && delta > -1) { + delta = -1; + } + + ambientSound.sound->setBalance(balance + delta); + return true; + } +} + +RivenSound::RivenSound(MohawkEngine *vm, Audio::RewindableAudioStream *rewindStream) : + _vm(vm), + _volume(Audio::Mixer::kMaxChannelVolume), + _balance(0), + _looping(false), + _stream(rewindStream) { + +} + +bool RivenSound::isPlaying() const { + return _vm->_mixer->isSoundHandleActive(_handle); +} + +void RivenSound::pause() { + _vm->_mixer->pauseHandle(_handle, true); +} + +void RivenSound::setVolume(uint16 volume) { + _volume = volume; + if (isPlaying()) { + byte mixerVolume = convertVolume(volume); + _vm->_mixer->setChannelVolume(_handle, mixerVolume); + } +} + +void RivenSound::setBalance(int16 balance) { + _balance = balance; + if (isPlaying()) { + int8 mixerBalance = convertBalance(balance); + _vm->_mixer->setChannelBalance(_handle, mixerBalance); + } +} + +void RivenSound::setLooping(bool loop) { + if (isPlaying() && _looping != loop) { + warning("Changing loop state while a sound is playing is not implemented."); + } + _looping = loop; +} + +void RivenSound::play() { + if (isPlaying()) { + // If the sound is already playing, make sure it is not paused + _vm->_mixer->pauseHandle(_handle, false); + return; + } + + if (!_stream) { + warning("Trying to play a sound without a stream"); + return; + } + + Audio::AudioStream *playStream; + if (_looping) { + playStream = new Audio::LoopingAudioStream(_stream, 0); + } else { + playStream = _stream; + } + + int8 mixerBalance = convertBalance(_balance); + byte mixerVolume = convertVolume(_volume); + _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, playStream, -1, mixerVolume, mixerBalance); + _stream = nullptr; +} + +byte RivenSound::convertVolume(uint16 volume) { + // The volume is a fixed point value in the Mohawk part of the original engine. + // It's not clear what happens when it is higher than one. + return (volume > 255) ? 255 : volume; +} + +int8 RivenSound::convertBalance(int16 balance) { + return (int8)(balance >> 8); +} + +RivenSound::~RivenSound() { + _vm->_mixer->stopHandle(_handle); + delete _stream; +} + +int16 RivenSound::getBalance() const { + return _balance; +} + +uint16 RivenSound::getVolume() const { + return _volume; +} + +RivenSoundManager::AmbientSound::AmbientSound() : + sound(nullptr), + targetVolume(0), + targetBalance(0) { + +} + +RivenSoundManager::AmbientSoundList::AmbientSoundList() : + fading(false), + suspend(false) { +} + +} // End of namespace Mohawk diff --git a/engines/mohawk/riven_sound.h b/engines/mohawk/riven_sound.h new file mode 100644 index 0000000000..f673d1ee3f --- /dev/null +++ b/engines/mohawk/riven_sound.h @@ -0,0 +1,197 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MOHAWK_RIVEN_SOUND_H +#define MOHAWK_RIVEN_SOUND_H + +#include "common/array.h" +#include "common/str.h" + +#include "audio/mixer.h" + +namespace Audio { +class RewindableAudioStream; +} + +namespace Mohawk { + +class MohawkEngine; +class RivenSound; + +/** + * Ambient sound list + */ +struct SLSTRecord { + uint16 index; + Common::Array<uint16> soundIds; + uint16 fadeFlags; + uint16 loop; + uint16 globalVolume; + uint16 u0; + uint16 suspend; + Common::Array<uint16> volumes; + Common::Array<int16> balances; + Common::Array<uint16> u2; +}; + +/** + * Sound manager for Riven + * + * The sound manager can play simulteaneously: + * - An effect sound + * - A list of ambient sounds + * + * The list of ambient sounds can be cross faded + * with the previously running ambient sounds. + */ +class RivenSoundManager { +public: + RivenSoundManager(MohawkEngine *vm); + ~RivenSoundManager(); + + /** + * Play an effect sound + * + * @param id Sound ID in the stack + * @param volume Playback volume, between 0 and 255 + * @param playOnDraw Start playing when the current card is drawn instead of immediatly + */ + void playSound(uint16 id, uint16 volume = 255, bool playOnDraw = false); + + /** Start playing the scheduled on-draw effect sound, if any. Called by the GraphicsManager. */ + void triggerDrawSound(); + + /** Stop playing the current effect sound, if any */ + void stopSound(); + + /** Start playing an ambient sound list */ + void playSLST(const SLSTRecord &slstRecord); + + /** Start playing an ambient sound list from a resource */ + void playSLST(uint16 index, uint16 card); + + /** Stop playing the current ambient sounds */ + void stopAllSLST(bool fade = false); + + /** Update the ambient sounds for fading. Called once per frame. */ + void updateSLST(); + +private: + struct AmbientSound { + RivenSound *sound; + uint16 targetVolume; + int16 targetBalance; + + AmbientSound(); + }; + + struct AmbientSoundList { + bool fading; + bool suspend; + Common::Array<AmbientSound> sounds; + + AmbientSoundList(); + }; + + enum FadeFlags { + kFadeOutPreviousSounds = 1, + kFadeInNewSounds = 2 + }; + + MohawkEngine *_vm; + + int16 _mainAmbientSoundId; + AmbientSoundList _ambientSounds; + AmbientSoundList _previousAmbientSounds; + uint32 _nextFadeUpdate; + + RivenSound *_effect; + bool _effectPlayOnDraw; + + Audio::RewindableAudioStream *makeAudioStream(uint16 id); + + // Ambient sound management + void addAmbientSounds(const SLSTRecord &record); + void playAmbientSounds(); + void pauseAmbientSounds(); + void moveAmbientSoundsToPreviousSounds(); + void freePreviousAmbientSounds(); + + // Ambient sound fading + void setTargetVolumes(const SLSTRecord &record); + void applyTargetVolumes(); + void startFadingAmbientSounds(uint16 flags); + void fadeAmbientSoundList(AmbientSoundList &list); + bool fadeVolume(AmbientSound &ambientSound); + bool fadeBalance(AmbientSound &ambientSound); + void setAmbientLooping(bool loop); +}; + +/** + * A sound used internally by the SoundManager + */ +class RivenSound { +public: + RivenSound(MohawkEngine *vm, Audio::RewindableAudioStream *rewindStream); + ~RivenSound(); + + /** Start playing the sound stream passed to the constructor */ + void play(); + + /** Is the sound currently playing ar paused? */ + bool isPlaying() const; + + /** Pause the playback, the play method resumes */ + void pause(); + + /** Get the current volume */ + uint16 getVolume() const; + + /** Change the playback volume */ + void setVolume(uint16 volume); + + /** Get the current balance */ + int16 getBalance() const; + + /** Change the balance */ + void setBalance(int16 balance); + + /** Set the sound to indefinitely loop. Must be called before startting the playback */ + void setLooping(bool loop); + +private: + static byte convertVolume(uint16 volume); + static int8 convertBalance(int16 balance); + + MohawkEngine *_vm; + + Audio::SoundHandle _handle; + Audio::RewindableAudioStream *_stream; + + uint16 _volume; + int16 _balance; + bool _looping; +}; + +} // End of namespace Mohawk + +#endif diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 38cb0b3608..0711561068 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -37,6 +37,150 @@ namespace Mohawk { +Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) { + uint32 tag = 0; + ADPCMStatus adpcmStatus; + DataChunk dataChunk; + uint32 dataSize = 0; + + memset(&dataChunk, 0, sizeof(DataChunk)); + + if (stream->readUint32BE() != ID_MHWK) // MHWK tag again + error ("Could not find tag 'MHWK'"); + + stream->readUint32BE(); // Skip size + + if (stream->readUint32BE() != ID_WAVE) + error ("Could not find tag 'WAVE'"); + + while (!dataChunk.audioData) { + tag = stream->readUint32BE(); + + switch (tag) { + case ID_ADPC: + debug(2, "Found Tag ADPC"); + // ADPCM Sound Only + // + // This is useful for seeking in the stream, and is actually quite brilliant + // considering some of the other things Broderbund did with the engine. + // Only Riven and CSTime are known to use ADPCM audio and only CSTime + // actually requires this for seeking. On the other hand, it may be interesting + // to look at that one Riven sample that uses the cue points. + // + // Basically, the sample frame from the cue list is looked up here and then + // sets the starting sample and step index at the point specified. Quite + // an elegant/efficient system, really. + + adpcmStatus.size = stream->readUint32BE(); + adpcmStatus.itemCount = stream->readUint16BE(); + adpcmStatus.channels = stream->readUint16BE(); + adpcmStatus.statusItems = new ADPCMStatus::StatusItem[adpcmStatus.itemCount]; + + assert(adpcmStatus.channels <= 2); + + for (uint16 i = 0; i < adpcmStatus.itemCount; i++) { + adpcmStatus.statusItems[i].sampleFrame = stream->readUint32BE(); + + for (uint16 j = 0; j < adpcmStatus.channels; j++) { + adpcmStatus.statusItems[i].channelStatus[j].last = stream->readSint16BE(); + adpcmStatus.statusItems[i].channelStatus[j].stepIndex = stream->readUint16BE(); + } + } + + // TODO: Actually use this chunk. For now, just delete the status items... + delete[] adpcmStatus.statusItems; + break; + case ID_CUE: + debug(2, "Found Tag Cue#"); + // Cues are used for animation sync. There are a couple in Myst and + // Riven but are not used there at all. + + if (!cueList) { + uint32 size = stream->readUint32BE(); + stream->skip(size); + break; + } + + cueList->size = stream->readUint32BE(); + cueList->pointCount = stream->readUint16BE(); + + if (cueList->pointCount == 0) + debug(2, "Cue# chunk found with no points!"); + else + debug(2, "Cue# chunk found with %d point(s)!", cueList->pointCount); + + cueList->points.resize(cueList->pointCount); + for (uint16 i = 0; i < cueList->pointCount; i++) { + cueList->points[i].sampleFrame = stream->readUint32BE(); + + byte nameLength = stream->readByte(); + cueList->points[i].name.clear(); + for (byte j = 0; j < nameLength; j++) + cueList->points[i].name += stream->readByte(); + + // Realign to an even boundary + if (!(nameLength & 1)) + stream->readByte(); + + debug (3, "Cue# chunk point %d (frame %d): %s", i, cueList->points[i].sampleFrame, cueList->points[i].name.c_str()); + } + break; + case ID_DATA: + debug(2, "Found Tag DATA"); + // We subtract 20 from the actual chunk size, which is the total size + // of the chunk's header + dataSize = stream->readUint32BE() - 20; + dataChunk.sampleRate = stream->readUint16BE(); + dataChunk.sampleCount = stream->readUint32BE(); + dataChunk.bitsPerSample = stream->readByte(); + dataChunk.channels = stream->readByte(); + dataChunk.encoding = stream->readUint16BE(); + dataChunk.loopCount = stream->readUint16BE(); + dataChunk.loopStart = stream->readUint32BE(); + dataChunk.loopEnd = stream->readUint32BE(); + + // NOTE: We currently ignore all of the loop parameters here. Myst uses the + // loopCount variable but the loopStart and loopEnd are always 0 and the size of + // the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE + // files and therefore does not contain any of this metadata and we have to specify + // whether or not to loop elsewhere. + + dataChunk.audioData = stream->readStream(dataSize); + break; + default: + error ("Unknown tag found in 'tWAV' chunk -- '%s'", tag2str(tag)); + } + } + + // makeMohawkWaveStream always takes control of the original stream + delete stream; + + // The sound in Myst uses raw unsigned 8-bit data + // The sound in the CD version of Riven is encoded in Intel DVI ADPCM + // The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM + if (dataChunk.encoding == kCodecRaw) { + byte flags = Audio::FLAG_UNSIGNED; + + if (dataChunk.channels == 2) + flags |= Audio::FLAG_STEREO; + + return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags); + } else if (dataChunk.encoding == kCodecADPCM) { + uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8; + return Audio::makeADPCMStream(dataChunk.audioData, DisposeAfterUse::YES, dataSize, Audio::kADPCMDVI, dataChunk.sampleRate, dataChunk.channels, blockAlign); + } else if (dataChunk.encoding == kCodecMPEG2) { +#ifdef USE_MAD + return Audio::makeMP3Stream(dataChunk.audioData, DisposeAfterUse::YES); +#else + warning ("MAD library not included - unable to play MP2 audio"); +#endif + } else { + error ("Unknown Mohawk WAVE encoding %d", dataChunk.encoding); + } + + return nullptr; +} + Sound::Sound(MohawkEngine* vm) : _vm(vm) { _midiDriver = NULL; _midiParser = NULL; @@ -47,7 +191,6 @@ Sound::Sound(MohawkEngine* vm) : _vm(vm) { Sound::~Sound() { stopSound(); - stopAllSLST(); stopBackgroundMyst(); if (_midiParser) { @@ -234,300 +377,6 @@ void Sound::stopMidi() { _midiParser->unloadMusic(); } -byte Sound::convertRivenVolume(uint16 volume) { - return (volume == 256) ? 255 : volume; -} - -void Sound::playSLST(uint16 index, uint16 card) { - Common::SeekableReadStream *slstStream = _vm->getResource(ID_SLST, card); - SLSTRecord slstRecord; - uint16 recordCount = slstStream->readUint16BE(); - - for (uint16 i = 0; i < recordCount; i++) { - slstRecord.index = slstStream->readUint16BE(); - slstRecord.sound_count = slstStream->readUint16BE(); - slstRecord.sound_ids = new uint16[slstRecord.sound_count]; - - for (uint16 j = 0; j < slstRecord.sound_count; j++) - slstRecord.sound_ids[j] = slstStream->readUint16BE(); - - slstRecord.fade_flags = slstStream->readUint16BE(); - slstRecord.loop = slstStream->readUint16BE(); - slstRecord.global_volume = slstStream->readUint16BE(); - slstRecord.u0 = slstStream->readUint16BE(); // Unknown - - if (slstRecord.u0 > 1) - warning("slstRecord.u0: %d non-boolean", slstRecord.u0); - - slstRecord.u1 = slstStream->readUint16BE(); // Unknown - - if (slstRecord.u1 != 0) - warning("slstRecord.u1: %d non-zero", slstRecord.u1); - - slstRecord.volumes = new uint16[slstRecord.sound_count]; - slstRecord.balances = new int16[slstRecord.sound_count]; - slstRecord.u2 = new uint16[slstRecord.sound_count]; - - for (uint16 j = 0; j < slstRecord.sound_count; j++) - slstRecord.volumes[j] = slstStream->readUint16BE(); - - for (uint16 j = 0; j < slstRecord.sound_count; j++) - slstRecord.balances[j] = slstStream->readSint16BE(); // negative = left, 0 = center, positive = right - - for (uint16 j = 0; j < slstRecord.sound_count; j++) { - slstRecord.u2[j] = slstStream->readUint16BE(); // Unknown - - if (slstRecord.u2[j] != 255 && slstRecord.u2[j] != 256) - warning("slstRecord.u2[%d]: %d not 255 or 256", j, slstRecord.u2[j]); - } - - if (slstRecord.index == index) { - playSLST(slstRecord); - delete[] slstRecord.sound_ids; - delete[] slstRecord.volumes; - delete[] slstRecord.balances; - delete[] slstRecord.u2; - delete slstStream; - return; - } - - delete[] slstRecord.sound_ids; - delete[] slstRecord.volumes; - delete[] slstRecord.balances; - delete[] slstRecord.u2; - } - - delete slstStream; - - // If we have no matching entries, we do nothing and just let - // the previous ambient sounds continue. -} - -void Sound::playSLST(SLSTRecord slstRecord) { - // End old sounds - for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) { - bool noLongerPlay = true; - for (uint16 j = 0; j < slstRecord.sound_count; j++) - if (_currentSLSTSounds[i].id == slstRecord.sound_ids[j]) - noLongerPlay = false; - if (noLongerPlay) - stopSLSTSound(i, (slstRecord.fade_flags & 1) != 0); - } - - // Start new sounds - for (uint16 i = 0; i < slstRecord.sound_count; i++) { - bool alreadyPlaying = false; - for (uint16 j = 0; j < _currentSLSTSounds.size(); j++) { - if (_currentSLSTSounds[j].id == slstRecord.sound_ids[i]) - alreadyPlaying = true; - } - if (!alreadyPlaying) { - playSLSTSound(slstRecord.sound_ids[i], - (slstRecord.fade_flags & (1 << 1)) != 0, - slstRecord.loop != 0, - slstRecord.volumes[i], - slstRecord.balances[i]); - } - } -} - -void Sound::stopAllSLST(bool fade) { - for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) { - // TODO: Fade out, if requested - _vm->_mixer->stopHandle(*_currentSLSTSounds[i].handle); - delete _currentSLSTSounds[i].handle; - } - - _currentSLSTSounds.clear(); -} - -static int8 convertBalance(int16 balance) { - return (int8)(balance >> 8); -} - -void Sound::playSLSTSound(uint16 id, bool fade, bool loop, uint16 volume, int16 balance) { - // WORKAROUND: Some Riven SLST entries have a volume of 0, so we just ignore them. - if (volume == 0) - return; - - SLSTSndHandle sndHandle; - sndHandle.handle = new Audio::SoundHandle(); - sndHandle.id = id; - _currentSLSTSounds.push_back(sndHandle); - - Audio::RewindableAudioStream *rewindStream = makeMohawkWaveStream(_vm->getResource(ID_TWAV, id)); - - // Loop here if necessary - Audio::AudioStream *audStream = rewindStream; - if (loop) - audStream = Audio::makeLoopingAudioStream(rewindStream, 0); - - // TODO: Handle fading, possibly just raise the volume of the channel in increments? - - _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, sndHandle.handle, audStream, -1, convertRivenVolume(volume), convertBalance(balance)); -} - -void Sound::stopSLSTSound(uint16 index, bool fade) { - // TODO: Fade out, if requested - _vm->_mixer->stopHandle(*_currentSLSTSounds[index].handle); - delete _currentSLSTSounds[index].handle; - _currentSLSTSounds.remove_at(index); -} - -void Sound::pauseSLST() { - for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) - _vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, true); -} - -void Sound::resumeSLST() { - for (uint16 i = 0; i < _currentSLSTSounds.size(); i++) - _vm->_mixer->pauseHandle(*_currentSLSTSounds[i].handle, false); -} - -Audio::RewindableAudioStream *Sound::makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList) { - uint32 tag = 0; - ADPCMStatus adpcmStatus; - DataChunk dataChunk; - uint32 dataSize = 0; - - memset(&dataChunk, 0, sizeof(DataChunk)); - - if (stream->readUint32BE() != ID_MHWK) // MHWK tag again - error ("Could not find tag 'MHWK'"); - - stream->readUint32BE(); // Skip size - - if (stream->readUint32BE() != ID_WAVE) - error ("Could not find tag 'WAVE'"); - - while (!dataChunk.audioData) { - tag = stream->readUint32BE(); - - switch (tag) { - case ID_ADPC: - debug(2, "Found Tag ADPC"); - // ADPCM Sound Only - // - // This is useful for seeking in the stream, and is actually quite brilliant - // considering some of the other things Broderbund did with the engine. - // Only Riven and CSTime are known to use ADPCM audio and only CSTime - // actually requires this for seeking. On the other hand, it may be interesting - // to look at that one Riven sample that uses the cue points. - // - // Basically, the sample frame from the cue list is looked up here and then - // sets the starting sample and step index at the point specified. Quite - // an elegant/efficient system, really. - - adpcmStatus.size = stream->readUint32BE(); - adpcmStatus.itemCount = stream->readUint16BE(); - adpcmStatus.channels = stream->readUint16BE(); - adpcmStatus.statusItems = new ADPCMStatus::StatusItem[adpcmStatus.itemCount]; - - assert(adpcmStatus.channels <= 2); - - for (uint16 i = 0; i < adpcmStatus.itemCount; i++) { - adpcmStatus.statusItems[i].sampleFrame = stream->readUint32BE(); - - for (uint16 j = 0; j < adpcmStatus.channels; j++) { - adpcmStatus.statusItems[i].channelStatus[j].last = stream->readSint16BE(); - adpcmStatus.statusItems[i].channelStatus[j].stepIndex = stream->readUint16BE(); - } - } - - // TODO: Actually use this chunk. For now, just delete the status items... - delete[] adpcmStatus.statusItems; - break; - case ID_CUE: - debug(2, "Found Tag Cue#"); - // Cues are used for animation sync. There are a couple in Myst and - // Riven but are not used there at all. - - if (!cueList) { - uint32 size = stream->readUint32BE(); - stream->skip(size); - break; - } - - cueList->size = stream->readUint32BE(); - cueList->pointCount = stream->readUint16BE(); - - if (cueList->pointCount == 0) - debug(2, "Cue# chunk found with no points!"); - else - debug(2, "Cue# chunk found with %d point(s)!", cueList->pointCount); - - cueList->points.resize(cueList->pointCount); - for (uint16 i = 0; i < cueList->pointCount; i++) { - cueList->points[i].sampleFrame = stream->readUint32BE(); - - byte nameLength = stream->readByte(); - cueList->points[i].name.clear(); - for (byte j = 0; j < nameLength; j++) - cueList->points[i].name += stream->readByte(); - - // Realign to an even boundary - if (!(nameLength & 1)) - stream->readByte(); - - debug (3, "Cue# chunk point %d (frame %d): %s", i, cueList->points[i].sampleFrame, cueList->points[i].name.c_str()); - } - break; - case ID_DATA: - debug(2, "Found Tag DATA"); - // We subtract 20 from the actual chunk size, which is the total size - // of the chunk's header - dataSize = stream->readUint32BE() - 20; - dataChunk.sampleRate = stream->readUint16BE(); - dataChunk.sampleCount = stream->readUint32BE(); - dataChunk.bitsPerSample = stream->readByte(); - dataChunk.channels = stream->readByte(); - dataChunk.encoding = stream->readUint16BE(); - dataChunk.loopCount = stream->readUint16BE(); - dataChunk.loopStart = stream->readUint32BE(); - dataChunk.loopEnd = stream->readUint32BE(); - - // NOTE: We currently ignore all of the loop parameters here. Myst uses the - // loopCount variable but the loopStart and loopEnd are always 0 and the size of - // the sample. Myst ME doesn't use the Mohawk Sound format and just standard WAVE - // files and therefore does not contain any of this metadata and we have to specify - // whether or not to loop elsewhere. - - dataChunk.audioData = stream->readStream(dataSize); - break; - default: - error ("Unknown tag found in 'tWAV' chunk -- '%s'", tag2str(tag)); - } - } - - // makeMohawkWaveStream always takes control of the original stream - delete stream; - - // The sound in Myst uses raw unsigned 8-bit data - // The sound in the CD version of Riven is encoded in Intel DVI ADPCM - // The sound in the DVD version of Riven is encoded in MPEG-2 Layer II or Intel DVI ADPCM - if (dataChunk.encoding == kCodecRaw) { - byte flags = Audio::FLAG_UNSIGNED; - - if (dataChunk.channels == 2) - flags |= Audio::FLAG_STEREO; - - return Audio::makeRawStream(dataChunk.audioData, dataChunk.sampleRate, flags); - } else if (dataChunk.encoding == kCodecADPCM) { - uint32 blockAlign = dataChunk.channels * dataChunk.bitsPerSample / 8; - return Audio::makeADPCMStream(dataChunk.audioData, DisposeAfterUse::YES, dataSize, Audio::kADPCMDVI, dataChunk.sampleRate, dataChunk.channels, blockAlign); - } else if (dataChunk.encoding == kCodecMPEG2) { -#ifdef USE_MAD - return Audio::makeMP3Stream(dataChunk.audioData, DisposeAfterUse::YES); -#else - warning ("MAD library not included - unable to play MP2 audio"); -#endif - } else { - error ("Unknown Mohawk WAVE encoding %d", dataChunk.encoding); - } - - return NULL; -} - Audio::RewindableAudioStream *Sound::makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream) { uint16 header = stream->readUint16BE(); uint16 rate = 0; @@ -591,18 +440,6 @@ void Sound::stopSound(uint16 id) { } } -void Sound::pauseSound() { - for (uint32 i = 0; i < _handles.size(); i++) - if (_handles[i].type == kUsedHandle) - _vm->_mixer->pauseHandle(_handles[i].handle, true); -} - -void Sound::resumeSound() { - for (uint32 i = 0; i < _handles.size(); i++) - if (_handles[i].type == kUsedHandle) - _vm->_mixer->pauseHandle(_handles[i].handle, false); -} - bool Sound::isPlaying(uint16 id) { for (uint32 i = 0; i < _handles.size(); i++) if (_handles[i].type == kUsedHandle && _handles[i].id == id) diff --git a/engines/mohawk/sound.h b/engines/mohawk/sound.h index f09706e155..2b4b1ce091 100644 --- a/engines/mohawk/sound.h +++ b/engines/mohawk/sound.h @@ -42,20 +42,6 @@ namespace Mohawk { #define MAX_CHANNELS 2 // Can there be more than 2? -struct SLSTRecord { - uint16 index; - uint16 sound_count; - uint16 *sound_ids; - uint16 fade_flags; - uint16 loop; - uint16 global_volume; - uint16 u0; - uint16 u1; - uint16 *volumes; - int16 *balances; - uint16 *u2; -}; - enum SndHandleType { kFreeHandle, kUsedHandle @@ -68,11 +54,6 @@ struct SndHandle { uint16 id; }; -struct SLSTSndHandle { - Audio::SoundHandle *handle; - uint16 id; -}; - struct ADPCMStatus { // Holds ADPCM status data, but is irrelevant for us. uint32 size; uint16 itemCount; @@ -116,6 +97,8 @@ struct DataChunk { Common::SeekableReadStream *audioData; }; +Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = nullptr); + class MohawkEngine; class Sound { @@ -130,8 +113,6 @@ public: void stopMidi(); void stopSound(); void stopSound(uint16 id); - void pauseSound(); - void resumeSound(); bool isPlaying(uint16 id); bool isPlaying(); uint getNumSamplesPlayed(uint16 id); @@ -144,21 +125,12 @@ public: void stopBackgroundMyst(); void changeBackgroundVolumeMyst(uint16 vol); - // Riven-specific sound functions - void playSLST(uint16 index, uint16 card); - void playSLST(SLSTRecord slstRecord); - void pauseSLST(); - void resumeSLST(); - void stopAllSLST(bool fade = false); - static byte convertRivenVolume(uint16 volume); - private: MohawkEngine *_vm; MidiDriver *_midiDriver; MidiParser *_midiParser; byte *_midiData; - static Audio::RewindableAudioStream *makeMohawkWaveStream(Common::SeekableReadStream *stream, CueList *cueList = NULL); static Audio::RewindableAudioStream *makeLivingBooksWaveStream_v1(Common::SeekableReadStream *stream); void initMidi(); @@ -169,11 +141,6 @@ private: // Myst-specific SndHandle _mystBackgroundSound; - - // Riven-specific - void playSLSTSound(uint16 index, bool fade, bool loop, uint16 volume, int16 balance); - void stopSLSTSound(uint16 id, bool fade); - Common::Array<SLSTSndHandle> _currentSLSTSounds; }; } // End of namespace Mohawk diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 3e67a1819a..3aaf13efdb 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -489,6 +489,7 @@ bool Console::cmdGetVersion(int argc, const char **argv) { debugPrintf("Lofs type: %s\n", getSciVersionDesc(_engine->_features->detectLofsType())); debugPrintf("Move count type: %s\n", (_engine->_features->handleMoveCount()) ? "increment" : "ignore"); debugPrintf("SetCursor type: %s\n", getSciVersionDesc(_engine->_features->detectSetCursorType())); + debugPrintf("PseudoMouse ability: %s\n", _engine->_features->detectPseudoMouseAbility() == kPseudoMouseAbilityTrue ? "yes" : "no"); #ifdef ENABLE_SCI32 if ((getSciVersion() >= SCI_VERSION_2_1_EARLY) && (getSciVersion() <= SCI_VERSION_2_1_LATE)) debugPrintf("SCI2.1 kernel table: %s\n", (_engine->_features->detectSci21KernelType() == SCI_VERSION_2) ? "modified SCI2 (old)" : "SCI2.1 (new)"); diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index a993506f7a..e37a1651ef 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -45,6 +45,7 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan) if (!ConfMan.getBool("use_cdaudio")) _usesCdTrack = false; _forceDOSTracks = false; + _pseudoMouseAbility = kPseudoMouseAbilityUninitialized; } reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc, int methodNum) { @@ -605,4 +606,50 @@ bool GameFeatures::useAltWinGMSound() { } } +// PseudoMouse was added during SCI1 +// PseudoMouseAbility is about a tiny difference in the keyboard driver, which sets the event type to either +// 40h (old behaviour) or 44h (the keyboard driver actually added 40h to the existing value). +// See engine/kevent.cpp, kMapKeyToDir - also script 933 + +// SCI1EGA: +// Quest for Glory 2 still used the old way. +// +// SCI1EARLY: +// King's Quest 5 0.000.062 uses the old way. +// Leisure Suit Larry 1 demo uses the new way, but no PseudoMouse class. +// Fairy Tales uses the new way. +// X-Mas 1990 uses the old way, no PseudoMouse class. +// Space Quest 4 floppy (1.1) uses the new way. +// Mixed Up Mother Goose uses the old way, no PseudoMouse class. +// +// SCI1MIDDLE: +// Leisure Suit Larry 5 demo uses the new way. +// Conquests of the Longbow demo uses the new way. +// Leisure Suit Larry 1 (2.0) uses the new way. +// Astro Chicken II uses the new way. +PseudoMouseAbilityType GameFeatures::detectPseudoMouseAbility() { + if (_pseudoMouseAbility == kPseudoMouseAbilityUninitialized) { + if (getSciVersion() < SCI_VERSION_1_EARLY) { + // SCI1 EGA or earlier -> pseudo mouse ability is always disabled + _pseudoMouseAbility = kPseudoMouseAbilityFalse; + + } else if (getSciVersion() == SCI_VERSION_1_EARLY) { + // For SCI1 early some games had it enabled, some others didn't. + // We try to find an object called "PseudoMouse". If it's found, we enable the ability otherwise we don't. + reg_t pseudoMouseAddr = _segMan->findObjectByName("PseudoMouse", 0); + + if (pseudoMouseAddr != NULL_REG) { + _pseudoMouseAbility = kPseudoMouseAbilityTrue; + } else { + _pseudoMouseAbility = kPseudoMouseAbilityFalse; + } + + } else { + // SCI1 middle or later -> pseudo mouse ability is always enabled + _pseudoMouseAbility = kPseudoMouseAbilityTrue; + } + } + return _pseudoMouseAbility; +} + } // End of namespace Sci diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h index 1c410267e6..b2d40f400f 100644 --- a/engines/sci/engine/features.h +++ b/engines/sci/engine/features.h @@ -34,6 +34,12 @@ enum MoveCountType { kIncrementMoveCount }; +enum PseudoMouseAbilityType { + kPseudoMouseAbilityUninitialized, + kPseudoMouseAbilityFalse, + kPseudoMouseAbilityTrue +}; + class GameFeatures { public: GameFeatures(SegManager *segMan, Kernel *kernel); @@ -110,6 +116,12 @@ public: */ void forceDOSTracks() { _forceDOSTracks = true; } + /** + * Autodetects, if Pseudo Mouse ability is enabled (different behavior in keyboard driver) + * @return kPseudoMouseAbilityTrue or kPseudoMouseAbilityFalse + */ + PseudoMouseAbilityType detectPseudoMouseAbility(); + private: reg_t getDetectionAddr(const Common::String &objName, Selector slc, int methodNum = -1); @@ -130,6 +142,8 @@ private: bool _usesCdTrack; bool _forceDOSTracks; + PseudoMouseAbilityType _pseudoMouseAbility; + SegManager *_segMan; Kernel *_kernel; }; diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 5ff4f932be..b02a7e545a 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -450,6 +450,17 @@ reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv); reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv); reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovie32(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWin(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinOpen(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinInit(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinPlay(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinClose(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinCue(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv); +reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv); + reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv); reg_t kArray(EngineState *s, int argc, reg_t *argv); reg_t kListAt(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index e0e4dcc233..76c24b09e3 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -423,6 +423,27 @@ static const SciKernelMapSubEntry kList_subops[] = { SCI_SUBOPENTRY_TERMINATOR }; +// version, subId, function-mapping, signature, workarounds +static const SciKernelMapSubEntry kShowMovieWin_subops[] = { + { SIG_SCI2, 0, MAP_CALL(ShowMovieWinOpen), "r", NULL }, + { SIG_SCI2, 1, MAP_CALL(ShowMovieWinInit), "ii(ii)", NULL }, + { SIG_SCI2, 2, MAP_CALL(ShowMovieWinPlay), "i", NULL }, + { SIG_SCI2, 6, MAP_CALL(ShowMovieWinClose), "", NULL }, + { SIG_SINCE_SCI21, 0, MAP_CALL(ShowMovieWinOpen), "ir", NULL }, + { SIG_SINCE_SCI21, 1, MAP_CALL(ShowMovieWinInit), "iii(ii)", NULL }, + { SIG_SINCE_SCI21, 2, MAP_CALL(ShowMovieWinPlay), "i(ii)(i)(i)", NULL }, + { SIG_SINCE_SCI21, 6, MAP_CALL(ShowMovieWinClose), "i", NULL }, + // Since movies are rendered within the graphics engine in ScummVM, + // it is not necessary to copy the palette from SCI to MCI, so this + // can be a no-op + { SIG_SINCE_SCI21, 7, MAP_EMPTY(ShowMovieWinSetPalette), "i", NULL }, + { SIG_SINCE_SCI21, 8, MAP_CALL(ShowMovieWinGetDuration), "i", NULL }, + { SIG_SINCE_SCI21, 11, MAP_CALL(ShowMovieWinCue), "ii", NULL }, + { SIG_SINCE_SCI21, 14, MAP_CALL(ShowMovieWinPlayUntilEvent), "i(i)", NULL }, + { SIG_SINCE_SCI21, 15, MAP_CALL(ShowMovieWinInitDouble), "iii", NULL }, + SCI_SUBOPENTRY_TERMINATOR +}; + // There are a lot of subops to PlayVMD, but only a few of them are ever // actually used by games // version, subId, function-mapping, signature, workarounds @@ -688,7 +709,11 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(SetVideoMode), SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(ShakeScreen), SIG_EVERYWHERE, "(i)(i)", NULL, NULL }, - { MAP_CALL(ShowMovie), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(ShowMovie), SIG_SCI16, SIGFOR_ALL, "(.*)", NULL, NULL }, +#ifdef ENABLE_SCI32 + { "ShowMovie", kShowMovie32, SIG_SCI32, SIGFOR_DOS, "ri(i)(i)", NULL, NULL }, + { "ShowMovie", kShowMovieWin, SIG_SCI32, SIGFOR_WIN, "(.*)", kShowMovieWin_subops, NULL }, +#endif { MAP_CALL(Show), SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL }, @@ -820,7 +845,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", kPlayVMD_subops, NULL }, - { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_EMPTY(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL }, { MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL }, { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii(i)(i)", NULL, NULL }, diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index 534d9ce713..d7a716a504 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -258,11 +258,12 @@ reg_t kMapKeyToDir(EngineState *s, int argc, reg_t *argv) { if (readSelectorValue(segMan, obj, SELECTOR(type)) == SCI_EVENT_KEYBOARD) { // Keyboard uint16 message = readSelectorValue(segMan, obj, SELECTOR(message)); uint16 eventType = SCI_EVENT_DIRECTION; - // Check if the game is using cursor views. These games allowed control - // of the mouse cursor via the keyboard controls (the so called - // "PseudoMouse" functionality in script 933). - if (g_sci->_features->detectSetCursorType() == SCI_VERSION_1_1) + // It seems with SCI1 Sierra started to add the SCI_EVENT_DIRECTION bit instead of setting it directly. + // It was done inside the keyboard driver and is required for the PseudoMouse functionality and class + // to work (script 933). + if (g_sci->_features->detectPseudoMouseAbility() == kPseudoMouseAbilityTrue) { eventType |= SCI_EVENT_KEYBOARD; + } for (int i = 0; i < 9; i++) { if (keyToDirMap[i].key == message) { diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 4508a481a0..3bcadd143c 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -251,6 +251,25 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { return SIGNAL_REG; } + // Torin's autosave system checks for the presence of autosave.cat + // by opening it. Since we don't use .cat files, we instead check + // for autosave.000 or autosave.001. + // + // This has the added benefit of not detecting an SSCI autosave.cat + // accompanying SSCI autosave files that we wouldn't be able to load. + if (g_sci->getGameId() == GID_TORIN && name == "autosave.cat") { + Common::String pattern = g_sci->wrapFilename("autosave.###"); + Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); + bool exists = !saveFileMan->listSavefiles(pattern).empty(); + if (exists) { + // Dummy handle. Torin only checks if this is SIGNAL_REG, + // and calls kFileIOClose on it. + return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE); + } else { + return SIGNAL_REG; + } + } + if (name.empty()) { // Happens many times during KQ1 (e.g. when typing something) debugC(kDebugLevelFile, "Attempted to open a file with an empty filename"); @@ -688,7 +707,7 @@ reg_t kSave(EngineState *s, int argc, reg_t *argv) { #endif reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { - Common::String game_id; + Common::String game_id = !argv[0].isNull() ? s->_segMan->getString(argv[0]) : ""; int16 virtualId = argv[1].toSint16(); int16 savegameId = -1; Common::String game_description; @@ -703,6 +722,13 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } + // Torin has two sets of saves: autosave.### and torinsg.###, both with + // their own slots and .cat file. + // The autosave system uses autosave.000 and autosave.001. + // It also checks the presence of autosave.cat to determine if it should + // show the chapter selection menu on startup. (See kFileIOOpen.) + bool torinAutosave = g_sci->getGameId() == GID_TORIN && game_id == "Autosave"; + if (argv[0].isNull()) { // Direct call, from a patched Game::save if ((argv[1] != SIGNAL_REG) || (!argv[2].isNull())) @@ -722,9 +748,15 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { if (savegameId < 0) return NULL_REG; + } else if (torinAutosave) { + if (argv[2].isNull()) + error("kSaveGame: called with description being NULL"); + game_description = s->_segMan->getString(argv[2]); + savegameId = virtualId; + + debug(3, "kSaveGame(%s,%d,%s,%s) [Torin autosave]", game_id.c_str(), virtualId, game_description.c_str(), version.c_str()); } else { // Real call from script - game_id = s->_segMan->getString(argv[0]); if (argv[2].isNull()) error("kSaveGame: called with description being NULL"); game_description = s->_segMan->getString(argv[2]); @@ -798,6 +830,10 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); Common::OutSaveFile *out; + if (torinAutosave) { + filename = g_sci->wrapFilename(Common::String::format("autosave.%03d", savegameId)); + } + out = saveFileMan->openForSaving(filename); if (!out) { warning("Error opening savegame \"%s\" for writing", filename.c_str()); @@ -826,6 +862,10 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savegameId); + + // See comment in kSaveGame + bool torinAutosave = g_sci->getGameId() == GID_TORIN && game_id == "Autosave"; + if (argv[0].isNull()) { // Direct call, either from launcher or from a patched Game::restore if (savegameId == -1) { @@ -841,7 +881,7 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { pausedMusic = true; } // don't adjust ID of the saved game, it's already correct - } else { + } else if (!torinAutosave) { if (g_sci->getGameId() == GID_JONES) { // Jones has one save slot only savegameId = 0; @@ -858,8 +898,9 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { s->r_acc = NULL_REG; // signals success Common::Array<SavegameDesc> saves; - listSavegames(saves); - if (findSavegame(saves, savegameId) == -1) { + if (!torinAutosave) + listSavegames(saves); + if (!torinAutosave && findSavegame(saves, savegameId) == -1) { s->r_acc = TRUE_REG; warning("Savegame ID %d not found", savegameId); } else { @@ -867,6 +908,10 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { Common::String filename = g_sci->getSavegameName(savegameId); Common::SeekableReadStream *in; + if (torinAutosave) { + filename = g_sci->wrapFilename(Common::String::format("autosave.%03d", savegameId)); + } + in = saveFileMan->openForLoading(filename); if (in) { // found a savegame file diff --git a/engines/sci/engine/klists.cpp b/engines/sci/engine/klists.cpp index c0da2daaeb..53be26b37f 100644 --- a/engines/sci/engine/klists.cpp +++ b/engines/sci/engine/klists.cpp @@ -374,13 +374,21 @@ reg_t kFindKey(EngineState *s, int argc, reg_t *argv) { reg_t kDeleteKey(EngineState *s, int argc, reg_t *argv) { reg_t node_pos = kFindKey(s, 2, argv); - Node *n; List *list = s->_segMan->lookupList(argv[0]); if (node_pos.isNull()) return NULL_REG; // Signal failure - n = s->_segMan->lookupNode(node_pos); + Node *n = s->_segMan->lookupNode(node_pos); + +#ifdef ENABLE_SCI32 + for (int i = 1; i <= list->numRecursions; ++i) { + if (list->nextNodes[i] == node_pos) { + list->nextNodes[i] = n->succ; + } + } +#endif + if (list->first == node_pos) list->first = n->succ; if (list->last == node_pos) @@ -544,9 +552,18 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) { ObjVarRef address; + ++list->numRecursions; + + if (list->numRecursions > ARRAYSIZE(list->nextNodes)) { + error("Too much recursion in kListEachElementDo"); + } + while (curNode) { - // We get the next node here as the current node might be gone after the invoke - reg_t nextNode = curNode->succ; + // We get the next node here as the current node might be deleted by the + // invoke. In the case that the next node is also deleted, kDeleteKey + // needs to be able to adjust the location of the next node, which is + // why it is stored on the list instead of on the stack + list->nextNodes[list->numRecursions] = curNode->succ; curObject = curNode->value; // First, check if the target selector is a variable @@ -561,9 +578,11 @@ reg_t kListEachElementDo(EngineState *s, int argc, reg_t *argv) { invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2); } - curNode = s->_segMan->lookupNode(nextNode); + curNode = s->_segMan->lookupNode(list->nextNodes[list->numRecursions]); } + --list->numRecursions; + return s->r_acc; } diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index 1924848717..c99540967c 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -20,6 +20,7 @@ * */ +#include "common/config-manager.h" #include "common/system.h" #include "sci/sci.h" @@ -542,7 +543,7 @@ enum kSciPlatforms { enum kPlatformOps { kPlatformUnk0 = 0, kPlatformCDSpeed = 1, - kPlatformUnk2 = 2, + kPlatformColorDepth = 2, kPlatformCDCheck = 3, kPlatformGetPlatform = 4, kPlatformUnk5 = 5, @@ -563,11 +564,6 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } - if (g_sci->forceHiresGraphics()) { - // force Windows platform, so that hires-graphics are enabled - isWindows = true; - } - uint16 operation = (argc == 0) ? 0 : argv[0].toUint16(); switch (operation) { @@ -575,9 +571,9 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { // TODO: Returns CD Speed? warning("STUB: kPlatform(CDSpeed)"); break; - case kPlatformUnk2: + case kPlatformColorDepth: // Always returns 2 - return make_reg(0, 2); + return make_reg(0, /* 256-color */ 2); case kPlatformCDCheck: // TODO: Some sort of CD check? warning("STUB: kPlatform(CDCheck)"); @@ -591,9 +587,9 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { return make_reg(0, (isWindows) ? kSciPlatformWindows : kSciPlatformDOS); case kPlatformUnk5: // This case needs to return the opposite of case 6 to get hires graphics - return make_reg(0, !isWindows); + return make_reg(0, !ConfMan.getBool("enable_high_resolution_graphics")); case kPlatformIsHiRes: - return make_reg(0, isWindows); + return make_reg(0, ConfMan.getBool("enable_high_resolution_graphics")); case kPlatformIsItWindows: return make_reg(0, isWindows); default: diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index de4d4a282c..86d8a4b817 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -61,33 +61,15 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { uint16 screenWidth = g_sci->_gfxScreen->getDisplayWidth(); uint16 screenHeight = g_sci->_gfxScreen->getDisplayHeight(); - videoState.fileName.toLowercase(); - bool isVMD = videoState.fileName.hasSuffix(".vmd"); - - if (screenWidth == 640 && width <= 320 && height <= 240 && ((videoState.flags & kDoubled) || !isVMD)) { + if (screenWidth == 640 && width <= 320 && height <= 240) { width *= 2; height *= 2; pitch *= 2; scaleBuffer = new byte[width * height * bytesPerPixel]; } - uint16 x, y; - - // Sanity check... - if (videoState.x > 0 && videoState.y > 0 && isVMD) { - x = videoState.x; - y = videoState.y; - - if (x + width > screenWidth || y + height > screenHeight) { - // Happens in the Lighthouse demo - warning("VMD video won't fit on screen, centering it instead"); - x = (screenWidth - width) / 2; - y = (screenHeight - height) / 2; - } - } else { - x = (screenWidth - width) / 2; - y = (screenHeight - height) / 2; - } + uint16 x = (screenWidth - width) / 2; + uint16 y = (screenHeight - height) / 2; bool skipVideo = false; EngineState *s = g_sci->getEngineState(); @@ -181,16 +163,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { // TODO: This appears to be some sort of subop. case 0 contains the string // for the video, so we'll just play it from there for now. -#ifdef ENABLE_SCI32 - if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { - // SCI2.1 always has argv[0] as 1, the rest of the arguments seem to - // follow SCI1.1/2. - if (argv[0].toUint16() != 1) - error("SCI2.1 kShowMovie argv[0] not 1"); - argv++; - argc--; - } -#endif switch (argv[0].toUint16()) { case 0: { Common::String filename = s->_segMan->getString(argv[1]); @@ -243,52 +215,102 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } #ifdef ENABLE_SCI32 +reg_t kShowMovie32(EngineState *s, int argc, reg_t *argv) { + Common::String fileName = s->_segMan->getString(argv[0]); + const int16 numTicks = argv[1].toSint16(); + const int16 x = argc > 3 ? argv[2].toSint16() : 0; + const int16 y = argc > 3 ? argv[3].toSint16() : 0; -reg_t kRobot(EngineState *s, int argc, reg_t *argv) { - int16 subop = argv[0].toUint16(); - - switch (subop) { - case 0: { // init - int id = argv[1].toUint16(); - reg_t obj = argv[2]; - int16 flag = argv[3].toSint16(); - int16 x = argv[4].toUint16(); - int16 y = argv[5].toUint16(); - warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); - g_sci->_robotDecoder->load(id); - g_sci->_robotDecoder->start(); - g_sci->_robotDecoder->setPos(x, y); - } - break; - case 1: // LSL6 hires (startup) - // TODO - return NULL_REG; // an integer is expected - case 4: { // start - we don't really have a use for this one - //int id = argv[1].toUint16(); - //warning("kRobot(start), id %d", id); - } - break; - case 7: // unknown, called e.g. by Phantasmagoria - warning("kRobot(%d)", subop); - break; - case 8: // sync - //if (true) { // debug: automatically skip all robot videos - if (g_sci->_robotDecoder->endOfVideo()) { - g_sci->_robotDecoder->close(); - // Signal the engine scripts that the video is done - writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); - } else { - writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); - } - break; - default: - warning("kRobot(%d)", subop); - break; - } + g_sci->_video32->getSEQPlayer().play(fileName, numTicks, x, y); return s->r_acc; } +reg_t kShowMovieWin(EngineState *s, int argc, reg_t *argv) { + if (!s) + return make_reg(0, getSciVersion()); + error("not supposed to call this"); +} + +reg_t kShowMovieWinOpen(EngineState *s, int argc, reg_t *argv) { + // SCI2.1 adds a movie ID to the call, but the movie ID is broken, + // so just ignore it + if (getSciVersion() > SCI_VERSION_2) { + ++argv; + --argc; + } + + const Common::String fileName = s->_segMan->getString(argv[0]); + return make_reg(0, g_sci->_video32->getAVIPlayer().open(fileName)); +} + +reg_t kShowMovieWinInit(EngineState *s, int argc, reg_t *argv) { + // SCI2.1 adds a movie ID to the call, but the movie ID is broken, + // so just ignore it + if (getSciVersion() > SCI_VERSION_2) { + ++argv; + --argc; + } + + const int16 x = argv[0].toSint16(); + const int16 y = argv[1].toSint16(); + const int16 width = argc > 3 ? argv[2].toSint16() : 0; + const int16 height = argc > 3 ? argv[3].toSint16() : 0; + return make_reg(0, g_sci->_video32->getAVIPlayer().init1x(x, y, width, height)); +} + +reg_t kShowMovieWinPlay(EngineState *s, int argc, reg_t *argv) { + if (getSciVersion() == SCI_VERSION_2) { + AVIPlayer::EventFlags flags = (AVIPlayer::EventFlags)argv[0].toUint16(); + return make_reg(0, g_sci->_video32->getAVIPlayer().playUntilEvent(flags)); + } else { + // argv[0] is a broken movie ID + const int16 from = argc > 2 ? argv[1].toSint16() : 0; + const int16 to = argc > 2 ? argv[2].toSint16() : 0; + const int16 showStyle = argc > 3 ? argv[3].toSint16() : 0; + const bool cue = argc > 4 ? (bool)argv[4].toSint16() : false; + return make_reg(0, g_sci->_video32->getAVIPlayer().play(from, to, showStyle, cue)); + } +} + +reg_t kShowMovieWinClose(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, g_sci->_video32->getAVIPlayer().close()); +} + +reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv) { + return make_reg(0, g_sci->_video32->getAVIPlayer().getDuration()); +} + +reg_t kShowMovieWinCue(EngineState *s, int argc, reg_t *argv) { + // SCI2.1 adds a movie ID to the call, but the movie ID is broken, + // so just ignore it + if (getSciVersion() > SCI_VERSION_2) { + ++argv; + --argc; + } + + const uint16 frameNo = argv[0].toUint16(); + return make_reg(0, g_sci->_video32->getAVIPlayer().cue(frameNo)); +} + +reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv) { + const int defaultFlags = + AVIPlayer::kEventFlagEnd | + AVIPlayer::kEventFlagEscapeKey; + + // argv[0] is the movie number, which is not used by this method + const AVIPlayer::EventFlags flags = (AVIPlayer::EventFlags)(argc > 1 ? argv[1].toUint16() : defaultFlags); + + return make_reg(0, g_sci->_video32->getAVIPlayer().playUntilEvent(flags)); +} + +reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv) { + // argv[0] is a broken movie ID + const int16 x = argv[1].toSint16(); + const int16 y = argv[2].toSint16(); + return make_reg(0, g_sci->_video32->getAVIPlayer().init2x(x, y)); +} + reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { if (!s) return make_reg(0, getSciVersion()); diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 7c39050f18..97a6cb585f 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -200,6 +200,21 @@ struct Node { struct List { reg_t first; reg_t last; + +#ifdef ENABLE_SCI32 + /** + * The next node for each level of recursion during iteration over this list + * by kListEachElementDo. + */ + reg_t nextNodes[10]; + + /** + * The current level of recursion of kListEachElementDo for this list. + */ + int numRecursions; + + List() : numRecursions(0) {} +#endif }; struct Hunk { diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 3e12084ed6..548fd477bf 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -405,6 +405,21 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { error("[VM] k%s[%x]: no subfunction ID parameter given", kernelCall.name, kernelCallNr); if (argv[0].isPointer()) error("[VM] k%s[%x]: given subfunction ID is actually a pointer", kernelCall.name, kernelCallNr); + +#ifdef ENABLE_SCI32 + // The Windows version of kShowMovie has subops, but the subop number + // is put in the second parameter in SCI2.1+, even though every other + // kcall with subops puts the subop in the first parameter. To allow use + // of the normal subops system, we swap the arguments so the subop + // number is in the usual place. + if (getSciVersion() > SCI_VERSION_2 && + g_sci->getPlatform() == Common::kPlatformWindows && + strcmp(kernelCall.name, "ShowMovie") == 0) { + assert(argc > 1); + SWAP(argv[0], argv[1]); + } +#endif + const uint16 subId = argv[0].toUint16(); // Skip over subfunction-id argc--; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index f304f774af..9b3b329418 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -492,7 +492,7 @@ const SciWorkaroundEntry kDisplay_workarounds[] = { { GID_PQ2, 23, 23, 0, "rm23Script", "elements", sig_kDisplay_pq2_1, 0, { WORKAROUND_IGNORE, 0 } }, // when looking at the 2nd page of pate's file - 0x75 as id - bug #5223 { GID_QFG1, 11, 11, 0, "battle", "init", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // DEMO: When entering battle, 0x75 as id { GID_SQ4, 397, 0, 0, "", "export 12", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // FLOPPY: when going into the computer store - bug #5227 - { GID_SQ4, 391, 391, 0, "doCatalog", "mode", sig_kDisplay_sq4_1, 0, { WORKAROUND_IGNORE, 0 } }, // CD: clicking on catalog in roboter sale - a parameter is an object + { GID_SQ4, 391, 391, 0, "doCatalog", "changeState", sig_kDisplay_sq4_1, 0, { WORKAROUND_IGNORE, 0 } }, // CD: clicking on catalog in roboter sale - a parameter is an object { GID_SQ4, 391, 391, 0, "choosePlug", "changeState", NULL, 0, { WORKAROUND_IGNORE, 0 } }, // CD: ordering connector in roboter sale - a parameter is an object SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 1decfa03a9..21ffb5f937 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -56,7 +56,7 @@ namespace Sci { GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAdjuster *coordAdjuster, GfxScreen *screen, GfxPalette32 *palette, GfxTransitions32 *transitions) : - _isHiRes(false), + _isHiRes(ConfMan.getBool("enable_high_resolution_graphics")), _palette(palette), _resMan(resMan), _screen(screen), @@ -75,13 +75,9 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd _currentBuffer.setPixels(calloc(1, screen->getDisplayWidth() * screen->getDisplayHeight())); - // TODO: Make hires detection work uniformly across all SCI engine - // versions (this flag is normally passed by SCI::MakeGraphicsMgr - // to the GraphicsMgr constructor depending upon video configuration, - // so should be handled upstream based on game configuration instead - // of here) - if (getSciVersion() >= SCI_VERSION_2_1_EARLY && _resMan->detectHires()) { - _isHiRes = true; + // QFG4 is the only SCI32 game that doesn't have a high-resolution toggle + if (g_sci->getGameId() == GID_QFG4) { + _isHiRes = false; } switch (g_sci->getGameId()) { diff --git a/engines/sci/graphics/frameout.h b/engines/sci/graphics/frameout.h index 42f1d80101..012ecf9e64 100644 --- a/engines/sci/graphics/frameout.h +++ b/engines/sci/graphics/frameout.h @@ -41,7 +41,6 @@ struct PlaneShowStyle; */ class GfxFrameout { private: - bool _isHiRes; GfxCoordAdjuster32 *_coordAdjuster; GfxPalette32 *_palette; ResourceManager *_resMan; @@ -309,6 +308,8 @@ private: } public: + bool _isHiRes; + /** * Whether palMorphFrameOut should be used instead of * frameOut for rendering. Used by kMorphOn to diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp index dc2641c92a..757d793c44 100644 --- a/engines/sci/graphics/video32.cpp +++ b/engines/sci/graphics/video32.cpp @@ -20,20 +20,477 @@ * */ -#include "audio/mixer.h" -#include "common/config-manager.h" -#include "sci/console.h" -#include "sci/event.h" -#include "sci/graphics/cursor.h" -#include "sci/graphics/frameout.h" -#include "sci/graphics/palette32.h" -#include "sci/graphics/text32.h" +#include "common/config-manager.h" // for ConfMan +#include "common/textconsole.h" // for warning, error +#include "common/util.h" // for ARRAYSIZE +#include "common/system.h" // for g_system +#include "engine.h" // for Engine, g_engine +#include "engines/util.h" // for initGraphics +#include "sci/console.h" // for Console +#include "sci/engine/state.h" // for EngineState +#include "sci/engine/vm_types.h" // for reg_t +#include "sci/event.h" // for SciEvent, EventManager, SCI_... +#include "sci/graphics/celobj32.h" // for CelInfo32, ::kLowResX, ::kLo... +#include "sci/graphics/cursor.h" // for GfxCursor +#include "sci/graphics/frameout.h" // for GfxFrameout +#include "sci/graphics/helpers.h" // for Color, Palette +#include "sci/graphics/palette32.h" // for GfxPalette32 +#include "sci/graphics/plane32.h" // for Plane, PlanePictureCodes::kP... +#include "sci/graphics/screen_item32.h" // for ScaleInfo, ScreenItem, Scale... +#include "sci/sci.h" // for SciEngine, g_sci, getSciVersion #include "sci/graphics/video32.h" -#include "sci/sci.h" -#include "video/coktel_decoder.h" +#include "sci/video/seq_decoder.h" // for SEQDecoder +#include "video/avi_decoder.h" // for AVIDecoder +#include "video/coktel_decoder.h" // for AdvancedVMDDecoder +namespace Graphics { struct Surface; } namespace Sci { +#pragma mark SEQPlayer + +SEQPlayer::SEQPlayer(SegManager *segMan) : + _segMan(segMan), + _decoder(nullptr), + _plane(nullptr), + _screenItem(nullptr) {} + +void SEQPlayer::play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y) { + delete _decoder; + _decoder = new SEQDecoder(numTicks); + _decoder->loadFile(fileName); + + // NOTE: In the original engine, video was output directly to the hardware, + // bypassing the game's rendering engine. Instead of doing this, we use a + // mechanism that is very similar to that used by the VMD player, which + // allows the SEQ to be drawn into a bitmap ScreenItem and displayed using + // the normal graphics system. + _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false); + + CelInfo32 celInfo; + celInfo.type = kCelTypeMem; + celInfo.bitmap = _bitmap; + + _plane = new Plane(Common::Rect(kLowResX, kLowResY), kPlanePicColored); + g_sci->_gfxFrameout->addPlane(*_plane); + + // Normally we would use the x, y coordinates passed into the play function + // to position the screen item, but because the video frame bitmap is + // drawn in low-resolution coordinates, it gets automatically scaled up by + // the engine (pixel doubling with aspect ratio correction). As a result, + // the animation does not need the extra offsets from the game in order to + // be correctly positioned in the middle of the window, so we ignore them. + _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(0, 0), ScaleInfo()); + g_sci->_gfxFrameout->addScreenItem(*_screenItem); + g_sci->_gfxFrameout->frameOut(true); + _decoder->start(); + + while (!g_engine->shouldQuit() && !_decoder->endOfVideo()) { + renderFrame(); + g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame()); + g_sci->getEngineState()->_throttleTrigger = true; + } + + _segMan->freeBitmap(_screenItem->_celInfo.bitmap); + g_sci->_gfxFrameout->deletePlane(*_plane); + g_sci->_gfxFrameout->frameOut(true); + _screenItem = nullptr; + _plane = nullptr; +} + +void SEQPlayer::renderFrame() const { + const Graphics::Surface *surface = _decoder->decodeNextFrame(); + + SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap); + bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h)); + + const bool dirtyPalette = _decoder->hasDirtyPalette(); + if (dirtyPalette) { + Palette palette; + const byte *rawPalette = _decoder->getPalette(); + for (int i = 0; i < ARRAYSIZE(palette.colors); ++i) { + palette.colors[i].r = *rawPalette++; + palette.colors[i].g = *rawPalette++; + palette.colors[i].b = *rawPalette++; + palette.colors[i].used = true; + } + + g_sci->_gfxPalette32->submit(palette); + } + + g_sci->_gfxFrameout->updateScreenItem(*_screenItem); + g_sci->getSciDebugger()->onFrame(); + g_sci->_gfxFrameout->frameOut(true); +} + +#pragma mark - +#pragma mark AVIPlayer + +AVIPlayer::AVIPlayer(SegManager *segMan, EventManager *eventMan) : + _segMan(segMan), + _eventMan(eventMan), + _decoder(new Video::AVIDecoder(Audio::Mixer::kSFXSoundType)), + _scaleBuffer(nullptr), + _plane(nullptr), + _screenItem(nullptr), + _status(kAVINotOpen) {} + +AVIPlayer::~AVIPlayer() { + close(); + delete _decoder; +} + +AVIPlayer::IOStatus AVIPlayer::open(const Common::String &fileName) { + if (_status != kAVINotOpen) { + close(); + } + + if (!_decoder->loadFile(fileName)) { + return kIOFileNotFound; + } + + _status = kAVIOpen; + return kIOSuccess; +} + +AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width, int16 height) { + if (_status == kAVINotOpen) { + return kIOFileNotFound; + } + + _pixelDouble = false; + + if (!width || !height) { + width = _decoder->getWidth(); + height = _decoder->getHeight(); + } else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) { + // KQ7 1.51 provides an explicit width and height when it wants scaling, + // though the width and height it provides are not scaled + _pixelDouble = true; + width *= 2; + height *= 2; + } + + // QFG4CD gives non-multiple-of-2 values for width and height, + // which would normally be OK except the source video is a pixel bigger + // in each dimension + width = (width + 1) & ~1; + height = (height + 1) & ~1; + + _drawRect.left = x; + _drawRect.top = y; + _drawRect.right = x + width; + _drawRect.bottom = y + height; + + // SCI2.1mid uses init2x to draw a pixel-doubled AVI, but SCI2 has only the + // one play routine which automatically pixel-doubles in hi-res mode + if (getSciVersion() == SCI_VERSION_2) { + // This is somewhat of a hack; credits.avi from GK1 is not + // rendered correctly in SSCI because it is a 640x480 video, but the + // game script gives the wrong dimensions. Since this is the only + // high-resolution AVI ever used, just set the draw rectangle to draw + // the entire screen + if (_decoder->getWidth() > 320) { + _drawRect.left = 0; + _drawRect.top = 0; + _drawRect.right = 320; + _drawRect.bottom = 200; + } + + // In hi-res mode, video will be pixel doubled, so the origin (which + // corresponds to the correct position without pixel doubling) needs to + // be corrected + if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() <= 320) { + _drawRect.left /= 2; + _drawRect.top /= 2; + } + } + + init(); + + return kIOSuccess; +} + +AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) { + if (_status == kAVINotOpen) { + return kIOFileNotFound; + } + + _drawRect.left = x; + _drawRect.top = y; + _drawRect.right = x + _decoder->getWidth() * 2; + _drawRect.bottom = y + _decoder->getHeight() * 2; + + _pixelDouble = true; + init(); + + return kIOSuccess; +} + +void AVIPlayer::init() { + int16 xRes; + int16 yRes; + + bool useScreenDimensions = false; + if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) { + useScreenDimensions = true; + } + + // KQ7 1.51 gives video position in screen coordinates, not game + // coordinates, because in SSCI they are passed to Video for Windows, which + // renders as an overlay on the game video. Because we put the video into a + // ScreenItem instead of rendering directly to the hardware surface, the + // coordinates need to be converted to game script coordinates + if (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY) { + useScreenDimensions = !_pixelDouble; + // This y-translation is arbitrary, based on what roughly centers the + // videos in the game window + _drawRect.translate(-_drawRect.left / 2, -_drawRect.top * 2 / 3); + } + + if (useScreenDimensions) { + xRes = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + yRes = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + } else { + xRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + } + + _plane = new Plane(_drawRect); + g_sci->_gfxFrameout->addPlane(*_plane); + + if (_decoder->getPixelFormat().bytesPerPixel == 1) { + _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false); + + CelInfo32 celInfo; + celInfo.type = kCelTypeMem; + celInfo.bitmap = _bitmap; + + _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(_drawRect.left, _drawRect.top), ScaleInfo()); + g_sci->_gfxFrameout->addScreenItem(*_screenItem); + g_sci->_gfxFrameout->frameOut(true); + } else { + const Buffer ¤tBuffer = g_sci->_gfxFrameout->getCurrentBuffer(); + const Graphics::PixelFormat format = _decoder->getPixelFormat(); + initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, g_sci->_gfxFrameout->_isHiRes, &format); + + if (_pixelDouble) { + const int16 width = _drawRect.width(); + const int16 height = _drawRect.height(); + _scaleBuffer = calloc(1, width * height * format.bytesPerPixel); + } + } +} + +AVIPlayer::IOStatus AVIPlayer::play(const int16 from, const int16 to, const int16, const bool async) { + if (_status == kAVINotOpen) { + return kIOFileNotFound; + } + + if (from >= 0 && to > 0 && from <= to) { + _decoder->seekToFrame(from); + _decoder->setEndFrame(to); + } + + if (!async) { + renderVideo(); + } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) { + playUntilEvent((EventFlags)(kEventFlagEnd | kEventFlagEscapeKey)); + } else { + _status = kAVIPlaying; + } + + return kIOSuccess; +} + +void AVIPlayer::renderVideo() const { + _decoder->start(); + while (!g_engine->shouldQuit() && !_decoder->endOfVideo()) { + g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame()); + g_sci->getEngineState()->_throttleTrigger = true; + if (_decoder->needsUpdate()) { + renderFrame(); + } + } +} + +AVIPlayer::IOStatus AVIPlayer::close() { + if (_status == kAVINotOpen) { + return kIOSuccess; + } + + free(_scaleBuffer); + _scaleBuffer = nullptr; + + if (_decoder->getPixelFormat().bytesPerPixel != 1) { + const bool isHiRes = g_sci->_gfxFrameout->_isHiRes; + const Buffer ¤tBuffer = g_sci->_gfxFrameout->getCurrentBuffer(); + const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); + initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, isHiRes, &format); + } + + _decoder->close(); + _status = kAVINotOpen; + g_sci->_gfxFrameout->deletePlane(*_plane); + _plane = nullptr; + _screenItem = nullptr; + return kIOSuccess; +} + +AVIPlayer::IOStatus AVIPlayer::cue(const uint16 frameNo) { + if (!_decoder->seekToFrame(frameNo)) { + return kIOSeekFailed; + } + + _status = kAVIPaused; + return kIOSuccess; +} + +uint16 AVIPlayer::getDuration() const { + if (_status == kAVINotOpen) { + return 0; + } + + return _decoder->getFrameCount(); +} + +void AVIPlayer::renderFrame() const { + const Graphics::Surface *surface = _decoder->decodeNextFrame(); + + if (surface->format.bytesPerPixel == 1) { + SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap); + if (surface->w > bitmap.getWidth() || surface->h > bitmap.getHeight()) { + warning("Attempted to draw a video frame larger than the destination bitmap"); + return; + } + + // KQ7 1.51 encodes videos with palette entry 0 as white, which makes + // the area around the video turn white too, since it is coded to use + // palette entry 0. This happens to work in the original game because + // the video is rendered by VfW, not in the engine itself. To fix this, + // we just modify the incoming pixel data from the video so if a pixel + // is using entry 0, we change it to use entry 255, which is guaranteed + // to always be white + if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) { + uint8 *target = bitmap.getPixels(); + uint8 *source = (uint8 *)surface->getPixels(); + uint8 *end = (uint8 *)surface->getPixels() + surface->w * surface->h; + + while (source != end) { + uint8 value = *source++; + *target++ = value == 0 ? 255 : value; + } + } else { + bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h)); + } + + const bool dirtyPalette = _decoder->hasDirtyPalette(); + if (dirtyPalette) { + Palette palette; + const byte *rawPalette = _decoder->getPalette(); + for (int i = 0; i < ARRAYSIZE(palette.colors); ++i) { + palette.colors[i].r = *rawPalette++; + palette.colors[i].g = *rawPalette++; + palette.colors[i].b = *rawPalette++; + palette.colors[i].used = true; + } + + // Prevent KQ7 1.51 from setting entry 0 to white + palette.colors[0].used = false; + + g_sci->_gfxPalette32->submit(palette); + } + + g_sci->_gfxFrameout->updateScreenItem(*_screenItem); + g_sci->getSciDebugger()->onFrame(); + g_sci->_gfxFrameout->frameOut(true); + } else { + assert(surface->format.bytesPerPixel == 4); + + Common::Rect drawRect(_drawRect); + + if (_pixelDouble) { + const uint32 *source = (uint32 *)surface->getPixels(); + uint32 *target = (uint32 *)_scaleBuffer; + // target pitch here is in uint32s, not bytes + const uint16 pitch = surface->pitch / 2; + for (int y = 0; y < surface->h; ++y) { + for (int x = 0; x < surface->w; ++x) { + const uint32 value = *source++; + + target[0] = value; + target[1] = value; + target[pitch] = value; + target[pitch + 1] = value; + target += 2; + } + target += pitch; + } + + g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height()); + } else { + const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; + const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; + const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + mulinc(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight)); + + g_system->copyRectToScreen(surface->getPixels(), surface->pitch, drawRect.left, drawRect.top, surface->w, surface->h); + } + } +} + +AVIPlayer::EventFlags AVIPlayer::playUntilEvent(EventFlags flags) { + _decoder->start(); + + EventFlags stopFlag = kEventFlagNone; + while (!g_engine->shouldQuit()) { + if (_decoder->endOfVideo()) { + stopFlag = kEventFlagEnd; + break; + } + + g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame()); + g_sci->getEngineState()->_throttleTrigger = true; + if (_decoder->needsUpdate()) { + renderFrame(); + } + + SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK); + if ((flags & kEventFlagMouseDown) && event.type == SCI_EVENT_MOUSE_PRESS) { + stopFlag = kEventFlagMouseDown; + break; + } + + event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK); + if ((flags & kEventFlagEscapeKey) && event.type == SCI_EVENT_KEYBOARD) { + bool stop = false; + while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)), + event.type != SCI_EVENT_NONE) { + if (event.character == SCI_KEY_ESC) { + stop = true; + break; + } + } + + if (stop) { + stopFlag = kEventFlagEscapeKey; + break; + } + } + + // TODO: Hot rectangles + if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) { + warning("Hot rectangles not implemented in VMD player"); + stopFlag = kEventFlagHotRectangle; + break; + } + } + + return stopFlag; +} + +#pragma mark - #pragma mark VMDPlayer VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) : @@ -117,7 +574,7 @@ VMDPlayer::IOStatus VMDPlayer::close() { if (!_planeIsOwned && _screenItem != nullptr) { g_sci->_gfxFrameout->deleteScreenItem(*_screenItem); - g_sci->getEngineState()->_segMan->freeBitmap(_screenItem->_celInfo.bitmap); + _segMan->freeBitmap(_screenItem->_celInfo.bitmap); _screenItem = nullptr; } else if (_plane != nullptr) { g_sci->_gfxFrameout->deletePlane(*_plane); diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h index 7033f7c647..0496f61d5d 100644 --- a/engines/sci/graphics/video32.h +++ b/engines/sci/graphics/video32.h @@ -23,16 +23,215 @@ #ifndef SCI_GRAPHICS_VIDEO32_H #define SCI_GRAPHICS_VIDEO32_H -namespace Video { class AdvancedVMDDecoder; } +#include "common/rect.h" // for Rect +#include "common/scummsys.h" // for int16, uint8, uint16, int32 +#include "common/str.h" // for String +#include "sci/engine/vm_types.h" // for reg_t + +namespace Video { +class AdvancedVMDDecoder; +class AVIDecoder; +} namespace Sci { +class EventManager; class Plane; class ScreenItem; class SegManager; +class SEQDecoder; +struct Palette; +#pragma mark SEQPlayer + +/** + * SEQPlayer is used to play SEQ animations. + * Used by DOS versions of GK1 and QFG4CD. + */ +class SEQPlayer { +public: + SEQPlayer(SegManager *segMan); + + /** + * Plays a SEQ animation with the given + * file name, with each frame being displayed + * for `numTicks` ticks. + */ + void play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y); + +private: + SegManager *_segMan; + SEQDecoder *_decoder; + + /** + * The plane where the SEQ will be drawn. + */ + Plane *_plane; + + /** + * The screen item representing the SEQ surface. + */ + ScreenItem *_screenItem; + + /** + * The bitmap used to render video output. + */ + reg_t _bitmap; + + /** + * Renders a single frame of video. + */ + void renderFrame() const; +}; + +#pragma mark - +#pragma mark AVIPlayer + +/** + * AVIPlayer is used to play AVI videos. Used by + * Windows versions of GK1CD, KQ7, and QFG4CD. + */ +class AVIPlayer { +public: + enum IOStatus { + kIOSuccess = 0, + kIOFileNotFound = 2, + kIOSeekFailed = 12 + }; + + enum AVIStatus { + kAVINotOpen = 0, + kAVIOpen = 1, + kAVIPlaying = 2, + kAVIPaused = 3 + }; + + enum EventFlags { + kEventFlagNone = 0, + kEventFlagEnd = 1, + kEventFlagEscapeKey = 2, + kEventFlagMouseDown = 4, + kEventFlagHotRectangle = 8 + }; + + AVIPlayer(SegManager *segMan, EventManager *eventMan); + ~AVIPlayer(); + + /** + * Opens a stream to an AVI resource. + */ + IOStatus open(const Common::String &fileName); + + /** + * Initializes the AVI rendering parameters for the + * current AVI. This must be called after `open`. + */ + IOStatus init1x(const int16 x, const int16 y, const int16 width, const int16 height); + + /** + * Initializes the AVI rendering parameters for the + * current AVI, in pixel-doubling mode. This must + * be called after `open`. + */ + IOStatus init2x(const int16 x, const int16 y); + + /** + * Begins playback of the current AVI. + */ + IOStatus play(const int16 from, const int16 to, const int16 showStyle, const bool cue); + + /** + * Stops playback and closes the currently open AVI stream. + */ + IOStatus close(); + + /** + * Seeks the currently open AVI stream to the given frame. + */ + IOStatus cue(const uint16 frameNo); + + /** + * Returns the duration of the current video. + */ + uint16 getDuration() const; + + /** + * Plays the AVI until an event occurs (e.g. user + * presses escape, clicks, etc.). + */ + EventFlags playUntilEvent(const EventFlags flags); + +private: + typedef Common::HashMap<uint16, AVIStatus> StatusMap; + + SegManager *_segMan; + EventManager *_eventMan; + Video::AVIDecoder *_decoder; + + /** + * Playback status of the player. + */ + AVIStatus _status; + + /** + * The plane where the AVI will be drawn. + */ + Plane *_plane; + + /** + * The screen item representing the AVI surface, + * in 8bpp mode. In 24bpp mode, video is drawn + * directly to the screen. + */ + ScreenItem *_screenItem; + + /** + * The bitmap used to render video output in + * 8bpp mode. + */ + reg_t _bitmap; + + /** + * The rectangle where the video will be drawn, + * in game script coordinates. + */ + Common::Rect _drawRect; + + /** + * The scale buffer for pixel-doubled videos + * drawn in 24bpp mode. + */ + void *_scaleBuffer; + + /** + * In SCI2.1, whether or not the video should + * be pixel doubled for playback. + */ + bool _pixelDouble; + + /** + * Performs common initialisation for both + * scaled and unscaled videos. + */ + void init(); + + /** + * Renders video without event input until the + * video is complete. + */ + void renderVideo() const; + + /** + * Renders a single frame of video. + */ + void renderFrame() const; +}; + +#pragma mark - #pragma mark VMDPlayer /** * VMDPlayer is used to play VMD videos. + * Used by Phant1, GK2, PQ:SWAT, Shivers, SQ6, + * Torin, and Lighthouse. */ class VMDPlayer { public: @@ -297,14 +496,24 @@ private: bool _showCursor; }; +/** + * Video32 provides facilities for playing back + * video in SCI engine. + */ class Video32 { public: Video32(SegManager *segMan, EventManager *eventMan) : + _SEQPlayer(segMan), + _AVIPlayer(segMan, eventMan), _VMDPlayer(segMan, eventMan) {} + SEQPlayer &getSEQPlayer() { return _SEQPlayer; } + AVIPlayer &getAVIPlayer() { return _AVIPlayer; } VMDPlayer &getVMDPlayer() { return _VMDPlayer; } private: + SEQPlayer _SEQPlayer; + AVIPlayer _AVIPlayer; VMDPlayer _VMDPlayer; }; } // End of namespace Sci diff --git a/engines/titanic/carry/auditory_centre.cpp b/engines/titanic/carry/auditory_centre.cpp index d88989a801..0bda975a36 100644 --- a/engines/titanic/carry/auditory_centre.cpp +++ b/engines/titanic/carry/auditory_centre.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CAuditoryCentre, CBrain) + ON_MESSAGE(PuzzleSolvedMsg) +END_MESSAGE_MAP() + void CAuditoryCentre::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CBrain::save(file, indent); @@ -34,4 +38,10 @@ void CAuditoryCentre::load(SimpleFile *file) { CBrain::load(file); } +bool CAuditoryCentre::PuzzleSolvedMsg(CPuzzleSolvedMsg *msg) { + _fieldE0 = 1; + setVisible(true); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/carry/auditory_centre.h b/engines/titanic/carry/auditory_centre.h index 743f8f2498..6f24e86208 100644 --- a/engines/titanic/carry/auditory_centre.h +++ b/engines/titanic/carry/auditory_centre.h @@ -28,6 +28,8 @@ namespace Titanic { class CAuditoryCentre : public CBrain { + DECLARE_MESSAGE_MAP; + bool PuzzleSolvedMsg(CPuzzleSolvedMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/core/background.cpp b/engines/titanic/core/background.cpp index f180df8867..733dfc1cf3 100644 --- a/engines/titanic/core/background.cpp +++ b/engines/titanic/core/background.cpp @@ -30,13 +30,13 @@ BEGIN_MESSAGE_MAP(CBackground, CGameObject) ON_MESSAGE(VisibleMsg) END_MESSAGE_MAP() -CBackground::CBackground() : CGameObject(), _fieldBC(0), _fieldC0(0), _fieldDC(0) { +CBackground::CBackground() : CGameObject(), _startFrame(0), _endFrame(0), _fieldDC(0) { } void CBackground::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); - file->writeNumberLine(_fieldC0, indent); + file->writeNumberLine(_startFrame, indent); + file->writeNumberLine(_endFrame, indent); file->writeQuotedLine(_string1, indent); file->writeQuotedLine(_string2, indent); file->writeNumberLine(_fieldDC, indent); @@ -46,8 +46,8 @@ void CBackground::save(SimpleFile *file, int indent) { void CBackground::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); - _fieldC0 = file->readNumber(); + _startFrame = file->readNumber(); + _endFrame = file->readNumber(); _string1 = file->readString(); _string2 = file->readString(); _fieldDC = file->readNumber(); @@ -58,9 +58,9 @@ void CBackground::load(SimpleFile *file) { bool CBackground::StatusChangeMsg(CStatusChangeMsg *msg) { setVisible(true); if (_fieldDC) { - playMovie(_fieldBC, _fieldC0, 16); + playMovie(_startFrame, _endFrame, 16); } else { - playMovie(_fieldBC, _fieldC0, 0); + playMovie(_startFrame, _endFrame, 0); } return true; } diff --git a/engines/titanic/core/background.h b/engines/titanic/core/background.h index 6a2fd21454..b7f160db28 100644 --- a/engines/titanic/core/background.h +++ b/engines/titanic/core/background.h @@ -34,8 +34,8 @@ class CBackground : public CGameObject { bool SetFrameMsg(CSetFrameMsg *msg); bool VisibleMsg(CVisibleMsg *msg); protected: - int _fieldBC; - int _fieldC0; + int _startFrame; + int _endFrame; CString _string1; CString _string2; int _fieldDC; diff --git a/engines/titanic/core/game_object.cpp b/engines/titanic/core/game_object.cpp index 95ebe6a1e7..723f2456f3 100644 --- a/engines/titanic/core/game_object.cpp +++ b/engines/titanic/core/game_object.cpp @@ -487,7 +487,7 @@ void CGameObject::playGlobalSound(const CString &resName, int mode, bool initial sound.setVolume(_soundHandles[handleIndex], newVolume, 2); } -void CGameObject::setSoundVolume(uint handle, uint percent, uint seconds) { +void CGameObject::setSoundVolume(int handle, uint percent, uint seconds) { if (handle != 0 && handle != -1) { CGameManager *gameManager = getGameManager(); if (gameManager) @@ -726,7 +726,7 @@ int CGameObject::playSound(const CString &name, uint volume, int val3, bool repe } int CGameObject::playSound(const CString &name, CProximity &prox) { - if (prox._field28 == 2) { + if (prox._positioningMode == POSMODE_VECTOR) { // If the proximity doesn't have a position defined, default it to // the position of the view to which the game object belongs if (prox._posX == 0.0 && prox._posY == 0.0 && prox._posZ == 0.0) @@ -748,7 +748,7 @@ int CGameObject::queueSound(const CString &name, uint priorHandle, uint volume, prox._fieldC = val3; prox._repeated = repeated; prox._channelVolume = volume; - prox._soundHandle = priorHandle; + prox._priorSoundHandle = priorHandle; return playSound(name, prox); } @@ -783,6 +783,14 @@ int CGameObject::addTimer(uint firstDuration, uint repeatDuration) { return timer->_id; } +int CGameObject::startAnimTimer(const CString &action, uint firstDuration, uint repeatDuration) { + CTimeEventInfo *timer = new CTimeEventInfo(g_vm->_events->getTicksCount(), + repeatDuration > 0, firstDuration, repeatDuration, this, 0, action); + getGameManager()->addTimer(timer); + + return timer->_id; +} + void CGameObject::stopTimer(int id) { getGameManager()->stopTimer(id); } @@ -1164,6 +1172,10 @@ void CGameObject::loadSurface() { _surface->loadIfReady(); } +bool CGameObject::changeView(const CString &viewName) { + return changeView(viewName, ""); +} + bool CGameObject::changeView(const CString &viewName, const CString &clipName) { CViewItem *newView = parseView(viewName); CGameManager *gameManager = getGameManager(); @@ -1330,14 +1342,14 @@ void CGameObject::fn10(int v1, int v2, int v3) { _field4C = v3; } -void CGameObject::setMovie14(int v) { +void CGameObject::movieSetAudioTiming(bool flag) { if (!_surface && !_resource.empty()) { loadResource(_resource); _resource.clear(); } if (_surface && _surface->_movie) - _surface->_movie->_field14 = v; + _surface->_movie->_hasAudioTiming = flag; } void CGameObject::movieEvent(int frameNumber) { @@ -1481,6 +1493,11 @@ CTreeItem *CGameObject::petContainerRemove(CGameObject *obj) { return item; } +bool CGameObject::petCheckNode(const CString &name) { + CPetControl *pet = getPetControl(); + return pet ? pet->checkNode(name) : false; +} + bool CGameObject::petDismissBot(const CString &name) { CPetControl *pet = getPetControl(); return pet ? pet->dismissBot(name) : false; diff --git a/engines/titanic/core/game_object.h b/engines/titanic/core/game_object.h index 322b62636c..2dc539f739 100644 --- a/engines/titanic/core/game_object.h +++ b/engines/titanic/core/game_object.h @@ -220,7 +220,7 @@ protected: * @param volume Volume percentage (0 to 100) * @param seconds Number of seconds to transition to the new volume */ - void setSoundVolume(uint handle, uint percent, uint seconds); + void setSoundVolume(int handle, uint percent, uint seconds); /** * Plays a sound, and saves it's handle in the global sound handles list @@ -260,6 +260,11 @@ protected: int addTimer(uint firstDuration, uint repeatDuration = 0); /** + * Start an animation timer + */ + int startAnimTimer(const CString &action, uint firstDuration, uint repeatDuration = 0); + + /** * Stops a timer */ void stopTimer(int id); @@ -331,6 +336,11 @@ protected: bool changeView(const CString &viewName, const CString &clipName); /** + * Change the view + */ + bool changeView(const CString &viewName); + + /** * Get the centre of the game object's bounds */ Point getControid() const; @@ -417,7 +427,10 @@ protected: */ void setPassengerClass(int newClass); - void setMovie14(int v); + /** + * Overrides whether the object's movie has audio timing + */ + void movieSetAudioTiming(bool flag); void fn10(int v1, int v2, int v3); @@ -768,6 +781,8 @@ public: CTreeItem *petContainerRemove(CGameObject *obj); + bool petCheckNode(const CString &name); + /** * Dismiss a bot */ diff --git a/engines/titanic/events.cpp b/engines/titanic/events.cpp index 8a7cd550e8..318ddf5726 100644 --- a/engines/titanic/events.cpp +++ b/engines/titanic/events.cpp @@ -84,6 +84,11 @@ void Events::pollEvents() { void Events::pollEventsAndWait() { pollEvents(); g_system->delayMillis(10); + + // Regularly update the sound mixer + CGameManager *gameManager = g_vm->_window->_gameManager; + if (gameManager) + gameManager->_sound.updateMixer(); } bool Events::checkForNextFrameCounter() { @@ -114,12 +119,9 @@ uint32 Events::getTicksCount() const { void Events::sleep(uint time) { uint32 delayEnd = g_system->getMillis() + time; - CSound &sound = g_vm->_window->_gameManager->_sound; - while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) { + while (!_vm->shouldQuit() && g_system->getMillis() < delayEnd) pollEventsAndWait(); - sound.updateMixer(); - } } bool Events::waitForPress(uint expiry) { diff --git a/engines/titanic/game/announce.cpp b/engines/titanic/game/announce.cpp index df6689d262..04e7a84271 100644 --- a/engines/titanic/game/announce.cpp +++ b/engines/titanic/game/announce.cpp @@ -21,30 +21,113 @@ */ #include "titanic/game/announce.h" +#include "titanic/titanic.h" namespace Titanic { -CAnnounce::CAnnounce() : _fieldBC(0), _fieldC0(0), _fieldC4(1), _fieldC8(0) { +BEGIN_MESSAGE_MAP(CAnnounce, CGameObject) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(LeaveRoomMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + +CAnnounce::CAnnounce() : _nameIndex(0), _soundHandle(0), _leaveFlag(1), _enabled(false) { } void CAnnounce::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldBC, indent); - file->writeNumberLine(_fieldC0, indent); - file->writeNumberLine(_fieldC4, indent); - file->writeNumberLine(_fieldC8, indent); + file->writeNumberLine(_nameIndex, indent); + file->writeNumberLine(_soundHandle, indent); + file->writeNumberLine(_leaveFlag, indent); + file->writeNumberLine(_enabled, indent); CGameObject::save(file, indent); } void CAnnounce::load(SimpleFile *file) { file->readNumber(); - _fieldBC = file->readNumber(); - _fieldC0 = file->readNumber(); - _fieldC4 = file->readNumber(); - _fieldC8 = file->readNumber(); + _nameIndex = file->readNumber(); + _soundHandle = file->readNumber(); + _leaveFlag = file->readNumber(); + _enabled = file->readNumber(); CGameObject::load(file); } +bool CAnnounce::TimerMsg(CTimerMsg *msg) { + if (!_enabled) + return false; + + if (msg->_timerCtr == 1) { + CString numStr = "0"; + CString waveNames1[20] = { + "z#181.wav", "z#211.wav", "z#203.wav", "z#202.wav", "z#201.wav", + "z#200.wav", "z#199.wav", "z#198.wav", "z#197.wav", "z#196.wav", + "z#210.wav", "z#209.wav", "z#208.wav", "z#207.wav", "z#206.wav", + "z#205.wav", "z#204.wav", "z#145.wav", "", "" + }; + CString waveNames2[37] = { + "z#154.wav", "z#153.wav", "z#152.wav", "z#151.wav", "z#150.wav", + "z#149.wav", "z#148.wav", "z#169.wav", "z#171.wav", "z#178.wav", + "z#176.wav", "z#177.wav", "z#165.wav", "z#170.wav", "z#180.wav", + "z#156.wav", "z#172.wav", "z#173.wav", "z#160.wav", "z#158.wav", + "z#161.wav", "z#179.wav", "z#163.wav", "z#164.wav", "z#162.wav", + "z#159.wav", "z#175.wav", "z#166.wav", "z#174.wav", "z#157.wav", + "", "", "", "", "", "", "" + }; + + int randVal = _nameIndex ? g_vm->getRandomNumber(2) : 0; + switch (randVal) { + case 0: + case 1: + _soundHandle = playSound("z#189.wav"); + if (_nameIndex < 20) { + queueSound(waveNames1[_nameIndex], _soundHandle); + ++_nameIndex; + } else { + queueSound(waveNames1[1 + g_vm->getRandomNumber(17)], _soundHandle); + } + break; + + case 2: + _soundHandle = playSound("z#189.wav"); + queueSound(waveNames2[1 + g_vm->getRandomNumber(35)], _soundHandle); + break; + + default: + break; + } + + addTimer(1, 300000 + g_vm->getRandomNumber(30000), 0); + if (g_vm->getRandomNumber(3) == 0) + addTimer(2, 4000, 0); + + } else if (msg->_timerCtr == 2) { + CParrotSpeakMsg speakMsg; + speakMsg._value1 = "Announcements"; + speakMsg.execute("PerchedParrot"); + } + + return true; +} + +bool CAnnounce::LeaveRoomMsg(CLeaveRoomMsg *msg) { + if (_leaveFlag) { + addTimer(1, 1000, 0); + _leaveFlag = 0; + _enabled = true; + } + + return true; +} + +bool CAnnounce::ActMsg(CActMsg *msg) { + if (msg->_action == "Enable") + _enabled = true; + else if (msg->_action == "Disable") + _enabled = false; + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/announce.h b/engines/titanic/game/announce.h index f960241c36..9bf060daae 100644 --- a/engines/titanic/game/announce.h +++ b/engines/titanic/game/announce.h @@ -28,11 +28,15 @@ namespace Titanic { class CAnnounce : public CGameObject { + DECLARE_MESSAGE_MAP; + bool TimerMsg(CTimerMsg *msg); + bool LeaveRoomMsg(CLeaveRoomMsg *msg); + bool ActMsg(CActMsg *msg); private: - int _fieldBC; - int _fieldC0; - int _fieldC4; - int _fieldC8; + int _nameIndex; + int _soundHandle; + bool _leaveFlag; + bool _enabled; public: CLASSDEF; CAnnounce(); diff --git a/engines/titanic/game/annoy_barbot.cpp b/engines/titanic/game/annoy_barbot.cpp index d69d9fff3c..8b22f9c13a 100644 --- a/engines/titanic/game/annoy_barbot.cpp +++ b/engines/titanic/game/annoy_barbot.cpp @@ -26,6 +26,10 @@ namespace Titanic { int CAnnoyBarbot::_v1; +BEGIN_MESSAGE_MAP(CAnnoyBarbot, CGameObject) + ON_MESSAGE(MouseButtonDownMsg) +END_MESSAGE_MAP() + void CAnnoyBarbot::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_v1, indent); @@ -38,4 +42,13 @@ void CAnnoyBarbot::load(SimpleFile *file) { CGameObject::load(file); } +bool CAnnoyBarbot::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if ((++_v1 % 3) == 1) { + CActMsg actMsg("GoRingBell"); + actMsg.execute("Barbot"); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/annoy_barbot.h b/engines/titanic/game/annoy_barbot.h index 955a82bdf8..0ccfe43794 100644 --- a/engines/titanic/game/annoy_barbot.h +++ b/engines/titanic/game/annoy_barbot.h @@ -28,6 +28,8 @@ namespace Titanic { class CAnnoyBarbot : public CGameObject { + DECLARE_MESSAGE_MAP; + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); private: static int _v1; public: diff --git a/engines/titanic/game/arboretum_gate.cpp b/engines/titanic/game/arboretum_gate.cpp index 9caa87c48d..1f92f56acb 100644 --- a/engines/titanic/game/arboretum_gate.cpp +++ b/engines/titanic/game/arboretum_gate.cpp @@ -21,139 +21,311 @@ */ #include "titanic/game/arboretum_gate.h" +#include "titanic/titanic.h" namespace Titanic { BEGIN_MESSAGE_MAP(CArboretumGate, CBackground) + ON_MESSAGE(ChangeSeasonMsg) ON_MESSAGE(ActMsg) + ON_MESSAGE(MovieEndMsg) ON_MESSAGE(LeaveViewMsg) ON_MESSAGE(TurnOff) ON_MESSAGE(MouseButtonDownMsg) ON_MESSAGE(EnterViewMsg) ON_MESSAGE(TurnOn) - ON_MESSAGE(MovieEndMsg) END_MESSAGE_MAP() int CArboretumGate::_v1; -int CArboretumGate::_v2; +int CArboretumGate::_initialFrame; int CArboretumGate::_v3; CArboretumGate::CArboretumGate() : CBackground() { - _string1 = "NULL"; - _string2 = "NULL"; - _fieldE0 = 0; + _viewName1 = "NULL"; + _viewName2 = "NULL"; + _seasonNum = 0; _fieldF0 = 0; - _fieldF4 = 244; - _fieldF8 = 304; - _fieldFC = 122; - _field100 = 182; - _field104 = 183; - _field108 = 243; - _field10C = 665; - _field110 = 724; - _field114 = 61; - _field118 = 121; - _field11C = 0; - _field120 = 60; - _field124 = 485; - _field128 = 544; - _field12C = 425; - _field130 = 484; - _field134 = 545; - _field138 = 604; - _field13C = 605; - _field140 = 664; - _field144 = 305; - _field148 = 364; - _field14C = 365; - _field150 = 424; + _winterOffStartFrame = 244; + _winterOffEndFrame = 304; + _springOffStartFrame = 122; + _springOffEndFrame = 182; + _summerOffStartFrame1 = 183; + _summerOffEndFrame1 = 243; + _summerOffStartFrame2 = 665; + _summerOffEndFrame2 = 724; + _autumnOffStartFrame1 = 61; + _autumnOffEndFrame1 = 121; + _autumnOffStartFrame2 = 0; + _autumnOffEndFrame2 = 60; + _winterOnStartFrame = 485; + _winterOnEndFrame = 544; + _springOnStartFrame = 425; + _springOnEndFrame = 484; + _summerOnStartFrame1 = 545; + _summerOnEndFrame1 = 604; + _summerOnStartFrame2 = 605; + _summerOnEndFrame2 = 664; + _autumnOnStartFrame1 = 305; + _autumnOnEndFrame1 = 364; + _autumnOnStartFrame2 = 365; + _autumnOnEndFrame2 = 424; } void CArboretumGate::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); + file->writeNumberLine(_seasonNum, indent); file->writeNumberLine(_v1, indent); - file->writeNumberLine(_v2, indent); + file->writeNumberLine(_initialFrame, indent); file->writeNumberLine(_v3, indent); - file->writeQuotedLine(_string1, indent); + file->writeQuotedLine(_viewName1, indent); file->writeNumberLine(_fieldF0, indent); - file->writeNumberLine(_fieldF4, indent); - file->writeNumberLine(_fieldF8, indent); - file->writeNumberLine(_fieldFC, indent); - file->writeNumberLine(_field100, indent); - file->writeNumberLine(_field104, indent); - file->writeNumberLine(_field108, indent); - file->writeNumberLine(_field10C, indent); - file->writeNumberLine(_field110, indent); - file->writeNumberLine(_field114, indent); - file->writeNumberLine(_field118, indent); - file->writeNumberLine(_field11C, indent); - file->writeNumberLine(_field120, indent); - file->writeNumberLine(_field124, indent); - file->writeNumberLine(_field128, indent); - file->writeNumberLine(_field12C, indent); - file->writeNumberLine(_field130, indent); - file->writeNumberLine(_field134, indent); - file->writeNumberLine(_field138, indent); - file->writeNumberLine(_field13C, indent); - file->writeNumberLine(_field140, indent); - file->writeNumberLine(_field144, indent); - file->writeNumberLine(_field148, indent); - file->writeNumberLine(_field14C, indent); - file->writeNumberLine(_field150, indent); - file->writeQuotedLine(_string2, indent); + file->writeNumberLine(_winterOffStartFrame, indent); + file->writeNumberLine(_winterOffEndFrame, indent); + file->writeNumberLine(_springOffStartFrame, indent); + file->writeNumberLine(_springOffEndFrame, indent); + file->writeNumberLine(_summerOffStartFrame1, indent); + file->writeNumberLine(_summerOffEndFrame1, indent); + file->writeNumberLine(_summerOffStartFrame2, indent); + file->writeNumberLine(_summerOffEndFrame2, indent); + file->writeNumberLine(_autumnOffStartFrame1, indent); + file->writeNumberLine(_autumnOffEndFrame1, indent); + file->writeNumberLine(_autumnOffStartFrame2, indent); + file->writeNumberLine(_autumnOffEndFrame2, indent); + file->writeNumberLine(_winterOnStartFrame, indent); + file->writeNumberLine(_winterOnEndFrame, indent); + file->writeNumberLine(_springOnStartFrame, indent); + file->writeNumberLine(_springOnEndFrame, indent); + file->writeNumberLine(_summerOnStartFrame1, indent); + file->writeNumberLine(_summerOnEndFrame1, indent); + file->writeNumberLine(_summerOnStartFrame2, indent); + file->writeNumberLine(_summerOnEndFrame2, indent); + file->writeNumberLine(_autumnOnStartFrame1, indent); + file->writeNumberLine(_autumnOnEndFrame1, indent); + file->writeNumberLine(_autumnOnStartFrame2, indent); + file->writeNumberLine(_autumnOnEndFrame2, indent); + file->writeQuotedLine(_viewName2, indent); CBackground::save(file, indent); } void CArboretumGate::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); + _seasonNum = file->readNumber(); _v1 = file->readNumber(); - _v2 = file->readNumber(); + _initialFrame = file->readNumber(); _v3 = file->readNumber(); - _string1 = file->readString(); + _viewName1 = file->readString(); _fieldF0 = file->readNumber(); - _fieldF4 = file->readNumber(); - _fieldF8 = file->readNumber(); - _fieldFC = file->readNumber(); - _field100 = file->readNumber(); - _field104 = file->readNumber(); - _field108 = file->readNumber(); - _field10C = file->readNumber(); - _field110 = file->readNumber(); - _field114 = file->readNumber(); - _field118 = file->readNumber(); - _field11C = file->readNumber(); - _field120 = file->readNumber(); - _field124 = file->readNumber(); - _field128 = file->readNumber(); - _field12C = file->readNumber(); - _field130 = file->readNumber(); - _field134 = file->readNumber(); - _field138 = file->readNumber(); - _field13C = file->readNumber(); - _field140 = file->readNumber(); - _field144 = file->readNumber(); - _field148 = file->readNumber(); - _field14C = file->readNumber(); - _field150 = file->readNumber(); - _string2 = file->readString(); + _winterOffStartFrame = file->readNumber(); + _winterOffEndFrame = file->readNumber(); + _springOffStartFrame = file->readNumber(); + _springOffEndFrame = file->readNumber(); + _summerOffStartFrame1 = file->readNumber(); + _summerOffEndFrame1 = file->readNumber(); + _summerOffStartFrame2 = file->readNumber(); + _summerOffEndFrame2 = file->readNumber(); + _autumnOffStartFrame1 = file->readNumber(); + _autumnOffEndFrame1 = file->readNumber(); + _autumnOffStartFrame2 = file->readNumber(); + _autumnOffEndFrame2 = file->readNumber(); + _winterOnStartFrame = file->readNumber(); + _winterOnEndFrame = file->readNumber(); + _springOnStartFrame = file->readNumber(); + _springOnEndFrame = file->readNumber(); + _summerOnStartFrame1 = file->readNumber(); + _summerOnEndFrame1 = file->readNumber(); + _summerOnStartFrame2 = file->readNumber(); + _summerOnEndFrame2 = file->readNumber(); + _autumnOnStartFrame1 = file->readNumber(); + _autumnOnEndFrame1 = file->readNumber(); + _autumnOnStartFrame2 = file->readNumber(); + _autumnOnEndFrame2 = file->readNumber(); + _viewName2 = file->readString(); CBackground::load(file); } -bool CArboretumGate::ActMsg(CActMsg *msg) { return false; } -bool CArboretumGate::LeaveViewMsg(CLeaveViewMsg *msg) { return false; } -bool CArboretumGate::TurnOff(CTurnOff *msg) { return false; } -bool CArboretumGate::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { return false; } +bool CArboretumGate::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + _seasonNum = (_seasonNum + 1) % 4; + return true; +} -bool CArboretumGate::EnterViewMsg(CEnterViewMsg *msg) { - warning("CArboretumGate::handleEvent"); +bool CArboretumGate::ActMsg(CActMsg *msg) { + if (msg->_action == "PlayerGetsSpeechCentre") { + _v1 = 1; + CVisibleMsg visibleMsg(true); + visibleMsg.execute("SpCtrOverlay"); + } else if (msg->_action == "ExitLFrozen") { + if (_v3) { + _viewName2 = "FrozenArboretum.Node 2.W"; + CTurnOn onMsg; + onMsg.execute(this); + } else { + changeView("FrozenArboretum.Node 2.W"); + } + } else if (msg->_action == "ExitRFrozen") { + if (_v3) { + _viewName2 = "FrozenArboretum.Node 2.E"; + CTurnOn onMsg; + onMsg.execute(this); + } else { + changeView("FrozenArboretum.Node 2.E"); + } + } else if (msg->_action == "ExitLNormal") { + if (_v3) { + _viewName2 = "Arboretum.Node 2.W"; + CTurnOn onMsg; + onMsg.execute(this); + } else { + changeView("Arboretum.Node 2.W"); + } + } else if (msg->_action == "ExitRNormal") { + if (_v3) { + _viewName2 = "Arboretum.Node 2.E"; + CTurnOn onMsg; + onMsg.execute(this); + } + else { + changeView("Arboretum.Node 2.E"); + } + } + + return true; +} + +bool CArboretumGate::MovieEndMsg(CMovieEndMsg *msg) { + setVisible(!_v3); + + if (_viewName1 != "NULL") { + changeView(_viewName1); + } else if (_viewName2 != "NULL") { + changeView(_viewName2); + _viewName2 = "NULL"; + } + + return true; +} + +bool CArboretumGate::LeaveViewMsg(CLeaveViewMsg *msg) { return false; } -bool CArboretumGate::TurnOn(CTurnOn *msg) { return false; } -bool CArboretumGate::MovieEndMsg(CMovieEndMsg *msg) { return false; } +bool CArboretumGate::TurnOff(CTurnOff *msg) { + if (!_v3) { + switch (_seasonNum) { + case SPRING: + playMovie(_springOffStartFrame, _springOffEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + break; + + case SUMMER: + if (_v1) { + playMovie(_summerOffStartFrame2, _summerOffEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } else { + playMovie(_summerOffStartFrame1, _summerOffEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } + break; + + case AUTUMN: + if (_v1) { + playMovie(_autumnOffStartFrame2, _autumnOffEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } else { + playMovie(_autumnOffStartFrame1, _autumnOffEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } + break; + + case WINTER: + playMovie(_winterOffStartFrame, _winterOffEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + break; + + default: + break; + } + + _v3 = 1; + CArboretumGateMsg gateMsg; + gateMsg.execute("Arboretum", nullptr, MSGFLAG_SCAN); + } + + return true; +} + +bool CArboretumGate::TurnOn(CTurnOn *msg) { + if (_v3) { + CArboretumGateMsg gateMsg(0); + gateMsg.execute("Arboretum"); + setVisible(true); + + switch (_seasonNum) { + case SPRING: + playMovie(_springOnStartFrame, _springOnEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + break; + + case SUMMER: + if (_v1) { + playMovie(_summerOnStartFrame2, _summerOnEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } else { + playMovie(_summerOnStartFrame1, _summerOnEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } + break; + + case AUTUMN: + if (_v1) { + playMovie(_autumnOnStartFrame2, _autumnOnEndFrame2, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } else { + playMovie(_autumnOnStartFrame1, _autumnOnEndFrame1, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + } + break; + + case WINTER: + playMovie(_winterOnStartFrame, _winterOnEndFrame, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + break; + + default: + break; + } + + _v3 = 0; + } + + return true; +} + +bool CArboretumGate::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if (!_v3) { + CTurnOff offMsg; + offMsg.execute(this); + } + + return true; +} + +bool CArboretumGate::EnterViewMsg(CEnterViewMsg *msg) { + if (!_v3) { + switch (_seasonNum) { + case SPRING: + _initialFrame = _springOffStartFrame; + break; + + case SUMMER: + _initialFrame = _v1 ? _summerOffStartFrame2 : _summerOffStartFrame1; + break; + + case AUTUMN: + _initialFrame = _v1 ? _autumnOffStartFrame1 : _autumnOffStartFrame2; + break; + + case WINTER: + _initialFrame = _winterOffStartFrame; + break; + + default: + break; + } + + loadFrame(_initialFrame); + } + + return true; +} } // End of namespace Titanic diff --git a/engines/titanic/game/arboretum_gate.h b/engines/titanic/game/arboretum_gate.h index 927b2190c7..62c9200a64 100644 --- a/engines/titanic/game/arboretum_gate.h +++ b/engines/titanic/game/arboretum_gate.h @@ -31,48 +31,47 @@ namespace Titanic { class CArboretumGate : public CBackground { DECLARE_MESSAGE_MAP; + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); bool ActMsg(CActMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); bool LeaveViewMsg(CLeaveViewMsg *msg); bool TurnOff(CTurnOff *msg); bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); bool EnterViewMsg(CEnterViewMsg *msg); bool TurnOn(CTurnOn *msg); - bool MovieEndMsg(CMovieEndMsg *msg); private: static int _v1; - static int _v2; + static int _initialFrame; static int _v3; private: - int _fieldE0; - CString _string1; - int _fieldE8; - int _fieldEC; + int _seasonNum; + CString _viewName1; int _fieldF0; - int _fieldF4; - int _fieldF8; - int _fieldFC; - int _field100; - int _field104; - int _field108; - int _field10C; - int _field110; - int _field114; - int _field118; - int _field11C; - int _field120; - int _field124; - int _field128; - int _field12C; - int _field130; - int _field134; - int _field138; - int _field13C; - int _field140; - int _field144; - int _field148; - int _field14C; - int _field150; - CString _string2; + int _winterOffStartFrame; + int _winterOffEndFrame; + int _springOffStartFrame; + int _springOffEndFrame; + int _summerOffStartFrame2; + int _summerOffEndFrame2; + int _summerOffStartFrame1; + int _summerOffEndFrame1; + int _autumnOffStartFrame2; + int _autumnOffEndFrame2; + int _autumnOffStartFrame1; + int _autumnOffEndFrame1; + int _winterOnStartFrame; + int _winterOnEndFrame; + int _springOnStartFrame; + int _springOnEndFrame; + int _summerOnStartFrame1; + int _summerOnEndFrame1; + int _summerOnStartFrame2; + int _summerOnEndFrame2; + int _autumnOnStartFrame1; + int _autumnOnEndFrame1; + int _autumnOnStartFrame2; + int _autumnOnEndFrame2; + CString _viewName2; public: CLASSDEF; CArboretumGate(); diff --git a/engines/titanic/game/auto_animate.cpp b/engines/titanic/game/auto_animate.cpp index 172b8c44df..16e6e56747 100644 --- a/engines/titanic/game/auto_animate.cpp +++ b/engines/titanic/game/auto_animate.cpp @@ -24,24 +24,44 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CAutoAnimate, CBackground) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(InitializeAnimMsg) +END_MESSAGE_MAP() + void CAutoAnimate::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldE0, indent); + file->writeNumberLine(_enabled, indent); file->writeNumberLine(_fieldE4, indent); - file->writeNumberLine(_fieldE8, indent); + file->writeNumberLine(_repeat, indent); CBackground::save(file, indent); } void CAutoAnimate::load(SimpleFile *file) { file->readNumber(); - _fieldE0 = file->readNumber(); + _enabled = file->readNumber(); _fieldE4 = file->readNumber(); - _fieldE8 = file->readNumber(); + _repeat = file->readNumber(); CBackground::load(file); } bool CAutoAnimate::EnterViewMsg(CEnterViewMsg *msg) { - warning("CAutoAnimate::handleEvent"); + if (_enabled) { + uint flags = _repeat ? MOVIE_REPEAT : 0; + if (_startFrame != _endFrame) + playMovie(_startFrame, _endFrame, flags); + else + playMovie(flags); + + if (!_fieldE4) + _enabled = false; + } + + return true; +} + +bool CAutoAnimate::InitializeAnimMsg(CInitializeAnimMsg *msg) { + _enabled = true; return true; } diff --git a/engines/titanic/game/auto_animate.h b/engines/titanic/game/auto_animate.h index 7bca808bfb..735aba922e 100644 --- a/engines/titanic/game/auto_animate.h +++ b/engines/titanic/game/auto_animate.h @@ -29,14 +29,16 @@ namespace Titanic { class CAutoAnimate : public CBackground { + DECLARE_MESSAGE_MAP; bool EnterViewMsg(CEnterViewMsg *msg); + bool InitializeAnimMsg(CInitializeAnimMsg *msg); private: - int _fieldE0; + bool _enabled; int _fieldE4; - int _fieldE8; + bool _repeat; public: CLASSDEF; - CAutoAnimate() : CBackground(), _fieldE0(1), _fieldE4(1), _fieldE8(0) {} + CAutoAnimate() : CBackground(), _enabled(true), _fieldE4(1), _repeat(false) {} /** * Save the data for the class to file diff --git a/engines/titanic/game/bar_bell.cpp b/engines/titanic/game/bar_bell.cpp index b33ee1c26c..207644a00e 100644 --- a/engines/titanic/game/bar_bell.cpp +++ b/engines/titanic/game/bar_bell.cpp @@ -24,15 +24,22 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CBarBell, CGameObject) + ON_MESSAGE(EnterRoomMsg) + ON_MESSAGE(MouseButtonDownMsg) + ON_MESSAGE(MouseButtonUpMsg) + ON_MESSAGE(ActMsg) +END_MESSAGE_MAP() + CBarBell::CBarBell() : CGameObject(), _fieldBC(0), - _fieldC0(65), _fieldC4(0), _fieldC8(0), _fieldCC(0) { + _volume(65), _soundVal3(0), _fieldC8(0), _fieldCC(0) { } void CBarBell::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_fieldBC, indent); - file->writeNumberLine(_fieldC0, indent); - file->writeNumberLine(_fieldC4, indent); + file->writeNumberLine(_volume, indent); + file->writeNumberLine(_soundVal3, indent); file->writeNumberLine(_fieldC8, indent); file->writeNumberLine(_fieldCC, indent); @@ -42,8 +49,8 @@ void CBarBell::save(SimpleFile *file, int indent) { void CBarBell::load(SimpleFile *file) { file->readNumber(); _fieldBC = file->readNumber(); - _fieldC0 = file->readNumber(); - _fieldC4 = file->readNumber(); + _volume = file->readNumber(); + _soundVal3 = file->readNumber(); _fieldC8 = file->readNumber(); _fieldCC = file->readNumber(); @@ -55,4 +62,70 @@ bool CBarBell::EnterRoomMsg(CEnterRoomMsg *msg) { return true; } +bool CBarBell::MouseButtonDownMsg(CMouseButtonDownMsg *msg) { + if ((_fieldC8 % 3) == 2) { + switch (_fieldBC) { + case 0: + case 1: + case 5: + playSound("c#54.wav", _volume, _soundVal3); + break; + + case 2: + playSound("c#52.wav", _volume, _soundVal3); + break; + + case 3: + playSound("c#53.wav", _volume, _soundVal3); + break; + + case 4: + playSound("c#55.wav", _volume, _soundVal3); + break; + + default: + playSound("c#51.wav", _volume, _soundVal3); + break; + } + } else if (_fieldBC >= 5) { + if (_fieldBC == 6) { + CActMsg actMsg("BellRing3"); + actMsg.execute("Barbot"); + } + + playSound("c#51.wav", _volume, _soundVal3); + } else { + if (_fieldBC == 3) { + CActMsg actMsg("BellRing1"); + actMsg.execute("Barbot"); + } else if (_fieldBC == 4) { + CActMsg actMsg("BellRing2"); + actMsg.execute("Barbot"); + } + + playSound("c#54.wav", _volume, _soundVal3); + } + + return true; +} + +bool CBarBell::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + if (!_fieldBC) { + CTurnOn onMsg; + onMsg.execute("Barbot"); + } + + ++_fieldBC; + return 2; +} + +bool CBarBell::ActMsg(CActMsg *msg) { + if (msg->_action == "ResetCount") { + _fieldBC = 0; + ++_fieldC8; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/bar_bell.h b/engines/titanic/game/bar_bell.h index 5d1d2c54e0..b50fe505ba 100644 --- a/engines/titanic/game/bar_bell.h +++ b/engines/titanic/game/bar_bell.h @@ -29,11 +29,15 @@ namespace Titanic { class CBarBell : public CGameObject { + DECLARE_MESSAGE_MAP; bool EnterRoomMsg(CEnterRoomMsg *msg); + bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); + bool ActMsg(CActMsg *msg); public: int _fieldBC; - int _fieldC0; - int _fieldC4; + int _volume; + int _soundVal3; int _fieldC8; int _fieldCC; public: diff --git a/engines/titanic/game/sgt/armchair.cpp b/engines/titanic/game/sgt/armchair.cpp index 4c4ef44199..f547c3ef9a 100644 --- a/engines/titanic/game/sgt/armchair.cpp +++ b/engines/titanic/game/sgt/armchair.cpp @@ -24,6 +24,12 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CArmchair, CSGTStateRoom) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(MovieEndMsg) +END_MESSAGE_MAP() + void CArmchair::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CSGTStateRoom::save(file, indent); @@ -34,4 +40,48 @@ void CArmchair::load(SimpleFile *file) { CSGTStateRoom::load(file); } +bool CArmchair::TurnOn(CTurnOn *msg) { + if (_statics->_v8 == "Closed" && _statics->_v12 == "Closed") { + CVisibleMsg visibleMsg(false); + visibleMsg.execute("Deskchair"); + + if (_statics->_v9 == "Open") { + CActMsg actMsg("Squash"); + actMsg.execute("Deskchair"); + _startFrame = 22; + _endFrame = 31; + } else { + _startFrame = 0; + _endFrame = 10; + } + + playMovie(_startFrame, _endFrame, MOVIE_GAMESTATE); + playSound("b#0.wav"); + _statics->_v8 = "Open"; + _fieldE0 = 0; + } + + return true; +} + +bool CArmchair::TurnOff(CTurnOff *msg) { + if (_statics->_v8 == "Open") { + _statics->_v8 = "Closed"; + _startFrame = 11; + _endFrame = 21; + _fieldE0 = 1; + playMovie(11, 21, MOVIE_GAMESTATE | MOVIE_NOTIFY_OBJECT); + playSound("b#0.wav"); + } + + return true; +} + +bool CArmchair::MovieEndMsg(CMovieEndMsg *msg) { + if (_statics->_v8 == "Closed") + loadFrame(0); + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/game/sgt/armchair.h b/engines/titanic/game/sgt/armchair.h index b5505554f0..169b9b4aa0 100644 --- a/engines/titanic/game/sgt/armchair.h +++ b/engines/titanic/game/sgt/armchair.h @@ -28,6 +28,10 @@ namespace Titanic { class CArmchair : public CSGTStateRoom { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool MovieEndMsg(CMovieEndMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/game/sgt/sgt_state_room.h b/engines/titanic/game/sgt/sgt_state_room.h index 375da71326..d9ffdb8e9e 100644 --- a/engines/titanic/game/sgt/sgt_state_room.h +++ b/engines/titanic/game/sgt/sgt_state_room.h @@ -48,9 +48,9 @@ struct CSGTStateRoomStatics { class CSGTStateRoom : public CBackground { DECLARE_MESSAGE_MAP; bool EnterRoomMsg(CEnterRoomMsg *msg); -private: +protected: static CSGTStateRoomStatics *_statics; -private: +protected: int _fieldE0; int _fieldE4; int _fieldE8; diff --git a/engines/titanic/gfx/act_button.cpp b/engines/titanic/gfx/act_button.cpp index c84f358ca9..75c999b10f 100644 --- a/engines/titanic/gfx/act_button.cpp +++ b/engines/titanic/gfx/act_button.cpp @@ -24,6 +24,10 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CActButton, CSTButton) + ON_MESSAGE(MouseButtonUpMsg) +END_MESSAGE_MAP() + CActButton::CActButton() : CSTButton() { } @@ -37,4 +41,10 @@ void CActButton::load(SimpleFile *file) { CSTButton::load(file); } +bool CActButton::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { + CActMsg actMsg(_actionName); + actMsg.execute(_actionTarget); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/gfx/act_button.h b/engines/titanic/gfx/act_button.h index 26e5595411..910ace1d13 100644 --- a/engines/titanic/gfx/act_button.h +++ b/engines/titanic/gfx/act_button.h @@ -28,6 +28,8 @@ namespace Titanic { class CActButton : public CSTButton { + DECLARE_MESSAGE_MAP; + bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); public: CLASSDEF; CActButton(); diff --git a/engines/titanic/gfx/st_button.cpp b/engines/titanic/gfx/st_button.cpp index 4b93d46595..6fc31f4c64 100644 --- a/engines/titanic/gfx/st_button.cpp +++ b/engines/titanic/gfx/st_button.cpp @@ -32,10 +32,10 @@ END_MESSAGE_MAP() CSTButton::CSTButton() : CBackground() { _statusInc = 0; - _statusTarget = "NULL"; + _actionTarget = "NULL"; _fieldF0 = 0; _currentStatus = 0; - _string4 = "NULL"; + _actionName = "NULL"; _soundName = "NULL"; _buttonFrame = 0; } @@ -43,10 +43,10 @@ CSTButton::CSTButton() : CBackground() { void CSTButton::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_statusInc, indent); - file->writeQuotedLine(_statusTarget, indent); + file->writeQuotedLine(_actionTarget, indent); file->writeNumberLine(_fieldF0, indent); file->writeNumberLine(_currentStatus, indent); - file->writeQuotedLine(_string4, indent); + file->writeQuotedLine(_actionName, indent); file->writeQuotedLine(_soundName, indent); file->writeNumberLine(_buttonFrame, indent); @@ -56,10 +56,10 @@ void CSTButton::save(SimpleFile *file, int indent) { void CSTButton::load(SimpleFile *file) { file->readNumber(); _statusInc = file->readNumber(); - _statusTarget = file->readString(); + _actionTarget = file->readString(); _fieldF0 = file->readNumber(); _currentStatus = file->readNumber(); - _string4 = file->readString(); + _actionName = file->readString(); _soundName = file->readString(); _buttonFrame = file->readNumber() != 0; @@ -79,7 +79,7 @@ bool CSTButton::MouseButtonUpMsg(CMouseButtonUpMsg *msg) { CStatusChangeMsg statusMsg(oldStatus, newStatus, false); _currentStatus = newStatus; - statusMsg.execute(_statusTarget); + statusMsg.execute(_actionTarget); if (!statusMsg._success) { _currentStatus -= _statusInc; diff --git a/engines/titanic/gfx/st_button.h b/engines/titanic/gfx/st_button.h index 789437691b..444c883f59 100644 --- a/engines/titanic/gfx/st_button.h +++ b/engines/titanic/gfx/st_button.h @@ -34,12 +34,12 @@ class CSTButton : public CBackground { bool MouseButtonDownMsg(CMouseButtonDownMsg *msg); bool MouseButtonUpMsg(CMouseButtonUpMsg *msg); bool EnterViewMsg(CEnterViewMsg *msg); -private: +protected: int _statusInc; - CString _statusTarget; + CString _actionTarget; int _fieldF0; int _currentStatus; - CString _string4; + CString _actionName; CString _soundName; int _buttonFrame; public: diff --git a/engines/titanic/messages/auto_sound_event.cpp b/engines/titanic/messages/auto_sound_event.cpp index baa11c7d41..bc2cd7d074 100644 --- a/engines/titanic/messages/auto_sound_event.cpp +++ b/engines/titanic/messages/auto_sound_event.cpp @@ -24,7 +24,11 @@ namespace Titanic { -CAutoSoundEvent::CAutoSoundEvent() : CGameObject(), _value1(0), _value2(70) { +BEGIN_MESSAGE_MAP(CAutoSoundEvent, CGameObject) + ON_MESSAGE(FrameMsg) +END_MESSAGE_MAP() + +CAutoSoundEvent::CAutoSoundEvent() : CGameObject(), _value1(0), _value2(0xFFFFFF) { } void CAutoSoundEvent::save(SimpleFile *file, int indent) { @@ -43,4 +47,11 @@ void CAutoSoundEvent::load(SimpleFile *file) { CGameObject::load(file); } +bool CAutoSoundEvent::FrameMsg(CFrameMsg *msg) { + if (_value1 >= 0) + _value1 = (_value1 + 1) & _value2; + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/messages/auto_sound_event.h b/engines/titanic/messages/auto_sound_event.h index eb1c11c4ff..d88976708e 100644 --- a/engines/titanic/messages/auto_sound_event.h +++ b/engines/titanic/messages/auto_sound_event.h @@ -28,6 +28,8 @@ namespace Titanic { class CAutoSoundEvent : public CGameObject { + DECLARE_MESSAGE_MAP; + bool FrameMsg(CFrameMsg *msg); public: int _value1; int _value2; diff --git a/engines/titanic/messages/messages.h b/engines/titanic/messages/messages.h index c1d962f656..0935689db7 100644 --- a/engines/titanic/messages/messages.h +++ b/engines/titanic/messages/messages.h @@ -331,7 +331,7 @@ MESSAGE0(CSubSendCCarryMsg); MESSAGE0(CSUBTransition); MESSAGE0(CSubTurnOffMsg); MESSAGE0(CSubTurnOnMsg); -MESSAGE2(CSummonBotMsg, CString, strValue, "", int, numValue, 0); +MESSAGE2(CSummonBotMsg, CString, npcName, "", int, value, 0); MESSAGE1(CSummonBotQueryMsg, CString, npcName, ""); MESSAGE1(CTakeHeadPieceMsg, CString, value, "NULL"); MESSAGE2(CTextInputMsg, CString, input, "", CString, response, ""); diff --git a/engines/titanic/module.mk b/engines/titanic/module.mk index ba46c4b57c..5c041174a2 100644 --- a/engines/titanic/module.mk +++ b/engines/titanic/module.mk @@ -402,6 +402,7 @@ MODULE_OBJS := \ sound/music_handler.o \ sound/music_room.o \ sound/music_player.o \ + sound/music_wave.o \ sound/node_auto_sound_player.o \ sound/proximity.o \ sound/qmixer.o \ diff --git a/engines/titanic/npcs/barbot.cpp b/engines/titanic/npcs/barbot.cpp index 8f1c5e6ab3..079e8fe10b 100644 --- a/engines/titanic/npcs/barbot.cpp +++ b/engines/titanic/npcs/barbot.cpp @@ -26,6 +26,23 @@ namespace Titanic { int CBarbot::_v0; +BEGIN_MESSAGE_MAP(CBarbot, CTrueTalkNPC) + ON_MESSAGE(ActMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(TurnOn) + ON_MESSAGE(TurnOff) + ON_MESSAGE(LeaveViewMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(TrueTalkSelfQueueAnimSetMsg) + ON_MESSAGE(TrueTalkQueueUpAnimSetMsg) + ON_MESSAGE(TrueTalkGetStateValueMsg) + ON_MESSAGE(TrueTalkTriggerActionMsg) + ON_MESSAGE(FrameMsg) + ON_MESSAGE(LoadSuccessMsg) + ON_MESSAGE(MovieFrameMsg) + ON_MESSAGE(EnterRoomMsg) +END_MESSAGE_MAP() + CBarbot::CBarbot() : CTrueTalkNPC() { _field108 = 0; _field10C = 0; @@ -233,9 +250,74 @@ void CBarbot::load(SimpleFile *file) { CTrueTalkNPC::load(file); } +bool CBarbot::ActMsg(CActMsg *msg) { + // TODO + return false; +} + +bool CBarbot::EnterViewMsg(CEnterViewMsg *msg) { + // TODO + return false; +} + +bool CBarbot::TurnOn(CTurnOn *msg) { + // TODO + return false; +} + +bool CBarbot::TurnOff(CTurnOff *msg) { + // TODO + return false; +} + +bool CBarbot::LeaveViewMsg(CLeaveViewMsg *msg) { + // TODO + return false; +} + +bool CBarbot::MovieEndMsg(CMovieEndMsg *msg) { + // TODO + return false; +} + +bool CBarbot::TrueTalkSelfQueueAnimSetMsg(CTrueTalkSelfQueueAnimSetMsg *msg) { + // TODO + return false; +} + +bool CBarbot::TrueTalkQueueUpAnimSetMsg(CTrueTalkQueueUpAnimSetMsg *msg) { + // TODO + return false; +} + +bool CBarbot::TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg) { + // TODO + return false; +} + +bool CBarbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) { + // TODO + return false; +} + +bool CBarbot::FrameMsg(CFrameMsg *msg) { + // TODO + return false; +} + +bool CBarbot::LoadSuccessMsg(CLoadSuccessMsg *msg) { + // TODO + return false; +} + +bool CBarbot::MovieFrameMsg(CMovieFrameMsg *msg) { + // TODO + return false; +} + bool CBarbot::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("TODO: Barbot::CEnterRoomMsg"); - return true; + // TODO + return false; } } // End of namespace Titanic diff --git a/engines/titanic/npcs/barbot.h b/engines/titanic/npcs/barbot.h index 7557fdd2c6..123e39afed 100644 --- a/engines/titanic/npcs/barbot.h +++ b/engines/titanic/npcs/barbot.h @@ -29,6 +29,20 @@ namespace Titanic { class CBarbot : public CTrueTalkNPC { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool TurnOn(CTurnOn *msg); + bool TurnOff(CTurnOff *msg); + bool LeaveViewMsg(CLeaveViewMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool TrueTalkSelfQueueAnimSetMsg(CTrueTalkSelfQueueAnimSetMsg *msg); + bool TrueTalkQueueUpAnimSetMsg(CTrueTalkQueueUpAnimSetMsg *msg); + bool TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg); + bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg); + bool FrameMsg(CFrameMsg *msg); + bool LoadSuccessMsg(CLoadSuccessMsg *msg); + bool MovieFrameMsg(CMovieFrameMsg *msg); bool EnterRoomMsg(CEnterRoomMsg *msg); private: static int _v0; diff --git a/engines/titanic/npcs/callbot.cpp b/engines/titanic/npcs/callbot.cpp index eb0d4b71d5..4af9876b35 100644 --- a/engines/titanic/npcs/callbot.cpp +++ b/engines/titanic/npcs/callbot.cpp @@ -21,26 +21,54 @@ */ #include "titanic/npcs/callbot.h" +#include "titanic/core/room_item.h" namespace Titanic { -CCallBot::CCallBot() : CGameObject(), _fieldC8(0) { +BEGIN_MESSAGE_MAP(CCallBot, CGameObject) + ON_MESSAGE(TurnOn) + ON_MESSAGE(EnterViewMsg) +END_MESSAGE_MAP() + +CCallBot::CCallBot() : CGameObject(), _enabled(0) { } void CCallBot::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string1, indent); - file->writeNumberLine(_fieldC8, indent); + file->writeQuotedLine(_npcName, indent); + file->writeNumberLine(_enabled, indent); CGameObject::save(file, indent); } void CCallBot::load(SimpleFile *file) { file->readNumber(); - _string1 = file->readString(); - _fieldC8 = file->readNumber(); + _npcName = file->readString(); + _enabled = file->readNumber(); CGameObject::load(file); } +bool CCallBot::TurnOn(CTurnOn *msg) { + _enabled = true; + return true; +} + +bool CCallBot::EnterViewMsg(CEnterViewMsg *msg) { + if (_enabled) { + CRoomItem *room = getRoom(); + + if (room) { + CSummonBotQueryMsg queryMsg; + queryMsg._npcName = _npcName; + if (queryMsg.execute(room)) + petOnSummonBot(_npcName, 0); + } + + _enabled = false; + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/npcs/callbot.h b/engines/titanic/npcs/callbot.h index 9b89d59d3f..ca0e0c55b2 100644 --- a/engines/titanic/npcs/callbot.h +++ b/engines/titanic/npcs/callbot.h @@ -28,9 +28,12 @@ namespace Titanic { class CCallBot : public CGameObject { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool EnterViewMsg(CEnterViewMsg *msg); protected: - CString _string1; - int _fieldC8; + CString _npcName; + bool _enabled; public: CLASSDEF; CCallBot(); diff --git a/engines/titanic/npcs/robot_controller.cpp b/engines/titanic/npcs/robot_controller.cpp index 98866e4505..34c75e30eb 100644 --- a/engines/titanic/npcs/robot_controller.cpp +++ b/engines/titanic/npcs/robot_controller.cpp @@ -24,21 +24,37 @@ namespace Titanic { -CRobotController::CRobotController() : CGameObject(), _string1("BellBot") { +BEGIN_MESSAGE_MAP(CRobotController, CGameObject) + ON_MESSAGE(SummonBotMsg) + ON_MESSAGE(SummonBotQueryMsg) +END_MESSAGE_MAP() + +CRobotController::CRobotController() : CGameObject(), _robotName("BellBot") { } void CRobotController::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string1, indent); + file->writeQuotedLine(_robotName, indent); CGameObject::save(file, indent); } void CRobotController::load(SimpleFile *file) { file->readNumber(); - _string1 = file->readString(); + _robotName = file->readString(); CGameObject::load(file); } +bool CRobotController::SummonBotMsg(CSummonBotMsg *msg) { + if (!petDismissBot(msg->_npcName)) + petOnSummonBot(msg->_npcName, msg->_value); + + return true; +} + +bool CRobotController::SummonBotQueryMsg(CSummonBotQueryMsg *msg) { + return _robotName == msg->_npcName; +} + } // End of namespace Titanic diff --git a/engines/titanic/npcs/robot_controller.h b/engines/titanic/npcs/robot_controller.h index 6cbf57aef2..326c2280dd 100644 --- a/engines/titanic/npcs/robot_controller.h +++ b/engines/titanic/npcs/robot_controller.h @@ -28,8 +28,11 @@ namespace Titanic { class CRobotController : public CGameObject { + DECLARE_MESSAGE_MAP; + bool SummonBotMsg(CSummonBotMsg *msg); + bool SummonBotQueryMsg(CSummonBotQueryMsg *msg); protected: - CString _string1; + CString _robotName; public: CLASSDEF; CRobotController(); diff --git a/engines/titanic/npcs/starlings.cpp b/engines/titanic/npcs/starlings.cpp index 333f4c4b7a..7e5907f577 100644 --- a/engines/titanic/npcs/starlings.cpp +++ b/engines/titanic/npcs/starlings.cpp @@ -24,23 +24,40 @@ namespace Titanic { -int CStarlings::_v1; +BEGIN_MESSAGE_MAP(CStarlings, CCharacter) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(StatusChangeMsg) +END_MESSAGE_MAP() -CStarlings::CStarlings() : CCharacter() { +CStarlings::CStarlings() : CCharacter(), _enabled(false) { } void CStarlings::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_v1, indent); + file->writeNumberLine(_enabled, indent); CCharacter::save(file, indent); } void CStarlings::load(SimpleFile *file) { file->readNumber(); - _v1 = file->readNumber(); + _enabled = file->readNumber(); CCharacter::load(file); } +bool CStarlings::EnterViewMsg(CEnterViewMsg *msg) { + if (_enabled) + setVisible(false); + else + playMovie(MOVIE_REPEAT); + return true; +} + +bool CStarlings::StatusChangeMsg(CStatusChangeMsg *msg) { + _enabled = msg->_newStatus == 1; + setVisible(!_enabled); + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/npcs/starlings.h b/engines/titanic/npcs/starlings.h index 4d96e5c77f..1998e6490d 100644 --- a/engines/titanic/npcs/starlings.h +++ b/engines/titanic/npcs/starlings.h @@ -28,8 +28,11 @@ namespace Titanic { class CStarlings : public CCharacter { + DECLARE_MESSAGE_MAP; + bool EnterViewMsg(CEnterViewMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); private: - static int _v1; + bool _enabled; public: CLASSDEF; CStarlings(); diff --git a/engines/titanic/npcs/true_talk_npc.cpp b/engines/titanic/npcs/true_talk_npc.cpp index 290922f660..9310f285e5 100644 --- a/engines/titanic/npcs/true_talk_npc.cpp +++ b/engines/titanic/npcs/true_talk_npc.cpp @@ -198,14 +198,6 @@ void CTrueTalkNPC::processInput(CTextInputMsg *msg, CViewItem *view) { talkManager->processInput(this, msg, view); } -int CTrueTalkNPC::startAnimTimer(const CString &action, uint firstDuration, uint duration) { - CTimeEventInfo *timer = new CTimeEventInfo(g_vm->_events->getTicksCount(), - duration > 0, firstDuration, duration, this, 0, action); - getGameManager()->addTimer(timer); - - return timer->_id; -} - void CTrueTalkNPC::stopAnimTimer(int id) { getGameManager()->stopTimer(id); } diff --git a/engines/titanic/npcs/true_talk_npc.h b/engines/titanic/npcs/true_talk_npc.h index 0deb832c82..0319f7e059 100644 --- a/engines/titanic/npcs/true_talk_npc.h +++ b/engines/titanic/npcs/true_talk_npc.h @@ -62,11 +62,6 @@ protected: int _field104; protected: void processInput(CTextInputMsg *msg, CViewItem *view); - - /** - * Start an animation timer - */ - int startAnimTimer(const CString &action, uint firstDuration, uint duration); /** * Stop an animation timer diff --git a/engines/titanic/sound/auto_sound_player.cpp b/engines/titanic/sound/auto_sound_player.cpp index 1fb67858da..8267d65037 100644 --- a/engines/titanic/sound/auto_sound_player.cpp +++ b/engines/titanic/sound/auto_sound_player.cpp @@ -75,7 +75,7 @@ bool CAutoSoundPlayer::TurnOn(CTurnOn *msg) { prox._fieldC = _fieldD0; prox._repeated = _repeated; if (_fieldE8) - prox._field28 = 2; + prox._positioningMode = POSMODE_VECTOR; prox._channelVolume = (_startSeconds == -1) ? _volume : 0; _soundHandle = playSound(_filename, prox); diff --git a/engines/titanic/sound/gondolier_song.cpp b/engines/titanic/sound/gondolier_song.cpp index b44400b2db..5c96718723 100644 --- a/engines/titanic/sound/gondolier_song.cpp +++ b/engines/titanic/sound/gondolier_song.cpp @@ -24,16 +24,71 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CGondolierSong, CRoomAutoSoundPlayer) + ON_MESSAGE(TurnOn) + ON_MESSAGE(SignalObject) + ON_MESSAGE(SetVolumeMsg) + ON_MESSAGE(StatusChangeMsg) +END_MESSAGE_MAP() + void CGondolierSong::save(SimpleFile *file, int indent) { - file->writeNumberLine(1, indent); + file->writeNumberLine(_enabled, indent); file->writeNumberLine(_value, indent); CRoomAutoSoundPlayer::save(file, indent); } void CGondolierSong::load(SimpleFile *file) { - file->readNumber(); + _enabled = file->readNumber(); _value = file->readNumber(); CRoomAutoSoundPlayer::load(file); } +bool CGondolierSong::TurnOn(CTurnOn *msg) { + if (_enabled) { + if (_soundHandle != -1) { + int volume = _value * _volume / 100; + + if (_startSeconds == -1) { + _soundHandle = playSound(_filename, volume, _fieldD0, _repeated); + } else { + _soundHandle = playSound(_filename, 0, _fieldD0, _repeated); + setSoundVolume(_soundHandle, _volume, _startSeconds); + } + + _active = true; + } + } + + return true; +} + +bool CGondolierSong::SignalObject(CSignalObject *msg) { + _enabled = false; + CAutoSoundPlayer::SignalObject(msg); + return true; +} + +bool CGondolierSong::SetVolumeMsg(CSetVolumeMsg *msg) { + if (_enabled) { + _volume = msg->_volume; + + if (_soundHandle != -1 && isSoundActive(_soundHandle)) { + int newVolume = _value * _volume / 100; + setSoundVolume(_soundHandle, newVolume, msg->_secondsTransition); + } + } + + return true; +} + +bool CGondolierSong::StatusChangeMsg(CStatusChangeMsg *msg) { + if (_enabled) { + _value = CLIP(msg->_newStatus, 0, 100); + CSetVolumeMsg volumeMsg(_volume, _stopSeconds); + volumeMsg.execute(this); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/sound/gondolier_song.h b/engines/titanic/sound/gondolier_song.h index 0a7120c0fc..d586711de9 100644 --- a/engines/titanic/sound/gondolier_song.h +++ b/engines/titanic/sound/gondolier_song.h @@ -28,11 +28,17 @@ namespace Titanic { class CGondolierSong : public CRoomAutoSoundPlayer { + DECLARE_MESSAGE_MAP; + bool TurnOn(CTurnOn *msg); + bool SignalObject(CSignalObject *msg); + bool SetVolumeMsg(CSetVolumeMsg *msg); + bool StatusChangeMsg(CStatusChangeMsg *msg); public: + bool _enabled; int _value; public: CLASSDEF; - CGondolierSong() : CRoomAutoSoundPlayer(), _value(0) {} + CGondolierSong() : CRoomAutoSoundPlayer(), _enabled(true), _value(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/sound/music_handler.cpp b/engines/titanic/sound/music_handler.cpp index 32277ef031..037c340f0b 100644 --- a/engines/titanic/sound/music_handler.cpp +++ b/engines/titanic/sound/music_handler.cpp @@ -27,9 +27,35 @@ namespace Titanic { CMusicHandler::CMusicHandler(CProjectItem *project, CSoundManager *soundManager) : - _project(project), _soundManager(soundManager), - _field124(0) { + _project(project), _soundManager(soundManager), _stopWaves(false), + _soundHandle(-1), _waveFile(nullptr) { + Common::fill(&_musicWaves[0], &_musicWaves[4], (CMusicWave *)nullptr); +} + +CMusicHandler::~CMusicHandler() { + stop(); +} + +CMusicWave *CMusicHandler::createMusicWave(int waveIndex, int count) { + switch (waveIndex) { + case 0: + _musicWaves[waveIndex] = new CMusicWave(_project, _soundManager, 2); + break; + case 1: + _musicWaves[waveIndex] = new CMusicWave(_project, _soundManager, 3); + break; + case 2: + _musicWaves[waveIndex] = new CMusicWave(_project, _soundManager, 0); + break; + case 3: + _musicWaves[waveIndex] = new CMusicWave(_project, _soundManager, 1); + break; + default: + return nullptr; + } + _musicWaves[waveIndex]->setSize(count); + return _musicWaves[waveIndex]; } bool CMusicHandler::isBusy() { @@ -37,4 +63,18 @@ bool CMusicHandler::isBusy() { return false; } +void CMusicHandler::stop() { + if (_waveFile) { + _soundManager->stopSound(_soundHandle); + delete _waveFile; + _waveFile = nullptr; + _soundHandle = -1; + } + + for (int idx = 0; idx < 4; ++idx) { + if (_stopWaves && _musicWaves[idx]) + _musicWaves[idx]->stop(); + } +} + } // End of namespace Titanic diff --git a/engines/titanic/sound/music_handler.h b/engines/titanic/sound/music_handler.h index 99dcbe8619..17ffea965a 100644 --- a/engines/titanic/sound/music_handler.h +++ b/engines/titanic/sound/music_handler.h @@ -23,6 +23,9 @@ #ifndef TITANIC_MUSIC_HANDLER_H #define TITANIC_MUSIC_HANDLER_H +#include "titanic/sound/music_wave.h" +#include "titanic/sound/wave_file.h" + namespace Titanic { class CProjectItem; @@ -32,13 +35,34 @@ class CMusicHandler { private: CProjectItem *_project; CSoundManager *_soundManager; - int _field124; + CMusicWave *_musicWaves[4]; + bool _stopWaves; + CWaveFile *_waveFile; + int _soundHandle; public: CMusicHandler(CProjectItem *project, CSoundManager *soundManager); + ~CMusicHandler(); + + /** + * Creates a new music wave class instance, and assigns it to a slot + * in the music handler + * @param waveIndex Slot to save new instance in + * @param count Number of files the new instance will contain + */ + CMusicWave *createMusicWave(int waveIndex, int count); bool isBusy(); - void set124(int val) { _field124 = val; } + /** + * Flags whether the loaded music waves will be stopped when the + * music handler is stopped + */ + void setStopWaves(bool flag) { _stopWaves = flag; } + + /** + * Stop playing the music + */ + void stop(); }; } // End of namespace Titanic diff --git a/engines/titanic/sound/music_player.cpp b/engines/titanic/sound/music_player.cpp index 86ec0dbb22..cd764c7f93 100644 --- a/engines/titanic/sound/music_player.cpp +++ b/engines/titanic/sound/music_player.cpp @@ -39,7 +39,7 @@ void CMusicPlayer::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); file->writeNumberLine(_isActive, indent); file->writeQuotedLine(_stopTarget, indent); - file->writeNumberLine(_fieldCC, indent); + file->writeNumberLine(_stopWaves, indent); file->writeNumberLine(_musicId, indent); CGameObject::save(file, indent); @@ -49,7 +49,7 @@ void CMusicPlayer::load(SimpleFile *file) { file->readNumber(); _isActive = file->readNumber(); _stopTarget = file->readString(); - _fieldCC = file->readNumber(); + _stopWaves = file->readNumber(); _musicId = file->readNumber(); CGameObject::load(file); @@ -120,15 +120,43 @@ bool CMusicPlayer::LeaveRoomMsg(CLeaveRoomMsg *msg) { bool CMusicPlayer::CreateMusicPlayerMsg(CCreateMusicPlayerMsg *msg) { if (CMusicRoom::_musicHandler) { - CMusicRoom::_musicHandler->set124(_fieldCC); + CMusicRoom::_musicHandler->setStopWaves(_stopWaves); return true; } CMusicHandler *musicHandler = getMusicRoom()->createMusicHandler(); - if (musicHandler) { - // TODO + CMusicWave *wave; - CMusicRoom::_musicHandler->set124(_fieldCC); + if (musicHandler) { + wave = musicHandler->createMusicWave(0, 3); + wave->load(0, "z#490.wav", 60); + wave->load(1, "z#488.wav", 62); + wave->load(2, "z#489.wav", 63); + + wave = musicHandler->createMusicWave(1, 5); + wave->load(0, "z#493.wav", 22); + wave->load(1, "z#495.wav", 29); + wave->load(2, "z#492.wav", 34); + wave->load(3, "z#494.wav", 41); + wave->load(4, "z#491.wav", 46); + + wave = musicHandler->createMusicWave(2, 5); + wave->load(0, "z#499.wav", 26); + wave->load(1, "z#497.wav", 34); + wave->load(2, "z#498.wav", 38); + wave->load(3, "z#496.wav", 46); + wave->load(4, "z#500.wav", 60); + + wave = musicHandler->createMusicWave(3, 7); + wave->load(0, "z#504.wav", 22); + wave->load(1, "z#507.wav", 29); + wave->load(2, "z#503.wav", 34); + wave->load(3, "z#506.wav", 41); + wave->load(4, "z#502.wav", 46); + wave->load(5, "z#505.wav", 53); + wave->load(6, "z#501.wav", 58); + + CMusicRoom::_musicHandler->setStopWaves(_stopWaves); } return true; diff --git a/engines/titanic/sound/music_player.h b/engines/titanic/sound/music_player.h index 3ed1bffdbd..7b82d4da00 100644 --- a/engines/titanic/sound/music_player.h +++ b/engines/titanic/sound/music_player.h @@ -41,12 +41,12 @@ class CMusicPlayer : public CGameObject { protected: bool _isActive; CString _stopTarget; - int _fieldCC; + bool _stopWaves; int _musicId; public: CLASSDEF; CMusicPlayer() : CGameObject(), - _isActive(false), _fieldCC(0), _musicId(100) {} + _isActive(false), _stopWaves(false), _musicId(100) {} /** * Save the data for the class to file diff --git a/engines/titanic/sound/music_room.cpp b/engines/titanic/sound/music_room.cpp index 06cf866811..34217de184 100644 --- a/engines/titanic/sound/music_room.cpp +++ b/engines/titanic/sound/music_room.cpp @@ -58,7 +58,8 @@ void CMusicRoom::startMusic(int musicId) { } void CMusicRoom::stopMusic() { - // TODO + if (_musicHandler) + _musicHandler->stop(); } } // End of namespace Titanic diff --git a/engines/titanic/sound/music_wave.cpp b/engines/titanic/sound/music_wave.cpp new file mode 100644 index 0000000000..6b5b187805 --- /dev/null +++ b/engines/titanic/sound/music_wave.cpp @@ -0,0 +1,54 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "titanic/sound/music_wave.h" +#include "titanic/sound/sound_manager.h" +#include "titanic/core/project_item.h" + +namespace Titanic { + +CMusicWave::CMusicWave(CProjectItem *project, CSoundManager *soundManager, int index) : + _project(project), _soundManager(soundManager) { +} + +void CMusicWave::setSize(uint count) { + assert(_items.empty()); + _items.resize(count); +} + +void CMusicWave::load(int index, const CString &filename, int v3) { + assert(!_items[index]._waveFile); + _items[index]._waveFile = createWaveFile(filename); + _items[index]._value = v3; +} + +CWaveFile *CMusicWave::createWaveFile(const CString &name) { + if (name.empty()) + return nullptr; + return _soundManager->loadSound(name); +} + +void CMusicWave::stop() { + +} + +} // End of namespace Titanic diff --git a/engines/titanic/sound/music_wave.h b/engines/titanic/sound/music_wave.h new file mode 100644 index 0000000000..b240f4a856 --- /dev/null +++ b/engines/titanic/sound/music_wave.h @@ -0,0 +1,71 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef TITANIC_MUSIC_WAVE_H +#define TITANIC_MUSIC_WAVE_H + +#include "common/array.h" +#include "titanic/support/string.h" + +namespace Titanic { + +class CProjectItem; +class CSoundManager; +class CWaveFile; + +class CMusicWave { + struct CMusicWaveFile { + CWaveFile *_waveFile; + int _value; + CMusicWaveFile() : _waveFile(nullptr), _value(0) {} + }; +private: + CProjectItem *_project; + CSoundManager *_soundManager; + Common::Array<CMusicWaveFile> _items; +private: + /** + * Loads the specified wave file, and returns a CWaveFile instance for it + */ + CWaveFile *createWaveFile(const CString &name); +public: + CMusicWave(CProjectItem *project, CSoundManager *soundManager, int index); + + /** + * Sets the maximum number of allowed files that be defined + */ + void setSize(uint count); + + /** + * Loads a new file into the list of available entries + */ + void load(int index, const CString &filename, int v3); + + /** + * Stops the music + */ + void stop(); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_MUSIC_WAVE_H */ diff --git a/engines/titanic/sound/proximity.cpp b/engines/titanic/sound/proximity.cpp index ce91a0770f..7f4e6784f2 100644 --- a/engines/titanic/sound/proximity.cpp +++ b/engines/titanic/sound/proximity.cpp @@ -26,11 +26,11 @@ namespace Titanic { CProximity::CProximity() : _field4(0), _channelVolume(100), _fieldC(0), - _soundHandle((uint)-1), _field14(0), _frequencyMultiplier(0.0), _field1C(1.875), - _repeated(false), _channel(10), _field28(0), _azimuth(0.0), + _priorSoundHandle(-1), _field14(0), _frequencyMultiplier(0.0), _field1C(1.875), + _repeated(false), _channel(10), _positioningMode(POSMODE_NONE), _azimuth(0.0), _range(0.5), _elevation(0), _posX(0.0), _posY(0.0), _posZ(0.0), _hasVelocity(false), _velocityX(0), _velocityY(0), _velocityZ(0), - _field54(0), _field58(0), _field5C(0), _field60(0), _endTalkerFn(nullptr), + _field54(0), _field58(0), _field5C(0), _freeSoundFlag(false), _endTalkerFn(nullptr), _talker(nullptr), _field6C(0) { } diff --git a/engines/titanic/sound/proximity.h b/engines/titanic/sound/proximity.h index d8eee4d9e5..b728f22c26 100644 --- a/engines/titanic/sound/proximity.h +++ b/engines/titanic/sound/proximity.h @@ -27,6 +27,8 @@ namespace Titanic { +enum PositioningMode { POSMODE_NONE = 0, POSMODE_POLAR = 1, POSMODE_VECTOR = 2 }; + class TTtalker; typedef void (*CEndTalkerFn)(TTtalker *talker); @@ -36,13 +38,13 @@ public: int _field4; int _channelVolume; int _fieldC; - uint _soundHandle; + int _priorSoundHandle; int _field14; double _frequencyMultiplier; double _field1C; bool _repeated; int _channel; - int _field28; + PositioningMode _positioningMode; double _azimuth; double _range; double _elevation; @@ -56,7 +58,7 @@ public: int _field54; int _field58; int _field5C; - int _field60; + bool _freeSoundFlag; CEndTalkerFn _endTalkerFn; TTtalker *_talker; int _field6C; diff --git a/engines/titanic/sound/qmixer.cpp b/engines/titanic/sound/qmixer.cpp index da707c9527..145d142b2d 100644 --- a/engines/titanic/sound/qmixer.cpp +++ b/engines/titanic/sound/qmixer.cpp @@ -28,7 +28,10 @@ QMixer::QMixer(Audio::Mixer *mixer) : _mixer(mixer) { } bool QMixer::qsWaveMixInitEx(const QMIXCONFIG &config) { - // Not currently implemented in ScummVM + assert(_channels.empty()); + assert(config.iChannels > 0 && config.iChannels < 256); + + _channels.resize(config.iChannels); return true; } @@ -48,6 +51,7 @@ int QMixer::qsWaveMixEnableChannel(int iChannel, uint flags, bool enabled) { void QMixer::qsWaveMixCloseSession() { _mixer->stopAll(); + _channels.clear(); } void QMixer::qsWaveMixFreeWave(Audio::SoundHandle &handle) { @@ -94,18 +98,76 @@ void QMixer::qsWaveMixSetSourceVelocity(int iChannel, uint flags, const QSVECTOR // Not currently implemented in ScummVM } -int QMixer::qsWaveMixPlayEx(int iChannel, uint flags, CWaveFile *mixWave, int loops, const QMIXPLAYPARAMS ¶ms) { - // Not currently implemented in ScummVM +int QMixer::qsWaveMixPlayEx(int iChannel, uint flags, CWaveFile *waveFile, int loops, const QMIXPLAYPARAMS ¶ms) { + if (iChannel == -1) { + // Find a free channel + for (iChannel = 0; iChannel < (int)_channels.size(); ++iChannel) { + if (_channels[iChannel]._sounds.empty()) + break; + } + assert(iChannel != (int)_channels.size()); + } + + // If the new sound replaces current ones, then clear the channel + ChannelEntry &channel = _channels[iChannel]; + if (flags & QMIX_CLEARQUEUE) { + if (!channel._sounds.empty() && channel._sounds.front()._started) + _mixer->stopHandle(channel._sounds.front()._soundHandle); + + channel._sounds.clear(); + } + + // Add the sound to the channel + channel._sounds.push_back(SoundEntry(waveFile, params.callback, loops, params.dwUser)); + qsWaveMixPump(); + return 0; } bool QMixer::qsWaveMixIsChannelDone(int iChannel) const { - // Not currently implemented in ScummVM - return true; + return _channels[iChannel]._sounds.empty(); } void QMixer::qsWaveMixPump() { - // TODO: Handle checking for done sounds, and calling their end functions + // Iterate through each of the channels + for (uint iChannel = 0; iChannel < _channels.size(); ++iChannel) { + ChannelEntry &channel = _channels[iChannel]; + + // If the playing sound on the channel is finished, then call + // the callback registered for it, and remove it from the list + if (!channel._sounds.empty()) { + SoundEntry &sound = channel._sounds.front(); + if (sound._started && !_mixer->isSoundHandleActive(sound._soundHandle)) { + if (sound._loops == -1 || sound._loops-- > 0) { + // Need to loop the sound again + sound._waveFile->_stream->rewind(); + _mixer->playStream(sound._waveFile->_soundType, + &sound._soundHandle, sound._waveFile->_stream, + -1, 0xff, 0, DisposeAfterUse::NO); + } else { + // Sound is finished + if (sound._callback) + // Call the callback to signal end + sound._callback(iChannel, sound._waveFile, sound._userData); + + // Remove sound record from channel + channel._sounds.erase(channel._sounds.begin()); + } + } + } + + // If there's an unstarted sound at the front of a channel's + // sound list, then start it playing + if (!channel._sounds.empty()) { + SoundEntry &sound = channel._sounds.front(); + if (!sound._started) { + _mixer->playStream(sound._waveFile->_soundType, + &sound._soundHandle, sound._waveFile->_stream, + -1, 0xff, 0, DisposeAfterUse::NO); + sound._started = true; + } + } + } } } // End of namespace Titanic z diff --git a/engines/titanic/sound/qmixer.h b/engines/titanic/sound/qmixer.h index fa4604cd2e..4ba76a8969 100644 --- a/engines/titanic/sound/qmixer.h +++ b/engines/titanic/sound/qmixer.h @@ -152,9 +152,12 @@ struct QMIXPLAYPARAMS { int lEndLoop; int lEnd; const void *lpChannelParams; // initialize with these parameters + // Properties introduced by ScummVM + Audio::Mixer::SoundType _soundType; QMIXPLAYPARAMS() : dwSize(36), lpImage(nullptr), hwndNotify(0), callback(nullptr), - dwUser(nullptr), lStart(0), lStartLoop(0), lEndLoop(0), lEnd(0), lpChannelParams(nullptr) {} + dwUser(nullptr), lStart(0), lStartLoop(0), lEndLoop(0), lEnd(0), + lpChannelParams(nullptr), _soundType(Audio::Mixer::kPlainSoundType) {} }; /** @@ -169,8 +172,25 @@ struct QMIXPLAYPARAMS { * currently ignored, and all sounds play at full volume. */ class QMixer { + struct SoundEntry { + bool _started; + CWaveFile *_waveFile; + Audio::SoundHandle _soundHandle; + LPQMIXDONECALLBACK _callback; + int _loops; + void *_userData; + SoundEntry() : _started(false), _waveFile(nullptr), _callback(nullptr), + _loops(0), _userData(nullptr) {} + + SoundEntry(CWaveFile *waveFile, LPQMIXDONECALLBACK callback, int loops, void *userData) : + _started(false), _waveFile(waveFile), _callback(callback), _loops(loops), _userData(userData) {} + }; + struct ChannelEntry { + Common::List<SoundEntry> _sounds; + }; private: Audio::Mixer *_mixer; + Common::Array<ChannelEntry> _channels; public: QMixer(Audio::Mixer *mixer); virtual ~QMixer() {} diff --git a/engines/titanic/sound/restricted_auto_music_player.cpp b/engines/titanic/sound/restricted_auto_music_player.cpp index 4ccfecc58d..2384d4da25 100644 --- a/engines/titanic/sound/restricted_auto_music_player.cpp +++ b/engines/titanic/sound/restricted_auto_music_player.cpp @@ -21,32 +21,59 @@ */ #include "titanic/sound/restricted_auto_music_player.h" +#include "titanic/core/room_item.h" namespace Titanic { +BEGIN_MESSAGE_MAP(CRestrictedAutoMusicPlayer, CAutoMusicPlayer) + ON_MESSAGE(EnterRoomMsg) + ON_MESSAGE(LeaveRoomMsg) +END_MESSAGE_MAP() + void CRestrictedAutoMusicPlayer::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeQuotedLine(_string3, indent); - file->writeQuotedLine(_string4, indent); - file->writeQuotedLine(_string5, indent); - file->writeQuotedLine(_string6, indent); + file->writeQuotedLine(_oldNodeName, indent); + file->writeQuotedLine(_newNodeName, indent); + file->writeQuotedLine(_newRoomName, indent); + file->writeQuotedLine(_oldRoomName, indent); CAutoMusicPlayer::save(file, indent); } void CRestrictedAutoMusicPlayer::load(SimpleFile *file) { file->readNumber(); - _string3 = file->readString(); - _string4 = file->readString(); - _string5 = file->readString(); - _string6 = file->readString(); + _oldNodeName = file->readString(); + _newNodeName = file->readString(); + _newRoomName = file->readString(); + _oldRoomName = file->readString(); CAutoMusicPlayer::load(file); } bool CRestrictedAutoMusicPlayer::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CRestrictedAutoMusicPlayer::handleEvent"); - return true; + if (!msg->_oldRoom) + return true; + if (petCheckNode(_oldNodeName)) + return false; + + CString roomName = msg->_oldRoom->getName(); + if (_oldRoomName.compareToIgnoreCase(roomName)) { + _isRepeated = true; + return false; + } else { + return CAutoMusicPlayer::EnterRoomMsg(msg); + } +} + +bool CRestrictedAutoMusicPlayer::LeaveRoomMsg(CLeaveRoomMsg *msg) { + CString roomName = msg->_newRoom->getName(); + + if (petCheckNode(_newNodeName) || _newRoomName.compareToIgnoreCase(roomName)) { + _isRepeated = false; + return true; + } else { + return CAutoMusicPlayer::LeaveRoomMsg(msg); + } } } // End of namespace Titanic diff --git a/engines/titanic/sound/restricted_auto_music_player.h b/engines/titanic/sound/restricted_auto_music_player.h index 4a26d3770a..d36ee5a7ab 100644 --- a/engines/titanic/sound/restricted_auto_music_player.h +++ b/engines/titanic/sound/restricted_auto_music_player.h @@ -29,12 +29,14 @@ namespace Titanic { class CRestrictedAutoMusicPlayer : public CAutoMusicPlayer { + DECLARE_MESSAGE_MAP; bool EnterRoomMsg(CEnterRoomMsg *msg); + bool LeaveRoomMsg(CLeaveRoomMsg *msg); private: - CString _string3; - CString _string4; - CString _string5; - CString _string6; + CString _oldNodeName; + CString _newNodeName; + CString _newRoomName; + CString _oldRoomName; public: CLASSDEF; diff --git a/engines/titanic/sound/room_trigger_auto_music_player.cpp b/engines/titanic/sound/room_trigger_auto_music_player.cpp index 4506dfd7d4..7782cef0e2 100644 --- a/engines/titanic/sound/room_trigger_auto_music_player.cpp +++ b/engines/titanic/sound/room_trigger_auto_music_player.cpp @@ -24,6 +24,11 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CRoomTriggerAutoMusicPlayer, CTriggerAutoMusicPlayer) + ON_MESSAGE(LeaveRoomMsg) + ON_MESSAGE(EnterRoomMsg) +END_MESSAGE_MAP() + void CRoomTriggerAutoMusicPlayer::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); CTriggerAutoMusicPlayer::save(file, indent); @@ -34,8 +39,23 @@ void CRoomTriggerAutoMusicPlayer::load(SimpleFile *file) { CTriggerAutoMusicPlayer::load(file); } +bool CRoomTriggerAutoMusicPlayer::LeaveRoomMsg(CLeaveRoomMsg *msg) { + if (msg->_oldRoom == findRoom()) { + CTriggerAutoMusicPlayerMsg triggerMsg; + triggerMsg._value = 1; + triggerMsg.execute(this); + } + + return true; +} + bool CRoomTriggerAutoMusicPlayer::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CRoomTriggerAutoMusicPlayer::handleEvent"); + if (msg->_newRoom == findRoom()) { + CTriggerAutoMusicPlayerMsg triggerMsg; + triggerMsg._value = 2; + triggerMsg.execute(this); + } + return true; } diff --git a/engines/titanic/sound/room_trigger_auto_music_player.h b/engines/titanic/sound/room_trigger_auto_music_player.h index 250adad864..a57e133eb6 100644 --- a/engines/titanic/sound/room_trigger_auto_music_player.h +++ b/engines/titanic/sound/room_trigger_auto_music_player.h @@ -29,7 +29,9 @@ namespace Titanic { class CRoomTriggerAutoMusicPlayer : public CTriggerAutoMusicPlayer { - bool EnterRoomMsg(CEnterRoomMsg *msg); + DECLARE_MESSAGE_MAP; + bool LeaveRoomMsg(CLeaveRoomMsg *msg); + bool EnterRoomMsg(CEnterRoomMsg *msg); public: CLASSDEF; diff --git a/engines/titanic/sound/season_noises.cpp b/engines/titanic/sound/season_noises.cpp index e7307654fe..ce045488ee 100644 --- a/engines/titanic/sound/season_noises.cpp +++ b/engines/titanic/sound/season_noises.cpp @@ -24,30 +24,92 @@ namespace Titanic { -CSeasonNoises::CSeasonNoises() : CViewAutoSoundPlayer(), _fieldF0(0), - _string2("NULL"), _string3("NULL"), _string4("NULL"), _string5("NULL") { +BEGIN_MESSAGE_MAP(CSeasonNoises, CViewAutoSoundPlayer) + ON_MESSAGE(ChangeSeasonMsg) + ON_MESSAGE(EnterViewMsg) + ON_MESSAGE(ActMsg) + ON_MESSAGE(LoadSuccessMsg) +END_MESSAGE_MAP() + +CSeasonNoises::CSeasonNoises() : CViewAutoSoundPlayer(), _seasonNumber(0), + _springName("NULL"), _summerName("NULL"), _autumnName("NULL"), _winterName("NULL") { } void CSeasonNoises::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldF0, indent); - file->writeQuotedLine(_string2, indent); - file->writeQuotedLine(_string3, indent); - file->writeQuotedLine(_string4, indent); - file->writeQuotedLine(_string5, indent); + file->writeNumberLine(_seasonNumber, indent); + file->writeQuotedLine(_springName, indent); + file->writeQuotedLine(_summerName, indent); + file->writeQuotedLine(_autumnName, indent); + file->writeQuotedLine(_winterName, indent); CViewAutoSoundPlayer::save(file, indent); } void CSeasonNoises::load(SimpleFile *file) { file->readNumber(); - _fieldF0 = file->readNumber(); - _string2 = file->readString(); - _string3 = file->readString(); - _string4 = file->readString(); - _string5 = file->readString(); + _seasonNumber = file->readNumber(); + _springName = file->readString(); + _summerName = file->readString(); + _autumnName = file->readString(); + _winterName = file->readString(); CViewAutoSoundPlayer::load(file); } +bool CSeasonNoises::ChangeSeasonMsg(CChangeSeasonMsg *msg) { + _seasonNumber = (_seasonNumber + 1) % 4; + CActMsg actMsg("Update"); + actMsg.execute(this); + + return true; +} + +bool CSeasonNoises::EnterViewMsg(CEnterViewMsg *msg) { + CActMsg actMsg("Update"); + return true; +} + +bool CSeasonNoises::ActMsg(CActMsg *msg) { + msg->_action = "Update"; + + switch (_seasonNumber) { + case 0: + _filename = _springName; + break; + case 1: + _filename = _summerName; + break; + case 2: + _filename = _autumnName; + break; + case 3: + _filename = _winterName; + break; + default: + break; + } + + CSignalObject signalMsg; + signalMsg._numValue = 2; + signalMsg.execute(this); + + CTurnOn onMsg; + onMsg.execute(this); + + return true; +} + +bool CSeasonNoises::LoadSuccessMsg(CLoadSuccessMsg *msg) { + if (_active) { + _active = false; + _soundHandle = -1; + + CActMsg actMsg("Update"); + actMsg.execute(this); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/sound/season_noises.h b/engines/titanic/sound/season_noises.h index ff39b01d73..796628d10d 100644 --- a/engines/titanic/sound/season_noises.h +++ b/engines/titanic/sound/season_noises.h @@ -28,12 +28,17 @@ namespace Titanic { class CSeasonNoises : public CViewAutoSoundPlayer { + DECLARE_MESSAGE_MAP; + bool ChangeSeasonMsg(CChangeSeasonMsg *msg); + bool EnterViewMsg(CEnterViewMsg *msg); + bool ActMsg(CActMsg *msg); + bool LoadSuccessMsg(CLoadSuccessMsg *msg); private: - int _fieldF0; - CString _string2; - CString _string3; - CString _string4; - CString _string5; + int _seasonNumber; + CString _springName; + CString _summerName; + CString _autumnName; + CString _winterName; public: CLASSDEF; CSeasonNoises(); diff --git a/engines/titanic/sound/sound.cpp b/engines/titanic/sound/sound.cpp index d86262ae23..7e791c2ba5 100644 --- a/engines/titanic/sound/sound.cpp +++ b/engines/titanic/sound/sound.cpp @@ -48,16 +48,12 @@ void CSound::preLoad() { void CSound::preEnterView(CViewItem *newView, bool isNewRoom) { CNodeItem *node = newView->findNode(); - CRoomItem *room = node->findRoom(); double xp, yp, zp; node->getPosition(xp, yp, zp); double cosVal = cos(newView->_angle); double sinVal = -sin(newView->_angle); - // WORKAROUND: The original does a weird call below, doing the room's - // (width + height) / 2 and passing it in the isNewRoom field, along with - // two extra unused parameters that aren't used _soundManager.setListenerPosition(xp, yp, zp, cosVal, sinVal, 0, isNewRoom); } @@ -72,8 +68,18 @@ void CSound::setVolume(uint handle, uint volume, uint seconds) { _soundManager.setVolume(handle, volume, seconds); } -void CSound::fn4(CWaveFile *waveFile, int val) { - // TODO +void CSound::activateSound(CWaveFile *waveFile, bool freeFlag) { + for (CSoundItemList::iterator i = _sounds.begin(); i != _sounds.end(); ++i) { + CSoundItem *sound = *i; + if (sound->_waveFile == waveFile) { + sound->_active = true; + sound->_freeFlag = freeFlag; + + if (!freeFlag && waveFile->size() > 51200) + sound->_freeFlag = true; + break; + } + } } void CSound::stopChannel(int channel) { @@ -83,7 +89,7 @@ void CSound::stopChannel(int channel) { void CSound::checkSounds() { for (CSoundItemList::iterator i = _sounds.begin(); i != _sounds.end(); ++i) { CSoundItem *soundItem = *i; - if (soundItem->_field24 && soundItem->_field28) { + if (soundItem->_active && soundItem->_freeFlag) { if (_soundManager.isActive(soundItem->_waveFile)) { _sounds.remove(soundItem); delete soundItem; @@ -96,7 +102,7 @@ void CSound::removeOldest() { for (CSoundItemList::iterator i = _sounds.reverse_begin(); i != _sounds.end(); --i) { CSoundItem *soundItem = *i; - if (soundItem->_field28 && !_soundManager.isActive(soundItem->_waveFile)) { + if (soundItem->_active && !_soundManager.isActive(soundItem->_waveFile)) { _sounds.remove(soundItem); delete soundItem; break; @@ -149,7 +155,7 @@ int CSound::playSound(const CString &name, CProximity &prox) { return -1; prox._field6C = waveFile->fn1(); - fn4(waveFile, prox._field60); + activateSound(waveFile, prox._freeSoundFlag); return _soundManager.playSound(*waveFile, prox); } @@ -196,7 +202,7 @@ int CSound::playSpeech(CDialogueFile *dialogueFile, int speechId, CProximity &pr return -1; prox._field6C = waveFile->fn1(); - fn4(waveFile, prox._field60); + activateSound(waveFile, prox._freeSoundFlag); return _soundManager.playSound(*waveFile, prox); } diff --git a/engines/titanic/sound/sound.h b/engines/titanic/sound/sound.h index b6c77e76b2..de95f9edf1 100644 --- a/engines/titanic/sound/sound.h +++ b/engines/titanic/sound/sound.h @@ -41,15 +41,15 @@ public: CWaveFile *_waveFile; File *_dialogueFileHandle; int _speechId; - int _field24; - int _field28; + bool _freeFlag; + bool _active; public: CSoundItem() : ListItem(), _waveFile(nullptr), _dialogueFileHandle(nullptr), - _speechId(0), _field24(0), _field28(0) {} + _speechId(0), _freeFlag(false), _active(false) {} CSoundItem(const CString &name) : ListItem(), _name(name), _waveFile(nullptr), - _dialogueFileHandle(nullptr), _speechId(0), _field24(0), _field28(0) {} + _dialogueFileHandle(nullptr), _speechId(0), _freeFlag(false), _active(false) {} CSoundItem(File *dialogueFile, int speechId) : ListItem(), _waveFile(nullptr), - _dialogueFileHandle(dialogueFile), _speechId(speechId), _field24(0), _field28(0) {} + _dialogueFileHandle(dialogueFile), _speechId(speechId), _freeFlag(false), _active(false) {} }; class CSoundItemList : public List<CSoundItem> { @@ -123,7 +123,10 @@ public: */ void setVolume(uint handle, uint volume, uint seconds); - void fn4(CWaveFile *waveFile, int val); + /** + * Flags a sound about to be played as activated + */ + void activateSound(CWaveFile *waveFile, bool freeFlag); /** * Stops any sounds attached to a given channel diff --git a/engines/titanic/sound/sound_manager.cpp b/engines/titanic/sound/sound_manager.cpp index 7a188524ad..84d38ed2ab 100644 --- a/engines/titanic/sound/sound_manager.cpp +++ b/engines/titanic/sound/sound_manager.cpp @@ -32,7 +32,7 @@ CSoundManager::CSoundManager() : _musicPercent(75.0), _speechPercent(75.0), _masterPercent(75.0), _parrotPercent(75.0), _handleCtr(1) { } -uint CSoundManager::getModeVolume(int mode) { +double CSoundManager::getModeVolume(int mode) { switch (mode) { case -1: return _masterPercent; @@ -97,7 +97,7 @@ void QSoundManager::Slot::clear() { _ticks = 0; _channel = -1; _handle = 0; - _val3 = 0; + _positioningMode = POSMODE_NONE; } /*------------------------------------------------------------------------*/ @@ -142,20 +142,31 @@ CWaveFile *QSoundManager::loadSpeech(CDialogueFile *dialogueFile, int speechId) return waveFile; } -int QSoundManager::proc5() const { - error("TODO"); - return 0; +CWaveFile *QSoundManager::loadMusic(const CString &name) { + CWaveFile *waveFile = new CWaveFile(); + + // Try to load the specified sound + if (!waveFile->loadMusic(name)) { + delete waveFile; + return nullptr; + } + + return waveFile; } int QSoundManager::playSound(CWaveFile &waveFile, CProximity &prox) { int channel = -1; uint flags = QMIX_CLEARQUEUE; - for (uint idx = 0; idx < _slots.size(); ++idx) { - if (_slots[idx]._handle == prox._soundHandle) { - channel = _slots[idx]._channel; - flags = QMIX_QUEUEWAVE; - break; + if (prox._priorSoundHandle >= 1) { + // This sound should only be started after a prior one finishes, + // so scan the slots for the specified sound + for (uint idx = 0; idx < _slots.size(); ++idx) { + if (_slots[idx]._handle == prox._priorSoundHandle) { + channel = _slots[idx]._channel; + flags = QMIX_QUEUEWAVE; + break; + } } } @@ -166,7 +177,7 @@ int QSoundManager::playSound(CWaveFile &waveFile, CProximity &prox) { return 0; } -void QSoundManager::stopSound(uint handle) { +void QSoundManager::stopSound(int handle) { resetChannel(10); for (uint idx = 0; idx < _slots.size(); ++idx) { @@ -202,7 +213,7 @@ void QSoundManager::stopChannel(int channel) { } } -void QSoundManager::setCanFree(uint handle) { +void QSoundManager::setCanFree(int handle) { for (uint idx = 0; idx < _slots.size(); ++idx) { if (_slots[idx]._handle == handle) _slots[idx]._isTimed = true; @@ -256,7 +267,7 @@ int QSoundManager::resetChannel(int iChannel) { return newChannel; } -void QSoundManager::setVolume(uint handle, uint volume, uint seconds) { +void QSoundManager::setVolume(int handle, uint volume, uint seconds) { for (uint idx = 0; idx < _slots.size(); ++idx) { Slot &slot = _slots[idx]; if (slot._handle == handle) { @@ -275,7 +286,7 @@ void QSoundManager::setVolume(uint handle, uint volume, uint seconds) { } } -void QSoundManager::setVectorPosition(uint handle, double x, double y, double z, uint panRate) { +void QSoundManager::setVectorPosition(int handle, double x, double y, double z, uint panRate) { for (uint idx = 0; idx < _slots.size(); ++idx) { Slot &slot = _slots[idx]; if (slot._handle == handle) { @@ -286,7 +297,7 @@ void QSoundManager::setVectorPosition(uint handle, double x, double y, double z, } } -void QSoundManager::setPolarPosition(uint handle, double range, double azimuth, double elevation, uint panRate) { +void QSoundManager::setPolarPosition(int handle, double range, double azimuth, double elevation, uint panRate) { for (uint idx = 0; idx < _slots.size(); ++idx) { Slot &slot = _slots[idx]; if (slot._handle == handle) { @@ -298,7 +309,7 @@ void QSoundManager::setPolarPosition(uint handle, double range, double azimuth, } } -bool QSoundManager::isActive(uint handle) const { +bool QSoundManager::isActive(int handle) const { for (uint idx = 0; idx < _slots.size(); ++idx) { if (_slots[idx]._handle == handle) return true; @@ -312,7 +323,7 @@ bool QSoundManager::isActive(const CWaveFile *waveFile) const { } void QSoundManager::waveMixPump() { - + qsWaveMixPump(); } uint QSoundManager::getLatency() const { @@ -343,7 +354,7 @@ void QSoundManager::setListenerPosition(double posX, double posY, double posZ, if (stopSounds) { // Stop any running sounds for (uint idx = 0; idx < _slots.size(); ++idx) { - if (_slots[idx]._val3) + if (_slots[idx]._positioningMode != 0) stopSound(_slots[idx]._handle); } } @@ -364,14 +375,14 @@ int QSoundManager::playWave(CWaveFile *waveFile, int iChannel, uint flags, CProx if (slotIndex == -1) return -1; - switch (prox._field28) { - case 1: + switch (prox._positioningMode) { + case POSMODE_POLAR: qsWaveMixSetPolarPosition(iChannel, 8, QSPOLAR(prox._azimuth, prox._range, prox._elevation)); qsWaveMixEnableChannel(iChannel, QMIX_CHANNEL_ELEVATION, true); qsWaveMixSetDistanceMapping(iChannel, 8, QMIX_DISTANCES(5.0, 3.0, 1.0)); break; - case 2: + case POSMODE_VECTOR: qsWaveMixSetSourcePosition(iChannel, 8, QSVECTOR(prox._posX, prox._posY, prox._posZ)); qsWaveMixEnableChannel(iChannel, QMIX_CHANNEL_ELEVATION, true); qsWaveMixSetDistanceMapping(iChannel, 8, QMIX_DISTANCES(5.0, 3.0, 1.0)); @@ -398,12 +409,12 @@ int QSoundManager::playWave(CWaveFile *waveFile, int iChannel, uint flags, CProx slot._handle = _handleCtr++; slot._channel = iChannel; slot._waveFile = waveFile; - slot._val3 = prox._field28; + slot._positioningMode = prox._positioningMode; return slot._handle; } else { _sounds.flushChannel(waveFile, iChannel); - if (prox._field60) + if (prox._freeSoundFlag) delete waveFile; return 0; } @@ -443,7 +454,7 @@ void QSoundManager::updateVolume(int channel, uint panRate) { } void QSoundManager::updateVolumes() { - for (int idx = 0; idx < CHANNELS_COUNT; ++idx) + for (uint idx = 0; idx < CHANNELS_COUNT; ++idx) updateVolume(idx, 250); } diff --git a/engines/titanic/sound/sound_manager.h b/engines/titanic/sound/sound_manager.h index 466607a1d5..3dfba92e9c 100644 --- a/engines/titanic/sound/sound_manager.h +++ b/engines/titanic/sound/sound_manager.h @@ -60,7 +60,15 @@ public: */ virtual CWaveFile *loadSpeech(CDialogueFile *dialogueFile, int speechId) { return 0; } - virtual int proc5() const { return 0; } + /** + * Loads a music file + * @param name Name of music resource + * @returns Loaded wave file + * @remarks The original created a streaming audio buffer for the wave file, + * and passed this to the method. For ScummVM, this has been discarded + * in favor of simply passing the filename. + */ + virtual CWaveFile *loadMusic(const CString &name) { return nullptr; } /** * Start playing a previously loaded wave file @@ -70,14 +78,14 @@ public: /** * Stop playing the specified sound */ - virtual void stopSound(uint handle) = 0; + virtual void stopSound(int handle) = 0; /** * Stops a designated range of channels */ virtual void stopChannel(int channel) = 0; - virtual void proc9(uint handle) {} + virtual void proc9(int handle) {} /** * Stops sounds on all playing channels @@ -90,7 +98,7 @@ public: * @param volume New volume * @param seconds Number of seconds to transition to the new volume */ - virtual void setVolume(uint handle, uint volume, uint seconds) = 0; + virtual void setVolume(int handle, uint volume, uint seconds) = 0; /** * Set the position for a sound @@ -100,7 +108,7 @@ public: * @param z z position in metres * @param panRate Rate in milliseconds to transition */ - virtual void setVectorPosition(uint handle, double x, double y, double z, uint panRate) {} + virtual void setVectorPosition(int handle, double x, double y, double z, uint panRate) {} /** * Set the position for a sound @@ -110,12 +118,12 @@ public: * @param elevation Elevation value in degrees * @param panRate Rate in milliseconds to transition */ - virtual void setPolarPosition(uint handle, double range, double azimuth, double elevation, uint panRate) {} + virtual void setPolarPosition(int handle, double range, double azimuth, double elevation, uint panRate) {} /** * Returns true if the given sound is currently active */ - virtual bool isActive(uint handle) const = 0; + virtual bool isActive(int handle) const = 0; /** * Returns true if the given sound is currently active @@ -191,22 +199,22 @@ public: /** * Returns the music volume percent */ - int getMusicVolume() const { return _musicPercent; } + double getMusicVolume() const { return _musicPercent; } /** * Returns the speech volume percent */ - int getSpeechVolume() const { return _speechPercent; } + double getSpeechVolume() const { return _speechPercent; } /** * Returns the parrot volume percent */ - int getParrotVolume() const { return _parrotPercent; } + double getParrotVolume() const { return _parrotPercent; } /** * Gets the volume for a given mode? value */ - uint getModeVolume(int mode); + double getModeVolume(int mode); }; class QSoundManagerSound : public ListItem { @@ -255,10 +263,11 @@ class QSoundManager : public CSoundManager, public QMixer { bool _isTimed; uint _ticks; int _channel; - uint _handle; - uint _val3; + int _handle; + PositioningMode _positioningMode; - Slot() : _waveFile(0), _isTimed(0), _ticks(0), _channel(-1), _handle(0), _val3(0) {} + Slot() : _waveFile(0), _isTimed(0), _ticks(0), _channel(-1), + _handle(0), _positioningMode(POSMODE_NONE) {} void clear(); }; private: @@ -320,7 +329,15 @@ public: */ virtual CWaveFile *loadSpeech(CDialogueFile *dialogueFile, int speechId); - virtual int proc5() const; + /** + * Loads a music file + * @param name Name of music resource + * @returns Loaded wave file + * @remarks The original created a streaming audio buffer for the wave file, + * and passed this to the method. For ScummVM, this has been discarded + * in favor of simply passing the filename. + */ + virtual CWaveFile *loadMusic(const CString &name); /** * Start playing a previously loaded sound resource @@ -330,7 +347,7 @@ public: /** * Stop playing the specified sound */ - virtual void stopSound(uint handle); + virtual void stopSound(int handle); /** * Stops a designated range of channels @@ -340,7 +357,7 @@ public: /** * Flags that a sound can be freed if a timeout is set */ - virtual void setCanFree(uint handle); + virtual void setCanFree(int handle); /** * Stops sounds on all playing channels @@ -353,7 +370,7 @@ public: * @param volume New volume * @param seconds Number of seconds to transition to the new volume */ - virtual void setVolume(uint handle, uint volume, uint seconds); + virtual void setVolume(int handle, uint volume, uint seconds); /** * Set the position for a sound @@ -363,7 +380,7 @@ public: * @param z z position in metres * @param panRate Rate in milliseconds to transition */ - virtual void setVectorPosition(uint handle, double x, double y, double z, uint panRate); + virtual void setVectorPosition(int handle, double x, double y, double z, uint panRate); /** * Set the position for a sound @@ -373,12 +390,12 @@ public: * @param elevation Elevation value in degrees * @param panRate Rate in milliseconds to transition */ - virtual void setPolarPosition(uint handle, double range, double azimuth, double elevation, uint panRate); + virtual void setPolarPosition(int handle, double range, double azimuth, double elevation, uint panRate); /** * Returns true if the given sound is currently active */ - virtual bool isActive(uint handle) const; + virtual bool isActive(int handle) const; /** * Returns true if the given sound is currently active diff --git a/engines/titanic/sound/titania_speech.cpp b/engines/titanic/sound/titania_speech.cpp index f9d5b91705..a07cc79334 100644 --- a/engines/titanic/sound/titania_speech.cpp +++ b/engines/titanic/sound/titania_speech.cpp @@ -24,24 +24,133 @@ namespace Titanic { +BEGIN_MESSAGE_MAP(CTitaniaSpeech, CGameObject) + ON_MESSAGE(ActMsg) + ON_MESSAGE(MovieEndMsg) + ON_MESSAGE(MovieFrameMsg) + ON_MESSAGE(TimerMsg) + ON_MESSAGE(EnterRoomMsg) +END_MESSAGE_MAP() + void CTitaniaSpeech::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_value1, indent); - file->writeNumberLine(_value2, indent); + file->writeNumberLine(_paraNum, indent); + file->writeNumberLine(_frameNum, indent); CGameObject::save(file, indent); } void CTitaniaSpeech::load(SimpleFile *file) { file->readNumber(); - _value1 = file->readNumber(); - _value2 = file->readNumber(); + _paraNum = file->readNumber(); + _frameNum = file->readNumber(); CGameObject::load(file); } +bool CTitaniaSpeech::ActMsg(CActMsg *msg) { + CSetFrameMsg frameMsg; + CVisibleMsg visibleMsg; + CActMsg actMsg; + + if (msg->_action == "TitaniaSpeech") { + switch (_paraNum) { + case 0: + movieSetAudioTiming(true); + loadSound("a#12.wav"); + sleep(1000); + playMovie(0, 187, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + movieEvent(0); + break; + + case 1: + loadSound("a#11.wav"); + addTimer(0); + startAnimTimer("Para2", 300); + addTimer(6000); + addTimer(12000); + addTimer(18000); + addTimer(24000); + startAnimTimer("NextPara", 30000); + break; + + case 2: + visibleMsg._visible = false; + visibleMsg.execute("TitaniaStillControl"); + loadSound("a#10.wav"); + playMovie(585, 706, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playSound("a#10.wav"); + break; + + case 3: + visibleMsg._visible = false; + visibleMsg.execute("TitaniaStillControl"); + loadSound("a#9.wav"); + playMovie(707, 905, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playSound("a#9.wav"); + break; + + case 4: + visibleMsg._visible = false; + visibleMsg.execute("TitaniaStillControl"); + loadSound("a#8.wav"); + playMovie(906, 938, MOVIE_GAMESTATE || MOVIE_NOTIFY_OBJECT); + playSound("a#8.wav"); + break; + + default: + sleep(3000); + actMsg._action = "SleepTitania"; + actMsg.execute(this); + } + } + + return true; +} + +bool CTitaniaSpeech::MovieEndMsg(CMovieEndMsg *msg) { + if (_paraNum == 5) { + startAnimTimer("NextPara", 0); + } else { + if (_paraNum != 1) + addTimer(0); + startAnimTimer("NextPara", 3000); + } + + return true; +} + +bool CTitaniaSpeech::MovieFrameMsg(CMovieFrameMsg *msg) { + int frame = getMovieFrame(); + if (!frame) + playSound("a#12.wav"); + + return true; +} + +bool CTitaniaSpeech::TimerMsg(CTimerMsg *msg) { + CSetFrameMsg frameMsg; + CVisibleMsg visibleMsg; + CActMsg actMsg("TitaniaSpeech"); + + if (msg->_action == "NextPara") { + visibleMsg.execute("TitaniaStillControl"); + ++_paraNum; + actMsg.execute(this); + } else if (msg->_action == "Para2") { + playSound("a#11.wav"); + } else { + frameMsg._frameNumber = _frameNum; + frameMsg.execute("TitaniaStillControl"); + } + + return true; +} + bool CTitaniaSpeech::EnterRoomMsg(CEnterRoomMsg *msg) { - warning("CTitaniaSpeech::handleEvent"); + CActMsg actMsg("Disable"); + actMsg.execute("ShipAnnouncements"); + return true; } diff --git a/engines/titanic/sound/titania_speech.h b/engines/titanic/sound/titania_speech.h index c9b93043f6..2244bb01af 100644 --- a/engines/titanic/sound/titania_speech.h +++ b/engines/titanic/sound/titania_speech.h @@ -29,12 +29,17 @@ namespace Titanic { class CTitaniaSpeech : public CGameObject { + DECLARE_MESSAGE_MAP; + bool ActMsg(CActMsg *msg); + bool MovieEndMsg(CMovieEndMsg *msg); + bool MovieFrameMsg(CMovieFrameMsg *msg); + bool TimerMsg(CTimerMsg *msg); bool EnterRoomMsg(CEnterRoomMsg *msg); private: - int _value1, _value2; + int _paraNum, _frameNum; public: CLASSDEF; - CTitaniaSpeech() : CGameObject(), _value1(1), _value2(0) {} + CTitaniaSpeech() : CGameObject(), _paraNum(1), _frameNum(0) {} /** * Save the data for the class to file diff --git a/engines/titanic/sound/view_toggles_other_music.cpp b/engines/titanic/sound/view_toggles_other_music.cpp index 35888fba9d..731f59bd53 100644 --- a/engines/titanic/sound/view_toggles_other_music.cpp +++ b/engines/titanic/sound/view_toggles_other_music.cpp @@ -24,21 +24,35 @@ namespace Titanic { -CViewTogglesOtherMusic::CViewTogglesOtherMusic() : CEnterViewTogglesOtherMusic(), _fieldCC(0) { +BEGIN_MESSAGE_MAP(CViewTogglesOtherMusic, CEnterViewTogglesOtherMusic) + ON_MESSAGE(LeaveViewMsg) +END_MESSAGE_MAP() + +CViewTogglesOtherMusic::CViewTogglesOtherMusic() : + CEnterViewTogglesOtherMusic(), _value(1) { } void CViewTogglesOtherMusic::save(SimpleFile *file, int indent) { file->writeNumberLine(1, indent); - file->writeNumberLine(_fieldCC, indent); + file->writeNumberLine(_value, indent); CEnterViewTogglesOtherMusic::save(file, indent); } void CViewTogglesOtherMusic::load(SimpleFile *file) { file->readNumber(); - _fieldCC = file->readNumber(); + _value = file->readNumber(); CEnterViewTogglesOtherMusic::load(file); } +bool CViewTogglesOtherMusic::LeaveViewMsg(CLeaveViewMsg *msg) { + if (msg->_oldView == findView()) { + CTriggerAutoMusicPlayerMsg playerMsg(_value); + playerMsg.execute(this); + } + + return true; +} + } // End of namespace Titanic diff --git a/engines/titanic/sound/view_toggles_other_music.h b/engines/titanic/sound/view_toggles_other_music.h index a5ba68ba45..1b5f110e70 100644 --- a/engines/titanic/sound/view_toggles_other_music.h +++ b/engines/titanic/sound/view_toggles_other_music.h @@ -28,8 +28,10 @@ namespace Titanic { class CViewTogglesOtherMusic : public CEnterViewTogglesOtherMusic { + DECLARE_MESSAGE_MAP; + bool LeaveViewMsg(CLeaveViewMsg *msg); private: - int _fieldCC; + int _value; public: CLASSDEF; CViewTogglesOtherMusic(); diff --git a/engines/titanic/sound/wave_file.cpp b/engines/titanic/sound/wave_file.cpp index 7093856217..8c00637d73 100644 --- a/engines/titanic/sound/wave_file.cpp +++ b/engines/titanic/sound/wave_file.cpp @@ -28,11 +28,12 @@ namespace Titanic { -CWaveFile::CWaveFile() : _owner(nullptr), _stream(nullptr), _soundType(SOUND_SFX) { +CWaveFile::CWaveFile() : _owner(nullptr), _stream(nullptr), + _soundType(Audio::Mixer::kPlainSoundType) { } CWaveFile::CWaveFile(QSoundManager *owner) : _owner(owner), _stream(nullptr), - _soundType(SOUND_SFX) { + _soundType(Audio::Mixer::kPlainSoundType) { } CWaveFile::~CWaveFile() { @@ -57,7 +58,8 @@ bool CWaveFile::loadSound(const CString &name) { Common::SeekableReadStream *stream = file.readStream(); _size = stream->size(); _stream = Audio::makeWAVStream(stream->readStream(_size), DisposeAfterUse::YES); - _soundType = SOUND_SFX; + _soundType = Audio::Mixer::kSFXSoundType; + return true; } @@ -72,7 +74,23 @@ bool CWaveFile::loadSpeech(CDialogueFile *dialogueFile, int speechIndex) { _size = res->_size; _stream = Audio::makeWAVStream(new Common::MemoryReadStream(data, _size, DisposeAfterUse::YES), DisposeAfterUse::YES); - _soundType = SOUND_SPEECH; + _soundType = Audio::Mixer::kSpeechSoundType; + + return true; +} + +bool CWaveFile::loadMusic(const CString &name) { + assert(!_stream); + + StdCWadFile file; + if (!file.open(name)) + return false; + + Common::SeekableReadStream *stream = file.readStream(); + _size = stream->size(); + _stream = Audio::makeWAVStream(stream->readStream(_size), DisposeAfterUse::YES); + _soundType = Audio::Mixer::kMusicSoundType; + return true; } diff --git a/engines/titanic/sound/wave_file.h b/engines/titanic/sound/wave_file.h index 33b2a8dedf..aede0c9328 100644 --- a/engines/titanic/sound/wave_file.h +++ b/engines/titanic/sound/wave_file.h @@ -32,19 +32,14 @@ namespace Titanic { class QSoundManager; -enum SoundType { - SOUND_SFX = 0, - SOUND_SPEECH = 1 -}; - class CWaveFile { private: uint _size; public: QSoundManager *_owner; - Audio::AudioStream *_stream; + Audio::SeekableAudioStream *_stream; Audio::SoundHandle _soundHandle; - SoundType _soundType; + Audio::Mixer::SoundType _soundType; public: CWaveFile(); CWaveFile(QSoundManager *owner); @@ -68,6 +63,11 @@ public: bool loadSpeech(CDialogueFile *dialogueFile, int speechIndex); /** + * Tries to load the specified music wave file + */ + bool loadMusic(const CString &name); + + /** * Returns true if the wave file has data loaded */ bool isLoaded() const { return _stream != nullptr; } diff --git a/engines/titanic/support/movie.cpp b/engines/titanic/support/movie.cpp index 5453d8ca9c..3bb9fb88cf 100644 --- a/engines/titanic/support/movie.cpp +++ b/engines/titanic/support/movie.cpp @@ -37,7 +37,7 @@ CMovieList *CMovie::_playingMovies; CVideoSurface *CMovie::_movieSurface; CMovie::CMovie() : ListItem(), _handled(false), _hasVideoFrame(false), - _field14(0) { + _hasAudioTiming(false) { } CMovie::~CMovie() { diff --git a/engines/titanic/support/movie.h b/engines/titanic/support/movie.h index 2a7d589194..2d1c264f03 100644 --- a/engines/titanic/support/movie.h +++ b/engines/titanic/support/movie.h @@ -50,7 +50,7 @@ protected: public: bool _handled; bool _hasVideoFrame; - int _field14; + bool _hasAudioTiming; public: static CMovieList *_playingMovies; static CVideoSurface *_movieSurface; diff --git a/engines/titanic/titanic.h b/engines/titanic/titanic.h index ec015551b8..3c71f68b6e 100644 --- a/engines/titanic/titanic.h +++ b/engines/titanic/titanic.h @@ -58,6 +58,13 @@ enum TitanicDebugChannels { kDebugSound = 1 << 3 }; +enum Season { + SPRING = 0, + SUMMER = 1, + AUTUMN = 2, + WINTER = 3 +}; + #define TITANIC_SAVEGAME_VERSION 1 #define SCREEN_WIDTH 640 diff --git a/engines/titanic/true_talk/true_talk_manager.cpp b/engines/titanic/true_talk/true_talk_manager.cpp index 82d443fcda..977edd5399 100644 --- a/engines/titanic/true_talk/true_talk_manager.cpp +++ b/engines/titanic/true_talk/true_talk_manager.cpp @@ -505,13 +505,13 @@ void CTrueTalkManager::playSpeech(TTtalker *talker, TTroomScript *roomScript, CV if (milli > 0) { p3._channelVolume = (index * 3) / 2; - p3._field28 = 1; + p3._positioningMode = POSMODE_POLAR; p3._azimuth = -135.0; p3._range = 1.0; p3._elevation = 0; p2._channelVolume = (index * 3) / 4; - p2._field28 = 0; + p2._positioningMode = POSMODE_NONE; p2._azimuth = 135.0; p2._range = 1.0; p2._elevation = 0; @@ -519,10 +519,13 @@ void CTrueTalkManager::playSpeech(TTtalker *talker, TTroomScript *roomScript, CV _gameManager->_sound.stopChannel(p1._channel); if (view) { - p1._field28 = 2; + p1._positioningMode = POSMODE_VECTOR; view->getPosition(p1._posX, p1._posY, p1._posZ); } + // Loop through adding each of the speech portions in. We use the + // _priorSoundHandle of CProximity to chain each successive speech + // to start when the prior one finishes for (uint idx = 0; idx < _titleEngine._indexes.size(); ++idx) { uint id = _titleEngine._indexes[idx]; if (id > 100000) @@ -535,18 +538,18 @@ void CTrueTalkManager::playSpeech(TTtalker *talker, TTroomScript *roomScript, CV } // Start the speech - p1._soundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p1); + p1._priorSoundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p1); if (!milli) continue; if (idx == 0) g_vm->_events->sleep(milli); - p3._soundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p3); + p3._priorSoundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p3); if (idx == 0) g_vm->_events->sleep(milli); - p2._soundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p2); + p2._priorSoundHandle = _gameManager->_sound.playSpeech(_dialogueFile, id - _dialogueId, p2); } } |