diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 96bd87f2ebd..3c80c1f16ba 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -180,28 +180,42 @@ Common::Error GroovieEngine::run() { error("GROOVIE: Unknown Game version. groovie.cpp:run()"); } - // Detect ScummVM Music Enhancement Project presence (T7G only) - if (Common::File::exists("gu16.ogg") && _gameDescription->version == kGroovieT7G) { - // Load player for external files - _musicPlayer = new MusicPlayerIOS(this); - } else { - // Create the music player - switch (getPlatform()) { - case Common::kPlatformMacintosh: - if (_gameDescription->version == kGroovieT7G) - _musicPlayer = new MusicPlayerMac_t7g(this); - else - _musicPlayer = new MusicPlayerMac_v2(this); - break; - case Common::kPlatformIOS: + + switch (_gameDescription->version) { + case kGroovieT7G: + case kGroovieT11H: + case kGroovieCDY: + case kGroovieUHP: + // Detect ScummVM Music Enhancement Project presence (T7G only) + if (Common::File::exists("gu16.ogg") && _gameDescription->version == kGroovieT7G) { + // Load player for external files _musicPlayer = new MusicPlayerIOS(this); - break; - default: - _musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample"); - break; } + else { + // Create the music player + switch (getPlatform()) { + case Common::kPlatformMacintosh: + if (_gameDescription->version == kGroovieT7G) + _musicPlayer = new MusicPlayerMac_t7g(this); + else + _musicPlayer = new MusicPlayerMac_v2(this); + break; + case Common::kPlatformIOS: + _musicPlayer = new MusicPlayerIOS(this); + break; + default: + _musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample"); + break; + } + } + break; + + case kGroovieTLC: + _musicPlayer = new MusicPlayerTlc(this); + break; } + // Load volume levels syncSoundSettings(); @@ -268,7 +282,7 @@ Common::Error GroovieEngine::run() { // Check that the game files and the audio tracks aren't together run from // the same cd - if (getPlatform() != Common::kPlatformIOS) { + if (getPlatform() != Common::kPlatformIOS && _gameDescription->version != kGroovieTLC) { if (!existExtractedCDAudioFiles() && !isDataAndCDAudioReadFromSameCD()) { warnMissingExtractedCDAudio(); diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp index 4640f59615e..5e53b92ccf7 100644 --- a/engines/groovie/music.cpp +++ b/engines/groovie/music.cpp @@ -26,6 +26,7 @@ #include "groovie/music.h" #include "groovie/groovie.h" #include "groovie/resource.h" +#include "groovie/tlcgame.h" #include "backends/audiocd/audiocd.h" #include "common/config-manager.h" @@ -37,6 +38,7 @@ #include "audio/audiostream.h" #include "audio/midiparser.h" #include "audio/miles.h" +#include "audio/decoders/mp3.h" namespace Groovie { @@ -746,4 +748,59 @@ bool MusicPlayerIOS::load(uint32 fileref, bool loop) { return true; } + +MusicPlayerTlc::MusicPlayerTlc(GroovieEngine *vm) : MusicPlayer(vm) { + vm->getTimerManager()->installTimerProc(&onTimer, 50 * 1000, this, "groovieMusic"); +} + +MusicPlayerTlc::~MusicPlayerTlc() { + _vm->getTimerManager()->removeTimerProc(&onTimer); +} + +void MusicPlayerTlc::updateVolume() { + // Just set the mixer volume for the music sound type + _vm->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _userVolume * _gameVolume / 100); +} + +void MusicPlayerTlc::unload() { + MusicPlayer::unload(); + + _vm->_system->getMixer()->stopHandle(_handle); +} + +bool MusicPlayerTlc::load(uint32 fileref, bool loop) { + // Find correct filename + Common::String filename; + Common::File *fileHandle = new Common::File(); + Audio::SeekableAudioStream *seekStream = NULL; + + // Create the audio stream from fileref + filename = TlcGame::getTlcMusicFilename(fileref); + fileHandle->open(filename); + if (fileHandle->isOpen()) { + seekStream = Audio::makeMP3Stream(fileHandle, DisposeAfterUse::YES); + } else { + delete fileHandle; + } + + if (!seekStream) { + warning("Could not play audio file '%s'", filename.c_str()); + return false; + } + + Audio::AudioStream *audStream = seekStream; + + // Loop if requested + if (loop || 1) + audStream = Audio::makeLoopingAudioStream(seekStream, 0); + + // MIDI player handles volume reset on load, IOS player doesn't - force update here + updateVolume(); + + // Play! + _vm->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_handle, audStream); + return true; +} + + } // End of Groovie namespace diff --git a/engines/groovie/music.h b/engines/groovie/music.h index 35a4ae0cbd3..06d1408fc59 100644 --- a/engines/groovie/music.h +++ b/engines/groovie/music.h @@ -35,6 +35,7 @@ class MidiParser; namespace Groovie { class GroovieEngine; +class TlcGame; class MusicPlayer { public: @@ -204,6 +205,20 @@ private: Audio::SoundHandle _handle; }; +class MusicPlayerTlc : public MusicPlayer { +public: + MusicPlayerTlc(GroovieEngine *vm); + ~MusicPlayerTlc(); + +protected: + void updateVolume(); + bool load(uint32 fileref, bool loop); + void unload(); + +private: + Audio::SoundHandle _handle; +}; + } // End of Groovie namespace #endif // GROOVIE_MUSIC_H diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index 17dab95fc70..e81f12b74fd 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -371,8 +371,7 @@ uint8 Script::readScriptChar(bool allow7C, bool limitVal, bool limitVar) { return result; } -uint32 Script::getVideoRefString() { - Common::String str; +void Script::readScriptString(Common::String &str) { byte c; while ((c = readScript8bits())) { @@ -398,17 +397,22 @@ uint32 Script::getVideoRefString() { // Append the current character at the end of the string str += c; } +} + +uint32 Script::getVideoRefString(Common::String &resName) { + // Read String from Script (includes variable values) + readScriptString(resName); // Add a trailing dot - str += 0x2E; + resName += 0x2E; - debugCN(0, kDebugScript, "%s", str.c_str()); + debugCN(0, kDebugScript, "%s", resName.c_str()); // Extract the script name. Common::String scriptname(_scriptFile.c_str(), _scriptFile.size() - 4); // Get the fileref of the resource - return _vm->_resMan->getRef(str, scriptname); + return _vm->_resMan->getRef(resName, scriptname); } bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { @@ -521,77 +525,82 @@ void Script::printString(Graphics::Surface *surface, const char *str) { Common::rtrim(message); // Draw the string - _vm->_font->drawString(surface, message, 0, 16, 640, 0xE2, Graphics::kTextAlignCenter); + if (_version == kGroovieT7G) { + _vm->_font->drawString(surface, message, 0, 16, 640, 0xE2, Graphics::kTextAlignCenter); + } else { + _vm->_font->drawString(surface, message, 190, 190, 640, _vm->_pixelFormat.RGBToColor(0xff, 0x0A, 0x0A), Graphics::kTextAlignLeft); + } } // OPCODES void Script::o_invalid() { - error("Invalid opcode"); + error("Groovie::Script: Invalid opcode"); } void Script::o_nop() { - debugC(1, kDebugScript, "NOP"); + debugC(1, kDebugScript, "Groovie::Script: NOP"); } void Script::o_nop8() { uint8 tmp = readScript8bits(); - debugC(1, kDebugScript, "NOP8: 0x%02X", tmp); + debugC(1, kDebugScript, "Groovie::Script: NOP8: 0x%02X", tmp); } void Script::o_nop16() { uint16 tmp = readScript16bits(); - debugC(1, kDebugScript, "NOP16: 0x%04X", tmp); + debugC(1, kDebugScript, "Groovie::Script: NOP16: 0x%04X", tmp); } void Script::o_nop32() { uint32 tmp = readScript32bits(); - debugC(1, kDebugScript, "NOP32: 0x%08X", tmp); + debugC(1, kDebugScript, "Groovie::Script: NOP32: 0x%08X", tmp); } void Script::o_nop8or16() { uint16 tmp = readScript8or16bits(); - debugC(1, kDebugScript, "NOP8OR16: 0x%04X", tmp); + debugC(1, kDebugScript, "Groovie::Script: NOP8OR16: 0x%04X", tmp); } void Script::o_playsong() { // 0x02 uint16 fileref = readScript16bits(); - debugC(1, kDebugScript, "PlaySong(0x%04X): Play xmidi file", fileref); + debugC(1, kDebugScript, "Groovie::Script: PlaySong(0x%04X): Play xmidi file", fileref); if (fileref == 0x4C17) { - warning("this song is special somehow"); + warning("Groovie::Script: this song is special somehow"); // don't save the reference? } _vm->_musicPlayer->playSong(fileref); } void Script::o_bf9on() { // 0x03 - debugC(1, kDebugScript, "BF9ON: bitflag 9 turned on"); + debugC(1, kDebugScript, "Groovie::Script: BF9ON: bitflag 9 turned on"); _bitflags |= 1 << 9; } void Script::o_palfadeout() { - debugC(1, kDebugScript, "PALFADEOUT"); + debugC(1, kDebugScript, "Groovie::Script: PALFADEOUT"); + debugC(2, kDebugVideo, "Groovie::Script: PALFADEOUT"); _vm->_graphicsMan->fadeOut(); } void Script::o_bf8on() { // 0x05 - debugC(1, kDebugScript, "BF8ON: bitflag 8 turned on"); + debugC(1, kDebugScript, "Groovie::Script: BF8ON: bitflag 8 turned on"); _bitflags |= 1 << 8; } void Script::o_bf6on() { // 0x06 - debugC(1, kDebugScript, "BF6ON: bitflag 6 turned on"); + debugC(1, kDebugScript, "Groovie::Script: BF6ON: bitflag 6 turned on"); _bitflags |= 1 << 6; } void Script::o_bf7on() { // 0x07 - debugC(1, kDebugScript, "BF7ON: bitflag 7 turned on"); + debugC(1, kDebugScript, "Groovie::Script: BF7ON: bitflag 7 turned on"); _bitflags |= 1 << 7; } void Script::o_setbackgroundsong() { // 0x08 uint16 fileref = readScript16bits(); - debugC(1, kDebugScript, "SetBackgroundSong(0x%04X)", fileref); + debugC(1, kDebugScript, "Groovie::Script: SetBackgroundSong(0x%04X)", fileref); _vm->_musicPlayer->setBackgroundSong(fileref); } @@ -600,15 +609,15 @@ void Script::o_videofromref() { // 0x09 // Show the debug information just when starting the playback if (fileref != _videoRef) { - debugC(1, kDebugScript, "VIDEOFROMREF(0x%04X) (Not fully imp): Play video file from ref", fileref); - debugC(5, kDebugVideo, "Playing video 0x%04X via 0x09", fileref); + debugC(1, kDebugScript, "Groovie::Script: VIDEOFROMREF(0x%04X) (Not fully imp): Play video file from ref", fileref); + debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing video %d via 0x09 (VideoFromRef)", _currentInstruction-3, fileref); } switch (fileref) { case 0x1C03: // Trilobyte logo case 0x1C04: // Virgin logo case 0x1C05: // Credits if (fileref != _videoRef) { - debugC(1, kDebugScript, "Use external file if available"); + debugC(1, kDebugScript, "Groovie::Script: Use external file if available"); } break; @@ -620,8 +629,8 @@ void Script::o_videofromref() { // 0x09 case 0x206D: // Cards on table puzzle (bedroom) case 0x2001: // Coins on table puzzle (bedroom) if (fileref != _videoRef) { - debugCN(1, kDebugScript, " (This video is special somehow!)"); - warning("(This video (0x%04X) is special somehow!)", fileref); + debugCN(1, kDebugScript, "Groovie::Script: (This video is special somehow!)"); + warning("Groovie::Script: (This video (0x%04X) is special somehow!)", fileref); } default: @@ -659,7 +668,7 @@ bool Script::playvideofromref(uint32 fileref, bool loopUntilAudioDone) { if (fileref != _videoRef) { // Debug bitflags - debugCN(1, kDebugScript, "Play video 0x%04X (bitflags:", fileref); + debugCN(1, kDebugScript, "Groovie::Script: Play video 0x%04X (bitflags:", fileref); for (int i = 15; i >= 0; i--) { debugCN(1, kDebugScript, "%d", _bitflags & (1 << i)? 1 : 0); if (i % 4 == 0) { @@ -685,7 +694,7 @@ bool Script::playvideofromref(uint32 fileref, bool loopUntilAudioDone) { _bitflags |= (1 << 15); _vm->_videoPlayer->load(_videoFile, _bitflags); } else { - error("Couldn't open file"); + error("Groovie::Script: Couldn't open file"); return true; } @@ -751,12 +760,12 @@ bool Script::playvideofromref(uint32 fileref, bool loopUntilAudioDone) { } void Script::o_bf5on() { // 0x0A - debugC(1, kDebugScript, "BF5ON: bitflag 5 turned on"); + debugC(1, kDebugScript, "Groovie::Script: BF5ON: bitflag 5 turned on"); _bitflags |= 1 << 5; } void Script::o_inputloopstart() { //0x0B - debugC(5, kDebugScript, "Input loop start"); + debugC(5, kDebugScript, "Groovie::Script: Input loop start"); // For TLC the regions for many questions are in an extra database. Reset internal region counters if (_version == kGroovieTLC && _tlcGame != NULL) { @@ -785,13 +794,13 @@ void Script::o_keyboardaction() { // If there's an already planned action, do nothing if (_inputAction != -1) { - debugC(5, kDebugScript, "Test key == 0x%02X @0x%04X - skipped", val, address); + debugC(5, kDebugScript, "Groovie::Script: Test key == 0x%02X @0x%04X - skipped", val, address); return; } // Check the typed key if (_kbdChar == val) { - debugC(5, kDebugScript, "Test key == 0x%02X @0x%04X - match", val, address); + debugC(5, kDebugScript, "Groovie::Script: Test key == 0x%02X @0x%04X - match", val, address); // Exit the input loop _inputLoopAddress = 0; @@ -799,7 +808,7 @@ void Script::o_keyboardaction() { // Save the action address _inputAction = address; } else { - debugC(5, kDebugScript, "Test key == 0x%02X @0x%04X", val, address); + debugC(5, kDebugScript, "Groovie::Script: Test key == 0x%02X @0x%04X", val, address); } } @@ -814,12 +823,12 @@ void Script::o_hotspot_rect() { // TLC: The regions for many questions are in an extra database if (_version == kGroovieTLC && left == 0 && top == 0 && right == 0 && bottom == 0 && _tlcGame != NULL) { if (_tlcGame->getRegionNext(left, top, right, bottom) < 0) { - debugC(5, kDebugScript, "HOTSPOT-RECT(x,x,x,x) @0x%04X cursor=%d SKIPPED", left, top, right, bottom, address, cursor); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-RECT(x,x,x,x) @0x%04X cursor=%d SKIPPED", left, top, right, bottom, address, cursor); return; } } - debugC(5, kDebugScript, "HOTSPOT-RECT(%d,%d,%d,%d) @0x%04X cursor=%d", left, top, right, bottom, address, cursor); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-RECT(%d,%d,%d,%d) @0x%04X cursor=%d", left, top, right, bottom, address, cursor); // Mark the specified rectangle Common::Rect rect(left, top, right, bottom); @@ -829,7 +838,7 @@ void Script::o_hotspot_rect() { void Script::o_hotspot_left() { uint16 address = readScript16bits(); - debugC(5, kDebugScript, "HOTSPOT-LEFT @0x%04X", address); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-LEFT @0x%04X", address); // Mark the leftmost 100 pixels of the game area Common::Rect rect(0, 80, 100, 400); @@ -839,7 +848,7 @@ void Script::o_hotspot_left() { void Script::o_hotspot_right() { uint16 address = readScript16bits(); - debugC(5, kDebugScript, "HOTSPOT-RIGHT @0x%04X", address); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-RIGHT @0x%04X", address); // Mark the rightmost 100 pixels of the game area Common::Rect rect(540, 80, 640, 400); @@ -849,7 +858,7 @@ void Script::o_hotspot_right() { void Script::o_hotspot_center() { uint16 address = readScript16bits(); - debugC(5, kDebugScript, "HOTSPOT-CENTER @0x%04X", address); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-CENTER @0x%04X", address); // Mark the centermost 240 pixels of the game area Common::Rect rect(200, 80, 440, 400); @@ -859,7 +868,7 @@ void Script::o_hotspot_center() { void Script::o_hotspot_current() { uint16 address = readScript16bits(); - debugC(5, kDebugScript, "HOTSPOT-CURRENT @0x%04X", address); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-CURRENT @0x%04X", address); // The original interpreter doesn't check the position, so accept the // whole screen @@ -868,7 +877,7 @@ void Script::o_hotspot_current() { } void Script::o_inputloopend() { - debugC(5, kDebugScript, "Input loop end"); + debugC(5, kDebugScript, "Groovie::Script: Input loop end"); // Handle the predefined hotspots if (_hotspotTopAction) { @@ -921,15 +930,20 @@ void Script::o_random() { uint16 varnum = readScript8or16bits(); uint8 maxnum = readScript8bits(); - debugC(1, kDebugScript, "RANDOM: var[0x%04X] = rand(%d)", varnum, maxnum); + debugC(1, kDebugScript, "Groovie::Script: RANDOM: var[0x%04X] = rand(%d)", varnum, maxnum); - setVariable(varnum, _random.getRandomNumber(maxnum)); + // TODO: Check if this is really different between the Engines + if (_version == kGroovieT7G) { + setVariable(varnum, _random.getRandomNumber(maxnum)); + } else { + setVariable(varnum, _random.getRandomNumber(maxnum-1)); + } } void Script::o_jmp() { uint16 address = readScript16bits(); - debugC(1, kDebugScript, "JMP @0x%04X", address); + debugC(1, kDebugScript, "Groovie::Script: JMP @0x%04X", address); // Set the current address _currentInstruction = address; @@ -938,7 +952,7 @@ void Script::o_jmp() { void Script::o_loadstring() { uint16 varnum = readScript8or16bits(); - debugCN(1, kDebugScript, "LOADSTRING var[0x%04X..] =", varnum); + debugCN(1, kDebugScript, "Groovie::Script: LOADSTRING var[0x%04X..] =", varnum); do { setVariable(varnum++, readScriptChar(true, true, true)); debugCN(1, kDebugScript, " 0x%02X", _variables[varnum - 1]); @@ -949,7 +963,7 @@ void Script::o_loadstring() { void Script::o_ret() { uint8 val = readScript8bits(); - debugC(1, kDebugScript, "RET %d", val); + debugC(1, kDebugScript, "Groovie::Script: RET %d", val); // Set the return value setVariable(0x102, val); @@ -959,14 +973,14 @@ void Script::o_ret() { _stacktop--; _currentInstruction = _stack[_stacktop]; } else { - error("Return: Stack is empty"); + error("Groovie::Script: Return: Stack is empty"); } } void Script::o_call() { uint16 address = readScript16bits(); - debugC(1, kDebugScript, "CALL @0x%04X", address); + debugC(1, kDebugScript, "Groovie::Script: CALL @0x%04X", address); // Save return address in the call stack _stack[_stacktop] = _currentInstruction; @@ -979,7 +993,7 @@ void Script::o_call() { void Script::o_sleep() { uint16 time = readScript16bits(); - debugC(1, kDebugScript, "SLEEP 0x%04X", time); + debugC(1, kDebugScript, "Groovie::Script: SLEEP 0x%04X (%d ms)", time, time*3); _vm->_system->delayMillis(time * 3); } @@ -988,7 +1002,7 @@ void Script::o_strcmpnejmp() { // 0x1A uint16 varnum = readScript8or16bits(); uint8 result = 1; - debugCN(1, kDebugScript, "STRCMP-NEJMP: var[0x%04X..],", varnum); + debugCN(1, kDebugScript, "Groovie::Script: STRCMP-NEJMP: var[0x%04X..],", varnum); do { uint8 val = readScriptChar(true, true, true); @@ -1012,7 +1026,7 @@ void Script::o_strcmpnejmp() { // 0x1A void Script::o_xor_obfuscate() { uint16 varnum = readScript8or16bits(); - debugCN(1, kDebugScript, "XOR OBFUSCATE: var[0x%04X..] = ", varnum); + debugCN(1, kDebugScript, "Groovie::Script: XOR OBFUSCATE: var[0x%04X..] = ", varnum); do { uint8 val = readScript8bits(); _firstbit = ((val & 0x80) != 0); @@ -1031,8 +1045,8 @@ void Script::o_vdxtransition() { // 0x1C // Show the debug information just when starting the playback if (fileref != _videoRef) { - debugC(1, kDebugScript, "VDX transition fileref = 0x%04X", fileref); - debugC(1, kDebugVideo, "Playing video 0x%04X with transition", fileref); + debugC(1, kDebugScript, "Groovie::Script: VDX transition fileref = 0x%04X", fileref); + debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing video %d via 0x1C (VdxTransition)", _currentInstruction-3, fileref); } // Set bit 1 @@ -1057,7 +1071,7 @@ void Script::o_swap() { uint16 varnum1 = readScript8or16bits(); uint16 varnum2 = readScript16bits(); - debugC(1, kDebugScript, "SWAP var[0x%04X] <-> var[0x%04X]", varnum1, varnum2); + debugC(1, kDebugScript, "Groovie::Script: SWAP var[0x%04X] <-> var[0x%04X]", varnum1, varnum2); uint8 tmp = _variables[varnum1]; setVariable(varnum1, _variables[varnum2]); @@ -1067,7 +1081,7 @@ void Script::o_swap() { void Script::o_inc() { uint16 varnum = readScript8or16bits(); - debugC(1, kDebugScript, "INC var[0x%04X]", varnum); + debugC(1, kDebugScript, "Groovie::Script: INC var[0x%04X]", varnum); setVariable(varnum, _variables[varnum] + 1); } @@ -1075,7 +1089,7 @@ void Script::o_inc() { void Script::o_dec() { uint16 varnum = readScript8or16bits(); - debugC(1, kDebugScript, "DEC var[0x%04X]", varnum); + debugC(1, kDebugScript, "Groovie::Script: DEC var[0x%04X]", varnum); setVariable(varnum, _variables[varnum] - 1); } @@ -1101,7 +1115,8 @@ void Script::o_strcmpnejmp_var() { // 0x21 } void Script::o_copybgtofg() { // 0x22 - debugC(1, kDebugScript, "COPY_BG_TO_FG"); + debugC(1, kDebugScript, "Groovie::Script: COPY_BG_TO_FG"); + debugC(2, kDebugVideo, "Groovie::Script: @0x%04X: COPY_BG_TO_FG", _currentInstruction-1); memcpy(_vm->_graphicsMan->_foreground.getPixels(), _vm->_graphicsMan->_background.getPixels(), 640 * _vm->_graphicsMan->_foreground.h); } @@ -1109,7 +1124,7 @@ void Script::o_strcmpeqjmp() { // 0x23 uint16 varnum = readScript8or16bits(); uint8 result = 1; - debugCN(1, kDebugScript, "STRCMP-EQJMP: var[0x%04X..],", varnum); + debugCN(1, kDebugScript, "Groovie::Script: STRCMP-EQJMP: var[0x%04X..],", varnum); do { uint8 val = readScriptChar(true, true, true); @@ -1133,7 +1148,7 @@ void Script::o_mov() { uint16 varnum1 = readScript8or16bits(); uint16 varnum2 = readScript16bits(); - debugC(1, kDebugScript, "MOV var[0x%04X] = var[0x%04X]", varnum1, varnum2); + debugC(1, kDebugScript, "Groovie::Script: MOV var[0x%04X] = var[0x%04X]", varnum1, varnum2); setVariable(varnum1, _variables[varnum2]); } @@ -1142,20 +1157,25 @@ void Script::o_add() { uint16 varnum1 = readScript8or16bits(); uint16 varnum2 = readScript16bits(); - debugC(1, kDebugScript, "ADD var[0x%04X] += var[0x%04X]", varnum1, varnum2); + debugC(1, kDebugScript, "Groovie::Script: ADD var[0x%04X] += var[0x%04X]", varnum1, varnum2); setVariable(varnum1, _variables[varnum1] + _variables[varnum2]); } void Script::o_videofromstring1() { + Common::String vidName; uint16 instStart = _currentInstruction; - uint32 fileref = getVideoRefString(); + uint32 fileref = getVideoRefString(vidName); // Show the debug information just when starting the playback if (fileref != _videoRef) { - debugC(0, kDebugScript, "VIDEOFROMSTRING1 0x%04X", fileref); + debugC(0, kDebugScript, "Groovie::Script: VIDEOFROMSTRING1 %d ('%s')", fileref, vidName.c_str()); + debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing video %d ('%s') via 0x26 (VideoFromString1)", instStart-1, fileref, vidName.c_str()); } + // Clear bit 1 + _bitflags &= ~(1 << 1); + // Play the video if (!playvideofromref(fileref)) { // Move _currentInstruction back @@ -1164,12 +1184,14 @@ void Script::o_videofromstring1() { } void Script::o_videofromstring2() { + Common::String vidName; uint16 instStart = _currentInstruction; - uint32 fileref = getVideoRefString(); + uint32 fileref = getVideoRefString(vidName); // Show the debug information just when starting the playback if (fileref != _videoRef) { - debugC(0, kDebugScript, "VIDEOFROMSTRING2 0x%04X", fileref); + debugC(0, kDebugScript, "Groovie::Script: VIDEOFROMSTRING2 %d ('%s')", fileref, vidName.c_str()); + debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing video %d ('%s') via 0x27 (VideoFromString2)", instStart-1, fileref, vidName.c_str()); } // Set bit 1 @@ -1188,11 +1210,11 @@ void Script::o_videofromstring2() { } void Script::o_stopmidi() { - debugC(1, kDebugScript, "STOPMIDI (TODO)"); + debugC(1, kDebugScript, "Groovie::Script: STOPMIDI (TODO)"); } void Script::o_endscript() { - debugC(1, kDebugScript, "END OF SCRIPT"); + debugC(1, kDebugScript, "Groovie::Script: END OF SCRIPT"); _vm->quitGame(); } @@ -1200,7 +1222,7 @@ void Script::o_sethotspottop() { uint16 address = readScript16bits(); uint8 cursor = readScript8bits(); - debugC(5, kDebugScript, "SETHOTSPOTTOP @0x%04X cursor=%d", address, cursor); + debugC(5, kDebugScript, "Groovie::Script: SETHOTSPOTTOP @0x%04X cursor=%d", address, cursor); _hotspotTopAction = address; _hotspotTopCursor = cursor; @@ -1210,7 +1232,7 @@ void Script::o_sethotspotbottom() { uint16 address = readScript16bits(); uint8 cursor = readScript8bits(); - debugC(5, kDebugScript, "SETHOTSPOTBOTTOM @0x%04X cursor=%d", address, cursor); + debugC(5, kDebugScript, "Groovie::Script: SETHOTSPOTBOTTOM @0x%04X cursor=%d", address, cursor); _hotspotBottomAction = address; _hotspotBottomCursor = cursor; @@ -1220,7 +1242,7 @@ void Script::o_loadgame() { uint16 varnum = readScript8or16bits(); uint8 slot = _variables[varnum]; - debugC(1, kDebugScript, "LOADGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot); + debugC(1, kDebugScript, "Groovie::Script: LOADGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot); loadgame(slot); if (_version == kGroovieT7G) { @@ -1232,7 +1254,7 @@ void Script::o_savegame() { uint16 varnum = readScript8or16bits(); uint8 slot = _variables[varnum]; - debugC(1, kDebugScript, "SAVEGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot); + debugC(1, kDebugScript, "Groovie::Script: SAVEGAME var[0x%04X] -> slot=%d (TODO)", varnum, slot); savegame(slot); } @@ -1240,7 +1262,7 @@ void Script::o_savegame() { void Script::o_hotspotbottom_4() { //0x30 uint16 address = readScript16bits(); - debugC(5, kDebugScript, "HOTSPOT-BOTTOM @0x%04X", address); + debugC(5, kDebugScript, "Groovie::Script: HOTSPOT-BOTTOM @0x%04X", address); // Mark the 80 pixels under the game area Common::Rect rect(0, 400, 640, 480); @@ -1251,7 +1273,7 @@ void Script::o_midivolume() { uint16 arg1 = readScript16bits(); uint16 arg2 = readScript16bits(); - debugC(1, kDebugScript, "MIDI volume: %d %d", arg1, arg2); + debugC(1, kDebugScript, "Groovie::Script: MIDI volume: %d %d", arg1, arg2); _vm->_musicPlayer->setGameVolume(arg1, arg2); } @@ -1260,7 +1282,7 @@ void Script::o_jne() { uint16 varnum2 = readScript16bits(); uint16 address = readScript16bits(); - debugCN(1, kDebugScript, "JNE: var[var[0x%04X] - 0x31] != var[0x%04X] @0x%04X", varnum1, varnum2, address); + debugCN(1, kDebugScript, "Groovie::Script: JNE: var[var[0x%04X] - 0x31] != var[0x%04X] @0x%04X", varnum1, varnum2, address); if (_variables[_variables[varnum1] - 0x31] != _variables[varnum2]) { _currentInstruction = address; @@ -1274,7 +1296,7 @@ void Script::o_loadstringvar() { uint16 varnum = readScript8or16bits(); varnum = _variables[varnum] - 0x31; - debugCN(1, kDebugScript, "LOADSTRINGVAR var[0x%04X..] =", varnum); + debugCN(1, kDebugScript, "Groovie::Script: LOADSTRINGVAR var[0x%04X..] =", varnum); do { setVariable(varnum++, readScriptChar(true, true, true)); debugCN(1, kDebugScript, " 0x%02X", _variables[varnum - 1]); @@ -1286,7 +1308,7 @@ void Script::o_chargreatjmp() { uint16 varnum = readScript8or16bits(); uint8 result = 0; - debugCN(1, kDebugScript, "CHARGREAT-JMP: var[0x%04X..],", varnum); + debugCN(1, kDebugScript, "Groovie::Script: CHARGREAT-JMP: var[0x%04X..],", varnum); do { uint8 val = readScriptChar(true, true, true); @@ -1307,7 +1329,7 @@ void Script::o_chargreatjmp() { } void Script::o_bf7off() { - debugC(1, kDebugScript, "BF7OFF: bitflag 7 turned off"); + debugC(1, kDebugScript, "Groovie::Script: BF7OFF: bitflag 7 turned off"); _bitflags &= ~(1 << 7); } @@ -1315,7 +1337,7 @@ void Script::o_charlessjmp() { uint16 varnum = readScript8or16bits(); uint8 result = 0; - debugCN(1, kDebugScript, "CHARLESS-JMP: var[0x%04X..],", varnum); + debugCN(1, kDebugScript, "Groovie::Script: CHARLESS-JMP: var[0x%04X..],", varnum); do { uint8 val = readScriptChar(true, true, true); @@ -1344,7 +1366,7 @@ void Script::o_copyrecttobg() { // 0x37 // Sanity checks to prevent bad pointer access crashes if (left > right) { - warning("COPYRECT left:%d > right:%d", left, right); + warning("Groovie::Script: COPYRECT left:%d > right:%d", left, right); // swap over left and right parameters uint16 j; j = right; @@ -1352,7 +1374,7 @@ void Script::o_copyrecttobg() { // 0x37 left = j; } if (top > bottom) { - warning("COPYRECT top:%d > bottom:%d", top, bottom); + warning("Groovie::Script: COPYRECT top:%d > bottom:%d", top, bottom); // swap over top and bottom parameters uint16 j; j = bottom; @@ -1360,50 +1382,58 @@ void Script::o_copyrecttobg() { // 0x37 top = j; } if (top < baseTop) { - warning("COPYRECT top < baseTop... clamping"); + warning("Groovie::Script: COPYRECT top < baseTop... clamping"); top = baseTop; } if (top >= 480) { - warning("COPYRECT top >= 480... clamping"); + warning("Groovie::Script: COPYRECT top >= 480... clamping"); top = 480 - 1; } if (bottom >= 480) { - warning("COPYRECT bottom >= 480... clamping"); + warning("Groovie::Script: COPYRECT bottom >= 480... clamping"); bottom = 480 - 1; } if (left >= 640) { - warning("COPYRECT left >= 640... clamping"); + warning("Groovie::Script: COPYRECT left >= 640... clamping"); left = 640 - 1; } if (right >= 640) { - warning("COPYRECT right >= 640... clamping"); + warning("Groovie::Script: COPYRECT right >= 640... clamping"); right = 640 - 1; } uint16 i, width = right - left, height = bottom - top; uint32 offset = 0; byte *fg, *bg; + uint32 pitch = _vm->_graphicsMan->_foreground.pitch; - debugC(1, kDebugScript, "COPYRECT((%d,%d)->(%d,%d))", left, top, right, bottom); + debugC(1, kDebugScript, "Groovie::Script: COPYRECT((%d,%d)->(%d,%d))", left, top, right, bottom); + debugC(2, kDebugVideo, "Groovie::Script: @0x%04X: COPYRECT((%d,%d)->(%d,%d))",_currentInstruction-9, left, top, right, bottom); fg = (byte *)_vm->_graphicsMan->_foreground.getBasePtr(left, top - baseTop); bg = (byte *)_vm->_graphicsMan->_background.getBasePtr(left, top - baseTop); for (i = 0; i < height; i++) { - memcpy(bg + offset, fg + offset, width); - offset += 640; + memcpy(bg + offset, fg + offset, width * _vm->_graphicsMan->_foreground.format.bytesPerPixel); + offset += pitch; } - _vm->_system->copyRectToScreen(_vm->_graphicsMan->_background.getBasePtr(left, top - baseTop), 640, left, top, width, height); + // _vm->_graphicsMan->_background.copyFrom(_vm->_graphicsMan->_foreground); + + //{ + // Graphics::Surface *_bg = &_vm->_graphicsMan->_background; + // _vm->_system->copyRectToScreen(_bg->getPixels(), _bg->pitch, 0, (_vm->_system->getHeight() - _bg->h) / 2, _bg->w, _bg->h); + //} + _vm->_system->copyRectToScreen(_vm->_graphicsMan->_background.getBasePtr(left, top - baseTop), pitch, left, top, width, height); _vm->_graphicsMan->change(); } void Script::o_restorestkpnt() { - debugC(1, kDebugScript, "Restore stack pointer from saved (TODO)"); + debugC(1, kDebugScript, "Groovie::Script: Restore stack pointer from saved (TODO)"); } void Script::o_obscureswap() { uint16 var1, var2, tmp; - debugC(1, kDebugScript, "OBSCSWAP"); + debugC(1, kDebugScript, "Groovie::Script: OBSCSWAP"); // Read the first variable var1 = readScriptChar(false, true, true) * 10; @@ -1423,7 +1453,8 @@ void Script::o_printstring() { char stringstorage[15]; uint8 counter = 0; - debugC(1, kDebugScript, "PRINTSTRING"); + debugC(1, kDebugScript, "Groovie::Script: PRINTSTRING"); + debugC(2, kDebugVideo, "Groovie::Script: @0x%04X: PRINTSTRING", _currentInstruction-1); memset(stringstorage, 0, 15); do { @@ -1461,7 +1492,22 @@ void Script::o_hotspot_slot() { uint16 address = readScript16bits(); uint16 cursor = readScript8bits(); - debugC(1, kDebugScript, "HOTSPOT-SLOT %d (%d,%d,%d,%d) @0x%04X cursor=%d (TODO)", slot, left, top, right, bottom, address, cursor); + debugC(1, kDebugScript, "Groovie::Script: HOTSPOT-SLOT %d (%d,%d,%d,%d) @0x%04X cursor=%d (TODO)", slot, left, top, right, bottom, address, cursor); + + // Set rectangle according to the used engine. To remove the previously written text an the screen. + Common::Rect removeText; + if (_version == kGroovieT7G) { + removeText.left = 0; + removeText.top = 0; + removeText.right = 640; + removeText.bottom = 80; + } else { + // Only tested for 11th hour. TLC does not use this command. + removeText.left = 120; + removeText.top = 185; + removeText.right = 400; + removeText.bottom = 215; + } Common::Rect rect(left, top, right, bottom); if (hotspot(rect, address, cursor)) { @@ -1469,11 +1515,10 @@ void Script::o_hotspot_slot() { return; } - Common::Rect topbar(640, 80); Graphics::Surface *gamescreen = _vm->_system->lockScreen(); // Clear the top bar - gamescreen->fillRect(topbar, 0); + gamescreen->fillRect(removeText, 0); // 0 works for both color formats (Groovie V1 and V2) printString(gamescreen, _saveNames[slot].c_str()); @@ -1481,19 +1526,21 @@ void Script::o_hotspot_slot() { // Save the currently highlighted slot _hotspotSlot = slot; + _vm->_graphicsMan->change(); + } else { if (_hotspotSlot == slot) { - Common::Rect topbar(640, 80); - Graphics::Surface *gamescreen; gamescreen = _vm->_system->lockScreen(); - gamescreen->fillRect(topbar, 0); + gamescreen->fillRect(removeText, 0); // 0 works for both color formats (Groovie V1 and V2) _vm->_system->unlockScreen(); // Removing the slot highlight _hotspotSlot = (uint16)-1; + + _vm->_graphicsMan->change(); } } } @@ -1501,7 +1548,7 @@ void Script::o_hotspot_slot() { // Checks valid save games. Even for TLC (uses only 4 user save games) the function // checks for 10 save games. void Script::o_checkvalidsaves() { - debugC(1, kDebugScript, "CHECKVALIDSAVES"); + debugC(1, kDebugScript, "Groovie::Script: CHECKVALIDSAVES"); // Reset the array of valid saves and the savegame names cache for (int i = 0; i < MAX_SAVES; i++) { @@ -1518,7 +1565,7 @@ void Script::o_checkvalidsaves() { while (it != list.end()) { int8 slot = it->getSaveSlot(); if (SaveLoad::isSlotValid(slot)) { - debugC(2, kDebugScript, " Found valid savegame: %s", it->getDescription().encode().c_str()); + debugC(2, kDebugScript, "Groovie::Script: Found valid savegame: %s", it->getDescription().encode().c_str()); // Mark this slot as used setVariable(slot, 1); @@ -1532,7 +1579,7 @@ void Script::o_checkvalidsaves() { // Save the number of valid saves setVariable(0x104, count); - debugC(1, kDebugScript, " Found %d valid savegames", count); + debugC(1, kDebugScript, "Groovie::Script: Found %d valid savegames", count); } void Script::o_resetvars() { @@ -1546,7 +1593,7 @@ void Script::o_mod() { uint16 varnum = readScript8or16bits(); uint8 val = readScript8bits(); - debugC(1, kDebugScript, "MOD var[0x%04X] %%= %d", varnum, val); + debugC(1, kDebugScript, "Groovie::Script: MOD var[0x%04X] %%= %d", varnum, val); setVariable(varnum, _variables[varnum] % val); } @@ -1558,11 +1605,11 @@ void Script::o_loadscript() { while ((c = readScript8bits())) { filename += c; } - debugC(1, kDebugScript, "LOADSCRIPT %s", filename.c_str()); + debugC(1, kDebugScript, "Groovie::Script: LOADSCRIPT %s", filename.c_str()); // Just 1 level of sub-scripts are allowed if (_savedCode) { - error("Tried to load a level 2 sub-script"); + error("Groovie::Script: Tried to load a level 2 sub-script"); } // Save the current code @@ -1575,7 +1622,7 @@ void Script::o_loadscript() { // Load the sub-script if (!loadScript(filename)) { - error("Couldn't load sub-script %s", filename.c_str()); + error("Groovie::Script: Couldn't load sub-script %s", filename.c_str()); } // Save the current stack top @@ -1593,7 +1640,7 @@ void Script::o_setvideoorigin() { // Set bitflag 7 _bitflags |= 1 << 7; - debugC(1, kDebugScript, "SetVideoOrigin(0x%04X,0x%04X) (%d, %d)", origX, origY, origX, origY); + debugC(1, kDebugScript, "Groovie::Script: SetVideoOrigin(0x%04X,0x%04X) (%d, %d)", origX, origY, origX, origY); _vm->_videoPlayer->setOrigin(origX, origY); } @@ -1601,7 +1648,7 @@ void Script::o_sub() { uint16 varnum1 = readScript8or16bits(); uint16 varnum2 = readScript16bits(); - debugC(1, kDebugScript, "SUB var[0x%04X] -= var[0x%04X]", varnum1, varnum2); + debugC(1, kDebugScript, "Groovie::Script: SUB var[0x%04X] -= var[0x%04X]", varnum1, varnum2); setVariable(varnum1, _variables[varnum1] - _variables[varnum2]); } @@ -1611,7 +1658,7 @@ void Script::o_cellmove() { byte *scriptBoard = &_variables[0x19]; byte startX, startY, endX, endY; - debugC(1, kDebugScript, "CELL MOVE var[0x%02X]", depth); + debugC(1, kDebugScript, "Groovie::Script: CELL MOVE var[0x%02X]", depth); if (!_staufsMove) _staufsMove = new CellGame; @@ -1634,11 +1681,11 @@ void Script::o_cellmove() { void Script::o_returnscript() { uint8 val = readScript8bits(); - debugC(1, kDebugScript, "RETURNSCRIPT @0x%02X", val); + debugC(1, kDebugScript, "Groovie::Script: RETURNSCRIPT @0x%02X", val); // Are we returning from a sub-script? if (!_savedCode) { - error("Tried to return from the main script"); + error("Groovie::Script: Tried to return from the main script"); } // Set the return value @@ -1667,7 +1714,7 @@ void Script::o_returnscript() { void Script::o_sethotspotright() { uint16 address = readScript16bits(); - debugC(1, kDebugScript, "SETHOTSPOTRIGHT @0x%04X", address); + debugC(1, kDebugScript, "Groovie::Script: SETHOTSPOTRIGHT @0x%04X", address); _hotspotRightAction = address; } @@ -1675,13 +1722,13 @@ void Script::o_sethotspotright() { void Script::o_sethotspotleft() { uint16 address = readScript16bits(); - debugC(1, kDebugScript, "SETHOTSPOTLEFT @0x%04X", address); + debugC(1, kDebugScript, "Groovie::Script: SETHOTSPOTLEFT @0x%04X", address); _hotspotLeftAction = address; } void Script::o_getcd() { - debugC(1, kDebugScript, "GETCD"); + debugC(1, kDebugScript, "Groovie::Script: GETCD"); // By default set it to no CD available int8 cd = -1; @@ -1708,7 +1755,7 @@ void Script::o_getcd() { void Script::o_playcd() { uint8 val = readScript8bits(); - debugC(1, kDebugScript, "PLAYCD %d", val); + debugC(1, kDebugScript, "Groovie::Script: PLAYCD %d", val); if (val == 2) { // TODO: Play the alternative logo @@ -1720,7 +1767,7 @@ void Script::o_playcd() { void Script::o_musicdelay() { uint16 delay = readScript16bits(); - debugC(1, kDebugScript, "MUSICDELAY %d", delay); + debugC(1, kDebugScript, "Groovie::Script: MUSICDELAY %d", delay); _vm->_musicPlayer->setBackgroundDelay(delay); } @@ -1732,7 +1779,7 @@ void Script::o_hotspot_outrect() { uint16 bottom = readScript16bits(); uint16 address = readScript16bits(); - debugC(1, kDebugScript, "HOTSPOT-OUTRECT(%d,%d,%d,%d) @0x%04X (TODO)", left, top, right, bottom, address); + debugC(1, kDebugScript, "Groovie::Script: HOTSPOT-OUTRECT(%d,%d,%d,%d) @0x%04X (TODO)", left, top, right, bottom, address); // Test if the current mouse position is outside the specified rectangle Common::Rect rect(left, top, right, bottom); @@ -1749,14 +1796,14 @@ void Script::o_stub56() { uint8 val2 = readScript8bits(); uint8 val3 = readScript8bits(); - debugC(1, kDebugScript, "STUB56: 0x%08X 0x%02X 0x%02X", val1, val2, val3); + debugC(1, kDebugScript, "Groovie::Script: STUB56: 0x%08X 0x%02X 0x%02X", val1, val2, val3); } void Script::o_stub59() { uint16 val1 = readScript8or16bits(); uint8 val2 = readScript8bits(); - debugC(1, kDebugScript, "STUB59: 0x%04X 0x%02X", val1, val2); + debugC(1, kDebugScript, "Groovie::Script: STUB59: 0x%04X 0x%02X", val1, val2); } void Script::o2_printstring() { @@ -1766,35 +1813,57 @@ void Script::o2_printstring() { uint8 colg = readScript8bits(); uint8 colb = readScript8bits(); uint32 col = _vm->_pixelFormat.RGBToColor(colr, colg, colb); - char message[20]; - memset(message, 0, sizeof(message)); + Common::String text; - for (int i = 0; i < 19; i++) { - if (_variables[i] > 0) { - message[i] = _variables[i] + 0x30; - } - } - - debugC(1, kDebugScript, "PRINTSTRING (%d, %d): %s", posx, posy, message); + // Read string from Script + readScriptString(text); + debugC(1, kDebugScript, "Groovie::Script: PRINTSTRING (%d, %d): %s", posx, posy, text.c_str()); Graphics::Surface *gamescreen = _vm->_system->lockScreen(); - _vm->_font->drawString(gamescreen, message, posx, posy, 640, col, Graphics::kTextAlignLeft); + _vm->_font->drawString(gamescreen, text.c_str(), posx, posy, 640, col, Graphics::kTextAlignLeft); _vm->_system->unlockScreen(); _vm->_graphicsMan->change(); // Force Update screen after step - - // 42 Bytes unknown - _currentInstruction += 39; } void Script::o2_playsong() { uint32 fileref = readScript32bits(); - debugC(1, kDebugScript, "PlaySong(0x%08X): Play xmidi file", fileref); + debugC(1, kDebugScript, "Groovie::Script: PlaySong(0x%08X): Play xmidi file", fileref); _vm->_musicPlayer->playSong(fileref); } +void Script::o2_midicontrol() { + uint16 arg1 = readScript16bits(); + uint16 arg2 = readScript16bits(); + + switch (arg1) { + case 0: + // Stop Playback + debugC(1, kDebugScript, "Groovie::Script: MIDI %d:Stop: %d", arg1, arg2); + _vm->_musicPlayer->setUserVolume(0); + // _vm->_musicPlayer->setBackgroundDelay(0); + break; + + case 1: + // Play song from index + debugC(1, kDebugScript, "Groovie::Script: MIDI %d: Play song %d", arg1, arg2); + _vm->_musicPlayer->playSong(arg2); + _vm->_musicPlayer->setUserVolume(100); +// _vm->_musicPlayer->setBackgroundSong(arg2); +// _vm->_musicPlayer->startBackground(); + break; + + case 3: + // Set Volume? Or is it some kind of fade in / out + debugC(1, kDebugScript, "Groovie::Script: MIDI %d: Set volume/time: %d", arg1, arg2); + //_vm->_musicPlayer->setUserVolume(arg2); + break; + } + + //_vm->_musicPlayer->setGameVolume(arg1, arg2); +} void Script::o2_setbackgroundsong() { uint32 fileref = readScript32bits(); - debugC(1, kDebugScript, "SetBackgroundSong(0x%08X)", fileref); + debugC(1, kDebugScript, "Groovie::Script: SetBackgroundSong(0x%08X)", fileref); _vm->_musicPlayer->setBackgroundSong(fileref); } @@ -1803,10 +1872,13 @@ void Script::o2_videofromref() { // Show the debug information just when starting the playback if (fileref != _videoRef) { - debugC(1, kDebugScript, "VIDEOFROMREF(0x%08X) (Not fully imp): Play video file from ref", fileref); - debugC(5, kDebugVideo, "Playing video 0x%08X via 0x09", fileref); + debugC(1, kDebugScript, "Groovie::Script: VIDEOFROMREF(0x%08X) (Not fully imp): Play video file from ref", fileref); + debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing video %d via 0x09", _currentInstruction-5, fileref); } + // Clear bit 1 + _bitflags &= ~(1 << 1); + // Play the video if (!playvideofromref(fileref)) { // Move _currentInstruction back @@ -1819,8 +1891,8 @@ void Script::o2_vdxtransition() { // Show the debug information just when starting the playback if (fileref != _videoRef) { - debugC(1, kDebugScript, "VDX transition fileref = 0x%08X", fileref); - debugC(1, kDebugVideo, "Playing video 0x%08X with transition", fileref); + debugC(1, kDebugScript, "Groovie::Script: VDX transition fileref = 0x%08X", fileref); + debugC(2, kDebugVideo, "\nGroovie::Script: @0x%04X: Playing video %d with transition via 0x1C", _currentInstruction-5, fileref); } // Set bit 1 @@ -1843,13 +1915,14 @@ void Script::o2_copyscreentobg() { // TODO: Parameter if (val) - warning("o2_copyscreentobg: Param is %d", val); + warning("Groovie::Script: o2_copyscreentobg: Param is %d", val); Graphics::Surface *screen = _vm->_system->lockScreen(); _vm->_graphicsMan->_background.copyFrom(screen->getSubArea(Common::Rect(0, 80, 640, 320))); _vm->_system->unlockScreen(); - debugC(1, kDebugScript, "CopyScreenToBG3: 0x%04X", val); + debugC(1, kDebugScript, "Groovie::Script: CopyScreenToBG3: 0x%04X", val); + debugC(2, kDebugVideo, "Groovie::Script: @0x%04X: CopyScreenToBG3: 0x%04X", _currentInstruction-3, val); } void Script::o2_copybgtoscreen() { @@ -1857,18 +1930,19 @@ void Script::o2_copybgtoscreen() { // TODO: Parameter if (val) - warning("o2_copybgtoscreen: Param is %d", val); + warning("Groovie::Script: o2_copybgtoscreen: Param is %d", val); Graphics::Surface *screen = _vm->_system->lockScreen(); _vm->_graphicsMan->_background.copyRectToSurface(*screen, 0, 80, Common::Rect(0, 0, 640, 320 - 80)); _vm->_system->unlockScreen(); - debugC(1, kDebugScript, "CopyBG3ToScreen: 0x%04X", val); + debugC(1, kDebugScript, "Groovie::Script: CopyBG3ToScreen: 0x%04X", val); + debugC(2, kDebugVideo, "Groovie::Script: @0x%04X: CopyBG3ToScreen: 0x%04X", _currentInstruction-3, val); } void Script::o2_setvideoskip() { _videoSkipAddress = readScript16bits(); - debugC(1, kDebugScript, "SetVideoSkip (0x%04X)", _videoSkipAddress); + debugC(1, kDebugScript, "Groovie::Script: SetVideoSkip (0x%04X)", _videoSkipAddress); } // This function depends on the actual game played. So it is different for @@ -1884,44 +1958,49 @@ void Script::o2_stub42() { } switch (arg) { case 0: - debugC(1, kDebugScript, "Op42 (0x%02X): TLC Regions", arg); + debugC(1, kDebugScript, "Groovie::Script: Op42 (0x%02X): TLC Regions", arg); _tlcGame->opRegions(); break; case 1: - debugC(1, kDebugScript, "Op42 (0x%02X): TLC Exit Polls", arg); + debugC(1, kDebugScript, "Groovie::Script: Op42 (0x%02X): TLC Exit Polls", arg); _tlcGame->opExitPoll(); break; case 2: _tlcGame->opFlags(); - debugC(1, kDebugScript, "Op42 (0x%02X): TLC TATFlags", arg); + debugC(1, kDebugScript, "Groovie::Script: Op42 (0x%02X): TLC TATFlags", arg); break; case 3: - debugC(1, kDebugScript, "Op42 (0x%02X): TLC TATs (TODO)", arg); + debugC(1, kDebugScript, "Groovie::Script: Op42 (0x%02X): TLC TATs (TODO)", arg); _tlcGame->opTat(); break; default: - debugC(1, kDebugScript, "Op42 (0x%02X): TLC Invalid -> NOP", arg); + debugC(1, kDebugScript, "Groovie::Script: Op42 (0x%02X): TLC Invalid -> NOP", arg); } break; default: - debugC(1, kDebugScript, "STUB42 (0x%02X)", arg); - warning("OpCode 0x42 for current game not implemented yet."); + debugC(1, kDebugScript, "Groovie::Script: STUB42 (0x%02X)", arg); + warning("Groovie::Script: OpCode 0x42 for current game not implemented yet."); } } void Script::o2_stub52() { uint8 arg = readScript8bits(); - debugC(1, kDebugScript, "STUB52 (0x%02X)", arg); + debugC(1, kDebugScript, "Groovie::Script: STUB52 (0x%02X)", arg); + debugC(2, kDebugVideo, "Groovie::Script: @0x%04X: STUB52 (0x%02X)", _currentInstruction-2, arg); + // return; + + _vm->_graphicsMan->_background.copyFrom(_vm->_graphicsMan->_foreground); + _vm->_graphicsMan->updateScreen(&_vm->_graphicsMan->_background); } void Script::o2_setscriptend() { uint16 arg = readScript16bits(); - debugC(1, kDebugScript, "SetScriptEnd (0x%04X)", arg); + debugC(1, kDebugScript, "Groovie::Script: SetScriptEnd (0x%04X)", arg); } Script::OpcodeFunc Script::_opcodesT7G[NUM_OPCODES] = { @@ -2070,7 +2149,7 @@ Script::OpcodeFunc Script::_opcodesV2[NUM_OPCODES] = { &Script::o_loadgame, &Script::o_savegame, &Script::o_hotspotbottom_4, // 0x30 - &Script::o_midivolume, + &Script::o2_midicontrol, &Script::o_jne, &Script::o_loadstringvar, &Script::o_chargreatjmp, // 0x34 diff --git a/engines/groovie/script.h b/engines/groovie/script.h index a4b2e4a6e87..dac0b4434e9 100644 --- a/engines/groovie/script.h +++ b/engines/groovie/script.h @@ -146,8 +146,9 @@ private: uint32 readScript32bits(); uint16 readScript8or16bits(); uint8 readScriptChar(bool allow7C, bool limitVal, bool limitVar); + void readScriptString(Common::String &str); uint8 readScriptVar(); - uint32 getVideoRefString(); + uint32 getVideoRefString(Common::String &resName); bool hotspot(Common::Rect rect, uint16 addr, uint8 cursor); @@ -243,6 +244,7 @@ private: void o2_printstring(); void o2_playsong(); + void o2_midicontrol(); void o2_setbackgroundsong(); void o2_videofromref(); void o2_vdxtransition(); diff --git a/engines/groovie/tlcgame.cpp b/engines/groovie/tlcgame.cpp index 537f5739142..f01cf5b96bd 100644 --- a/engines/groovie/tlcgame.cpp +++ b/engines/groovie/tlcgame.cpp @@ -34,7 +34,7 @@ namespace Groovie { // This a list of files for background music. These list is hard-coded in the TLC player. -const Common::String kTlcMidiFiles[] = {"ep01epm.mpg", "ep01tatm.mpg", "amb_hs.mpg", "amb_mr.mpg", "amb_kr.mpg", "amb_mo.mpg", "music_rc.mpg", "amb_ds.mpg", "amb_ds3.mpg", "amb_jr.mpg", "amb_mr4.mpg", "amb_jr4.mpg", "amb_jr2.mpg", "amb_kr2.mpg", "amb_mr2.mpg", "amb_br.mpg", "amb_ds2.mpg", "amb_jr3.mpg", "amb_ds4.mpg", "amb_kr3.mpg", "amb_to1.mpg", "amb_to2.mpg", "ep02epm.mpg", "ep02tatm.mpg", "ep03epm.mpg", "ep03tatm.mpg", "ep04epm.mpg", "ep04tatm.mpg", "ep05epm.mpg", "ep05tatm.mpg", "ep06epm.mpg", "ep06tatm.mpg", "ep07epm.mpg", "ep07tatm.mpg", "ep08epm.mpg", "ep08tatm.mpg", "ep09epm.mpg", "ep09tatm.mpg", "ep10epm.mpg", "ep10tatm.mpg", "ep11epm.mpg", "ep11tatm.mpg", "ep12epm.mpg", "ep12tatm.mpg", "ep13epm.mpg", "ep13tatm.mpg", "ep14epm.mpg", "ep14tatm.mpg", "ep15epm.mpg", "ep15tatm.mpg" }; +const Common::String kTlcMusicFiles[] = {"ep01epm.mpg", "ep01tatm.mpg", "amb_hs.mpg", "amb_mr.mpg", "amb_kr.mpg", "amb_mo.mpg", "music_rc.mpg", "amb_ds.mpg", "amb_ds3.mpg", "amb_jr.mpg", "amb_mr4.mpg", "amb_jr4.mpg", "amb_jr2.mpg", "amb_kr2.mpg", "amb_mr2.mpg", "amb_br.mpg", "amb_ds2.mpg", "amb_jr3.mpg", "amb_ds4.mpg", "amb_kr3.mpg", "amb_to1.mpg", "amb_to2.mpg", "ep02epm.mpg", "ep02tatm.mpg", "ep03epm.mpg", "ep03tatm.mpg", "ep04epm.mpg", "ep04tatm.mpg", "ep05epm.mpg", "ep05tatm.mpg", "ep06epm.mpg", "ep06tatm.mpg", "ep07epm.mpg", "ep07tatm.mpg", "ep08epm.mpg", "ep08tatm.mpg", "ep09epm.mpg", "ep09tatm.mpg", "ep10epm.mpg", "ep10tatm.mpg", "ep11epm.mpg", "ep11tatm.mpg", "ep12epm.mpg", "ep12tatm.mpg", "ep13epm.mpg", "ep13tatm.mpg", "ep14epm.mpg", "ep14tatm.mpg", "ep15epm.mpg", "ep15tatm.mpg" }; const uint8 kTlcEpQuestToPlay[] = { 0x0E, 0x0F, 0x0B, 0x10, 0x11, 0x12, 0x0C, 0x0C, 0x09, 0x06, 0x0F, 0x0C, 0x0B, 0x0D, 0x0D }; @@ -78,6 +78,10 @@ uint16 inline TlcGame::getScriptVar16(uint16 var) { return value; } +// Gets the filename of the background music file. +Common::String TlcGame::getTlcMusicFilename(int musicId) { + return kTlcMusicFiles[musicId]; +} void TlcGame::opRegions() { if (_scriptVariables[0x1A] == 1) { diff --git a/engines/groovie/tlcgame.h b/engines/groovie/tlcgame.h index 3648c3fbcdc..3fc1f561916 100644 --- a/engines/groovie/tlcgame.h +++ b/engines/groovie/tlcgame.h @@ -1,94 +1,96 @@ -/* 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 GROOVIE_TLCGAME_H -#define GROOVIE_TLCGAME_H - -#include "common/textconsole.h" -#include "common/random.h" - -#define GROOVIE_TLC_MAX_EPSIODES (15) -#define GROOVIE_TLC_MAX_QUEST_EP (50) - -namespace Groovie { - -class GroovieEngine; - -// The regions.rle contains 898 entries. Round about 18 kByte in memory. -struct TlcRegionsHeader { - char name[12]; - int numAnswers; - uint32 offset; -}; - -struct TlcRegion { - uint16 left; - uint16 top; - uint16 right; - uint16 bottom; -}; - -struct TlcEpQuestionData { - bool questionUsed; - uint32 questionScore; -}; - -struct TlcTatHeader { - uint32 questionsNum; - uint32 questionsOffset; - uint8 binDividends[16]; -}; - -struct TlcTatAnswer { - uint8 binScore[8]; -}; - -struct TlcTatQuestions { - char name[6]; - int answerCount; - TlcTatAnswer answerData[8]; -}; - -class TlcGame -{ -public: - TlcGame(); - ~TlcGame(); - - /** - * Sets a pointer to the script variables. This makes it easier if we want - * to debug write accesses to the script variables +/* 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 GROOVIE_TLCGAME_H +#define GROOVIE_TLCGAME_H + +#include "common/textconsole.h" +#include "common/random.h" + +#define GROOVIE_TLC_MAX_EPSIODES (15) +#define GROOVIE_TLC_MAX_QUEST_EP (50) + +namespace Groovie { + +class GroovieEngine; + +// The regions.rle contains 898 entries. Round about 18 kByte in memory. +struct TlcRegionsHeader { + char name[12]; + int numAnswers; + uint32 offset; +}; + +struct TlcRegion { + uint16 left; + uint16 top; + uint16 right; + uint16 bottom; +}; + +struct TlcEpQuestionData { + bool questionUsed; + uint32 questionScore; +}; + +struct TlcTatHeader { + uint32 questionsNum; + uint32 questionsOffset; + uint8 binDividends[16]; +}; + +struct TlcTatAnswer { + uint8 binScore[8]; +}; + +struct TlcTatQuestions { + char name[6]; + int answerCount; + TlcTatAnswer answerData[8]; +}; + +class TlcGame +{ +public: + TlcGame(); + ~TlcGame(); + + static Common::String getTlcMusicFilename(int musicId); + + /** + * Sets a pointer to the script variables. This makes it easier if we want + * to debug write accesses to the script variables * @param scriptVariables The current variables from the script. - */ - void setVariables(byte *scriptVariables); - + */ + void setVariables(byte *scriptVariables); + /** * Handle region commands. A region describes the coordinates of * a rectangle as clickable area in the question dialogs. These regions * are provided by a the extra file. * screen coordinates. - */ - void opRegions(); - + */ + void opRegions(); + /** * Get the coordiantes of the region for the next answer. There are * up to 8 answers possible for each question. In the script the @@ -99,95 +101,95 @@ public: * @param bottom Bottom value of the rectangle * @return 0 if anwer was found. -1 in case no more answer * available for this question - */ - int getRegionNext(uint16 &left, uint16 &top, uint16 &right, uint16 &bottom); - + */ + int getRegionNext(uint16 &left, uint16 &top, uint16 &right, uint16 &bottom); + /** * Rewinds the internal answer counter for the function * getRegionNext() - */ - void getRegionRewind(); - - - /** - * Handles some flags which are used during a TAT. The game seems to - * use this flags to skip some questions during a TAT. - * OpCode_0x42(2) - */ - void opFlags(); - - - /** - * Handles all Exit Poll commands. The exit poll (EP) questions are - * described in detail in the file EPAIDB.RLE. - * OpCode_0x42(1) - */ - void opExitPoll(); - - /** - * Handles all TAT commands. The TAT questions are described in detail - * in the file TATAIDB.RLE - */ - void opTat(); - -private: - Common::RandomSource _random; - - void inline setScriptVar(uint16 var, byte value); - void inline setScriptVar16(uint16 var, uint16 value); - uint16 inline getScriptVar16(uint16 var); - byte *_scriptVariables; - + */ + void getRegionRewind(); + + + /** + * Handles some flags which are used during a TAT. The game seems to + * use this flags to skip some questions during a TAT. + * OpCode_0x42(2) + */ + void opFlags(); + + + /** + * Handles all Exit Poll commands. The exit poll (EP) questions are + * described in detail in the file EPAIDB.RLE. + * OpCode_0x42(1) + */ + void opExitPoll(); + + /** + * Handles all TAT commands. The TAT questions are described in detail + * in the file TATAIDB.RLE + */ + void opTat(); + +private: + Common::RandomSource _random; + + void inline setScriptVar(uint16 var, byte value); + void inline setScriptVar16(uint16 var, uint16 value); + uint16 inline getScriptVar16(uint16 var); + byte *_scriptVariables; + /** * Loads the description part of the regions.rle file into memory * This makes it faster to search for the correct quesion. - */ - void regionsInit(); - void regionsLoad(); - - // Variables for region handling - int _numRegionHeaders; - int _curAnswerIndex; - int _curQuestNumAnswers; - TlcRegion _curQuestRegions[8]; - TlcRegionsHeader *_regionHeader; - - /** - * Functions for Exit Poll Commands - */ - void epInit(); - void epSelectNextQuestion(); - void epResultQuestion(); - void epResultEpisode(); - - // Variables for Exit Poll handling - int16 _epScoreBin[6]; - int _epEpisodeIdx; // 15 Episodes: 0..14 - int _epQuestionIdx; // 1..X (questions in current episode. counted up for every question) - int _epQuestionNumOfPool; // 1..X (question number in the data base. The questions are played in random order) - int _epQuestionsInEpisode; - TlcEpQuestionData *_epQuestionsData; - - // Variables for flag handling - byte _tatFlags[0x0E][0x09]; - - /** - * Functions for TAT Commands - */ - void tatInitRegs(); - void tatLoadDB(); - void tatResultQuest(); - void tatResultEpisode(); - void tatGetProfile(); - - // Variables for TAT handling - int _tatCount; - int _tatQuestCount; - TlcTatHeader *_tatHeaders; - TlcTatQuestions *_tatQuestions; - uint8 _tatCoeffs[15][16]; -}; - -} // End of Groovie namespace - -#endif // GROOVIE_TLCGAME_H + */ + void regionsInit(); + void regionsLoad(); + + // Variables for region handling + int _numRegionHeaders; + int _curAnswerIndex; + int _curQuestNumAnswers; + TlcRegion _curQuestRegions[8]; + TlcRegionsHeader *_regionHeader; + + /** + * Functions for Exit Poll Commands + */ + void epInit(); + void epSelectNextQuestion(); + void epResultQuestion(); + void epResultEpisode(); + + // Variables for Exit Poll handling + int16 _epScoreBin[6]; + int _epEpisodeIdx; // 15 Episodes: 0..14 + int _epQuestionIdx; // 1..X (questions in current episode. counted up for every question) + int _epQuestionNumOfPool; // 1..X (question number in the data base. The questions are played in random order) + int _epQuestionsInEpisode; + TlcEpQuestionData *_epQuestionsData; + + // Variables for flag handling + byte _tatFlags[0x0E][0x09]; + + /** + * Functions for TAT Commands + */ + void tatInitRegs(); + void tatLoadDB(); + void tatResultQuest(); + void tatResultEpisode(); + void tatGetProfile(); + + // Variables for TAT handling + int _tatCount; + int _tatQuestCount; + TlcTatHeader *_tatHeaders; + TlcTatQuestions *_tatQuestions; + uint8 _tatCoeffs[15][16]; +}; + +} // End of Groovie namespace + +#endif // GROOVIE_TLCGAME_H