aboutsummaryrefslogtreecommitdiff
path: root/engines/neverhood/diskplayerscene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/neverhood/diskplayerscene.cpp')
-rw-r--r--engines/neverhood/diskplayerscene.cpp511
1 files changed, 511 insertions, 0 deletions
diff --git a/engines/neverhood/diskplayerscene.cpp b/engines/neverhood/diskplayerscene.cpp
new file mode 100644
index 0000000000..d972943759
--- /dev/null
+++ b/engines/neverhood/diskplayerscene.cpp
@@ -0,0 +1,511 @@
+/* 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.
+ *
+ */
+
+#include "neverhood/diskplayerscene.h"
+#include "neverhood/mouse.h"
+
+namespace Neverhood {
+
+static const uint32 kDiskplayerPaletteFileHashes[] = {
+ 0x03B78240,
+ 0x34B32B08,
+ 0x4F2569D4,
+ 0x07620590,
+ 0x38422401
+};
+
+static const byte kDiskplayerInitArray[] = {
+ 2, 1, 4, 5, 3, 11, 8, 6, 7, 9, 10, 17, 16, 18, 19, 20, 15, 14, 13, 12
+};
+
+static const uint32 kDiskplayerSmackerFileHashes[] = {
+ 0x010A2810,
+ 0x020A2810,
+ 0x040A2810,
+ 0x080A2810,
+ 0x100A2810,
+ 0x200A2810,
+ 0x400A2810,
+ 0x800A2810,
+ 0x000A2811,
+ 0x010C2810,
+ 0x020C2810,
+ 0x040C2810,
+ 0x080C2810,
+ 0x100C2810,
+ 0x200C2810,
+ 0x400C2810,
+ 0x800C2810,
+ 0x000C2811,
+ 0x000C2812,
+ 0x02002810,
+ 0x04002810
+};
+
+static const uint32 kDiskplayerSlotFileHashes1[] = {
+ 0x81312280,
+ 0x01312281,
+ 0x01312282,
+ 0x01312284,
+ 0x01312288,
+ 0x01312290,
+ 0x013122A0,
+ 0x013122C0,
+ 0x01312200,
+ 0x82312280,
+ 0x02312281,
+ 0x02312282,
+ 0x02312284,
+ 0x02312288,
+ 0x02312290,
+ 0x023122A0,
+ 0x023122C0,
+ 0x02312200,
+ 0x02312380,
+ 0x04312281
+};
+
+static const uint32 kDiskplayerSlotFileHashes2[] = {
+ 0x90443A00,
+ 0x90443A18,
+ 0x90443A28,
+ 0x90443A48,
+ 0x90443A88,
+ 0x90443B08,
+ 0x90443808,
+ 0x90443E08,
+ 0x90443208,
+ 0xA0443A00,
+ 0xA0443A18,
+ 0xA0443A28,
+ 0xA0443A48,
+ 0xA0443A88,
+ 0xA0443B08,
+ 0xA0443808,
+ 0xA0443E08,
+ 0xA0443208,
+ 0xA0442A08,
+ 0xC0443A18
+};
+
+static const uint32 kDiskplayerSlotFileHashes3[] = {
+ 0x10357320,
+ 0x10557320,
+ 0x10957320,
+ 0x11157320,
+ 0x12157320,
+ 0x14157320,
+ 0x18157320,
+ 0x00157320,
+ 0x30157320,
+ 0x1035B320,
+ 0x1055B320,
+ 0x1095B320,
+ 0x1115B320,
+ 0x1215B320,
+ 0x1415B320,
+ 0x1815B320,
+ 0x0015B320,
+ 0x3015B320,
+ 0x5015B320,
+ 0x10543320
+};
+
+static const uint32 kDiskplayerSlotFileHashes4[] = {
+ 0xDC8020E4,
+ 0xDC802164,
+ 0xDC802264,
+ 0xDC802464,
+ 0xDC802864,
+ 0xDC803064,
+ 0xDC800064,
+ 0xDC806064,
+ 0xDC80A064,
+ 0xDC8020E7,
+ 0xDC802167,
+ 0xDC802267,
+ 0xDC802467,
+ 0xDC802867,
+ 0xDC803067,
+ 0xDC800067,
+ 0xDC806067,
+ 0xDC80A067,
+ 0xDC812067,
+ 0xDC802161
+};
+
+AsDiskplayerSceneKey::AsDiskplayerSceneKey(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100) {
+
+ createSurface1(0x100B90B4, 1200);
+ _x = 211;
+ _y = 195;
+ startAnimation(0x100B90B4, 0, -1);
+ _newStickFrameIndex = 0;
+ _needRefresh = true;
+ updatePosition();
+ setVisible(false);
+}
+
+uint32 AsDiskplayerSceneKey::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ gotoNextState();
+ break;
+ }
+ return messageResult;
+}
+
+void AsDiskplayerSceneKey::stDropKey() {
+ startAnimation(0x100B90B4, 0, -1);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsDiskplayerSceneKey::handleMessage);
+ NextState(&AsDiskplayerSceneKey::stDropKeyDone);
+ setVisible(true);
+}
+
+void AsDiskplayerSceneKey::stDropKeyDone() {
+ stopAnimation();
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Sprite::handleMessage);
+ setVisible(false);
+}
+
+DiskplayerPlayButton::DiskplayerPlayButton(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene)
+ : StaticSprite(vm, 1400), _diskplayerScene(diskplayerScene), _isPlaying(false) {
+
+ loadSprite(0x24A4A664, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
+ setVisible(false);
+ loadSound(0, 0x44043000);
+ loadSound(1, 0x44045000);
+ SetMessageHandler(&DiskplayerPlayButton::handleMessage);
+}
+
+uint32 DiskplayerPlayButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (!_diskplayerScene->getDropKey()) {
+ if (_isPlaying) {
+ sendMessage(_diskplayerScene, 0x2001, 0);
+ release();
+ } else {
+ sendMessage(_diskplayerScene, 0x2000, 0);
+ press();
+ }
+ }
+ updatePosition();
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+void DiskplayerPlayButton::press() {
+ if (!_isPlaying) {
+ setVisible(true);
+ updatePosition();
+ playSound(0);
+ _isPlaying = true;
+ }
+}
+
+void DiskplayerPlayButton::release() {
+ if (_isPlaying) {
+ setVisible(false);
+ updatePosition();
+ playSound(1);
+ _isPlaying = false;
+ }
+}
+
+DiskplayerSlot::DiskplayerSlot(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene, int slotIndex, bool isAvailable)
+ : Entity(vm, 0), _diskplayerScene(diskplayerScene), _isLocked(false), _isBlinking(false),
+ _blinkCountdown(0), _initialBlinkCountdown(2), _inactiveSlot(NULL), _appearSlot(NULL), _activeSlot(NULL) {
+
+ if (isAvailable && slotIndex < 20) {
+ _inactiveSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes1[slotIndex], 1100));
+ _appearSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes2[slotIndex], 1000));
+ _activeSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes3[slotIndex], 1100));
+ _inactiveSlot->setVisible(false);
+ _appearSlot->setVisible(false);
+ _activeSlot->setVisible(false);
+ loadSound(0, 0x46210074);
+ setSoundPan(0, slotIndex * 100 / 19);
+ } else if (slotIndex != 20) {
+ _activeSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes4[slotIndex], 1100));
+ _activeSlot->setVisible(false);
+ }
+ SetUpdateHandler(&DiskplayerSlot::update);
+}
+
+void DiskplayerSlot::update() {
+ if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) {
+ if (_isBlinking) {
+ if (_inactiveSlot)
+ _inactiveSlot->setVisible(true);
+ if (_activeSlot)
+ _activeSlot->setVisible(false);
+ _blinkCountdown = _initialBlinkCountdown / 2;
+ } else {
+ if (_inactiveSlot)
+ _inactiveSlot->setVisible(false);
+ if (_activeSlot)
+ _activeSlot->setVisible(true);
+ _blinkCountdown = _initialBlinkCountdown;
+ }
+ _isBlinking = !_isBlinking;
+ }
+}
+
+void DiskplayerSlot::appear() {
+ if (_inactiveSlot)
+ _inactiveSlot->setVisible(true);
+ if (_appearSlot)
+ _appearSlot->setVisible(true);
+ if (_inactiveSlot)
+ playSound(0);
+}
+
+void DiskplayerSlot::play() {
+ if (!_isLocked) {
+ if (_inactiveSlot)
+ _inactiveSlot->setVisible(false);
+ if (_activeSlot)
+ _activeSlot->setVisible(true);
+ _isBlinking = true;
+ _blinkCountdown = 0;
+ }
+}
+
+void DiskplayerSlot::activate() {
+ if (!_isLocked)
+ _blinkCountdown = _initialBlinkCountdown;
+}
+
+void DiskplayerSlot::stop() {
+ if (!_isLocked) {
+ if (_inactiveSlot)
+ _inactiveSlot->setVisible(true);
+ if (_activeSlot)
+ _activeSlot->setVisible(false);
+ _isBlinking = false;
+ _blinkCountdown = 0;
+ }
+}
+
+DiskplayerScene::DiskplayerScene(NeverhoodEngine *vm, Module *parentModule, int paletteIndex)
+ : Scene(vm, parentModule), _diskIndex(0), _appearCountdown(0), _tuneInCountdown(0),
+ _hasAllDisks(false), _dropKey(false), _inputDisabled(true), _updateStatus(kUSStopped) {
+
+ int availableDisksCount = 0;
+
+ setBackground(0x8A000044);
+ setPalette(kDiskplayerPaletteFileHashes[paletteIndex]);
+
+ _ssPlayButton = insertSprite<DiskplayerPlayButton>(this);
+ addCollisionSprite(_ssPlayButton);
+
+ _asKey = insertSprite<AsDiskplayerSceneKey>();
+
+ for (int i = 0; i < 20; i++) {
+ _diskAvailable[i] = false;
+ if (getSubVar(VA_IS_TAPE_INSERTED, i))
+ availableDisksCount++;
+ }
+
+ for (int i = 0; i < availableDisksCount; i++)
+ _diskAvailable[kDiskplayerInitArray[i] - 1] = true;
+
+ for (int slotIndex = 0; slotIndex < 20; slotIndex++) {
+ _diskSlots[slotIndex] = new DiskplayerSlot(_vm, this, slotIndex, _diskAvailable[slotIndex]);
+ addEntity(_diskSlots[slotIndex]);
+ }
+
+ _hasAllDisks = availableDisksCount == 20;
+
+ if (_hasAllDisks && !getGlobalVar(V_HAS_FINAL_KEY))
+ _dropKey = true;
+
+ _finalDiskSlot = new DiskplayerSlot(_vm, this, 20, false);
+ addEntity(_finalDiskSlot);
+
+ insertPuzzleMouse(0x000408A8, 20, 620);
+ showMouse(false);
+
+ _diskSmackerPlayer = new SmackerPlayer(_vm, this, 0x08288103, false, true);
+ addEntity(_diskSmackerPlayer);
+ addSurface(_diskSmackerPlayer->getSurface());
+ _diskSmackerPlayer->setDrawPos(154, 86);
+ _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder());
+
+ _palette->usePalette();
+
+ SetMessageHandler(&DiskplayerScene::handleMessage);
+ SetUpdateHandler(&DiskplayerScene::update);
+ _appearCountdown = 6;
+
+}
+
+void DiskplayerScene::update() {
+ Scene::update();
+
+ if (_updateStatus == kUSTuningIn && _diskSmackerPlayer->isDone()) {
+ if (_diskAvailable[_diskIndex])
+ playDisk();
+ else
+ playStatic();
+ } else if (_updateStatus == kUSPlaying && _diskSmackerPlayer->isDone()) {
+ _diskSlots[_diskIndex]->stop();
+ _diskIndex++;
+ if (_hasAllDisks) {
+ if (_diskIndex != 20) {
+ playDisk();
+ } else if (_dropKey) {
+ playDisk();
+ _updateStatus = kUSPlayingFinal;
+ } else {
+ _diskIndex = 0;
+ stop();
+ }
+ } else if (_diskIndex != 20) {
+ tuneIn();
+ } else {
+ _diskIndex = 0;
+ stop();
+ }
+ } else if (_updateStatus == kUSPlayingFinal) {
+ if (_diskSmackerPlayer->getFrameNumber() == 133) {
+ _asKey->stDropKey();
+ setGlobalVar(V_HAS_FINAL_KEY, 1);
+ } else if (_diskSmackerPlayer->isDone()) {
+ for (int i = 0; i < 20; i++) {
+ _diskSlots[i]->setLocked(false);
+ _diskSlots[i]->stop();
+ }
+ _diskIndex = 0;
+ stop();
+ showMouse(true);
+ _dropKey = false;
+ }
+ }
+
+ if (_appearCountdown != 0 && (--_appearCountdown == 0)) {
+ _diskSlots[_diskIndex]->appear();
+ if (_dropKey) {
+ _diskSlots[_diskIndex]->activate();
+ _diskSlots[_diskIndex]->setLocked(true);
+ }
+ _diskIndex++;
+ while (!_diskAvailable[_diskIndex] && _diskIndex < 19)
+ _diskIndex++;
+ if (_diskIndex < 20) {
+ _appearCountdown = 1;
+ } else {
+ _diskIndex = 0;
+ _inputDisabled = false;
+ if (_dropKey) {
+ _ssPlayButton->press();
+ _tuneInCountdown = 2;
+ } else {
+ showMouse(true);
+ _diskSlots[_diskIndex]->activate();
+ }
+ }
+ }
+
+ if (_tuneInCountdown != 0 && (--_tuneInCountdown == 0))
+ playDisk();
+
+}
+
+uint32 DiskplayerScene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ if (!_inputDisabled) {
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ sendMessage(_parentModule, 0x1009, 0);
+ } else if (!_dropKey &&
+ param.asPoint().x > 38 && param.asPoint().x < 598 &&
+ param.asPoint().y > 400 && param.asPoint().y < 460) {
+
+ _diskSlots[_diskIndex]->stop();
+ _diskIndex = (param.asPoint().x - 38) / 28;
+ _diskSlots[_diskIndex]->activate();
+ if (_updateStatus == kUSPlaying) {
+ if (_diskAvailable[_diskIndex])
+ playDisk();
+ else
+ playStatic();
+ }
+ }
+ break;
+ case 0x2000:
+ tuneIn();
+ break;
+ case 0x2001:
+ stop();
+ break;
+ }
+ }
+ return 0;
+}
+
+void DiskplayerScene::stop() {
+ _diskSmackerPlayer->open(0x08288103, true);
+ _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder());
+ _palette->usePalette();
+ _ssPlayButton->release();
+ _updateStatus = kUSStopped;
+ _diskSlots[_diskIndex]->activate();
+}
+
+void DiskplayerScene::tuneIn() {
+ _diskSmackerPlayer->open(0x900001C1, false);
+ _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder());
+ _palette->usePalette();
+ _ssPlayButton->release();
+ _updateStatus = kUSTuningIn;
+ _diskSlots[_diskIndex]->activate();
+}
+
+void DiskplayerScene::playDisk() {
+ _diskSmackerPlayer->open(kDiskplayerSmackerFileHashes[_diskIndex], false);
+ _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder());
+ _palette->usePalette();
+ _updateStatus = kUSPlaying;
+ _diskSlots[_diskIndex]->play();
+}
+
+void DiskplayerScene::playStatic() {
+ _diskSmackerPlayer->open(0x90000101, false);
+ _vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder());
+ _palette->usePalette();
+ _ssPlayButton->release();
+ _updateStatus = kUSPlaying;
+ _diskSlots[_diskIndex]->activate();
+}
+
+} // End of namespace Neverhood