From 01f6e2db12aa980aa316b80bc0e4b29e58cf2b5e Mon Sep 17 00:00:00 2001 From: Le Philousophe Date: Mon, 20 May 2019 20:56:35 +0200 Subject: CRYOMNI3D: Implement countdown --- engines/cryomni3d/fixed_image.cpp | 2 - engines/cryomni3d/versailles/engine.cpp | 37 ++++++++++---- engines/cryomni3d/versailles/engine.h | 18 ++++++- engines/cryomni3d/versailles/logic.cpp | 80 +++++++++++++++++++++++++++++++ engines/cryomni3d/versailles/menus.cpp | 3 +- engines/cryomni3d/versailles/saveload.cpp | 8 ++-- engines/cryomni3d/versailles/toolbar.cpp | 5 -- 7 files changed, 130 insertions(+), 23 deletions(-) (limited to 'engines/cryomni3d') diff --git a/engines/cryomni3d/fixed_image.cpp b/engines/cryomni3d/fixed_image.cpp index f4e900f333..f5f354aa0b 100644 --- a/engines/cryomni3d/fixed_image.cpp +++ b/engines/cryomni3d/fixed_image.cpp @@ -191,7 +191,6 @@ void ZonFixedImage::manage() { // Force poll events even when we must refresh the cursor if (!_engine.pollEvents() && !_refreshCursor) { g_system->updateScreen(); - // TODO: countdown even when no events return; } _refreshCursor = false; @@ -266,7 +265,6 @@ void ZonFixedImage::manage() { } - // TODO: handle countdown g_system->updateScreen(); } diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp index 124f638108..fd88f8efc1 100644 --- a/engines/cryomni3d/versailles/engine.cpp +++ b/engines/cryomni3d/versailles/engine.cpp @@ -54,7 +54,8 @@ CryOmni3DEngine_Versailles::CryOmni3DEngine_Versailles(OSystem *syst, _currentPlace(nullptr), _currentWarpImage(nullptr), _fixedImage(nullptr), _transitionAnimateWarp(true), _forceRedrawWarp(false), _forcePaletteUpdate(false), _fadedPalette(false), _loadedSave(-1), _dialogsMan(this), - _musicVolumeFactor(1.), _musicCurrentFile(nullptr) { + _musicVolumeFactor(1.), _musicCurrentFile(nullptr), + _countingDown(false), _countdownNextEvent(0) { } CryOmni3DEngine_Versailles::~CryOmni3DEngine_Versailles() { @@ -127,6 +128,8 @@ Common::Error CryOmni3DEngine_Versailles::run() { initDocPeopleRecord(); _docManager.init(&_sprites, &_fontManager, &_messages, this); + _countdownSurface.create(40, 15, Graphics::PixelFormat::createFormatCLUT8()); + initGraphics(640, 480); setMousePos(Common::Point(320, 200)); @@ -609,7 +612,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) { it++) { *it = 0; } - // TODO: countdown + initCountdown(); _inventory.clear(); } else if (_currentLevel <= 6) { // TODO: remove this when we implemented all levels @@ -1166,7 +1169,7 @@ int CryOmni3DEngine_Versailles::handleWarp() { const Graphics::Surface *result = _omni3dMan.getSurface(); g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h); if (!exit) { - // TODO: countdown + drawCountdown(); g_system->updateScreen(); if (firstDraw && _fadedPalette) { fadeInPalette(_mainPalette); @@ -1179,14 +1182,13 @@ int CryOmni3DEngine_Versailles::handleWarp() { const Graphics::Surface *result = _omni3dMan.getSurface(); g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h); if (!exit) { - // TODO: countdown + drawCountdown(); g_system->updateScreen(); } - // TODO: cursorUseZones moving = false; } else { if (!exit) { - // TODO: countdown + // Countdown is updated as soon as it changes g_system->updateScreen(); } } @@ -1203,6 +1205,11 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId, getNextKey().keycode == Common::KEYCODE_SPACE) { // Prepare background using alpha const Graphics::Surface *original = _omni3dMan.getSurface(); + + // Display surface with countdown before showing toolbar just to be sure + g_system->copyRectToScreen(original->getPixels(), original->pitch, 0, 0, original->w, original->h); + drawCountdown(); + bool mustRedraw = displayToolbar(original); // Don't redraw if we abort game if (_abortCommand != AbortNoAbort) { @@ -1216,7 +1223,16 @@ bool CryOmni3DEngine_Versailles::handleWarpMouse(unsigned int *actionId, return false; } - // TODO: countdown + if (countDown()) { + // Time has changed: need redraw + // Don't redraw if we abort game + if (_abortCommand != AbortNoAbort) { + return true; + } + + _forceRedrawWarp = true; + redrawWarp(); + } const Object *selectedObj = _inventory.selectedObject(); if (selectedObj) { @@ -1323,7 +1339,7 @@ void CryOmni3DEngine_Versailles::animateWarpTransition(const Transition *transit const Graphics::Surface *result = _omni3dMan.getSurface(); g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h); - // TODO: countdown + drawCountdown(); g_system->updateScreen(); if (fabs(oldDeltaAlpha - deltaAlpha) < 0.001 && fabs(oldDeltaBeta - deltaBeta) < 0.001) { @@ -1344,7 +1360,7 @@ void CryOmni3DEngine_Versailles::redrawWarp() { if (_forceRedrawWarp) { const Graphics::Surface *result = _omni3dMan.getSurface(); g_system->copyRectToScreen(result->getPixels(), result->pitch, 0, 0, result->w, result->h); - // TODO: countdown + drawCountdown(); g_system->updateScreen(); _forceRedrawWarp = false; } @@ -1534,7 +1550,8 @@ void CryOmni3DEngine_Versailles::playInGameVideo(const Common::String &filename, g_system->showMouse(false); lockPalette(0, 241); // Videos are like music because if you mute music in game it will mute videos soundtracks - playHNM(filename, Audio::Mixer::kMusicSoundType); + playHNM(filename, Audio::Mixer::kMusicSoundType, nullptr, + static_cast(&CryOmni3DEngine_Versailles::drawCountdownVideo)); clearKeys(); unlockPalette(); if (restoreCursorPalette) { diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h index e958e3ccb5..abfb1a4026 100644 --- a/engines/cryomni3d/versailles/engine.h +++ b/engines/cryomni3d/versailles/engine.h @@ -155,7 +155,7 @@ struct GameVariables { kUsedVaubanBlueprint2, // OK // 40 kSeenMemorandum, // OK kCollectScissors, // OK - kSavedCountdown, // TODO: calculate it in real time + kSavedCountdown, // OK kMax }; }; @@ -309,7 +309,7 @@ private: bool canVisit() const; Common::String getSaveFileName(bool visit, unsigned int saveNum) const; void getSavesList(bool visit, Common::Array &saveNames); - void saveGame(bool visit, unsigned int saveNum, const Common::String &saveName) const; + void saveGame(bool visit, unsigned int saveNum, const Common::String &saveName); bool loadGame(bool visit, unsigned int saveNum); void animateCursor(const Object *object); @@ -397,6 +397,20 @@ private: static const MsgBoxParameters kFixedimageMsgBoxParameters; static const FixedImageConfiguration kFixedImageConfiguration; + // Countdown + void initCountdown(); + void syncCountdown(); + inline bool countDown() { if (_countingDown) { return doCountDown(); } else { return false; } } + inline void drawCountdown(Graphics::ManagedSurface *surface = nullptr) { if (_countingDown) { doDrawCountdown(surface); } } + void drawCountdownVideo(unsigned int frameNum) { drawCountdown(); } + + bool _countingDown; + unsigned int _countdownNextEvent; + char _countdownValue[6]; + Graphics::ManagedSurface _countdownSurface; + bool doCountDown(); + void doDrawCountdown(Graphics::ManagedSurface *surface); + // Objects template void genericDisplayObject(); diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp index e65d5a62dc..af20e9c3af 100644 --- a/engines/cryomni3d/versailles/logic.cpp +++ b/engines/cryomni3d/versailles/logic.cpp @@ -4085,5 +4085,85 @@ FILTER_EVENT(6, 19) { #undef FILTER_EVENT #undef INIT_PLACE +// Countdown + +void CryOmni3DEngine_Versailles::initCountdown() { + strcpy(_countdownValue, "05:00"); + if (_gameVariables[GameVariables::kSavedCountdown]) { + unsigned int counter = _gameVariables[GameVariables::kSavedCountdown]; + _countdownValue[4] = counter; + counter >>= 8; + _countdownValue[3] = counter; + counter >>= 8; + _countdownValue[1] = counter; + counter >>= 8; + _countdownValue[0] = counter; + } +} + +void CryOmni3DEngine_Versailles::syncCountdown() { + unsigned int counter = 0; + counter |= _countdownValue[0]; + counter <<= 8; + counter |= _countdownValue[1]; + counter <<= 8; + counter |= _countdownValue[3]; + counter <<= 8; + counter |= _countdownValue[4]; + _gameVariables[GameVariables::kSavedCountdown] = counter; +} + +bool CryOmni3DEngine_Versailles::doCountDown() { + if (g_system->getMillis() > _countdownNextEvent) { + _countdownNextEvent = g_system->getMillis() + 1000; + // Decrement countdown + _countdownValue[4]--; + if (_countdownValue[4] < '0') { + _countdownValue[4] = '9'; + _countdownValue[3]--; + if (_countdownValue[3] < '0') { + _countdownValue[3] = '5'; + _countdownValue[1]--; + if (_countdownValue[1] < '0') { + _countdownValue[1] = '9'; + _countdownValue[0]--; + if (_countdownValue[0] < '0') { + // Finished! + _countingDown = false; + playTransitionEndLevel(8); + _abortCommand = AbortGameOver; + } + } + } + } + + // Redraw surface + _countdownSurface.clear(0); + _fontManager.setCurrentFont(3); + _fontManager.setTransparentBackground(true); + _fontManager.setForeColor(241); + _fontManager.setLineHeight(14); + _fontManager.setSpaceWidth(0); + _fontManager.setCharSpacing(1); + _fontManager.setSurface(&_countdownSurface); + + _fontManager.displayStr(0, 2, _countdownValue); + + // Surface changed: need redraw + return true; + } else { + return false; + } +} + +void CryOmni3DEngine_Versailles::doDrawCountdown(Graphics::ManagedSurface *surface) { + if (surface) { + surface->blitFrom(_countdownSurface, Common::Point(600, 0)); + } else { + g_system->copyRectToScreen(_countdownSurface.getPixels(), _countdownSurface.pitch, 600, 0, + _countdownSurface.w, _countdownSurface.h); + } +} + } // End of namespace Versailles } // End of namespace CryOmni3D diff --git a/engines/cryomni3d/versailles/menus.cpp b/engines/cryomni3d/versailles/menus.cpp index f052cd7165..9a4447876c 100644 --- a/engines/cryomni3d/versailles/menus.cpp +++ b/engines/cryomni3d/versailles/menus.cpp @@ -882,7 +882,8 @@ void CryOmni3DEngine_Versailles::displayMessageBox(const MsgBoxParameters ¶m rct.grow(-6); _fontManager.setupBlock(rct); _fontManager.displayBlockText(msg); - // TODO: countdown + + drawCountdown(&dstSurface); g_system->copyRectToScreen(dstSurface.getPixels(), dstSurface.pitch, 0, 0, dstSurface.w, dstSurface.h); diff --git a/engines/cryomni3d/versailles/saveload.cpp b/engines/cryomni3d/versailles/saveload.cpp index a5ea1a1beb..752cb761e4 100644 --- a/engines/cryomni3d/versailles/saveload.cpp +++ b/engines/cryomni3d/versailles/saveload.cpp @@ -114,7 +114,7 @@ void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &s } void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum, - const Common::String &saveName) const { + const Common::String &saveName) { if (visit && saveNum == 1) { error("Can't erase bootstrap visit"); } @@ -133,6 +133,9 @@ void CryOmni3DEngine_Versailles::saveGame(bool visit, unsigned int saveNum, return; } + // Sync countdown to game variable before saving it to file + syncCountdown(); + // Write save name char saveNameC[SAVE_DESCRIPTION_LEN]; memset(saveNameC, 0, sizeof(saveNameC)); @@ -292,6 +295,7 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) { if (_gameVariables[GameVariables::kCurrentTime] == 0) { _gameVariables[GameVariables::kCurrentTime] = 1; } + initCountdown(); // Everything has been loaded, setup new level // We will set places states and warp coordinates just after that to avoid them from being reset @@ -307,8 +311,6 @@ bool CryOmni3DEngine_Versailles::loadGame(bool visit, unsigned int saveNum) { placeIt->state = placesStates[i]; } - // TODO: countdown - return true; } diff --git a/engines/cryomni3d/versailles/toolbar.cpp b/engines/cryomni3d/versailles/toolbar.cpp index e0168e29cc..2f9426beac 100644 --- a/engines/cryomni3d/versailles/toolbar.cpp +++ b/engines/cryomni3d/versailles/toolbar.cpp @@ -410,9 +410,6 @@ bool Toolbar::displayToolbar(const Graphics::Surface *original) { _bgSurface.w, original->h)); _engine->makeTranslucent(_bgSurface, subset); - // Draw the original surface on the surface to use for toolbar - g_system->copyRectToScreen(original->getPixels(), original->pitch, 0, 0, original->w, original->h); - // WORKAROUND: Reset the inventory status at init to let sprites highlighted until toolbar is hidden _inventorySelected = -1; _inventoryHovered = -1; @@ -479,8 +476,6 @@ void Toolbar::handleToolbarEvents(const Graphics::Surface *original) { // No need of original surface because the toolbar is fully displayed drawToolbar(original); - // TODO: countdown - g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0, original->h - _destSurface.h, _destSurface.w, _destSurface.h); g_system->updateScreen(); -- cgit v1.2.3