aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--NEWS3
-rw-r--r--backends/graphics/opengl/opengl-sys.h12
-rw-r--r--base/plugins.h8
-rw-r--r--common/gui_options.h2
-rw-r--r--common/scummsys.h6
-rw-r--r--devtools/create_project/create_project.cpp4
-rw-r--r--engines/adl/display.cpp8
-rw-r--r--engines/adl/display.h1
-rw-r--r--engines/director/lingo/lingo-builtins.cpp344
-rw-r--r--engines/director/lingo/lingo-code.cpp53
-rw-r--r--engines/director/lingo/lingo-codegen.cpp12
-rw-r--r--engines/director/lingo/lingo-gr.cpp1118
-rw-r--r--engines/director/lingo/lingo-gr.h240
-rw-r--r--engines/director/lingo/lingo-gr.y13
-rw-r--r--engines/director/lingo/lingo-lex.cpp474
-rw-r--r--engines/director/lingo/lingo-lex.l2
-rw-r--r--engines/director/lingo/lingo-the.cpp4
-rw-r--r--engines/director/lingo/lingo-the.h2
-rw-r--r--engines/director/lingo/lingo.cpp19
-rw-r--r--engines/director/lingo/lingo.h153
-rw-r--r--engines/director/lingo/tests/factory2.lingo4
-rw-r--r--engines/fullpipe/gfx.cpp2
-rw-r--r--engines/fullpipe/interaction.cpp2
-rw-r--r--engines/fullpipe/mgm.cpp2
-rw-r--r--engines/mohawk/console.cpp1
-rw-r--r--engines/mohawk/cstime.cpp3
-rw-r--r--engines/mohawk/cstime.h1
-rw-r--r--engines/mohawk/livingbooks.cpp3
-rw-r--r--engines/mohawk/livingbooks.h1
-rw-r--r--engines/mohawk/module.mk1
-rw-r--r--engines/mohawk/mohawk.cpp9
-rw-r--r--engines/mohawk/mohawk.h1
-rw-r--r--engines/mohawk/myst.cpp3
-rw-r--r--engines/mohawk/myst.h1
-rw-r--r--engines/mohawk/riven.cpp7
-rw-r--r--engines/mohawk/riven.h2
-rw-r--r--engines/mohawk/riven_external.cpp6
-rw-r--r--engines/mohawk/riven_graphics.cpp2
-rw-r--r--engines/mohawk/riven_scripts.cpp46
-rw-r--r--engines/mohawk/riven_sound.cpp459
-rw-r--r--engines/mohawk/riven_sound.h197
-rw-r--r--engines/mohawk/sound.cpp451
-rw-r--r--engines/mohawk/sound.h37
-rw-r--r--engines/sci/console.cpp1
-rw-r--r--engines/sci/engine/features.cpp47
-rw-r--r--engines/sci/engine/features.h14
-rw-r--r--engines/sci/engine/kernel.h11
-rw-r--r--engines/sci/engine/kernel_tables.h29
-rw-r--r--engines/sci/engine/kevent.cpp9
-rw-r--r--engines/sci/engine/kfile.cpp55
-rw-r--r--engines/sci/engine/klists.cpp29
-rw-r--r--engines/sci/engine/kmisc.cpp16
-rw-r--r--engines/sci/engine/kvideo.cpp166
-rw-r--r--engines/sci/engine/segment.h15
-rw-r--r--engines/sci/engine/vm.cpp15
-rw-r--r--engines/sci/engine/workarounds.cpp2
-rw-r--r--engines/sci/graphics/frameout.cpp12
-rw-r--r--engines/sci/graphics/frameout.h3
-rw-r--r--engines/sci/graphics/video32.cpp479
-rw-r--r--engines/sci/graphics/video32.h211
-rw-r--r--engines/titanic/carry/auditory_centre.cpp10
-rw-r--r--engines/titanic/carry/auditory_centre.h2
-rw-r--r--engines/titanic/core/background.cpp14
-rw-r--r--engines/titanic/core/background.h4
-rw-r--r--engines/titanic/core/game_object.cpp27
-rw-r--r--engines/titanic/core/game_object.h19
-rw-r--r--engines/titanic/events.cpp10
-rw-r--r--engines/titanic/game/announce.cpp101
-rw-r--r--engines/titanic/game/announce.h12
-rw-r--r--engines/titanic/game/annoy_barbot.cpp13
-rw-r--r--engines/titanic/game/annoy_barbot.h2
-rw-r--r--engines/titanic/game/arboretum_gate.cpp358
-rw-r--r--engines/titanic/game/arboretum_gate.h61
-rw-r--r--engines/titanic/game/auto_animate.cpp30
-rw-r--r--engines/titanic/game/auto_animate.h8
-rw-r--r--engines/titanic/game/bar_bell.cpp83
-rw-r--r--engines/titanic/game/bar_bell.h8
-rw-r--r--engines/titanic/game/sgt/armchair.cpp50
-rw-r--r--engines/titanic/game/sgt/armchair.h4
-rw-r--r--engines/titanic/game/sgt/sgt_state_room.h4
-rw-r--r--engines/titanic/gfx/act_button.cpp10
-rw-r--r--engines/titanic/gfx/act_button.h2
-rw-r--r--engines/titanic/gfx/st_button.cpp14
-rw-r--r--engines/titanic/gfx/st_button.h6
-rw-r--r--engines/titanic/messages/auto_sound_event.cpp13
-rw-r--r--engines/titanic/messages/auto_sound_event.h2
-rw-r--r--engines/titanic/messages/messages.h2
-rw-r--r--engines/titanic/module.mk1
-rw-r--r--engines/titanic/npcs/barbot.cpp86
-rw-r--r--engines/titanic/npcs/barbot.h14
-rw-r--r--engines/titanic/npcs/callbot.cpp38
-rw-r--r--engines/titanic/npcs/callbot.h7
-rw-r--r--engines/titanic/npcs/robot_controller.cpp22
-rw-r--r--engines/titanic/npcs/robot_controller.h5
-rw-r--r--engines/titanic/npcs/starlings.cpp25
-rw-r--r--engines/titanic/npcs/starlings.h5
-rw-r--r--engines/titanic/npcs/true_talk_npc.cpp8
-rw-r--r--engines/titanic/npcs/true_talk_npc.h5
-rw-r--r--engines/titanic/sound/auto_sound_player.cpp2
-rw-r--r--engines/titanic/sound/gondolier_song.cpp59
-rw-r--r--engines/titanic/sound/gondolier_song.h8
-rw-r--r--engines/titanic/sound/music_handler.cpp44
-rw-r--r--engines/titanic/sound/music_handler.h28
-rw-r--r--engines/titanic/sound/music_player.cpp40
-rw-r--r--engines/titanic/sound/music_player.h4
-rw-r--r--engines/titanic/sound/music_room.cpp3
-rw-r--r--engines/titanic/sound/music_wave.cpp54
-rw-r--r--engines/titanic/sound/music_wave.h71
-rw-r--r--engines/titanic/sound/proximity.cpp6
-rw-r--r--engines/titanic/sound/proximity.h8
-rw-r--r--engines/titanic/sound/qmixer.cpp74
-rw-r--r--engines/titanic/sound/qmixer.h22
-rw-r--r--engines/titanic/sound/restricted_auto_music_player.cpp47
-rw-r--r--engines/titanic/sound/restricted_auto_music_player.h10
-rw-r--r--engines/titanic/sound/room_trigger_auto_music_player.cpp22
-rw-r--r--engines/titanic/sound/room_trigger_auto_music_player.h4
-rw-r--r--engines/titanic/sound/season_noises.cpp86
-rw-r--r--engines/titanic/sound/season_noises.h15
-rw-r--r--engines/titanic/sound/sound.cpp26
-rw-r--r--engines/titanic/sound/sound.h15
-rw-r--r--engines/titanic/sound/sound_manager.cpp59
-rw-r--r--engines/titanic/sound/sound_manager.h59
-rw-r--r--engines/titanic/sound/titania_speech.cpp119
-rw-r--r--engines/titanic/sound/titania_speech.h9
-rw-r--r--engines/titanic/sound/view_toggles_other_music.cpp20
-rw-r--r--engines/titanic/sound/view_toggles_other_music.h4
-rw-r--r--engines/titanic/sound/wave_file.cpp26
-rw-r--r--engines/titanic/sound/wave_file.h14
-rw-r--r--engines/titanic/support/movie.cpp2
-rw-r--r--engines/titanic/support/movie.h2
-rw-r--r--engines/titanic/titanic.h7
-rw-r--r--engines/titanic/true_talk/true_talk_manager.cpp15
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
diff --git a/NEWS b/NEWS
index fc2c10a4d1..4557506e08 100644
--- a/NEWS
+++ b/NEWS
@@ -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 &currentBuffer = 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 &currentBuffer = 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 &params) {
- // Not currently implemented in ScummVM
+int QMixer::qsWaveMixPlayEx(int iChannel, uint flags, CWaveFile *waveFile, int loops, const QMIXPLAYPARAMS &params) {
+ 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);
}
}