/* 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 3 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, see . * */ #include "engines/nancy/cursor.h" #include "engines/nancy/input.h" #include "engines/nancy/nancy.h" #include "engines/nancy/graphics.h" #include "engines/nancy/sound.h" #include "engines/nancy/time.h" #include "engines/nancy/util.h" #include "engines/nancy/state/scene.h" #include "engines/nancy/ui/clock.h" namespace Nancy { namespace UI { Clock::Clock() : RenderObject(g_nancy->getGameType() == kGameTypeVampire ? 11 : 10), _animation(g_nancy->getGameType() == kGameTypeVampire ? 10 : 11, this), _staticImage(9), _clockData(nullptr), _locked(false) {} void Clock::init() { Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0; _clockData = (const CLOK *)g_nancy->getEngineData("CLOK"); assert(_clockData); // Calculate the size and location of the surface we'll need to draw the clock hands, // since their dest rects are in absolute screen space Common::Rect clockSurfaceScreenBounds; for (const Common::Rect &r : _clockData->hoursHandDests) { clockSurfaceScreenBounds.extend(r); } for (const Common::Rect &r : _clockData->minutesHandDests) { clockSurfaceScreenBounds.extend(r); } _drawSurface.create(clockSurfaceScreenBounds.width(), clockSurfaceScreenBounds.height(), g_nancy->_graphics->getInputPixelFormat()); moveTo(clockSurfaceScreenBounds); _staticImage._drawSurface.create(object0, _clockData->staticImageSrc); _staticImage.moveTo(_clockData->staticImageDest); _staticImage.setVisible(false); _staticImage.setTransparent(g_nancy->getGameType() == kGameTypeVampire); _animation.setTransparent(true); _animation.setVisible(false); if (g_nancy->getGameType() == kGameTypeVampire) { GraphicsManager::loadSurfacePalette(_drawSurface, "OBJECT0"); } setTransparent(true); _animation.init(); } void Clock::registerGraphics() { _staticImage.registerGraphics(); _animation.registerGraphics(); RenderObject::registerGraphics(); } void Clock::updateGraphics() { setVisible(_animation.getCurrentFrame() >= (g_nancy->getGameType() == kGameTypeVampire ? 5 : 1)); if (_isVisible) { Time newPlayerTime = NancySceneState.getPlayerTime(); if (newPlayerTime == _playerTime || newPlayerTime.getMinutes() / 15 != _playerTime.getMinutes() / 15 || newPlayerTime.getHours() != _playerTime.getHours()) { _playerTime = newPlayerTime; drawClockHands(); } } } void Clock::handleInput(NancyInput &input) { if (!_locked) { _animation.handleInput(input); } } void Clock::drawClockHands() { Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0; uint hours = _playerTime.getHours(); if (hours >= 12) { hours -= 12; } uint minutesHand = _playerTime.getMinutes() / 15; Common::Rect hoursDest = _clockData->hoursHandDests[hours]; Common::Rect minutesDest = _clockData->minutesHandDests[minutesHand]; hoursDest.translate(-_screenPosition.left, -_screenPosition.top); minutesDest.translate(-_screenPosition.left, -_screenPosition.top); _drawSurface.clear(g_nancy->_graphics->getTransColor()); _drawSurface.blitFrom(object0, _clockData->hoursHandSrcs[hours], hoursDest); _drawSurface.blitFrom(object0, _clockData->minutesHandSrcs[minutesHand], minutesDest); } void Clock::ClockAnim::init() { auto *bootSummary = GetEngineData(BSUM); assert(bootSummary); _srcRects = _owner->_clockData->animSrcs; _destRects = _owner->_clockData->animDests; _highlightSrcRect = bootSummary->clockHighlightSrc; _highlightDestRect = bootSummary->extraButtonHighlightDest; if (_destRects.size()) { moveTo(bootSummary->extraButtonHotspot); } else { moveTo(_owner->_clockData->screenPosition); } _timeToKeepOpen = _owner->_clockData->timeToKeepOpen; _frameTime = _owner->_clockData->frameTime; _alwaysHighlightCursor = true; _hotspot = _screenPosition; } void Clock::ClockAnim::updateGraphics() { AnimatedButton::updateGraphics(); if (_isOpen && !isPlaying() && (g_nancy->getTotalPlayTime() > _closeTime || _owner->_locked) && _isVisible) { setOpen(false); if (g_nancy->getGameType() == kGameTypeVampire) { _owner->_staticImage.setVisible(false); } g_nancy->_sound->playSound("GLOB"); } } void Clock::ClockAnim::onClick() { if (!isPlaying()) { setOpen(!_isOpen); if (!_isOpen) { if (g_nancy->getGameType() == kGameTypeVampire) { _owner->_staticImage.setVisible(false); } } else if (g_nancy->getGameType() != kGameTypeVampire) { _owner->_staticImage.setVisible(true); } _owner->_playerTime = NancySceneState.getPlayerTime(); g_nancy->_sound->playSound("GLOB"); } } void Clock::ClockAnim::onTrigger() { if (_isOpen) { _closeTime = g_nancy->getTotalPlayTime() + _timeToKeepOpen; if (g_nancy->getGameType() == kGameTypeVampire) { _owner->_staticImage.setVisible(true); } } else { _owner->setVisible(false); _owner->_staticImage.setVisible(false); } } void Nancy5Clock::init() { _clockData = GetEngineData(CLOK); assert(_clockData); setVisible(true); } void Nancy5Clock::updateGraphics() { // Show current day if (_currentDay < 3) { if (NancySceneState.getEventFlag(59, true) && _currentDay == 1) { _currentDay = 2; _drawSurface.create(g_nancy->_graphics->_object0, _clockData->daySrcs[2]); moveTo(_clockData->staticImageDest); setVisible(true); setTransparent(true); } else if (NancySceneState.getEventFlag(58, true) && _currentDay == 0) { _currentDay = 1; _drawSurface.create(g_nancy->_graphics->_object0, _clockData->daySrcs[1]); moveTo(_clockData->staticImageDest); setVisible(true); setTransparent(true); } else if (NancySceneState.getEventFlag(57, true) && _currentDay == -1) { _currentDay = 0; _drawSurface.create(g_nancy->_graphics->_object0, _clockData->daySrcs[0]); moveTo(_clockData->staticImageDest); setVisible(true); setTransparent(true); } } // Show demolition countdown if (NancySceneState.getEventFlag(320, true)) { _currentDay = 3; Time timerTime = NancySceneState.getTimerTime(); int32 countdownFrameID = MIN((uint32)timerTime / (_clockData->countdownTime / 12), 13); if (countdownFrameID != _countdownProgress) { _countdownProgress = countdownFrameID; _drawSurface.create(g_nancy->_graphics->_object0, _clockData->countdownSrcs[_countdownProgress]); moveTo(_clockData->staticImageDest); setVisible(true); } } } } // End of namespace UI } // End of namespace Nancy