diff options
author | Eugene Sandulenko | 2013-05-15 09:19:34 -0700 |
---|---|---|
committer | Eugene Sandulenko | 2013-05-15 09:19:34 -0700 |
commit | 0638308ef13727b4b359d98d54bc09156752aaaa (patch) | |
tree | e6f6b131566c593f6731ffa058e396931afc2525 /engines/neverhood/modules/module3000.cpp | |
parent | bf9db9e20d75cc18cb711f148814a5d3aae79483 (diff) | |
parent | 32c21754e20afd589556ea862876c6e304b3326b (diff) | |
download | scummvm-rg350-0638308ef13727b4b359d98d54bc09156752aaaa.tar.gz scummvm-rg350-0638308ef13727b4b359d98d54bc09156752aaaa.tar.bz2 scummvm-rg350-0638308ef13727b4b359d98d54bc09156752aaaa.zip |
Merge pull request #330 from johndoe123/neverhood
NEVERHOOD: Neverhood engine
Diffstat (limited to 'engines/neverhood/modules/module3000.cpp')
-rw-r--r-- | engines/neverhood/modules/module3000.cpp | 1548 |
1 files changed, 1548 insertions, 0 deletions
diff --git a/engines/neverhood/modules/module3000.cpp b/engines/neverhood/modules/module3000.cpp new file mode 100644 index 0000000000..2bdb9f0497 --- /dev/null +++ b/engines/neverhood/modules/module3000.cpp @@ -0,0 +1,1548 @@ +/* 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/modules/module3000.h" +#include "neverhood/gamemodule.h" +#include "neverhood/navigationscene.h" + +namespace Neverhood { + +static const uint32 kModule3000SoundList[] = { + 0x92025040, + 0x90035066, + 0x90815450, + 0x99801500, + 0x90E14440, + 0x16805048, + 0x90F0D1C3, + 0 +}; + +Module3000::Module3000(NeverhoodEngine *vm, Module *parentModule, int which) + : Module(vm, parentModule), _soundVolume(0) { + + _vm->_soundMan->addSoundList(0x81293110, kModule3000SoundList); + _vm->_soundMan->setSoundListParams(kModule3000SoundList, true, 50, 600, 5, 150); + _vm->_soundMan->setSoundParams(0x90F0D1C3, false, 20000, 30000, 20000, 30000); + _vm->_soundMan->playTwoSounds(0x81293110, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); + _vm->_soundMan->playTwoSounds(0x81293110, 0x41861371, 0x43A2507F, 0); + + _isWallBroken = getGlobalVar(V_WALL_BROKEN) != 0; + + if (_isWallBroken) { + _vm->_soundMan->setSoundVolume(0x90F0D1C3, 0); + _vm->_soundMan->playSoundLooping(0x90F0D1C3); + } + + if (which < 0) { + createScene(_vm->gameState().sceneNum, -1); + } else if (which == 0) { + createScene(1, 0); + } else if (which == 1) { + createScene(4, 2); + } else if (which == 2) { + createScene(4, 1); + } else if (which == 3) { + createScene(5, 1); + } + +} + +Module3000::~Module3000() { + _vm->_soundMan->deleteGroup(0x81293110); +} + +void Module3000::createScene(int sceneNum, int which) { + static const byte kNavigationTypes05[] = {3, 0}; + static const byte kNavigationTypes06[] = {5}; + debug("Module3000::createScene(%d, %d)", sceneNum, which); + _vm->gameState().sceneNum = sceneNum; + switch (_vm->gameState().sceneNum) { + case 1: + if (!getGlobalVar(V_BOLT_DOOR_OPEN)) { + createNavigationScene(0x004B7C80, which); + } else if (getGlobalVar(V_WALL_BROKEN)) { + createNavigationScene(0x004B7CE0, which); + } else { + createNavigationScene(0x004B7CB0, which); + } + break; + case 2: + _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); + if (_isWallBroken) { + _soundVolume = 90; + _vm->_soundMan->setSoundVolume(0x90F0D1C3, 90); + } + if (getGlobalVar(V_WALL_BROKEN)) { + createNavigationScene(0x004B7D58, which); + } else { + createNavigationScene(0x004B7D10, which); + } + break; + case 3: + if (getGlobalVar(V_STAIRS_DOWN)) + createNavigationScene(0x004B7E60, which); + else if (getGlobalVar(V_WALL_BROKEN)) + createNavigationScene(0x004B7DA0, which); + else + createNavigationScene(0x004B7E00, which); + break; + case 4: + if (getGlobalVar(V_STAIRS_DOWN)) + createNavigationScene(0x004B7F20, which); + else + createNavigationScene(0x004B7EC0, which); + break; + case 5: + createNavigationScene(0x004B7F80, which, kNavigationTypes05); + break; + case 6: + createNavigationScene(0x004B7FB0, which, kNavigationTypes06); + break; + case 7: + _vm->_soundMan->setSoundListParams(kModule3000SoundList, false, 0, 0, 0, 0); + if (!getSubVar(VA_IS_PUZZLE_INIT, 0x089809C2)) { + setSubVar(VA_IS_PUZZLE_INIT, 0x089809C2, 1); + createSmackerScene(0x90022001, true, true, false); + } else + createSmackerScene(0x98022001, true, true, false); + break; + case 8: + _childObject = new Scene3009(_vm, this, which); + break; + case 9: + _childObject = new Scene3010(_vm, this, 0); + break; + case 10: + _childObject = new Scene3011(_vm, this, 0); + break; + case 11: + _vm->_soundMan->setSoundListParams(kModule3000SoundList, false, 0, 0, 0, 0); + if (!getSubVar(VA_IS_PUZZLE_INIT, 0x10130993)) { + setSubVar(VA_IS_PUZZLE_INIT, 0x10130993, 1); + createSmackerScene(0x31093019, true, true, false); + } else + createSmackerScene(0x20093019, true, true, false); + break; + case 12: + _childObject = new Scene3010(_vm, this, 1); + break; + // NOTE: Newly introduced sceneNums + case 1001: + if (!getGlobalVar(V_BOLT_DOOR_OPEN)) + if (getGlobalVar(V_WALL_BROKEN)) + createSmackerScene(0x00940021, true, true, false); + else + createSmackerScene(0x01140021, true, true, false); + else + if (getGlobalVar(V_WALL_BROKEN)) + createSmackerScene(0x001011B1, true, true, false); + else + createSmackerScene(0x001021B1, true, true, false); + setGlobalVar(V_BOLT_DOOR_OPEN, getGlobalVar(V_BOLT_DOOR_OPEN) ? 0 : 1); + break; + case 1006: + createSmackerScene(0x080810C5, true, true, false); + break; + case 1008: + createSmackerScene(getGlobalVar(V_CANNON_SMACKER_NAME), true, true, false); + break; + } + SetUpdateHandler(&Module3000::updateScene); + _childObject->handleUpdate(); +} + +void Module3000::updateScene() { + if (!updateChild()) { + switch (_vm->gameState().sceneNum) { + case 1: + if (!getGlobalVar(V_BOLT_DOOR_OPEN)) { + if (_moduleResult == 0) + createScene(9, -1); + else if (_moduleResult == 1) + leaveModule(0); + } else { + if (_moduleResult == 0) + if (_navigationAreaType == 2) + createScene(2, 0); + else + createScene(1001, -1); + else if (_moduleResult == 1) + leaveModule(0); + } + break; + case 2: + _vm->_soundMan->playTwoSounds(0x81293110, 0x41861371, 0x43A2507F, 0); + if (_isWallBroken) { + _soundVolume = 0; + _vm->_soundMan->setSoundVolume(0x90F0D1C3, 0); + } + if (_moduleResult == 0) { + createScene(3, 0); + } else if (_moduleResult == 1) { + setGlobalVar(V_BOLT_DOOR_OPEN, 0); + createScene(1, 1); + } + break; + case 3: + if (_moduleResult == 1) + createScene(4, 0); + else if (_moduleResult == 3) + createScene(10, -1); + else if (getGlobalVar(V_STAIRS_DOWN)) + createScene(5, 0); + else + createScene(2, 1); + break; + case 4: + if (_moduleResult == 0) + leaveModule(1); + else if (_moduleResult == 1) + createScene(7, -1); + else if (_moduleResult == 2) + createScene(3, 3); + break; + case 5: + if (_moduleResult == 0) + createScene(6, 0); + else if (_moduleResult == 1) + createScene(3, 0); + break; + case 6: + if (_navigationAreaType == 4) + createScene(11, -1); + else + createScene(1006, -1); + break; + case 7: + createScene(8, -1); + break; + case 8: + _isWallBroken = getGlobalVar(V_WALL_BROKEN) != 0; + if (_moduleResult != 1) { + _vm->_soundMan->setSoundListParams(kModule3000SoundList, true, 0, 0, 0, 0); + createScene(4, 1); + } else if (getGlobalVar(V_CANNON_SMACKER_NAME)) { + createScene(1008, -1); + } else { + _vm->_soundMan->setSoundListParams(kModule3000SoundList, true, 0, 0, 0, 0); + createScene(4, 1); + } + break; + case 9: + if (_moduleResult == 0 || _moduleResult == 2) + createScene(1, 0); + else if (_moduleResult == 1) + createScene(1001, -1); + break; + case 10: + createScene(3, 3); + break; + case 11: + leaveModule(3); + break; + case 12: + createScene(1, 0); + break; + case 1001: + if (getGlobalVar(V_BOLT_DOOR_OPEN)) + createScene(1, 0); + else + createScene(12, -1); + break; + case 1006: + createScene(5, 0); + break; + case 1008: + createScene(8, -1); + break; + } + } else { + switch (_vm->gameState().sceneNum) { + case 1: + if (navigationScene()->isWalkingForward()) { + uint32 frameNumber = navigationScene()->getFrameNumber(); + int navigationIndex = navigationScene()->getNavigationIndex(); + if (navigationIndex == 1) { + if (frameNumber == 0) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->setSoundVolume(0x48498E46, 70); + _vm->_soundMan->setSoundVolume(0x50399F64, 70); + } else if (frameNumber == 100) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x41861371, 0x43A2507F, 0); + } + } else if (navigationIndex == 0) { + if (frameNumber == 0) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->setSoundVolume(0x48498E46, 70); + _vm->_soundMan->setSoundVolume(0x50399F64, 70); + } else if (frameNumber == 10) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); + } + if (_isWallBroken && _soundVolume < 90 && frameNumber % 2) { + if (frameNumber == 0) + _soundVolume = 40; + else + _soundVolume++; + _vm->_soundMan->setSoundVolume(0x90F0D1C3, _soundVolume); + } + } + } + break; + case 2: + if (navigationScene()->isWalkingForward()) { + uint32 frameNumber = navigationScene()->getFrameNumber(); + int navigationIndex = navigationScene()->getNavigationIndex(); + if (_isWallBroken && _soundVolume > 1 && frameNumber % 2) { + _soundVolume--; + _vm->_soundMan->setSoundVolume(0x90F0D1C3, _soundVolume); + } + if (navigationIndex == 0) { + if (frameNumber == 35) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x41861371, 0x43A2507F, 0); + } + } else if (navigationIndex == 1) { + if (frameNumber == 55) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x48498E46, 0x50399F64, 0); + _vm->_soundMan->setSoundVolume(0x48498E46, 70); + _vm->_soundMan->setSoundVolume(0x50399F64, 70); + } + } + } + break; + case 3: + if (navigationScene()->isWalkingForward()) { + uint32 frameNumber = navigationScene()->getFrameNumber(); + int navigationIndex = navigationScene()->getNavigationIndex(); + if (navigationIndex == 2) { + if (frameNumber == 40) { + _vm->_soundMan->playTwoSounds(0x81293110, 0x40030A51, 0xC862CA15, 0); + } + if (_isWallBroken && _soundVolume < 90 && frameNumber % 2) { + if (frameNumber == 0) + _soundVolume = 40; + else + _soundVolume++; + _vm->_soundMan->setSoundVolume(0x90F0D1C3, _soundVolume); + } + } + } + break; + case 5: + if (navigationScene()->isWalkingForward() && navigationScene()->getNavigationIndex() == 0) { + _vm->_soundMan->setTwoSoundsPlayFlag(false); + } + break; + } + } +} + +// Scene3009 + +enum { + kCTSNull = 0, + kCTSBreakWall = 1, + kCTSWall = 2, + kCTSEmptyness = 3, + kCTSFireRobotNoTarget = 4, + kCTSFireRobotIsTarget = 5, + kCTSFireNoRobot = 6, + kCTSRaiseCannon = 7, + kCTSRightRobotNoTarget = 8, + kCTSRightRobotIsTarget = 9, + kCTSRightNoRobot = 10, + kCTSLeftRobotNoTarget = 11, + kCTSLeftRobotIsTarget = 12, + kCTSLeftNoRobot = 13, + kCTSLowerCannon = 14, + kCTSCount = 14 +}; + +static const uint32 kScene3009CannonScopeVideos[] = { + 0x1010000D, + 0x340A0049, + 0x340A0049, + 0x0282081D, + 0x0082080D, + 0x0882080D, + 0x0882080D, + 0x0282081D, + 0x004B000B, + 0x014B000B, + 0x044B000B, + 0x0282081D, + 0x0282081D, + 0x0282081D, + 0x340A0049 +}; + +static const uint32 kScene3009CannonActionVideos[] = { + 0x00000000, + 0x8004001B, // 1 Fire cannon at wall, it breaks (lowered) + 0x0004001A, // 2 Fire cannon at wall, nothing happens (lowered) + 0x1048404B, // 3 Fire cannon at emptyness (raised) + 0x50200109, // 4 Fire cannon, robot missed (raised) + 0x12032109, // 5 Fire cannon, robot hit (raised) + 0x10201109, // 6 Fire cannon, no robot (raised) + 0x000A2030, // 7 Raise the cannon + 0x000A0028, // 8 + 0x000A0028, // 9 + 0x000A0028, // 10 + 0x040A1069, // 11 + 0x040A1069, // 12 + 0x040A1069, // 13 + 0x240A1101 // 14 Lower the cannon +}; + +static const uint32 kSsScene3009SymbolEdgesFileHashes[] = { + 0x618827A0, + 0xB1A92322 +}; + +static const uint32 kSsScene3009TargetLineFileHashes[] = { + 0x4011018C, + 0x15086623 +}; + +static const NPoint kAsScene3009SymbolPoints[] = { + {289, 338}, + {285, 375}, + {284, 419}, + {456, 372}, + {498, 372}, + {541, 372} +}; + +static const uint32 kAsScene3009SymbolFileHashes[] = { + 0x24542582, + 0x1CD61D96 +}; + +static const uint32 kSsScene3009SymbolArrowFileHashes1[] = { + 0x24016060, + 0x21216221, + 0x486160A0, + 0x42216422, + 0x90A16120, + 0x84216824, + 0x08017029, + 0x08217029, + 0x10014032, + 0x10214032, + 0x20012004, + 0x20212004 +}; + +static const uint32 kSsScene3009SymbolArrowFileHashes2[] = { + 0x40092024, + 0x01636002, + 0x8071E028, + 0x02A56064, + 0x00806031, + 0x052960A8, + 0x0A116130, + 0x0A316130, + 0x14216200, + 0x14016200, + 0x28416460, + 0x28616460 +}; + +SsScene3009FireCannonButton::SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene) + : StaticSprite(vm, 1400), _parentScene(parentScene), _isClicked(false) { + + loadSprite(0x120B24B0, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + setVisible(false); + SetUpdateHandler(&SsScene3009FireCannonButton::update); + SetMessageHandler(&SsScene3009FireCannonButton::handleMessage); + loadSound(0, 0x3901B44F); +} + +void SsScene3009FireCannonButton::update() { + updatePosition(); + if (_isClicked && !isSoundPlaying(0)) { + sendMessage(_parentScene, 0x2000, 0); + setVisible(false); + } +} + +uint32 SsScene3009FireCannonButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (!_isClicked && !_parentScene->isTurning()) { + _isClicked = true; + setVisible(true); + playSound(0); + } + messageResult = 1; + break; + } + return messageResult; +} + +SsScene3009SymbolEdges::SsScene3009SymbolEdges(NeverhoodEngine *vm, int index) + : StaticSprite(vm, 1400), _blinkCountdown(0) { + + loadSprite(kSsScene3009SymbolEdgesFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600); + if (getGlobalVar(V_ROBOT_HIT)) + hide(); + else + startBlinking(); + SetUpdateHandler(&SsScene3009SymbolEdges::update); +} + +void SsScene3009SymbolEdges::update() { + if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) { + if (_blinkToggle) { + setVisible(true); + } else { + setVisible(false); + } + updatePosition(); + _blinkCountdown = 3; + _blinkToggle = !_blinkToggle; + } +} + +void SsScene3009SymbolEdges::show() { + setVisible(true); + updatePosition(); + _blinkCountdown = 0; +} + +void SsScene3009SymbolEdges::hide() { + setVisible(false); + updatePosition(); + _blinkCountdown = 0; +} + +void SsScene3009SymbolEdges::startBlinking() { + setVisible(true); + updatePosition(); + _blinkCountdown = 3; + _blinkToggle = true; +} + +SsScene3009TargetLine::SsScene3009TargetLine(NeverhoodEngine *vm, int index) + : StaticSprite(vm, 1400) { + + loadSprite(kSsScene3009TargetLineFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600); + setVisible(false); +} + +void SsScene3009TargetLine::show() { + setVisible(true); + updatePosition(); +} + +SsScene3009SymbolArrow::SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index) + : StaticSprite(vm, 1400), _asSymbol(asSymbol), _index(index), _enabled(true), _countdown(0) { + + _incrDecr = _index % 2; + + createSurface(1200, 33, 31); + loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefPosition); + _drawOffset.set(0, 0, 33, 31); + _collisionBoundsOffset = _drawOffset; + updateBounds(); + _needRefresh = true; + + SetUpdateHandler(&SsScene3009SymbolArrow::update); + SetMessageHandler(&SsScene3009SymbolArrow::handleMessage); + loadSound(0, 0x2C852206); +} + +void SsScene3009SymbolArrow::hide() { + _enabled = false; + setVisible(false); +} + +void SsScene3009SymbolArrow::update() { + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefDrawOffset); + } +} + +uint32 SsScene3009SymbolArrow::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_enabled && _countdown == 0) { + _countdown = 2; + loadSprite(kSsScene3009SymbolArrowFileHashes1[_index], kSLFDefDrawOffset); + playSound(0); + sendMessage(_asSymbol, 0x2005, _incrDecr); + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene3009VerticalIndicator::AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index) + : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { + + _x = 300; + _y = getGlobalVar(V_CANNON_RAISED) ? 52 : 266; + createSurface1(0xC2463913, 1200); + _needRefresh = true; + updatePosition(); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage); +} + +void AsScene3009VerticalIndicator::show() { + startAnimation(0xC2463913, 0, -1); + setVisible(true); + updatePosition(); + _enabled = true; +} + +uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_enabled) { + sendMessage(_parentScene, 0x2002, 0); + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene3009HorizontalIndicator::AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 cannonTargetStatus) + : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) { + + _x = getGlobalVar(V_CANNON_TURNED) ? 533 : 92; + _y = 150; + createSurface1(0xC0C12954, 1200); + _needRefresh = true; + updatePosition(); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene3009HorizontalIndicator::handleMessage); + if (cannonTargetStatus == kCTSRightRobotNoTarget || cannonTargetStatus == kCTSRightRobotIsTarget || cannonTargetStatus == kCTSRightNoRobot) { + SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight); + _x = 280; + } +} + +uint32 AsScene3009HorizontalIndicator::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_enabled) { + sendMessage(_parentScene, 0x2004, 0); + } + messageResult = 1; + break; + } + return messageResult; +} + +void AsScene3009HorizontalIndicator::suMoveLeft() { + _x -= 6; + if (_x < 92) { + SetSpriteUpdate(NULL); + _x = 92; + } +} + +void AsScene3009HorizontalIndicator::suMoveRight() { + _x += 6; + if (_x > 533) { + SetSpriteUpdate(NULL); + _x = 533; + } +} + +void AsScene3009HorizontalIndicator::show() { + startAnimation(0xC0C12954, 0, -1); + setVisible(true); + updatePosition(); + _enabled = true; +} + +void AsScene3009HorizontalIndicator::stMoveLeft() { + _x = 533; + SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveLeft); +} + +void AsScene3009HorizontalIndicator::stMoveRight() { + _x = 330; + SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight); +} + +AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _symbolPosition(symbolPosition) { + + _symbolIndex = getSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition); + + _x = kAsScene3009SymbolPoints[_symbolPosition].x; + _y = kAsScene3009SymbolPoints[_symbolPosition].y; + createSurface1(kAsScene3009SymbolFileHashes[_symbolPosition / 3], 1200); + startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1); + _newStickFrameIndex = _symbolIndex; + _needRefresh = true; + updatePosition(); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene3009Symbol::handleMessage); + _ssArrowPrev = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 0); + _parentScene->addCollisionSprite(_ssArrowPrev); + _ssArrowNext = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 1); + _parentScene->addCollisionSprite(_ssArrowNext); +} + +uint32 AsScene3009Symbol::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2005: + if (param.asInteger()) { + if (_symbolIndex == 11) + _symbolIndex = 0; + else + _symbolIndex++; + } else { + if (_symbolIndex == 0) + _symbolIndex = 11; + else + _symbolIndex--; + } + startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1); + _newStickFrameIndex = _symbolIndex; + setSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition, _symbolIndex); + if (_symbolPosition / 3 == 0) { + sendMessage(_parentScene, 0x2001, 0); + } else { + sendMessage(_parentScene, 0x2003, 0); + } + messageResult = 1; + break; + } + return messageResult; +} + +void AsScene3009Symbol::hide() { + _ssArrowPrev->hide(); + _ssArrowNext->hide(); +} + +Scene3009::Scene3009(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule), _keepVideo(false), _moveCannonLeftFirst(false), + _isTurning(false), _lockSymbolsPart1Countdown(1), _lockSymbolsPart2Countdown(1) { + + _cannonTargetStatus = getGlobalVar(V_CANNON_TARGET_STATUS); + + _vm->gameModule()->initCannonSymbolsPuzzle(); + + setGlobalVar(V_CANNON_SMACKER_NAME, 0); + + _vm->_screen->clear(); + + setBackground(0xD000420C); + setPalette(0xD000420C); + insertPuzzleMouse(0x04208D08, 20, 620); + + _ssFireCannonButton = insertSprite<SsScene3009FireCannonButton>(this); + addCollisionSprite(_ssFireCannonButton); + + _asVerticalIndicator = insertSprite<AsScene3009VerticalIndicator>(this, _cannonTargetStatus); + addCollisionSprite(_asVerticalIndicator); + + _asHorizontalIndicator = insertSprite<AsScene3009HorizontalIndicator>(this, _cannonTargetStatus); + addCollisionSprite(_asHorizontalIndicator); + + if (_cannonTargetStatus != kCTSNull && _cannonTargetStatus != kCTSRightRobotNoTarget && _cannonTargetStatus != kCTSRightRobotIsTarget && _cannonTargetStatus != kCTSRightNoRobot) { + _keepVideo = true; + } else { + _keepVideo = false; + if (_cannonTargetStatus != kCTSNull) { + _asHorizontalIndicator->stMoveRight(); + _isTurning = true; + } + } + + _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, kScene3009CannonScopeVideos[_cannonTargetStatus], false, _keepVideo)); + _smackerPlayer->setDrawPos(89, 37); + _palette->usePalette(); // Use it again since the SmackerPlayer overrides the usage + + insertStaticSprite(0x8540252C, 400); + + for (int i = 0; i < 2; i++) { + _ssSymbolEdges[i] = insertSprite<SsScene3009SymbolEdges>(i); + _ssTargetLines[i] = insertSprite<SsScene3009TargetLine>(i); + } + + for (int symbolPosition = 0; symbolPosition < 6; symbolPosition++) { + _asSymbols[symbolPosition] = insertSprite<AsScene3009Symbol>(this, symbolPosition); + if (symbolPosition < 3) + _correctSymbols[symbolPosition] = getSubVar(VA_GOOD_CANNON_SYMBOLS_1, symbolPosition); + else + _correctSymbols[symbolPosition] = getSubVar(VA_GOOD_CANNON_SYMBOLS_2, symbolPosition - 3); + } + + SetMessageHandler(&Scene3009::handleMessage); + SetUpdateHandler(&Scene3009::update); + + // DEBUG Enable to set the correct code +#if 0 + for (int i = 0; i < 6; i++) + setSubVar(VA_CURR_CANNON_SYMBOLS, i, _correctSymbols[i]); + sendMessage(this, 0x2003, 0); +#endif + +} + +void Scene3009::update() { + Scene::update(); + + if (!_keepVideo && _smackerPlayer->isDone() && _cannonTargetStatus <= kCTSCount) { + switch (_cannonTargetStatus) { + case kCTSNull: + case kCTSLowerCannon: + _smackerPlayer->open(0x340A0049, true); + _palette->usePalette(); + _keepVideo = true; + break; + case kCTSRightRobotNoTarget: + _smackerPlayer->open(0x0082080D, true); + _palette->usePalette(); + _keepVideo = true; + _isTurning = false; + break; + case kCTSRightRobotIsTarget: + _smackerPlayer->open(0x0282080D, true); + _palette->usePalette(); + _keepVideo = true; + _isTurning = false; + break; + case kCTSRightNoRobot: + _smackerPlayer->open(0x0882080D, true); + _palette->usePalette(); + _keepVideo = true; + _isTurning = false; + break; + case kCTSLeftRobotNoTarget: + case kCTSLeftRobotIsTarget: + case kCTSLeftNoRobot: + if (_moveCannonLeftFirst) { + if (_cannonTargetStatus == kCTSLeftRobotNoTarget) + _smackerPlayer->open(0x110A000F, false); + else if (_cannonTargetStatus == kCTSLeftRobotIsTarget) + _smackerPlayer->open(0x500B004F, false); + else if (_cannonTargetStatus == kCTSLeftNoRobot) + _smackerPlayer->open(0x100B010E, false); + _palette->usePalette(); + _moveCannonLeftFirst = false; + _asHorizontalIndicator->stMoveLeft(); + } else { + playActionVideo(); + } + break; + } + } + + if (_lockSymbolsPart1Countdown != 0 && (--_lockSymbolsPart1Countdown == 0) && isSymbolsPart1Solved()) { + for (int i = 0; i < 3; i++) + _asSymbols[i]->hide(); + if (!getGlobalVar(V_ROBOT_HIT) || getGlobalVar(V_CANNON_RAISED) || getGlobalVar(V_CANNON_TURNED)) { + _ssSymbolEdges[0]->show(); + _ssTargetLines[0]->show(); + _asVerticalIndicator->show(); + } + } + + if (_lockSymbolsPart2Countdown != 0 && (--_lockSymbolsPart2Countdown == 0) && isSymbolsPart2Solved()) { + for (int i = 3; i < 6; i++) + _asSymbols[i]->hide(); + if (!getGlobalVar(V_ROBOT_HIT) || getGlobalVar(V_CANNON_RAISED) || getGlobalVar(V_CANNON_TURNED)) { + _ssSymbolEdges[1]->show(); + _ssTargetLines[1]->show(); + _asHorizontalIndicator->show(); + } + } + +} + +uint32 Scene3009::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x0001: + if ((param.asPoint().x <= 20 || param.asPoint().x >= 620) && !getGlobalVar(V_CANNON_RAISED)) { + setGlobalVar(V_CANNON_TARGET_STATUS, 0); + leaveScene(0); + } + break; + case 0x2000: + if (!getGlobalVar(V_CANNON_RAISED)) { + if (!getGlobalVar(V_WALL_BROKEN)) { + _cannonTargetStatus = kCTSBreakWall; + setGlobalVar(V_WALL_BROKEN, 1); + } else { + _cannonTargetStatus = kCTSWall; + } + } else if (!getGlobalVar(V_CANNON_TURNED)) { + _cannonTargetStatus = kCTSEmptyness; + } else if (!getGlobalVar(V_ROBOT_TARGET)) { + _cannonTargetStatus = kCTSFireRobotNoTarget; + } else if (!getGlobalVar(V_ROBOT_HIT)) { + setGlobalVar(V_ROBOT_HIT, 1); + _cannonTargetStatus = kCTSFireRobotIsTarget; + } else { + _cannonTargetStatus = kCTSFireNoRobot; + } + playActionVideo(); + break; + case 0x2001: + _lockSymbolsPart1Countdown = 24; + break; + case 0x2002: + // Raise/lower the cannon + if (!getGlobalVar(V_CANNON_TURNED) && !_isTurning) { + if (getGlobalVar(V_CANNON_RAISED)) { + _cannonTargetStatus = kCTSLowerCannon; + setGlobalVar(V_CANNON_RAISED, 0); + } else { + _cannonTargetStatus = kCTSRaiseCannon; + setGlobalVar(V_CANNON_RAISED, 1); + } + playActionVideo(); + } + break; + case 0x2003: + _lockSymbolsPart2Countdown = 24; + break; + case 0x2004: + // Turn the cannon if it's raised + if (getGlobalVar(V_CANNON_RAISED)) { + if (!getGlobalVar(V_CANNON_TURNED)) { + // Cannon is at the left position + if (!getGlobalVar(V_ROBOT_TARGET)) { + _cannonTargetStatus = kCTSRightRobotNoTarget; + } else if (!getGlobalVar(V_ROBOT_HIT)) { + _cannonTargetStatus = kCTSRightRobotIsTarget; + } else { + _cannonTargetStatus = kCTSRightNoRobot; + } + setGlobalVar(V_CANNON_TURNED, 1); + _isTurning = true; + playActionVideo(); + } else { + // Cannon is at the right position + if (!getGlobalVar(V_ROBOT_TARGET)) { + _cannonTargetStatus = kCTSLeftRobotNoTarget; + _smackerPlayer->open(0x108A000F, false); + } else if (!getGlobalVar(V_ROBOT_HIT)) { + _cannonTargetStatus = kCTSLeftRobotIsTarget; + _smackerPlayer->open(0x500B002F, false); + } else { + _cannonTargetStatus = kCTSLeftNoRobot; + _smackerPlayer->open(0x100B008E, false); + } + _palette->usePalette(); + _moveCannonLeftFirst = true; + _isTurning = true; + _keepVideo = false; + setGlobalVar(V_CANNON_TURNED, 0); + } + } + break; + } + return 0; +} + +void Scene3009::playActionVideo() { + setGlobalVar(V_CANNON_TARGET_STATUS, _cannonTargetStatus); + setGlobalVar(V_CANNON_SMACKER_NAME, kScene3009CannonActionVideos[_cannonTargetStatus]); + leaveScene(1); +} + +bool Scene3009::isSymbolsPart1Solved() { + for (int i = 0; i < 3; i++) + if (_correctSymbols[i] != getSubVar(VA_CURR_CANNON_SYMBOLS, i)) + return false; + return true; +} + +bool Scene3009::isSymbolsPart2Solved() { + for (int i = 3; i < 6; i++) + if (_correctSymbols[i] != getSubVar(VA_CURR_CANNON_SYMBOLS, i)) + return false; + return true; +} + +bool Scene3009::isTurning() { + return _isTurning; +} + +// Scene3010 + +static const uint32 kScene3010ButtonNameHashes[] = { + 0x304008D2, + 0x40119852, + 0x01180951 +}; + +static const uint32 kScene3010DeadBoltButtonFileHashes1[] = { + 0x301024C2, + 0x20280580, + 0x30200452 +}; + +static const uint32 kScene3010DeadBoltButtonFileHashes2[] = { + 0x50C025A8, + 0x1020A0A0, + 0x5000A7E8 +}; + +static const NPoint kAsScene3010DeadBoltPoints[] = { + {550, 307}, + {564, 415}, + {560, 514} +}; + +static const uint32 kAsScene3010DeadBoltFileHashes2[] = { + 0x181A0042, + 0x580A08F2, + 0x18420076 +}; + +static const uint32 kAsScene3010DeadBoltFileHashes1[] = { + 0x300E105A, + 0x804E0052, + 0x040E485A +}; + +SsScene3010DeadBoltButton::SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled) + : StaticSprite(vm, 900), _parentScene(parentScene), _buttonLocked(false), _countdown1(0), _countdown2(0), _buttonIndex(buttonIndex) { + + _buttonEnabled = getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_buttonIndex]) != 0; + createSurface(400, 88, 95); + setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]); + if (initDisabled) + disableButton(); + else if (_buttonEnabled) + _countdown1 = initCountdown * 12 + 1; + loadSound(0, 0xF4217243); + loadSound(1, 0x44049000); + loadSound(2, 0x6408107E); + SetUpdateHandler(&SsScene3010DeadBoltButton::update); + SetMessageHandler(&SsScene3010DeadBoltButton::handleMessage); +} + +void SsScene3010DeadBoltButton::update() { + + if (_countdown1 != 0 && (--_countdown1 == 0)) { + playSound(0); + setVisible(false); + setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]); + } + + if (_countdown2 != 0 && (--_countdown2 == 0)) { + setVisible(true); + setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]); + } + +} + +uint32 SsScene3010DeadBoltButton::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (!_buttonLocked && _countdown1 == 0) { + if (_buttonEnabled) { + playSound(1); + playSound(2); + setVisible(true); + _buttonLocked = true; + sendMessage(_parentScene, 0x2000, _buttonIndex); + } else { + sendMessage(_parentScene, 0x2002, _buttonIndex); + } + _needRefresh = true; + updatePosition(); + } + messageResult = 1; + break; + } + return messageResult; +} + +void SsScene3010DeadBoltButton::disableButton() { + _buttonLocked = true; + setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]); + setVisible(true); +} + +void SsScene3010DeadBoltButton::setSprite(uint32 fileHash) { + loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset); +} + +void SsScene3010DeadBoltButton::setCountdown(int count) { + _countdown2 = count * 18 + 1; +} + +AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _boltIndex(boltIndex), _soundToggle(true), + _unlocked(false), _locked(false), _countdown(0) { + + _x = kAsScene3010DeadBoltPoints[_boltIndex].x; + _y = kAsScene3010DeadBoltPoints[_boltIndex].y; + + if (getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_boltIndex])) { + createSurface1(kAsScene3010DeadBoltFileHashes1[_boltIndex], 1200); + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); + loadSound(0, 0x46005BC4); + } else { + createSurface1(kAsScene3010DeadBoltFileHashes2[_boltIndex], 1200); + startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1); + loadSound(0, 0x420073DC); + loadSound(1, 0x420073DC); + } + + setVisible(false); + stIdle(); + if (initUnlocked) + unlock(true); + + _needRefresh = true; + AnimatedSprite::updatePosition(); + +} + +void AsScene3010DeadBolt::update() { + updateAnim(); + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + stDisabled(); + } +} + +uint32 AsScene3010DeadBolt::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +void AsScene3010DeadBolt::stIdle() { + stopAnimation(); + SetUpdateHandler(&AsScene3010DeadBolt::update); + SetMessageHandler(&Sprite::handleMessage); + _locked = false; +} + +void AsScene3010DeadBolt::unlock(bool skipAnim) { + if (!_unlocked) { + setVisible(true); + if (skipAnim) { + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0); + _newStickFrameIndex = STICK_LAST_FRAME; + } else { + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); + SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); + FinalizeState(&AsScene3010DeadBolt::stIdleMessage); + NextState(&AsScene3010DeadBolt::stIdle); + playSound(0); + } + _unlocked = true; + loadSound(2, 0x4010C345); + } +} + +void AsScene3010DeadBolt::stIdleMessage() { + stopAnimation(); + SetMessageHandler(&Sprite::handleMessage); + sendMessage(_parentScene, 0x2001, _boltIndex); +} + +void AsScene3010DeadBolt::lock() { + if (!_locked) { + _locked = true; + setVisible(true); + startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1); + SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); + FinalizeState(&AsScene3010DeadBolt::stDisabledMessage); + NextState(&AsScene3010DeadBolt::stIdle); + if (_soundToggle) { + playSound(0); + } else { + playSound(1); + } + _soundToggle = !_soundToggle; + } +} + +void AsScene3010DeadBolt::setCountdown(int count) { + _countdown = count * 18 + 1; +} + +void AsScene3010DeadBolt::stDisabled() { + setVisible(true); + startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1); + SetMessageHandler(&AsScene3010DeadBolt::hmAnimation); + FinalizeState(&AsScene3010DeadBolt::stDisabledMessage); + NextState(&AsScene3010DeadBolt::stIdle); + _playBackwards = true; + playSound(2); +} + +void AsScene3010DeadBolt::stDisabledMessage() { + setVisible(false); + sendMessage(_parentScene, 0x2003, _boltIndex); +} + +Scene3010::Scene3010(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule), _countdown(0), _doorUnlocked(false), _checkUnlocked(false) { + + int initCountdown = 0; + + // DEBUG Enable to activate all buttons +#if 0 + setSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[0], 1); + setSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[1], 1); + setSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[2], 1); +#endif + + setBackground(0x80802626); + setPalette(0x80802626); + + for (int i = 0; i < 3; i++) { + _asDeadBolts[i] = insertSprite<AsScene3010DeadBolt>(this, i, which == 1);//CHECKME + _ssDeadBoltButtons[i] = insertSprite<SsScene3010DeadBoltButton>(this, i, initCountdown, which == 1);//CHECKME + addCollisionSprite(_ssDeadBoltButtons[i]); + if (getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[i])) + initCountdown++; + _boltUnlocking[i] = false; + _boltUnlocked[i] = false; + } + + if (which == 0) { + insertPuzzleMouse(0x02622800, 20, 620); + } + + loadSound(0, 0x68E25540); + + SetMessageHandler(&Scene3010::handleMessage); + SetUpdateHandler(&Scene3010::update); + + if (which == 1) { + _checkUnlocked = true; + for (int i = 0; i < 3; i++) { + _boltUnlocked[i] = true; + _ssDeadBoltButtons[i]->setCountdown(i + 1); + _asDeadBolts[i]->setCountdown(i + 1); + } + } + +} + +void Scene3010::update() { + Scene::update(); + if (_checkUnlocked && !_boltUnlocked[0] && !_boltUnlocked[1] && !_boltUnlocked[2]) { + _countdown = 24; + _checkUnlocked = false; + } + if (_countdown != 0 && (--_countdown == 0)) { + leaveScene(_doorUnlocked ? 1 : 0); + } +} + +uint32 Scene3010::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x0001: + if ((param.asPoint().x <= 20 || param.asPoint().x >= 620) && _countdown == 0 && !_checkUnlocked) { + if (!_boltUnlocking[0] && !_boltUnlocking[1] && !_boltUnlocking[2]) { + showMouse(false); + if (!_boltUnlocked[0] && !_boltUnlocked[1] && !_boltUnlocked[2]) { + _countdown = 1; + } else { + _checkUnlocked = true; + for (int i = 0; i < 3; i++) { + _ssDeadBoltButtons[i]->setCountdown(i); + if (_boltUnlocked[i]) { + _asDeadBolts[i]->setCountdown(i); + } + } + } + } + } + break; + case 0x2000: + if (!_boltUnlocked[param.asInteger()] && !_checkUnlocked && _countdown == 0) { + _asDeadBolts[param.asInteger()]->unlock(false); + _boltUnlocking[param.asInteger()] = true; + } + break; + case 0x2001: + _boltUnlocked[param.asInteger()] = true; + _boltUnlocking[param.asInteger()] = false; + if (_boltUnlocked[0] && _boltUnlocked[1] && _boltUnlocked[2]) { + if (!getGlobalVar(V_BOLT_DOOR_UNLOCKED)) { + setGlobalVar(V_BOLT_DOOR_UNLOCKED, 1); + playSound(0); + _countdown = 60; + } else { + _countdown = 48; + } + _doorUnlocked = true; + } + break; + case 0x2002: + if (!_checkUnlocked && _countdown == 0) { + _asDeadBolts[param.asInteger()]->lock(); + } + break; + case 0x2003: + _boltUnlocked[param.asInteger()] = false; + break; + } + return 0; +} + +// Scene3011 + +static const uint32 kAsScene3011SymbolFileHashes[] = { + 0x00C88050, + 0x01488050, + 0x02488050, + 0x04488050, + 0x08488050, + 0x10488050, + 0x20488050, + 0x40488050, + 0x80488050, + 0x00488051, + 0x00488052, + 0x00488054, + 0x008B0000, + 0x008D0000, + 0x00810000, + 0x00990000, + 0x00A90000, + 0x00C90000, + 0x00090000, + 0x01890000, + 0x02890000, + 0x04890000, + 0x08890000, + 0x10890000 +}; + +SsScene3011Button::SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag) + : StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) { + + loadSprite(flag ? 0x11282020 : 0x994D0433, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400); + setVisible(false); + loadSound(0, 0x44061000); + SetUpdateHandler(&SsScene3011Button::update); + SetMessageHandler(&SsScene3011Button::handleMessage); +} + +void SsScene3011Button::update() { + updatePosition(); + if (_countdown != 0 && (--_countdown == 0)) { + setVisible(false); + } +} + +uint32 SsScene3011Button::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = 0; + StaticSprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x1011: + if (_countdown == 0) { + setVisible(true); + _countdown = 4; + sendMessage(_parentScene, 0x2000, 0); + playSound(0); + } + messageResult = 1; + break; + } + return messageResult; +} + +AsScene3011Symbol::AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol) + : AnimatedSprite(vm, 1000), _symbolIndex(symbolIndex), _largeSymbol(largeSymbol), _isNoisy(false) { + + if (_largeSymbol) { + _x = 310; + _y = 200; + createSurface1(kAsScene3011SymbolFileHashes[_symbolIndex], 1200); + loadSound(0, 0x6052C60F); + loadSound(1, 0x6890433B); + } else { + _symbolIndex = 12; + _x = symbolIndex * 39 + 96; + _y = 225; + createSurface(1200, 41, 48); + loadSound(0, 0x64428609); + loadSound(1, 0x7080023B); + } + setVisible(false); + _needRefresh = true; + SetUpdateHandler(&AnimatedSprite::update); +} + +void AsScene3011Symbol::show(bool isNoisy) { + _isNoisy = isNoisy; + startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1); + setVisible(true); + if (_isNoisy) { + playSound(1); + } else { + playSound(0); + } +} + +void AsScene3011Symbol::hide() { + stopAnimation(); + setVisible(false); +} + +void AsScene3011Symbol::stopSymbolSound() { + if (_isNoisy) { + stopSound(1); + } else { + stopSound(0); + } +} + +void AsScene3011Symbol::change(int symbolIndex, bool isNoisy) { + _symbolIndex = symbolIndex; + _isNoisy = isNoisy; + startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1); + setVisible(true); + if (_isNoisy) { + playSound(1); + } else { + playSound(0); + } +} + +Scene3011::Scene3011(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule), _updateStatus(0), _buttonClicked(false), _currentSymbolIndex(0), _countdown(0) { + + _vm->gameModule()->initCodeSymbolsPuzzle(); + _noisySymbolIndex = getGlobalVar(V_NOISY_SYMBOL_INDEX); + + SetMessageHandler(&Scene3011::handleMessage); + SetUpdateHandler(&Scene3011::update); + + setBackground(0x92124A04); + setPalette(0xA4070114); + addEntity(_palette); + + insertPuzzleMouse(0x24A00929, 20, 620); + + for (int symbolIndex = 0; symbolIndex < 12; symbolIndex++) + _asSymbols[symbolIndex] = insertSprite<AsScene3011Symbol>(symbolIndex, true); + + _ssButton = insertSprite<SsScene3011Button>(this, true); + addCollisionSprite(_ssButton); + +} + +void Scene3011::update() { + Scene::update(); + + if (_countdown != 0 && (--_countdown == 0)) { + switch (_updateStatus) { + case 0: + if (_buttonClicked) { + if (_noisySymbolIndex == _currentSymbolIndex) { + do { + _noisyRandomSymbolIndex = _vm->_rnd->getRandomNumber(12 - 1); + } while (_noisySymbolIndex == _noisyRandomSymbolIndex); + _asSymbols[getSubVar(VA_CODE_SYMBOLS, _noisyRandomSymbolIndex)]->show(true); + } else { + _asSymbols[getSubVar(VA_CODE_SYMBOLS, _currentSymbolIndex)]->show(false); + } + _updateStatus = 1; + _countdown = 24; + fadeIn(); + _buttonClicked = false; + } + break; + case 1: + _updateStatus = 2; + _countdown = 24; + break; + case 2: + fadeOut(); + _updateStatus = 3; + _countdown = 24; + break; + case 3: + _updateStatus = 0; + _countdown = 1; + if (_noisySymbolIndex == _currentSymbolIndex) { + _asSymbols[getSubVar(VA_CODE_SYMBOLS, _noisyRandomSymbolIndex)]->hide(); + } else { + _asSymbols[getSubVar(VA_CODE_SYMBOLS, _currentSymbolIndex)]->hide(); + } + _currentSymbolIndex++; + if (_currentSymbolIndex >= 12) + _currentSymbolIndex = 0; + break; + } + } +} + +uint32 Scene3011::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x0001: + if (param.asPoint().x <= 20 || param.asPoint().x >= 620) { + leaveScene(0); + } + break; + case 0x2000: + _buttonClicked = true; + if (_countdown == 0) + _countdown = 1; + break; + } + return 0; +} + +void Scene3011::fadeIn() { + _palette->addBasePalette(0x92124A04, 0, 256, 0); + _palette->startFadeToPalette(24); +} + +void Scene3011::fadeOut() { + _palette->addBasePalette(0xA4070114, 0, 256, 0); + _palette->startFadeToPalette(24); +} + +} // End of namespace Neverhood |