aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorjohndoe1232012-09-13 17:51:44 +0000
committerWillem Jan Palenstijn2013-05-08 20:43:41 +0200
commit402f4bd275f064f0ad7752be7aebfa1634b81fa1 (patch)
tree178963e48a9ff441f879e694df6e9699ca3600b4 /engines
parentd4e322bc78d30941f5f3ab31c2460412fe0d7fb5 (diff)
downloadscummvm-rg350-402f4bd275f064f0ad7752be7aebfa1634b81fa1.tar.gz
scummvm-rg350-402f4bd275f064f0ad7752be7aebfa1634b81fa1.tar.bz2
scummvm-rg350-402f4bd275f064f0ad7752be7aebfa1634b81fa1.zip
NEVERHOOD: Start with Module2400
- Implement Scene2401
Diffstat (limited to 'engines')
-rw-r--r--engines/neverhood/gamemodule.cpp29
-rw-r--r--engines/neverhood/gamemodule.h1
-rw-r--r--engines/neverhood/klayman.cpp144
-rw-r--r--engines/neverhood/klayman.h17
-rw-r--r--engines/neverhood/module.mk1
-rw-r--r--engines/neverhood/module2400.cpp501
-rw-r--r--engines/neverhood/module2400.h115
7 files changed, 807 insertions, 1 deletions
diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp
index 844ca58203..d657307256 100644
--- a/engines/neverhood/gamemodule.cpp
+++ b/engines/neverhood/gamemodule.cpp
@@ -37,6 +37,7 @@
#include "neverhood/module2100.h"
#include "neverhood/module2200.h"
#include "neverhood/module2300.h"
+#include "neverhood/module2400.h"
#include "neverhood/module2500.h"
#include "neverhood/module2600.h"
#include "neverhood/module2700.h"
@@ -221,6 +222,21 @@ void GameModule::initScene1405Vars() {
}
+void GameModule::initScene2401Vars() {
+
+ if (getSubVar(0x40050052, 0x40520234))
+ return;
+
+ setSubVar(0x90405038, 0, 3);
+ setSubVar(0x90405038, 1, 1);
+ setSubVar(0x90405038, 2, 2);
+ setSubVar(0x90405038, 3, 0);
+ setSubVar(0x90405038, 4, 4);
+
+ setSubVar(0x40050052, 0x40520234, 1);
+
+}
+
void GameModule::initScene2808Vars1() {
// Exit if it's already initialized
@@ -332,11 +348,15 @@ void GameModule::startup() {
_vm->gameState().sceneNum = 11;
createModule(2800, -1);
#endif
-#if 1
+#if 0
_vm->gameState().which = 0;
_vm->gameState().sceneNum = 0;
createModule(2500, -1);
#endif
+#if 1
+ _vm->gameState().sceneNum = 0;
+ createModule(2400, -1);
+#endif
}
void GameModule::createModule(int moduleNum, int which) {
@@ -400,6 +420,10 @@ void GameModule::createModule(int moduleNum, int which) {
setGlobalVar(0x91080831, 0x1A214010);
_childObject = new Module2300(_vm, this, which);
break;
+ case 2400:
+ setGlobalVar(0x91080831, 0x202D1010);
+ _childObject = new Module2400(_vm, this, which);
+ break;
case 2500:
setGlobalVar(0x91080831, 0x29220120);
_childObject = new Module2500(_vm, this, which);
@@ -523,6 +547,9 @@ void GameModule::updateModule() {
createModule(1000, 1);
}
break;
+ case 2400:
+ createModule(2300, 3);
+ break;
case 2500:
createModule(2600, 1);
break;
diff --git a/engines/neverhood/gamemodule.h b/engines/neverhood/gamemodule.h
index f453feb580..af72d53fc9 100644
--- a/engines/neverhood/gamemodule.h
+++ b/engines/neverhood/gamemodule.h
@@ -39,6 +39,7 @@ public:
void handleMouseDown(int16 x, int16 y);
void initScene1307Vars();
void initScene1405Vars();
+ void initScene2401Vars();
void initScene2808Vars1();
void initScene2808Vars2();
void initScene3009Vars();
diff --git a/engines/neverhood/klayman.cpp b/engines/neverhood/klayman.cpp
index 9d28b5f046..9a6e4fe1a1 100644
--- a/engines/neverhood/klayman.cpp
+++ b/engines/neverhood/klayman.cpp
@@ -5215,6 +5215,150 @@ void KmScene2247::sub453520() {
FinalizeState(&Klayman::stStartWalkingDone);
}
+KmScene2401::KmScene2401(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _readyToSpit(false) {
+ // Empty
+}
+
+uint32 KmScene2401::xHandleMessage(int messageNum, const MessageParam &param) {
+ uint32 messageResult = 0;
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ startWalkToX(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4816:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stTurnPressButton);
+ } else if (param.asInteger() == 2) {
+ GotoState(&Klayman::stStampFloorButton);
+ } else {
+ GotoState(&Klayman::stPressButtonSide);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ gotoNextStateExt();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else if (param.asInteger() == 0) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ gotoNextStateExt();
+ break;
+ case 0x482E:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWalkToFrontNoStep);
+ } else {
+ GotoState(&Klayman::stWalkToFront);
+ }
+ break;
+ case 0x482F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stTurnToFront);
+ } else {
+ GotoState(&Klayman::stTurnToBack);
+ }
+ break;
+ case 0x4832:
+ GotoState(&Klayman::sub421110);
+ break;
+ case 0x4833:
+ if (param.asInteger() == 1)
+ GotoState(&Klayman::stWonderAboutHalf);
+ else {
+ _spitPipeIndex = sendMessage(_parentScene, 0x2000, 0);
+ GotoState(&KmScene2401::stTrySpitIntoPipe);
+ }
+ break;
+ case 0x483F:
+ startSpecialWalkRight(param.asInteger());
+ break;
+ case 0x4840:
+ startSpecialWalkLeft(param.asInteger());
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene2401::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Klayman::handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x16401CA6) {
+ _canSpit = true;
+ if (_contSpit)
+ spitIntoPipe();
+ } else if (param.asInteger() == 0xC11C0008) {
+ _canSpit = false;
+ _acceptInput = false;
+ _readyToSpit = false;
+ } else if (param.asInteger() == 0x018A0001) {
+ sendMessage(_parentScene, 0x2001, _spitDestPipeIndex);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene2401::stTrySpitIntoPipe() {
+ if (_readyToSpit) {
+ _contSpit = true;
+ _spitContDestPipeIndex = _spitPipeIndex;
+ if (_canSpit)
+ spitIntoPipe();
+ } else if (!stStartAction(AnimationCallback(&KmScene2401::stTrySpitIntoPipe))) {
+ _status2 = 2;
+ _acceptInput = true;
+ _spitDestPipeIndex = _spitPipeIndex;
+ _readyToSpit = true;
+ _canSpit = false;
+ _contSpit = false;
+ startAnimation(0x1808B150, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene2401::handleMessage);
+ SetSpriteUpdate(NULL);
+ }
+}
+
+void KmScene2401::spitIntoPipe() {
+ _contSpit = false;
+ _spitDestPipeIndex = _spitContDestPipeIndex;
+ _canSpit = false;
+ _acceptInput = false;
+ startAnimation(0x1B08B553, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene2401::handleMessage);
+ SetSpriteUpdate(NULL);
+ NextState(&KmScene2401::stContSpitIntoPipe);
+}
+
+void KmScene2401::stContSpitIntoPipe() {
+ _canSpit = true;
+ _acceptInput = true;
+ startAnimationByHash(0x1808B150, 0x16401CA6, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene2401::handleMessage);
+ SetSpriteUpdate(NULL);
+}
+
KmScene2501::KmScene2501(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
: Klayman(vm, parentScene, x, y, 1000, 1000), _isSittingInTeleporter(false) {
// Empty
diff --git a/engines/neverhood/klayman.h b/engines/neverhood/klayman.h
index fea543cdc9..fdf9b6e9b4 100644
--- a/engines/neverhood/klayman.h
+++ b/engines/neverhood/klayman.h
@@ -578,6 +578,23 @@ protected:
void sub453520();
};
+class KmScene2401 : public Klayman {
+public:
+ KmScene2401(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _canSpit;
+ bool _contSpit;
+ bool _readyToSpit;
+ uint32 _spitPipeIndex;
+ uint32 _spitDestPipeIndex;
+ uint32 _spitContDestPipeIndex;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stTrySpitIntoPipe();
+ void spitIntoPipe();
+ void stContSpitIntoPipe();
+};
+
class KmScene2501 : public Klayman {
public:
KmScene2501(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
diff --git a/engines/neverhood/module.mk b/engines/neverhood/module.mk
index ac4064bf81..694d92dbd9 100644
--- a/engines/neverhood/module.mk
+++ b/engines/neverhood/module.mk
@@ -25,6 +25,7 @@ MODULE_OBJS = \
module2100.o \
module2200.o \
module2300.o \
+ module2400.o \
module2500.o \
module2600.o \
module2700.o \
diff --git a/engines/neverhood/module2400.cpp b/engines/neverhood/module2400.cpp
new file mode 100644
index 0000000000..4febe7429f
--- /dev/null
+++ b/engines/neverhood/module2400.cpp
@@ -0,0 +1,501 @@
+/* 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/module2400.h"
+
+namespace Neverhood {
+
+Module2400::Module2400(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ // TODO Music18hList_add(0x202D1010, 0xB110382D);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, _vm->gameState().which);
+ } else {
+ createScene(0, 0);
+ }
+
+}
+
+Module2400::~Module2400() {
+ // TODO Music18hList_deleteGroup(0x202D1010);
+}
+
+void Module2400::createScene(int sceneNum, int which) {
+ debug("Module2400::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ // TODO Music18hList_stop(0xB110382D, 0, 0);
+ _childObject = new Scene2401(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module2400::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module2400::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1)
+ createScene(1, 0);
+ else
+ leaveModule(0);
+ 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), _soundResource(vm) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2401WaterSpit::handleMessage);
+ SetSpriteUpdate(&AnimatedSprite::updateDeltaXY);
+ createSurface(100, 146, 74);
+ _x = 240;
+ _y = 447;
+ setVisible(false);
+}
+
+uint32 AsScene2401WaterSpit::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x120A0013)
+ _soundResource.play(kAsScene2401WaterSpitFileHashes1[_soundIndex]);
+ break;
+ case 0x2000:
+ _x = 240;
+ _y = 447;
+ _soundIndex = getSubVar(0x0800547C, param.asInteger());
+ _soundResource.play(0x48640244);
+ startAnimation(kAsScene2401WaterSpitFileHashes2[param.asInteger()], 0, -1);
+ setVisible(true);
+ break;
+ case 0x3002:
+ stopAnimation();
+ setVisible(false);
+ break;
+ }
+ return messageResult;
+}
+
+AsScene2401FlowingWater::AsScene2401FlowingWater(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1200), _isWaterFlowing(false) {
+
+ createSurface1(0x10203116, 100);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2401FlowingWater::handleMessage);
+ _x = 88;
+ _y = 421;
+ setVisible(false);
+}
+
+AsScene2401FlowingWater::~AsScene2401FlowingWater() {
+ // TODO Sound1ChList_sub_407AF0(0x40F11C09);
+}
+
+uint32 AsScene2401FlowingWater::handleMessage(int messageNum, const MessageParam &param, 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) {
+ // TODO Sound1ChList_addSoundResource(0x40F11C09, 0x980C1420, true);
+ // TODO Sound1ChList_playLooping(0x980C1420);
+ startAnimation(0x10203116, 0, -1);
+ setVisible(true);
+ _isWaterFlowing = true;
+ }
+ break;
+ case 0x2003:
+ // TODO Sound1ChList_deleteSoundByHash(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) {
+
+ createSurface1(0xB8596884, 100);
+ SetUpdateHandler(&AsScene2401WaterFlushing::update);
+ SetMessageHandler(&AsScene2401WaterFlushing::handleMessage);
+ _x = x;
+ _y = y;
+ setVisible(false);
+}
+
+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 &param, 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), _soundResource(vm) {
+
+ createSurface1(0x44687810, 100);
+ _x = 320;
+ _y = 240;
+ _newStickFrameIndex = -2;
+ SetUpdateHandler(&AsScene2401Door::update);
+ SetMessageHandler(&AsScene2401Door::handleMessage);
+ if (_isOpen) {
+ stopAnimation();
+ setVisible(false);
+ _countdown = 48;
+ } else {
+ startAnimation(0x44687810, 0, -1);
+ _newStickFrameIndex = 0;
+ }
+}
+
+void AsScene2401Door::update() {
+ if (_isOpen && _countdown != 0 && (--_countdown) == 0) {
+ _isOpen = false;
+ setVisible(true);
+ startAnimation(0x44687810, -1, -1);
+ _newStickFrameIndex = 0;
+ _playBackwards = true;
+ _soundResource.play(calcHash("fxDoorClose38"));
+ }
+ AnimatedSprite::update();
+}
+
+uint32 AsScene2401Door::handleMessage(int messageNum, const MessageParam &param, 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);
+ _soundResource.play(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, true), _countdown1(0), _countdown2(0), _flag(false),
+ _soundToggle(false), _asWaterSpitIndex(0), _soundResource1(vm), _soundResource2(vm) {
+
+ _vm->gameModule()->initScene2401Vars();
+
+ setGlobalVar(0x4E0BE910, 1); //DEBUG! Enables water
+ setGlobalVar(0x45080C38, 1); //DEBUG! Gives the test tube
+
+ _surfaceFlag = true;
+ 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);
+ insertMouse433(0x302028C8);
+
+ _sprite1 = insertStaticSprite(0x2E068A23, 200);
+ insertStaticSprite(0x401410A6, 200);
+ _asFlowingWater = insertSprite<AsScene2401FlowingWater>();
+ insertStaticSprite(0x90C0A4B4, 200);
+ _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x0092916A, 100, 0);
+ _ssFloorButton = insertSprite<Class427>(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) {
+ insertKlayman<KmScene2401>(200, 447);
+ setMessageList(0x004B2F70);
+ _asDoor = insertSprite<AsScene2401Door>(false);
+ } else if (which == 1) {
+ insertKlayman<KmScene2401>(280, 413);
+ setMessageList(0x004B2F80);
+ _palette->addBasePalette(0xB103B604, 0, 65, 0);
+ _palette->addPalette(0xB103B604, 0, 65, 0);
+ _asDoor = insertSprite<AsScene2401Door>(true);
+ } else {
+ insertKlayman<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 i = 0; i < 5; i++) {
+ if (getSubVar(0x0800547C, i) != getSubVar(0x90405038, i))
+ puzzleSolved = false;
+ if (getSubVar(0x0800547C, i) != 0)
+ waterInside = true;
+ }
+ if (puzzleSolved) {
+ setGlobalVar(0x0045D021, 1);
+ setGlobalVar(0x86615030, 1);
+ sendMessage(_asDoor, 0x4808, 0);
+ } else if (waterInside) {
+ playPipeSound(0xD0431020);
+ for (uint i = 0; i < 5; i++) {
+ sendMessage(_asWaterFlushing[i], 0x2002, getSubVar(0x0800547C, i));
+ setSubVar(0x0800547C, i, 0);
+ }
+ }
+ } else if (_pipeStatus >= 5) {
+ _ssWaterPipes[_pipeStatus]->setVisible(true);
+ _countdown1 = 8;
+ playPipeSound(kScene2401FileHashes3[getSubVar(0x0800547C, _pipeStatus - 5)]);
+ } else {
+ _ssWaterPipes[_pipeStatus]->setVisible(true);
+ _countdown1 = _pipeStatus == 4 ? 16 : 8;
+ playPipeSound(kScene2401FileHashes3[getSubVar(0x90405038, _pipeStatus)]);
+ }
+ _pipeStatus++;
+ }
+
+ if (_countdown2 != 0 && (--_countdown2) == 0) {
+ sendMessage(_asFlowingWater, 0x2003, 0);
+ }
+
+ Scene::update();
+
+}
+
+uint32 Scene2401::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ // case 0x0001: TODO DEBUG
+ // case 0x000D: TODO DEBUG
+ case 0x100D:
+ if (param.asInteger() == 0x402064D8)
+ sendEntityMessage(_klayman, 0x1014, _ssButton);
+ else if (param.asInteger() == 0x02144CB1)
+ sendEntityMessage(_klayman, 0x1014, _ssFloorButton);
+ else if (param.asInteger() == 0x11C40840) {
+ if (getGlobalVar(0x0045D021) && sendMessage(_asDoor, 0x2004, 0)) {
+ setMessageList(0x004B3090);
+ } else {
+ setMessageList(0x004B30B0);
+ }
+ } else if (param.asInteger() == 0x412722C0) {
+ if (_countdown2 > 0 && getGlobalVar(0x45080C38)) {
+ _countdown2 = 144;
+ setMessageList(0x004B3020);
+ } else {
+ setMessageList(0x004B3050);
+ }
+ } else if (param.asInteger() == 0x21142050) {
+ if (_flag && _countdown1 == 0 && getGlobalVar(0x86615030) == 0) {
+ setMessageList(0x004B2FA8);
+ } else {
+ setMessageList(0x004B2FC8);
+ }
+ } else if (param.asInteger() == 0x87441031) {
+ setSurfacePriority(_sprite1->getSurface(), 1100);
+ } else if (param.asInteger() == 0x80C40322) {
+ setSurfacePriority(_sprite1->getSurface(), 200);
+ messageList402220();
+ _flag = 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(0x0800547C, param.asInteger(), 1);
+ if (getSubVar(0x0800547C, param.asInteger()) >= 5)
+ setSubVar(0x0800547C, param.asInteger(), 4);
+ break;
+ case 0x480B:
+ if (sender == _ssButton) {
+ _pipeStatus = 0;
+ _countdown1 = 8;
+ } else if (sender == _ssFloorButton && getGlobalVar(0x4E0BE910)) {
+ _countdown2 = 144;
+ sendMessage(_asFlowingWater, 0x2002, 0);
+ _soundResource1.play(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) {
+ if (_soundToggle)
+ _soundResource1.play(fileHash);
+ else
+ _soundResource2.play(fileHash);
+ _soundToggle = !_soundToggle;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2400.h b/engines/neverhood/module2400.h
new file mode 100644
index 0000000000..c8cdb664c8
--- /dev/null
+++ b/engines/neverhood/module2400.h
@@ -0,0 +1,115 @@
+/* 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.
+ *
+ */
+
+#ifndef NEVERHOOD_MODULE2400_H
+#define NEVERHOOD_MODULE2400_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/module1000.h"
+#include "neverhood/module1100.h"
+#include "neverhood/module2100.h"
+
+namespace Neverhood {
+
+// Module2400
+
+class Module2400 : public Module {
+public:
+ Module2400(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2400();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene2401WaterSpit : public AnimatedSprite {
+public:
+ AsScene2401WaterSpit(NeverhoodEngine *vm);
+protected:
+ int _soundIndex;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene2401FlowingWater : public AnimatedSprite {
+public:
+ AsScene2401FlowingWater(NeverhoodEngine *vm);
+ virtual ~AsScene2401FlowingWater();
+protected:
+ bool _isWaterFlowing;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene2401WaterFlushing : public AnimatedSprite {
+public:
+ AsScene2401WaterFlushing(NeverhoodEngine *vm, int16 x, int16 y);
+protected:
+ int _countdown;
+ int _flushLoopCount;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene2401Door : public AnimatedSprite {
+public:
+ AsScene2401Door(NeverhoodEngine *vm, bool isOpen);
+protected:
+ int _countdown;
+ bool _isOpen;
+ SoundResource _soundResource;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stDoorOpenFinished();
+};
+
+class Scene2401 : public Scene {
+public:
+ Scene2401(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_sprite1;
+ Sprite *_asFlowingWater;
+ Sprite *_ssButton;
+ Sprite *_ssFloorButton;
+ Sprite *_asWaterSpit[2];
+ Sprite *_ssWaterPipes[10];
+ Sprite *_asWaterFlushing[5];
+ Sprite *_asDoor;
+ bool _soundToggle;
+ bool _flag;
+ int _countdown1;
+ int _countdown2;
+ int _pipeStatus;
+ int _asWaterSpitIndex;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void playPipeSound(uint32 fileHash);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2400_H */