diff options
Diffstat (limited to 'engines/neverhood/modules/module2400.cpp')
-rw-r--r-- | engines/neverhood/modules/module2400.cpp | 992 |
1 files changed, 992 insertions, 0 deletions
diff --git a/engines/neverhood/modules/module2400.cpp b/engines/neverhood/modules/module2400.cpp new file mode 100644 index 0000000000..450812a5f3 --- /dev/null +++ b/engines/neverhood/modules/module2400.cpp @@ -0,0 +1,992 @@ +/* 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/module2400.h" + +namespace Neverhood { + +Module2400::Module2400(NeverhoodEngine *vm, Module *parentModule, int which) + : Module(vm, parentModule) { + + _vm->_soundMan->addMusic(0x202D1010, 0xB110382D); + + if (which < 0) + createScene(_vm->gameState().sceneNum, _vm->gameState().which); + else + createScene(0, 0); + +} + +Module2400::~Module2400() { + _vm->_soundMan->deleteMusicGroup(0x202D1010); +} + +void Module2400::createScene(int sceneNum, int which) { + debug("Module2400::createScene(%d, %d)", sceneNum, which); + _sceneNum = sceneNum; + switch (_sceneNum) { + case 0: + _vm->gameState().sceneNum = 0; + _vm->_soundMan->stopMusic(0xB110382D, 0, 0); + _childObject = new Scene2401(_vm, this, which); + break; + case 1: + _vm->gameState().sceneNum = 1; + _vm->_soundMan->startMusic(0xB110382D, 0, 2); + _childObject = new Scene2402(_vm, this, which); + break; + case 2: + _vm->gameState().sceneNum = 2; + _vm->_soundMan->startMusic(0xB110382D, 0, 0); + _childObject = new Scene2403(_vm, this, which); + break; + case 4: + _vm->gameState().sceneNum = 4; + _vm->_soundMan->stopMusic(0xB110382D, 0, 2); + _childObject = new DiskplayerScene(_vm, this, 0); + break; + case 5: + _vm->gameState().sceneNum = 5; + _vm->_soundMan->startMusic(0xB110382D, 0, 2); + _childObject = new Scene2406(_vm, this, which); + break; + case 6: + _vm->gameState().sceneNum = 6; + _vm->_soundMan->stopMusic(0xB110382D, 0, 2); + createSmackerScene(0x20D80001, true, true, false); + break; + case 7: + _vm->gameState().sceneNum = 7; + createStaticScene(0x81523218, 0x2321C81D); + break; + case 8: + _vm->gameState().sceneNum = 8; + createStaticScene(0x08100210, 0x00214089); + break; + case 9: + _vm->gameState().sceneNum = 9; + createStaticScene(0x8C020505, 0x205018C8); + break; + } + SetUpdateHandler(&Module2400::updateScene); + _childObject->handleUpdate(); +} + +void Module2400::updateScene() { + if (!updateChild()) { + switch (_sceneNum) { + case 0: + if (_moduleResult == 1) + createScene(1, 0); + else + leaveModule(0); + break; + case 1: + if (_moduleResult == 1) + createScene(5, 0); + else if (_moduleResult == 2) + createScene(7, -1); + else + createScene(0, 1); + break; + case 2: + if (_moduleResult == 1) + createScene(9, -1); + else if (_moduleResult == 2) + createScene(6, -1); + else + createScene(5, 1); + break; + case 4: + createScene(5, 2); + break; + case 5: + if (_moduleResult == 1) + createScene(2, 0); + else if (_moduleResult == 2) + createScene(4, 0); + else if (_moduleResult == 3) + createScene(8, -1); + else + createScene(1, 1); + break; + case 6: + createScene(2, 2); + break; + case 7: + createScene(1, 2); + break; + case 8: + createScene(5, 3); + break; + case 9: + createScene(2, 1); + break; + } + } +} + +static const NPoint kScene2401Points[] = { + {384, 389}, {406, 389}, {429, 389}, + {453, 389}, {477, 389} +}; + +static const uint32 kScene2401FileHashes1[] = { + 0x02842920, 0x02882920, 0x02902920, + 0x02A02920, 0x02C02920, 0x02002920, + 0x03802920, 0x00802920, 0x06802920, + 0x03842920 +}; + +static const uint32 kScene2401FileHashes2[] = { + 0xD0910020, 0xD0910038, 0xD0910008, + 0xD0910068, 0xD09100A8, 0 +}; + +static const uint32 kScene2401FileHashes3[] = { + 0xD0910020, 0xD0910038, 0xD0910008, + 0xD0910068, 0xD09100A8, 0 +}; + +static const NRect kScene2401Rects[] = { + NRect(369, 331, 394, 389), + NRect(395, 331, 419, 389), + NRect(420, 331, 441, 389), + NRect(442, 331, 464, 389), + NRect(465, 331, 491, 389) +}; + +static const uint32 kAsScene2401WaterSpitFileHashes2[] = { + 0x5C044690, 0x5C644690, 0x5CA44690, + 0x5D244690, 0x5E244690 +}; + +static const uint32 kAsScene2401WaterSpitFileHashes1[] = { + 0xF4418408, 0xF4418808, 0xF4419008, + 0xF441A008, 0xCD4F8411 +}; + +AsScene2401WaterSpit::AsScene2401WaterSpit(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200) { + + _x = 240; + _y = 447; + createSurface(100, 146, 74); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2401WaterSpit::handleMessage); + SetSpriteUpdate(&AnimatedSprite::updateDeltaXY); +} + +uint32 AsScene2401WaterSpit::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x120A0013) + playSound(0, kAsScene2401WaterSpitFileHashes1[_soundIndex]); + break; + case 0x2000: + _x = 240; + _y = 447; + _soundIndex = getSubVar(VA_CURR_WATER_PIPES_LEVEL, param.asInteger()); + startAnimation(kAsScene2401WaterSpitFileHashes2[param.asInteger()], 0, -1); + setVisible(true); + playSound(0, 0x48640244); + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene2401FlowingWater::AsScene2401FlowingWater(NeverhoodEngine *vm) + : AnimatedSprite(vm, 1200), _isWaterFlowing(false) { + + _x = 88; + _y = 421; + createSurface1(0x10203116, 100); + setVisible(false); + SetUpdateHandler(&AnimatedSprite::update); + SetMessageHandler(&AsScene2401FlowingWater::handleMessage); +} + +AsScene2401FlowingWater::~AsScene2401FlowingWater() { + _vm->_soundMan->deleteSoundGroup(0x40F11C09); +} + +uint32 AsScene2401FlowingWater::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (_isWaterFlowing && param.asInteger() == 0x02421405) + startAnimationByHash(0x10203116, 0x01084280, 0); + break; + case 0x2002: + if (!_isWaterFlowing) { + _vm->_soundMan->addSound(0x40F11C09, 0x980C1420); + _vm->_soundMan->playSoundLooping(0x980C1420); + startAnimation(0x10203116, 0, -1); + setVisible(true); + _isWaterFlowing = true; + } + break; + case 0x2003: + _vm->_soundMan->deleteSound(0x980C1420); + _isWaterFlowing = false; + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene2401WaterFlushing::AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y) + : AnimatedSprite(vm, 1200), _countdown(0), _flushLoopCount(0) { + + _x = x; + _y = y; + createSurface1(0xB8596884, 100); + setVisible(false); + SetUpdateHandler(&AsScene2401WaterFlushing::update); + SetMessageHandler(&AsScene2401WaterFlushing::handleMessage); +} + +void AsScene2401WaterFlushing::update() { + if (_countdown != 0 && (--_countdown) == 0) { + setDoDeltaX(_vm->_rnd->getRandomNumber(1)); + startAnimation(0xB8596884, 0, -1); + setVisible(true); + } + AnimatedSprite::update(); +} + +uint32 AsScene2401WaterFlushing::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (_flushLoopCount > 0 && param.asInteger() == 0x02421405) { + startAnimationByHash(0xB8596884, 0x01084280, 0); + _flushLoopCount--; + } + break; + case 0x2002: + if (param.asInteger() > 0) { + _flushLoopCount = param.asInteger() - 1; + _countdown = _vm->_rnd->getRandomNumber(3) + 1; + } + break; + case 0x3002: + stopAnimation(); + setVisible(false); + break; + } + return messageResult; +} + +AsScene2401Door::AsScene2401Door(NeverhoodEngine *vm, bool isOpen) + : AnimatedSprite(vm, 1100), _countdown(0), _isOpen(isOpen) { + + _x = 320; + _y = 240; + createSurface1(0x44687810, 100); + _newStickFrameIndex = STICK_LAST_FRAME; + if (_isOpen) { + stopAnimation(); + setVisible(false); + _countdown = 48; + } else { + startAnimation(0x44687810, 0, -1); + _newStickFrameIndex = 0; + } + SetUpdateHandler(&AsScene2401Door::update); + SetMessageHandler(&AsScene2401Door::handleMessage); +} + +void AsScene2401Door::update() { + if (_isOpen && _countdown != 0 && (--_countdown) == 0) { + _isOpen = false; + setVisible(true); + startAnimation(0x44687810, -1, -1); + _newStickFrameIndex = 0; + _playBackwards = true; + playSound(0, calcHash("fxDoorClose38")); + } + AnimatedSprite::update(); +} + +uint32 AsScene2401Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2004: + if (_isOpen) + _countdown = 168; + messageResult = _isOpen ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + if (!_isOpen) { + _countdown = 168; + _isOpen = true; + setVisible(true); + startAnimation(0x44687810, 0, -1); + playSound(0, calcHash("fxDoorOpen38")); + NextState(&AsScene2401Door::stDoorOpenFinished); + } + break; + } + return messageResult; +} + +void AsScene2401Door::stDoorOpenFinished() { + stopAnimation(); + setVisible(false); +} + +Scene2401::Scene2401(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule), _countdown1(0), _countdown2(0), _unkFlag(false), + _soundToggle(false), _asWaterSpitIndex(0) { + + _vm->gameModule()->initWaterPipesPuzzle(); + + SetMessageHandler(&Scene2401::handleMessage); + SetUpdateHandler(&Scene2401::update); + + setRectList(0x004B3140); + setBackground(0x8C030206); + setPalette(0x8C030206); + addEntity(_palette); + _palette->addBasePalette(0x8C030206, 0, 256, 0); + _palette->addPalette(0x91D3A391, 0, 65, 0); + insertScreenMouse(0x302028C8); + + _sprite1 = insertStaticSprite(0x2E068A23, 200); + insertStaticSprite(0x401410A6, 200); + _asFlowingWater = insertSprite<AsScene2401FlowingWater>(); + insertStaticSprite(0x90C0A4B4, 200); + _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x0092916A, 100, 0); + _ssFloorButton = insertSprite<SsCommonFloorButton>(this, 0x28001120, 0x00911068, 100, 0); + + for (uint i = 0; i < 5; i++) + _asWaterFlushing[i] = insertSprite<AsScene2401WaterFlushing>(kScene2401Points[i].x, kScene2401Points[i].y); + + for (uint i = 0; i < 10; i++) { + _ssWaterPipes[i] = insertStaticSprite(kScene2401FileHashes1[i], 300); + _ssWaterPipes[i]->setVisible(false); + } + + _asWaterSpit[0] = insertSprite<AsScene2401WaterSpit>(); + _asWaterSpit[1] = insertSprite<AsScene2401WaterSpit>(); + + if (which < 0) { + // Restoring game + insertKlaymen<KmScene2401>(200, 447); + setMessageList(0x004B2F70); + _asDoor = insertSprite<AsScene2401Door>(false); + } else if (which == 1) { + // Klaymen entering from the back + insertKlaymen<KmScene2401>(280, 413); + setMessageList(0x004B2F80); + _palette->addBasePalette(0xB103B604, 0, 65, 0); + _palette->addPalette(0xB103B604, 0, 65, 0); + _asDoor = insertSprite<AsScene2401Door>(true); + } else { + // Klaymen entering from the left + insertKlaymen<KmScene2401>(-20, 447); + setMessageList(0x004B2F78); + _asDoor = insertSprite<AsScene2401Door>(false); + } + +} + +void Scene2401::update() { + + if (_countdown1 != 0 && (--_countdown1) == 0) { + if (_pipeStatus > 0 && _pipeStatus <= 10) + _ssWaterPipes[_pipeStatus - 1]->setVisible(false); + if (_pipeStatus >= 10) { + bool puzzleSolved = true, waterInside = false; + for (uint pipeIndex = 0; pipeIndex < 5; pipeIndex++) { + if (getSubVar(VA_CURR_WATER_PIPES_LEVEL, pipeIndex) != getSubVar(VA_GOOD_WATER_PIPES_LEVEL, pipeIndex)) + puzzleSolved = false; + if (getSubVar(VA_CURR_WATER_PIPES_LEVEL, pipeIndex) != 0) + waterInside = true; + } + if (puzzleSolved) { + setGlobalVar(V_NOTES_DOOR_UNLOCKED, 1); + setGlobalVar(V_NOTES_PUZZLE_SOLVED, 1); + sendMessage(_asDoor, 0x4808, 0); + } else if (waterInside) { + playPipeSound(0xD0431020); + for (uint i = 0; i < 5; i++) { + sendMessage(_asWaterFlushing[i], 0x2002, getSubVar(VA_CURR_WATER_PIPES_LEVEL, i)); + setSubVar(VA_CURR_WATER_PIPES_LEVEL, i, 0); + } + } + } else if (_pipeStatus >= 5) { + _ssWaterPipes[_pipeStatus]->setVisible(true); + _countdown1 = 8; + playPipeSound(kScene2401FileHashes3[getSubVar(VA_CURR_WATER_PIPES_LEVEL, _pipeStatus - 5)]); + } else { + _ssWaterPipes[_pipeStatus]->setVisible(true); + _countdown1 = _pipeStatus == 4 ? 16 : 8; + playPipeSound(kScene2401FileHashes3[getSubVar(VA_GOOD_WATER_PIPES_LEVEL, _pipeStatus)]); + } + _pipeStatus++; + } + + if (_countdown2 != 0 && (--_countdown2) == 0) + sendMessage(_asFlowingWater, 0x2003, 0); + + Scene::update(); + +} + +uint32 Scene2401::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x402064D8) + sendEntityMessage(_klaymen, 0x1014, _ssButton); + else if (param.asInteger() == 0x02144CB1) + sendEntityMessage(_klaymen, 0x1014, _ssFloorButton); + else if (param.asInteger() == 0x11C40840) { + if (getGlobalVar(V_NOTES_DOOR_UNLOCKED) && sendMessage(_asDoor, 0x2004, 0)) + setMessageList(0x004B3090); + else + setMessageList(0x004B30B0); + } else if (param.asInteger() == 0x412722C0) { + if (_countdown2 > 0 && getGlobalVar(V_HAS_TEST_TUBE)) { + _countdown2 = 144; + setMessageList(0x004B3020); + } else + setMessageList(0x004B3050); + } else if (param.asInteger() == 0x21142050) { + if (_unkFlag && _countdown1 == 0 && !getGlobalVar(V_NOTES_PUZZLE_SOLVED)) + setMessageList(0x004B2FA8); + else + setMessageList(0x004B2FC8); + } else if (param.asInteger() == 0x87441031) + setSurfacePriority(_sprite1->getSurface(), 1100); + else if (param.asInteger() == 0x80C40322) { + setSurfacePriority(_sprite1->getSurface(), 200); + cancelMessageList(); + _unkFlag = true; + } else if (param.asInteger() == 0x09C4B40A && _countdown2 > 12) + _countdown2 = 12; + break; + case 0x2000: + messageResult = 0; + for (uint32 i = 0; i < 5; i++) + if (kScene2401Rects[i].contains(_mouseClickPos.x, _mouseClickPos.y)) { + messageResult = i; + break; + } + break; + case 0x2001: + sendMessage(_asWaterSpit[_asWaterSpitIndex], 0x2000, param.asInteger()); + _asWaterSpitIndex = (_asWaterSpitIndex + 1) & 1; + incSubVar(VA_CURR_WATER_PIPES_LEVEL, param.asInteger(), 1); + if (getSubVar(VA_CURR_WATER_PIPES_LEVEL, param.asInteger()) >= 5) + setSubVar(VA_CURR_WATER_PIPES_LEVEL, param.asInteger(), 4); + break; + case 0x480B: + if (sender == _ssButton) { + _pipeStatus = 0; + _countdown1 = 8; + } else if (sender == _ssFloorButton && getGlobalVar(V_WATER_RUNNING)) { + _countdown2 = 144; + sendMessage(_asFlowingWater, 0x2002, 0); + playSound(0, 0xE1130324); + } + break; + case 0x482A: + _palette->addBasePalette(0xB103B604, 0, 65, 0); + _palette->startFadeToPalette(12); + break; + case 0x482B: + _palette->addBasePalette(0x91D3A391, 0, 65, 0); + _palette->startFadeToPalette(12); + break; + } + return messageResult; +} + +void Scene2401::playPipeSound(uint32 fileHash) { + playSound(_soundToggle ? 0 : 1, fileHash); + _soundToggle = !_soundToggle; +} + +static const uint32 kScene2402FileHashes[] = { + 0xD0910020, 0xD0910038, 0xD0910008, + 0xD0910068, 0xD09100A8 +}; + +AsScene2402Door::AsScene2402Door(NeverhoodEngine *vm, Scene *parentScene, bool isOpen) + : AnimatedSprite(vm, 1100), _parentScene(parentScene), _isOpen(isOpen), _countdown(0) { + + _x = 320; + _y = 240; + createSurface1(0x80495831, 100); + if (_isOpen) { + startAnimation(0x80495831, -1, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + _countdown = 48; + } else { + stopAnimation(); + setVisible(false); + } + SetUpdateHandler(&AsScene2402Door::update); + SetMessageHandler(&AsScene2402Door::handleMessage); +} + +void AsScene2402Door::update() { + if (_isOpen && _countdown != 0 && (--_countdown) == 0) { + _isOpen = false; + setVisible(true); + startAnimation(0x80495831, -1, -1); + _playBackwards = true; + playSound(0, calcHash("fxDoorClose38")); + NextState(&AsScene2402Door::stDoorClosingFinished); + } + AnimatedSprite::update(); +} + +uint32 AsScene2402Door::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x2000: + if (_isOpen) + _countdown = 144; + messageResult = _isOpen ? 1 : 0; + break; + case 0x3002: + gotoNextState(); + break; + case 0x4808: + _countdown = 144; + _isOpen = true; + setVisible(true); + startAnimation(0x80495831, 0, -1); + _newStickFrameIndex = STICK_LAST_FRAME; + playSound(0, calcHash("fxDoorOpen38")); + break; + } + return messageResult; +} + +void AsScene2402Door::stDoorClosingFinished() { + sendMessage(_parentScene, 0x2001, 0); + setVisible(false); +} + +AsScene2402TV::AsScene2402TV(NeverhoodEngine *vm, Klaymen *klaymen) + : AnimatedSprite(vm, 1100), _klaymen(klaymen), _countdown1(0), _countdown2(0) { + + _x = 260; + _y = 210; + createSurface(100, 127, 90); + setDoDeltaX(1); + SetMessageHandler(&Sprite::handleMessage); + if (!getGlobalVar(V_TV_JOKE_TOLD)) { + loadSound(0, 0x58208810); + _countdown1 = 48; + startAnimation(0x4919397A, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AsScene2402TV::upWait); + } else { + int16 frameIndex; + if (_klaymen->getX() > 320) + _currFrameIndex = 29; + frameIndex = CLIP<int16>((_klaymen->getX() - _x + 150) / 10, 0, 29); + startAnimation(0x050A0103, frameIndex, -1); + _newStickFrameIndex = frameIndex; + _countdown1 = 0; + SetUpdateHandler(&AsScene2402TV::upFocusKlaymen); + } +} + +AsScene2402TV::~AsScene2402TV() { + _vm->_soundMan->deleteSoundGroup(0x01520123); +} + +void AsScene2402TV::upWait() { + if (_countdown1 != 0 && (--_countdown1) == 0) { + startAnimation(0x4919397A, 0, -1); + SetMessageHandler(&AsScene2402TV::hmJoke); + NextState(&AsScene2402TV::stJokeFinished); + } + AnimatedSprite::update(); +} + +void AsScene2402TV::upFocusKlaymen() { + int16 frameIndex = CLIP<int16>((_klaymen->getX() - _x + 150) / 10, 0, 29); + if (frameIndex != _currFrameIndex) { + if (frameIndex > _currFrameIndex) + _currFrameIndex++; + else if (frameIndex < _currFrameIndex) + _currFrameIndex--; + startAnimation(0x050A0103, _currFrameIndex, -1); + _newStickFrameIndex = _currFrameIndex; + if (_countdown2 == 0) { + _vm->_soundMan->addSound(0x01520123, 0xC42D4528); + _vm->_soundMan->playSoundLooping(0xC42D4528); + } + _countdown2 = 5; + } else if (_countdown2 != 0 && (--_countdown2 == 0)) + _vm->_soundMan->deleteSound(0xC42D4528); + AnimatedSprite::update(); +} + +void AsScene2402TV::stJokeFinished() { + setGlobalVar(V_TV_JOKE_TOLD, 1); + startAnimation(0x050A0103, 0, -1); + _newStickFrameIndex = 0; + SetUpdateHandler(&AsScene2402TV::upFocusKlaymen); +} + +uint32 AsScene2402TV::hmJoke(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x431EA0B0) + playSound(0); + break; + case 0x3002: + gotoNextState(); + break; + } + return messageResult; +} + +Scene2402::Scene2402(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule), _countdown(0), _soundToggle(false) { + + Sprite *tempSprite; + + SetMessageHandler(&Scene2402::handleMessage); + SetUpdateHandler(&Scene2402::update); + + setRectList(0x004AF900); + setBackground(0x81660220); + setPalette(0x81660220); + insertScreenMouse(0x6022481E); + _asTape = insertSprite<AsScene1201Tape>(this, 9, 1100, 286, 409, 0x9148A011); + addCollisionSprite(_asTape); + _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x15288120, 100, 0); + + if (which < 0) { + // Restoring game + insertKlaymen<KmScene2402>(198, 404); + setMessageList(0x004AF7C8); + } else if (which == 1) { + // Klaymen entering from the right + insertKlaymen<KmScene2402>(660, 404); + setMessageList(0x004AF7D8); + } else if (which == 2) { + // Klaymen returning from looking through the window + insertKlaymen<KmScene2402>(409, 404); + _klaymen->setDoDeltaX(getGlobalVar(V_KLAYMEN_IS_DELTA_X) ? 1 : 0); + setMessageList(0x004AF888); + } else { + // Klaymen entering from the left + insertKlaymen<KmScene2402>(0, 404); + setMessageList(0x004AF7D0); + } + + tempSprite = insertStaticSprite(0x081A60A8, 1100); + _ssDoorFrame = (StaticSprite*)insertStaticSprite(0x406C0AE0, 1100); + _klaymen->setClipRect(_ssDoorFrame->getDrawRect().x, 0, 639, tempSprite->getDrawRect().y2()); + _asDoor = insertSprite<AsScene2402Door>(this, which == 0); + insertSprite<AsScene2402TV>(_klaymen); + insertStaticSprite(0x3A01A020, 200); + +} + +Scene2402::~Scene2402() { + setGlobalVar(V_KLAYMEN_IS_DELTA_X, _klaymen->isDoDeltaX() ? 1 : 0); +} + +void Scene2402::update() { + if (_countdown != 0 && (--_countdown) == 0) { + if (_pipeStatus >= 10) { + sendMessage(_asDoor, 0x4808, 0); + _ssDoorFrame->loadSprite(0x00B415E0, kSLFDefDrawOffset | kSLFDefPosition); + } else if (_pipeStatus >= 5) { + _countdown = 8; + playPipeSound(kScene2402FileHashes[getSubVar(VA_CURR_WATER_PIPES_LEVEL, _pipeStatus - 5)]); + } else { + _countdown = _pipeStatus == 4 ? 16 : 8; + playPipeSound(kScene2402FileHashes[getSubVar(VA_GOOD_WATER_PIPES_LEVEL, _pipeStatus)]); + } + _pipeStatus++; + } + Scene::update(); +} + +uint32 Scene2402::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x402064D8) + sendEntityMessage(_klaymen, 0x1014, _ssButton); + else if (param.asInteger() == 0x01C66840) { + if (sendMessage(_asDoor, 0x2000, 0)) + setMessageList(0x004AF800); + else + setMessageList(0x004AF818); + } + break; + case 0x2001: + _ssDoorFrame->loadSprite(0x406C0AE0, kSLFDefDrawOffset | kSLFDefPosition); + break; + case 0x480B: + if (sender == _ssButton) { + _pipeStatus = 0; + _countdown = 8; + } + break; + case 0x4826: + if (sender == _asTape) { + sendEntityMessage(_klaymen, 0x1014, _asTape); + setMessageList(0x004AF890); + } + break; + } + return messageResult; +} + +void Scene2402::playPipeSound(uint32 fileHash) { + playSound(_soundToggle ? 0 : 1, fileHash); + _soundToggle = !_soundToggle; +} + +Scene2403::Scene2403(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule) { + + Sprite *tempSprite1, *tempSprite2, *tempSprite3; + + SetMessageHandler(&Scene2403::handleMessage); + setBackground(0x0C05060C); + setPalette(0x0C05060C); + _palette->addPalette(0x414364B0, 0, 65, 0); + insertScreenMouse(0x506080C8); + _asTape = insertSprite<AsScene1201Tape>(this, 2, 1100, 480, 454, 0x9148A011); + addCollisionSprite(_asTape); + _asLightCord = insertSprite<AsScene2803LightCord>(this, 0xA1095A10, 0x836D3813, 368, 200); + _asLightCord->setClipRect(0, 25, 640, 480); + + if (which < 0) { + // Restoring game + _isClimbingLadder = false; + insertKlaymen<KmScene2403>(220, 449); + setMessageList(0x004B5C98); + setRectList(0x004B5E18); + } else if (which == 1) { + // Klaymen returning from looking through the window + _isClimbingLadder = false; + insertKlaymen<KmScene2403>(433, 449); + setMessageList(0x004B5D70); + setRectList(0x004B5E18); + } else if (which == 2) { + // Klaymen standing around after the critter video + _isClimbingLadder = false; + insertKlaymen<KmScene2403>(440, 449); + _klaymen->setDoDeltaX(1); + setMessageList(0x004B5C98); + setRectList(0x004B5E18); + } else { + // Klaymen coming up from ladder + _isClimbingLadder = true; + insertKlaymen<KmScene2403>(122, 599); + setMessageList(0x004B5CA0); + setRectList(0x004B5E28); + } + + _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x3130B0EB, 100, 0); + tempSprite1 = insertStaticSprite(0x20C24220, 1100); + tempSprite2 = insertStaticSprite(0x03080900, 1300); + tempSprite3 = insertSprite<AsScene1002KlaymenLadderHands>(_klaymen); + tempSprite3->setClipRect(tempSprite1->getDrawRect().x, 0, 640, tempSprite2->getDrawRect().y2()); + _klaymen->setClipRect(tempSprite1->getDrawRect().x, 0, 640, tempSprite2->getDrawRect().y2()); + loadSound(1, calcHash("fxFogHornSoft")); +} + +uint32 Scene2403::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x040424D0) + sendEntityMessage(_klaymen, 0x1014, _ssButton); + else if (param.asInteger() == 0x180CE614) + sendEntityMessage(_klaymen, 0x1014, _asLightCord); + break; + case 0x2000: + _isClimbingLadder = true; + setRectList(0x004B5E28); + break; + case 0x2001: + _isClimbingLadder = false; + setRectList(0x004B5E18); + break; + case 0x480B: + if (sender == _ssButton) { + if (getSubVar(VA_LOCKS_DISABLED, 0x304008D2)) { + setSubVar(VA_LOCKS_DISABLED, 0x304008D2, 0); + playSound(0, calcHash("fx3LocksDisable")); + } else { + setSubVar(VA_LOCKS_DISABLED, 0x304008D2, 1); + playSound(1); + } + } + break; + case 0x480F: + if (sender == _asLightCord) + leaveScene(2); + break; + case 0x4826: + if (sender == _asTape && !_isClimbingLadder) { + sendEntityMessage(_klaymen, 0x1014, _asTape); + setMessageList(0x004B5D98); + } + break; + } + return messageResult; +} + +Scene2406::Scene2406(NeverhoodEngine *vm, Module *parentModule, int which) + : Scene(vm, parentModule) { + + Sprite *tempSprite1, *tempSprite2; + + if (getGlobalVar(V_HAS_FINAL_KEY) && getGlobalVar(V_KEY3_LOCATION) == 0) + setGlobalVar(V_KEY3_LOCATION, 2); + + SetMessageHandler(&Scene2406::handleMessage); + + setRectList(0x004B78C8); + insertScreenMouse(0xB03001A8); + + if (getGlobalVar(V_KEY3_LOCATION) == 2) { + _asKey = insertSprite<AsCommonKey>(this, 2, 1100, 560, 409); + addCollisionSprite(_asKey); + } + + _asTape = insertSprite<AsScene1201Tape>(this, 5, 1100, 456, 409, 0x9148A011); + addCollisionSprite(_asTape); + tempSprite2 = insertStaticSprite(0x19625293, 1100); + _clipRects[0].x1 = 0; + _clipRects[0].y1 = 0; + _clipRects[0].x2 = tempSprite2->getDrawRect().x2(); + _clipRects[0].y2 = 480; + + if (getGlobalVar(V_SPIKES_RETRACTED)) { + setBackground(0x1A0B0304); + setPalette(0x1A0B0304); + tempSprite1 = insertStaticSprite(0x32923922, 1100); + } else { + setBackground(0x0A038595); + setPalette(0x0A038595); + tempSprite1 = insertStaticSprite(0x1712112A, 1100); + } + + tempSprite2 = insertStaticSprite(0x22300924, 1300); + _clipRects[1].x1 = tempSprite1->getDrawRect().x; + _clipRects[1].y1 = tempSprite2->getDrawRect().y; + _clipRects[1].x2 = 640; + _clipRects[1].y2 = 480; + + if (which < 0) { + // Restoring game + _isClimbingLadder = false; + insertKlaymen<KmScene2406>(307, 404, _clipRects, 2); + setMessageList(0x004B76C8); + setRectList(0x004B78C8); + } else if (which == 1) { + // Klaymen coming down the ladder + _isClimbingLadder = true; + insertKlaymen<KmScene2406>(253, -16, _clipRects, 2); + setMessageList(0x004B76D8); + setRectList(0x004B78D8); + } else if (which == 2) { + // Klaymen returning from the diskplayer + _isClimbingLadder = false; + insertKlaymen<KmScene2406>(480, 404, _clipRects, 2); + setMessageList(0x004B77C0); + setRectList(0x004B78C8); + } else if (which == 3) { + // Klaymen returning from looking through the window + _isClimbingLadder = false; + insertKlaymen<KmScene2406>(387, 404, _clipRects, 2); + setMessageList(0x004B7810); + setRectList(0x004B78C8); + } else { + // Klaymen entering from the left + _isClimbingLadder = false; + insertKlaymen<KmScene2406>(0, 404, _clipRects, 2); + setMessageList(0x004B76D0); + setRectList(0x004B78C8); + } + + tempSprite2 = insertSprite<AsScene1002KlaymenLadderHands>(_klaymen); + tempSprite2->setClipRect(_clipRects[1]); + +} + +uint32 Scene2406::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { + uint32 messageResult = Scene::handleMessage(messageNum, param, sender); + switch (messageNum) { + case 0x100D: + if (param.asInteger() == 0x41062804) { + if (getGlobalVar(V_SPIKES_RETRACTED)) + setMessageList(0x004B7758); + else + setMessageList(0x004B7738); + } + break; + case 0x2000: + _isClimbingLadder = true; + setRectList(0x004B78D8); + break; + case 0x2001: + _isClimbingLadder = false; + setRectList(0x004B78C8); + break; + case 0x4826: + if (sender == _asTape && !_isClimbingLadder) { + sendEntityMessage(_klaymen, 0x1014, _asTape); + setMessageList(0x004B77C8); + } else if (sender == _asKey && !_isClimbingLadder) { + sendEntityMessage(_klaymen, 0x1014, _asKey); + setMessageList(0x004B77D8); + } + break; + } + return messageResult; +} + +} // End of namespace Neverhood |