From af945ac7881ae7e414f004bd0e99e8c3b5d76be9 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 1 Dec 2008 20:35:36 +0000 Subject: Merged the tinsel 2 engine with tinsel 1. Both Discworld 1 and Discworld 2 should be completable svn-id: r35196 --- engines/tinsel/tinsel.cpp | 490 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 396 insertions(+), 94 deletions(-) (limited to 'engines/tinsel/tinsel.cpp') diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index fdf38d9409..85e6c2390f 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -24,6 +24,7 @@ */ #include "common/endian.h" +#include "common/error.h" #include "common/events.h" #include "common/keyboard.h" #include "common/file.h" @@ -44,13 +45,15 @@ #include "tinsel/background.h" #include "tinsel/config.h" #include "tinsel/cursor.h" +#include "tinsel/drives.h" #include "tinsel/dw.h" #include "tinsel/events.h" #include "tinsel/faders.h" #include "tinsel/film.h" #include "tinsel/handle.h" #include "tinsel/heapmem.h" // MemoryInit -#include "tinsel/inventory.h" +#include "tinsel/dialogs.h" +#include "tinsel/mareels.h" #include "tinsel/music.h" #include "tinsel/object.h" #include "tinsel/pid.h" @@ -60,6 +63,7 @@ #include "tinsel/serializer.h" #include "tinsel/sound.h" #include "tinsel/strres.h" +#include "tinsel/sysvar.h" #include "tinsel/timers.h" #include "tinsel/tinsel.h" @@ -71,6 +75,14 @@ namespace Tinsel { extern void SetDoFadeIn(bool tf); extern void DropBackground(void); +// In BMV.CPP +extern void FettleBMV(void); +extern bool MoviePlaying(void); +extern void CopyMovieToScreen(void); +extern void FinishBMV(); +extern int32 MovieAudioLag(); +extern uint32 NextMovieTime(); + // In CURSOR.CPP extern void CursorProcess(CORO_PARAM, const void *); @@ -79,7 +91,6 @@ extern void InventoryProcess(CORO_PARAM, const void *); // In SCENE.CPP extern void PrimeBackground(); -extern void NewScene(SCNHANDLE scene, int entry); extern SCNHANDLE GetSceneHandle(void); // In TIMER.CPP @@ -94,6 +105,12 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition); bool bRestart = false; bool bHasRestarted = false; +static bool bCuttingScene = false; + +static bool bChangingForRestore = false; + +static Common::Point clickPos; + #ifdef DEBUG bool bFast; // set to make it go ludicrously fast #endif @@ -110,11 +127,11 @@ static Scene NextScene = { 0, 0, 0 }; static Scene HookScene = { 0, 0, 0 }; static Scene DelayedScene = { 0, 0, 0 }; -static bool bHookSuspend = false; - static PROCESS *pMouseProcess = 0; static PROCESS *pKeyboardProcess = 0; +static SCNHANDLE hCdChangeScene; + // Stack of pending mouse button events Common::List mouseButtons; @@ -142,6 +159,7 @@ void KeyboardProcess(CORO_PARAM, const void *) { // Get the next keyboard event off the stack Common::Event evt = *keypresses.begin(); keypresses.erase(keypresses.begin()); + const Common::Point mousePos = _vm->getMousePosition(); // Switch for special keys switch (evt.kbd.keycode) { @@ -150,21 +168,21 @@ void KeyboardProcess(CORO_PARAM, const void *) { case Common::KEYCODE_RALT: if (evt.type == Common::EVENT_KEYDOWN) { if (!bSwapButtons) - ProcessButEvent(BE_RDSTART); + ProcessButEvent(PLR_DRAG2_START); else - ProcessButEvent(BE_LDSTART); + ProcessButEvent(PLR_DRAG1_START); } else { if (!bSwapButtons) - ProcessButEvent(BE_LDEND); + ProcessButEvent(PLR_DRAG1_END); else - ProcessButEvent(BE_RDEND); + ProcessButEvent(PLR_DRAG2_END); } continue; case Common::KEYCODE_LCTRL: case Common::KEYCODE_RCTRL: if (evt.type == Common::EVENT_KEYDOWN) { - ProcessKeyEvent(LOOK_KEY); + ProcessKeyEvent(PLR_LOOK); } else { // Control key release } @@ -186,42 +204,42 @@ void KeyboardProcess(CORO_PARAM, const void *) { switch (evt.kbd.keycode) { /*** SPACE = WALKTO ***/ case Common::KEYCODE_SPACE: - ProcessKeyEvent(WALKTO_KEY); + ProcessKeyEvent(PLR_WALKTO); continue; /*** RETURN = ACTION ***/ case Common::KEYCODE_RETURN: case Common::KEYCODE_KP_ENTER: - ProcessKeyEvent(ACTION_KEY); + ProcessKeyEvent(PLR_ACTION); continue; /*** l = LOOK ***/ case Common::KEYCODE_l: // LOOK - ProcessKeyEvent(LOOK_KEY); + ProcessKeyEvent(PLR_LOOK); continue; case Common::KEYCODE_ESCAPE: - // WORKAROUND: Check if any of the starting logo screens are active, and if so - // manually skip to the title screen, allowing them to be bypassed - { + if (!TinselV2) { + // WORKAROUND: For Discworld 1, check if any of the starting logo screens are + // active, and if so manually skip to the title screen, allowing them to be bypassed int sceneOffset = (_vm->getFeatures() & GF_SCNFILES) ? 1 : 0; int sceneNumber = (GetSceneHandle() >> SCNHANDLE_SHIFT) - sceneOffset; -#if 0 // FIXME: Disabled this code for now, as it doesn't work as it should (see bug #2078922). if ((g_language == TXT_GERMAN) && ((sceneNumber >= 25 && sceneNumber <= 27) || (sceneNumber == 17))) { // Skip to title screen // It seems the German CD version uses scenes 25,26,27,17 for the intro, // instead of 13,14,15,11; also, the title screen is 11 instead of 10 SetNewScene((11 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); - } else -#endif - if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { + } else if ((sceneNumber >= 13) && (sceneNumber <= 15) || (sceneNumber == 11)) { // Skip to title screen SetNewScene((10 + sceneOffset) << SCNHANDLE_SHIFT, 1, TRANS_CUT); } else { // Not on an intro screen, so process the key normally - ProcessKeyEvent(ESC_KEY); + ProcessKeyEvent(PLR_ESCAPE); } + } else { + // Running Discworld 2, so process the key normally + ProcessKeyEvent(PLR_ESCAPE); } continue; @@ -236,48 +254,79 @@ void KeyboardProcess(CORO_PARAM, const void *) { case Common::KEYCODE_F1: // Options dialog - ProcessKeyEvent(OPTION_KEY); + ProcessKeyEvent(PLR_MENU); continue; case Common::KEYCODE_F5: // Save game - ProcessKeyEvent(SAVE_KEY); + ProcessKeyEvent(PLR_SAVE); continue; case Common::KEYCODE_F7: // Load game - ProcessKeyEvent(LOAD_KEY); + ProcessKeyEvent(PLR_LOAD); continue; + case Common::KEYCODE_m: + // Debug facility - scene hopper + if (TinselV2 && (evt.kbd.flags == Common::KBD_ALT)) + ProcessKeyEvent(PLR_JUMP); + break; case Common::KEYCODE_q: if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT)) - ProcessKeyEvent(QUIT_KEY); + ProcessKeyEvent(PLR_QUIT); continue; case Common::KEYCODE_PAGEUP: case Common::KEYCODE_KP9: - ProcessKeyEvent(PGUP_KEY); + ProcessKeyEvent(PLR_PGUP); continue; case Common::KEYCODE_PAGEDOWN: case Common::KEYCODE_KP3: - ProcessKeyEvent(PGDN_KEY); + ProcessKeyEvent(PLR_PGDN); continue; case Common::KEYCODE_HOME: case Common::KEYCODE_KP7: - ProcessKeyEvent(HOME_KEY); + ProcessKeyEvent(PLR_HOME); continue; case Common::KEYCODE_END: case Common::KEYCODE_KP1: - ProcessKeyEvent(END_KEY); + ProcessKeyEvent(PLR_END); continue; default: - ProcessKeyEvent(NOEVENT_KEY); + ProcessKeyEvent(PLR_NOEVENT); break; } } CORO_END_CODE; } +/** + * Handles launching a single click action result if the timeout for a double-click + * expires + */ +static void SingleLeftProcess(CORO_PARAM, const void *) { + CORO_BEGIN_CONTEXT; + uint32 endTicks; + CORO_END_CONTEXT(_ctx); + + CORO_BEGIN_CODE(_ctx); + + // Work out when to wait until + _ctx->endTicks = DwGetCurrentTime() + (uint32)dclickSpeed; + + // Timeout a double click (may not work once every 49 days!) + do { + CORO_SLEEP(1); + } while(DwGetCurrentTime() < _ctx->endTicks); + + if (GetProvNotProcessed()) + PlayerEvent(PLR_WALKTO, clickPos); + + CORO_KILL_SELF(); + CORO_END_CODE; +} + /** * Process to handle changes in the mouse buttons. */ -void MouseProcess(CORO_PARAM, const void *) { +static void MouseProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; bool lastLWasDouble; @@ -292,9 +341,6 @@ void MouseProcess(CORO_PARAM, const void *) { _ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime(); while (true) { - // FIXME: I'm still keeping the ctrl/Alt handling in the ProcessKeyEvent method. - // Need to make sure that this works correctly - //DragKeys(); if (mouseButtons.empty()) { // allow scheduling @@ -306,23 +352,46 @@ void MouseProcess(CORO_PARAM, const void *) { Common::EventType type = *mouseButtons.begin(); mouseButtons.erase(mouseButtons.begin()); + int xp, yp; + GetCursorXYNoWait(&xp, &yp, true); + const Common::Point mousePos(xp, yp); + switch (type) { case Common::EVENT_LBUTTONDOWN: // left button press if (DwGetCurrentTime() - _ctx->lastLeftClick < (uint32)dclickSpeed) { - // signal left drag start - ProcessButEvent(BE_LDSTART); + // Left button double-click + + if (TinselV2) { + // Kill off the button process and fire off the action command + g_scheduler->killMatchingProcess(PID_BTN_CLICK, -1); + PlayerEvent(PLR_ACTION, clickPos); + } else { + // signal left drag start + ProcessButEvent(PLR_DRAG1_START); - // signal left double click event - ProcessButEvent(BE_DLEFT); + // signal left double click event + ProcessButEvent(PLR_DLEFT); + } _ctx->lastLWasDouble = true; } else { - // signal left drag start - ProcessButEvent(BE_LDSTART); + // Initial mouse down - either for a single click, or potentially + // the start of a double-click action + + if (TinselV2) { + PlayerEvent(PLR_DRAG1_START, mousePos); + + ProvNotProcessed(); + PlayerEvent(PLR_PROV_WALKTO, mousePos); + + } else { + // signal left drag start + ProcessButEvent(PLR_DRAG1_START); - // signal left single click event - ProcessButEvent(BE_SLEFT); + // signal left single click event + ProcessButEvent(PLR_SLEFT); + } _ctx->lastLWasDouble = false; } @@ -332,32 +401,53 @@ void MouseProcess(CORO_PARAM, const void *) { // left button release // update click timer - if (_ctx->lastLWasDouble == false) + if (_ctx->lastLWasDouble == false) { _ctx->lastLeftClick = DwGetCurrentTime(); - else + + // If player control is enabled, start a process which, if it times out, + // will activate a single button click + if (TinselV2 && ControlIsOn()) { + clickPos = mousePos; + g_scheduler->createProcess(PID_BTN_CLICK, SingleLeftProcess, NULL, 0); + } + } else _ctx->lastLeftClick -= dclickSpeed; - // signal left drag end - ProcessButEvent(BE_LDEND); + if (TinselV2) + // Signal left drag end + PlayerEvent(PLR_DRAG1_END, mousePos); + else + // signal left drag end + ProcessButEvent(PLR_DRAG1_END); break; case Common::EVENT_RBUTTONDOWN: // right button press if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) { - // signal right drag start - ProcessButEvent(BE_RDSTART); + // Right button double-click + if (TinselV2) { + PlayerEvent(PLR_NOEVENT, clickPos); + } else { + // signal right drag start + ProcessButEvent(PLR_DRAG2_START); - // signal right double click event - ProcessButEvent(BE_DRIGHT); + // signal right double click event + ProcessButEvent(PLR_DRIGHT); + } _ctx->lastRWasDouble = true; } else { - // signal right drag start - ProcessButEvent(BE_RDSTART); + if (TinselV2) { + PlayerEvent(PLR_DRAG2_START, mousePos); + PlayerEvent(PLR_LOOK, mousePos); + } else { + // signal right drag start + ProcessButEvent(PLR_DRAG2_START); - // signal right single click event - ProcessButEvent(BE_SRIGHT); + // signal right single click event + ProcessButEvent(PLR_SRIGHT); + } _ctx->lastRWasDouble = false; } @@ -372,8 +462,12 @@ void MouseProcess(CORO_PARAM, const void *) { else _ctx->lastRightClick -= dclickSpeed; - // signal right drag end - ProcessButEvent(BE_RDEND); + if (TinselV2) + // Signal left drag end + PlayerEvent(PLR_DRAG2_END, mousePos); + else + // signal right drag end + ProcessButEvent(PLR_DRAG2_END); break; default: @@ -402,9 +496,24 @@ static void MasterScriptProcess(CORO_PARAM, const void *) { /** * Store the facts pertaining to a scene change. */ - void SetNewScene(SCNHANDLE scene, int entrance, int transition) { - if (HookScene.scene == 0 || bHookSuspend) { + if (!bCuttingScene && TinselV2) + WrapScene(); + + // If CD change will be required, stick in the scene change scene + if (CdNumber(scene) != GetCurrentCD()) { + // This scene gets delayed + DelayedScene.scene = scene; + DelayedScene.entry = entrance; + DelayedScene.trans = transition; + + NextScene.scene = hCdChangeScene; + NextScene.entry = CdNumber(scene) - '0'; + NextScene.trans = TRANS_FADE; + return; + } + + if (HookScene.scene == 0 || bCuttingScene) { // This scene comes next NextScene.scene = scene; NextScene.entry = entrance; @@ -424,6 +533,9 @@ void SetNewScene(SCNHANDLE scene, int entrance, int transition) { } } +/** + * Store a scene as hooked + */ void SetHookScene(SCNHANDLE scene, int entrance, int transition) { assert(HookScene.scene == 0); // scene already hooked @@ -432,6 +544,9 @@ void SetHookScene(SCNHANDLE scene, int entrance, int transition) { HookScene.trans = transition; } +/** + * Hooked scene is over, trigger a change to the delayed scene + */ void UnHookScene(void) { assert(DelayedScene.scene != 0); // no scene delayed @@ -444,11 +559,40 @@ void UnHookScene(void) { } void SuspendHook(void) { - bHookSuspend = true; + bCuttingScene = true; +} + +void CdHasChanged(void) { + if (bChangingForRestore) { + bChangingForRestore = false; + RestoreGame(-2); + } else { + assert(DelayedScene.scene != 0); + + WrapScene(); + + // The delayed scene can go now + NextScene.scene = DelayedScene.scene; + NextScene.entry = DelayedScene.entry; + NextScene.trans = DelayedScene.trans; + + DelayedScene.scene = 0; + } +} + +void SetCdChangeScene(SCNHANDLE hScene) { + hCdChangeScene = hScene; +} + +void CDChangeForRestore(int cdNumber) { + NextScene.scene = hCdChangeScene; + NextScene.entry = cdNumber; + NextScene.trans = TRANS_FADE; + bChangingForRestore = true; } void UnSuspendHook(void) { - bHookSuspend = false; + bCuttingScene = false; } void syncSCdata(Serializer &s) { @@ -468,16 +612,23 @@ static void RestoredProcess(CORO_PARAM, const void *param) { // COROUTINE CORO_BEGIN_CONTEXT; INT_CONTEXT *pic; + bool bConverse; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); // get the stuff copied to process when it was created - _ctx->pic = *((INT_CONTEXT **)param); + _ctx->pic = *((INT_CONTEXT * const *)param); _ctx->pic = RestoreInterpretContext(_ctx->pic); + _ctx->bConverse = TinselV2 && (_ctx->pic->event == CONVERSE); + CORO_INVOKE_1(Interpret, _ctx->pic); + // Restore control after CallScene() from a conversation icon + if (_ctx->bConverse) + ControlOn(); + CORO_END_CODE; } @@ -500,10 +651,17 @@ static int CountOut = 1; // == 1 for immediate start of first scene * When the count expires, the screen will have faded. Ensure the scene | * is loaded, clear the screen, and start the new scene. */ -void ChangeScene() { +bool ChangeScene(bool bReset) { + + // Prevent attempt to fade-out when restarting game + if (bReset) { + CountOut = 1; // immediate start of first scene again + DelayedScene.scene = HookScene.scene = 0; + return false; + } if (IsRestoringScene()) - return; + return true; if (NextScene.scene != 0) { if (!CountOut) { @@ -517,12 +675,15 @@ void ChangeScene() { // Trigger pre-load and fade and start countdown CountOut = COUNTOUT_COUNT; FadeOutFast(NULL); + if (TinselV2) + _vm->_pcmMusic->startFadeOut(COUNTOUT_COUNT); break; } } else if (--CountOut == 0) { - ClearScreen(); + if (!TinselV2) + ClearScreen(); - NewScene(NextScene.scene, NextScene.entry); + StartNewScene(NextScene.scene, NextScene.entry); NextScene.scene = 0; switch (NextScene.trans) { @@ -535,20 +696,32 @@ void ChangeScene() { SetDoFadeIn(true); break; } - } + } else + _vm->_pcmMusic->fadeOutIteration(); } + + return false; } /** - * LoadBasicChunks + * CuttingScene */ +void CuttingScene(bool bCutting) { + bCuttingScene = bCutting; + + if (!bCutting) + WrapScene(); +} +/** + * LoadBasicChunks + */ void LoadBasicChunks(void) { byte *cptr; int numObjects; // Allocate RAM for savescene data - InitialiseSs(); + InitialiseSaveScenes(); // CHUNK_TOTAL_ACTORS seems to be missing in the released version, hard coding a value // TODO: Would be nice to just change 511 to MAX_SAVED_ALIVES @@ -581,6 +754,23 @@ void LoadBasicChunks(void) { cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_TOTAL_POLY); if (cptr != NULL) MaxPolygons(*cptr); + + if (TinselV2) { + // Global processes + cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_NUM_PROCESSES); + assert(cptr && (*cptr < 100)); + int num = *cptr; + cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_PROCESSES); + assert(!num || cptr); + GlobalProcesses(num, cptr); + + // CdPlay() stuff + cptr = FindChunk(MASTER_SCNHANDLE, CHUNK_CDPLAY_HANDLE); + assert(cptr); + uint32 playHandle = READ_LE_UINT32(cptr); + assert(playHandle < 512); + SetCdPlayHandle(playHandle); + } } //----------------- TinselEngine -------------------- @@ -602,10 +792,39 @@ static const GameSettings tinselSettings[] = { {NULL, NULL, 0, 0, NULL} }; +const char *TinselEngine::_sampleIndices[][3] = { + { "english.idx", "english1.idx", "english2.idx" }, + { "french.idx", "french1.idx", "french2.idx" }, + { "german.idx", "german1.idx", "german2.idx" }, + { "italian.idx", "italian1.idx", "italian2.idx" }, + { "spanish.idx", "spanish1.idx", "spanish2.idx" }, +}; +const char *TinselEngine::_sampleFiles[][3] = { + { "english.smp", "english1.smp", "english2.smp" }, + { "french.smp", "french1.smp", "french2.smp" }, + { "german.smp", "german1.smp", "german2.smp" }, + { "italian.smp", "italian1.smp", "italian2.smp" }, + { "spanish.smp", "spanish1.smp", "spanish2.smp" }, +}; +const char *TinselEngine::_textFiles[][3] = { + { "english.txt", "english1.txt", "english2.txt" }, + { "french.txt", "french1.txt", "french2.txt" }, + { "german.txt", "german1.txt", "german2.txt" }, + { "italian.txt", "italian1.txt", "italian2.txt" }, + { "spanish.txt", "spanish1.txt", "spanish2.txt" } +}; + + TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { _vm = this; + // Register debug flags + Common::addSpecialDebugLevel(kTinselDebugAnimations, "animations", "Animations debugging"); + Common::addSpecialDebugLevel(kTinselDebugActions, "actions", "Actions debugging"); + Common::addSpecialDebugLevel(kTinselDebugSound, "sound", "Sound debugging"); + Common::addSpecialDebugLevel(kTinselDebugMusic, "music", "Music debugging"); + // Setup mixer _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); @@ -629,9 +848,10 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) if (native_mt32) _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); - _music = new MusicPlayer(_driver); - //_music->setNativeMT32(native_mt32); - //_music->setAdlib(adlib); + _midiMusic = new MidiMusicPlayer(_driver); + _pcmMusic = new PCMMusicPlayer(); + //_midiMusic->setNativeMT32(native_mt32); + //_midiMusic->setAdlib(adlib); _musicVolume = ConfMan.getInt("music_volume"); @@ -644,25 +864,38 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) } TinselEngine::~TinselEngine() { + if (MoviePlaying()) + FinishBMV(); + delete _sound; - delete _music; + delete _midiMusic; + delete _pcmMusic; delete _console; delete _driver; _screenSurface.free(); - FreeSs(); + FreeSaveScenes(); FreeTextBuffer(); FreeHandleTable(); FreeActors(); FreeObjectList(); + FreeGlobalProcesses(); FreeGlobals(); delete _scheduler; } Common::Error TinselEngine::init() { // Initialize backend - initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, false); - - _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, 1); + if (getGameID() == GID_DW2) { +#ifndef DW2_EXACT_SIZE + initGraphics(640, 480, true); +#else + initGraphics(640, 432, true); +#endif + _screenSurface.create(640, 432, 1); + } else { + initGraphics(320, 200, false); + _screenSurface.create(320, 200, 1); + } g_system->getEventManager()->registerRandomSource(_random, "tinsel"); @@ -670,6 +903,8 @@ Common::Error TinselEngine::init() { _scheduler = new Scheduler(); + InitSysVars(); + // init memory manager MemoryInit(); @@ -684,20 +919,19 @@ Common::Error TinselEngine::init() { RebootCursor(); RebootDeadTags(); RebootMovers(); + resetUserEventTime(); RebootTimers(); RebootScalingReels(); DelayedScene.scene = HookScene.scene = 0; #endif + // Load in text strings + ChangeLanguage(g_language); + // Init palette and object managers, scheduler, keyboard and mouse RestartDrivers(); - // TODO: More stuff from dos_main.c may have to be added here - - // load in text strings - ChangeLanguage(g_language); - // load in graphics info SetupHandleTable(); @@ -707,14 +941,23 @@ Common::Error TinselEngine::init() { return Common::kNoError; } +void TinselEngine::syncSoundSettings() { + // Sync the engine with the config manager + int soundVolumeMusic = ConfMan.getInt("music_volume"); + int soundVolumeSFX = ConfMan.getInt("sfx_volume"); + int soundVolumeSpeech = ConfMan.getInt("speech_volume"); + + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX); + _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech); +} + Common::String TinselEngine::getSavegameFilename(int16 saveNum) const { char filename[256]; snprintf(filename, 256, "%s.%03d", getTargetName().c_str(), saveNum); return filename; } -#define GAME_FRAME_DELAY (1000 / ONE_SECOND) - Common::Error TinselEngine::go() { uint32 timerVal = 0; @@ -758,6 +1001,9 @@ Common::Error TinselEngine::go() { // Save/Restore scene file transfers ProcessSRQueue(); + // Handle any playing movie + FettleBMV(); + #ifdef DEBUG if (bFast) continue; // run flat-out @@ -765,7 +1011,12 @@ Common::Error TinselEngine::go() { // Loop processing events while there are any pending while (pollEvent()); - g_system->delayMillis(10); + DoCdChange(); + + if (MoviePlaying() && NextMovieTime()) + g_system->delayMillis(MAX(NextMovieTime() - g_system->getMillis() + MovieAudioLag(), 0)); + else + g_system->delayMillis(10); } // Write configuration @@ -776,8 +1027,11 @@ Common::Error TinselEngine::go() { void TinselEngine::NextGameCycle(void) { - // - ChangeScene(); + // Dim Music + _pcmMusic->dimIteration(); + + // Check for scene change + ChangeScene(false); // Allow a user event for this schedule ResetEcount(); @@ -785,8 +1039,11 @@ void TinselEngine::NextGameCycle(void) { // schedule process _scheduler->schedule(); - // redraw background - DrawBackgnd(); + if (MoviePlaying()) + CopyMovieToScreen(); + else + // redraw background + DrawBackgnd(); // Why waste resources on yet another process? FettleTimers(); @@ -810,7 +1067,13 @@ bool TinselEngine::pollEvent() { break; case Common::EVENT_MOUSEMOVE: - _mousePos = event.mouse; + { + // This fragment takes care of Tinsel 2 when it's been compiled with + // blank areas at the top and bottom of thes creen + int ySize = (g_system->getHeight() - _vm->screen().h) / 2; + if ((event.mouse.y >= ySize) && (event.mouse.y < (g_system->getHeight() - ySize))) + _mousePos = Common::Point(event.mouse.x, event.mouse.y - ySize); + } break; case Common::EVENT_KEYDOWN: @@ -828,7 +1091,6 @@ bool TinselEngine::pollEvent() { /** * Start the processes that continue between scenes. */ - void TinselEngine::CreateConstProcesses(void) { // Process to run the master script _scheduler->createProcess(PID_MASTER_SCR, MasterScriptProcess, NULL, 0); @@ -841,7 +1103,6 @@ void TinselEngine::CreateConstProcesses(void) { /** * Restart the game */ - void TinselEngine::RestartGame(void) { HoldItem(INV_NOICON); // Holding nothing @@ -878,7 +1139,6 @@ void TinselEngine::RestartGame(void) { /** * Init palette and object managers, scheduler, keyboard and mouse. */ - void TinselEngine::RestartDrivers(void) { // init the palette manager ResetPalAllocator(); @@ -902,13 +1162,12 @@ void TinselEngine::RestartDrivers(void) { } // Set midi volume - SetMidiVolume(volMidi); + SetMidiVolume(volMusic); } /** * Remove keyboard, mouse and joystick drivers. */ - void TinselEngine::ChopDrivers(void) { // remove sound driver StopMidi(); @@ -923,7 +1182,6 @@ void TinselEngine::ChopDrivers(void) { /** * Process a keyboard event */ - void TinselEngine::ProcessKeyEvent(const Common::Event &event) { // Handle any special keys immediately @@ -974,4 +1232,48 @@ void TinselEngine::ProcessKeyEvent(const Common::Event &event) { keypresses.push_back(event); } +const char *TinselEngine::getSampleIndex(LANGUAGE lang) { + int cd; + + if (TinselV2) { + cd = GetCurrentCD(); + assert((cd == 1) || (cd == 2)); + assert(((unsigned int) lang) < 5); + } else { + cd = 0; + lang = TXT_ENGLISH; + } + + return _sampleIndices[lang][cd]; +} + +const char *TinselEngine::getSampleFile(LANGUAGE lang) { + int cd; + + if (TinselV2) { + cd = GetCurrentCD(); + assert((cd == 1) || (cd == 2)); + assert(((unsigned int) lang) < 5); + } else { + cd = 0; + lang = TXT_ENGLISH; + } + + return _sampleFiles[lang][cd]; +} + +const char *TinselEngine::getTextFile(LANGUAGE lang) { + assert(((unsigned int) lang) < 5); + + int cd; + + if (TinselV2) { + cd = GetCurrentCD(); + assert((cd == 1) || (cd == 2)); + } else + cd = 0; + + return _textFiles[lang][cd]; +} + } // End of namespace Tinsel -- cgit v1.2.3