scummvm/engines/neverhood/diskplayerscene.cpp
johndoe123 add321c930 NEVERHOOD: Try to fix the Smacker issues inside of SmackerPlayer only (instead the numerous classes using it)
SmackerPlayer now creates a surface in the constructor and deletes it in the destructor. There will be only this surface during the lifetime of the player, so there shouldn't be any issues any more when the player is reused for different Smacker files. This is imo nicer than to remove/add the surface.
I kept the several openSmacker since it wraps some code which is nice.
2013-06-11 11:33:05 +02:00

508 lines
12 KiB
C++

/* 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 = addSmackerPlayer(new SmackerPlayer(_vm, this, 0x08288103, false, true));
_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::openSmacker(uint32 fileHash, bool keepLastFrame) {
_diskSmackerPlayer->open(fileHash, keepLastFrame);
_vm->_screen->setSmackerDecoder(_diskSmackerPlayer->getSmackerDecoder());
_palette->usePalette();
}
void DiskplayerScene::stop() {
openSmacker(0x08288103, true);
_ssPlayButton->release();
_updateStatus = kUSStopped;
_diskSlots[_diskIndex]->activate();
}
void DiskplayerScene::tuneIn() {
openSmacker(0x900001C1, false);
_ssPlayButton->release();
_updateStatus = kUSTuningIn;
_diskSlots[_diskIndex]->activate();
}
void DiskplayerScene::playDisk() {
openSmacker(kDiskplayerSmackerFileHashes[_diskIndex], false);
_updateStatus = kUSPlaying;
_diskSlots[_diskIndex]->play();
}
void DiskplayerScene::playStatic() {
openSmacker(0x90000101, false);
_ssPlayButton->release();
_updateStatus = kUSPlaying;
_diskSlots[_diskIndex]->activate();
}
} // End of namespace Neverhood