aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/tinsel.cpp
diff options
context:
space:
mode:
authorFilippos Karapetis2008-12-01 20:35:36 +0000
committerFilippos Karapetis2008-12-01 20:35:36 +0000
commitaf945ac7881ae7e414f004bd0e99e8c3b5d76be9 (patch)
tree72e9c6fd43406e2021973b4f163ab4faa10143fb /engines/tinsel/tinsel.cpp
parentf10f151ff742801e12534bb052bd89419bf906cb (diff)
downloadscummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.tar.gz
scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.tar.bz2
scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.zip
Merged the tinsel 2 engine with tinsel 1. Both Discworld 1 and Discworld 2 should be completable
svn-id: r35196
Diffstat (limited to 'engines/tinsel/tinsel.cpp')
-rw-r--r--engines/tinsel/tinsel.cpp490
1 files changed, 396 insertions, 94 deletions
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<Common::EventType> 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,38 +254,43 @@ 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;
}
}
@@ -275,9 +298,35 @@ void KeyboardProcess(CORO_PARAM, const void *) {
}
/**
+ * 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<int>(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