aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/neverhood/gamemodule.cpp39
-rw-r--r--engines/neverhood/gamemodule.h1
-rw-r--r--engines/neverhood/module1300.cpp386
-rw-r--r--engines/neverhood/module1300.h46
4 files changed, 470 insertions, 2 deletions
diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp
index 93ea6c5066..277b55da7c 100644
--- a/engines/neverhood/gamemodule.cpp
+++ b/engines/neverhood/gamemodule.cpp
@@ -85,6 +85,43 @@ void GameModule::handleMouseDown(int16 x, int16 y) {
}
}
+void GameModule::initScene1307Vars() {
+
+ if (getSubVar(0x40050052, 0x25400B10))
+ return;
+
+ for (uint i = 0; i < 3; i++) {
+ bool more;
+ do {
+ more = false;
+ setSubVar(0x0C10A000, i, _vm->_rnd->getRandomNumber(16 - 1));
+ if (i > 0) {
+ for (uint j = 0; j < i && !more; j++) {
+ more = getSubVar(0x0C10A000, j) == getSubVar(0x0C10A000, i);
+ }
+ }
+ } while (more);
+ }
+
+ for (uint i = 0; i < 3; i++) {
+ bool more;
+ do {
+ more = false;
+ setSubVar(0xA010B810, i, _vm->_rnd->getRandomNumber(16 - 1));
+ if (i > 0) {
+ for (uint j = 0; j < i && !more; j++) {
+ more = getSubVar(0xA010B810, j) == getSubVar(0xA010B810, i);
+ }
+ }
+ if (getSubVar(0xA010B810, i) == getSubVar(0x0C10A000, i))
+ more = true;
+ } while (more);
+ }
+
+ setSubVar(0x40050052, 0x25400B10, 1);
+
+}
+
void GameModule::initScene1405Vars() {
// TODO: Give better names
@@ -247,7 +284,7 @@ void GameModule::startup() {
createModule2200(-1);
#endif
#if 1
- _vm->gameState().sceneNum = 5;
+ _vm->gameState().sceneNum = 6;
createModule1300(-1);
#endif
}
diff --git a/engines/neverhood/gamemodule.h b/engines/neverhood/gamemodule.h
index ef199f772a..02f16c552b 100644
--- a/engines/neverhood/gamemodule.h
+++ b/engines/neverhood/gamemodule.h
@@ -37,6 +37,7 @@ public:
void startup();
void handleMouseMove(int16 x, int16 y);
void handleMouseDown(int16 x, int16 y);
+ void initScene1307Vars();
void initScene1405Vars();
void initScene3009Vars();
protected:
diff --git a/engines/neverhood/module1300.cpp b/engines/neverhood/module1300.cpp
index f437ddc730..27f8a11f75 100644
--- a/engines/neverhood/module1300.cpp
+++ b/engines/neverhood/module1300.cpp
@@ -24,6 +24,7 @@
#include "neverhood/module1000.h"
#include "neverhood/module1200.h"
#include "neverhood/module2200.h"
+#include "neverhood/gamemodule.h"
#include "neverhood/diskplayerscene.h"
#include "neverhood/navigationscene.h"
#include "neverhood/smackerscene.h"
@@ -189,6 +190,11 @@ void Module1300::createScene1306(int which) {
}
void Module1300::createScene1307(int which) {
+ _vm->gameState().sceneNum = 6;
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x203197, 0, 2, 1);
+ _childObject = new Scene1307(_vm, this, which);
+ SetUpdateHandler(&Module1300::updateScene1307);
}
void Module1300::createScene1308(int which) {
@@ -319,6 +325,14 @@ void Module1300::updateScene1306() {
}
void Module1300::updateScene1307() {
+ _childObject->handleUpdate();
+ if (_done) {
+ _done = false;
+ delete _childObject;
+ _childObject = NULL;
+ createScene1308(2);
+ _childObject->handleUpdate();
+ }
}
void Module1300::updateScene1308() {
@@ -1126,7 +1140,6 @@ Scene1306::~Scene1306() {
}
uint32 Scene1306::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
-if (messageNum) debug("%04X", messageNum);
Scene::handleMessage(messageNum, param, sender);
switch (messageNum) {
case 0x100D:
@@ -1213,4 +1226,375 @@ uint32 Scene1306::handleMessage416EB0(int messageNum, const MessageParam &param,
return 0;
}
+static const uint32 kAsScene1307KeyResourceList1[] = {
+ 0x0438069C,
+ 0x45B0023C,
+ 0x05700217
+};
+
+static const uint32 kAsScene1307KeyResourceList2[] = {
+ 0x04441334,
+ 0x061433F0,
+ 0x06019390
+};
+
+static const uint32 kAsScene1307KeyResourceList3[] = {
+ 0x11A80030,
+ 0x178812B1,
+ 0x1488121C
+};
+
+static const uint32 *kAsScene1307KeyResourceLists[] = {
+ kAsScene1307KeyResourceList1,
+ kAsScene1307KeyResourceList2,
+ kAsScene1307KeyResourceList3
+};
+
+static const int kAsScene1307KeySurfacePriorities[] = {
+ 700,
+ 500,
+ 300,
+ 100
+};
+
+const uint kAsScene1307KeyPointsCount = 12;
+
+static const NPoint kAsScene1307KeyPoints[] = {
+ {-2, 0},
+ {-5, 0},
+ { 5, 0},
+ {12, 0},
+ {17, 0},
+ {25, 0},
+ {16, -2},
+ {10, -6},
+ { 0, -7},
+ {-7, -3},
+ {-3, 4},
+ { 2, 2}
+};
+
+const uint kAsScene1307KeyFrameIndicesCount = 20;
+
+static const int16 kAsScene1307KeyFrameIndices[] = {
+ 1, 4, 8, 11, 15, 16, 17, 17, 17, 16,
+ 15, 14, 12, 10, 9, 7, 5, 3, 2, 1
+};
+
+const int kAsScene1307KeyDivValue = 200;
+
+const int16 kAsScene1307KeyXDelta = 70;
+const int16 kAsScene1307KeyYDelta = -12;
+
+AsScene1307Key::AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint index, NRect *clipRects)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm), _soundResource3(vm),
+ _soundResource4(vm), _parentScene(parentScene), _index(index), _clipRects(clipRects),
+ _isClickable(true) {
+
+ NPoint pt;
+ const uint32 *fileHashes = kAsScene1307KeyResourceLists[_index];
+
+ _dataResource.load(0x22102142);
+ _pointList = _dataResource.getPointArray(0xAC849240);
+
+ pt = (*_pointList)[getSubVar(0xA010B810, _index)];
+ _x = pt.x;
+ _y = pt.y;
+
+ // TODO createSurface3(kAsScene1307KeySurfacePriorities[getSubVar(0xA010B810, _index) % 4], fileHashes);
+ createSurface(kAsScene1307KeySurfacePriorities[getSubVar(0xA010B810, _index) % 4], 640, 480); //TODO: Remeove once the line above is done
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1307Key::handleMessage);
+
+ setFileHash(fileHashes[0], 0, -1);
+
+ _soundResource1.load(0xDC4A1280);
+ _soundResource2.load(0xCC021233);
+ _soundResource3.load(0xC4C23844);
+ _soundResource3.load(0xC4523208);
+
+}
+
+uint32 AsScene1307Key::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_isClickable) {
+ _parentScene->sendMessage(0x4826, 0, this);
+ stRemoveKey();
+ messageResult = 1;
+ }
+ break;
+ case 0x2000:
+ _isClickable = param.asInteger() != 0;
+ break;
+ case 0x2001:
+ setSubVar(0xA010B810, _index, param.asInteger());
+ stMoveKey();
+ break;
+ case 0x2003:
+ _soundResource4.play();
+ stUnlock();
+ break;
+ case 0x2004:
+ _soundResource3.play();
+ stInsert();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1307Key::suRemoveKey() {
+ if (_pointIndex < kAsScene1307KeyPointsCount) {
+ _x += kAsScene1307KeyPoints[_pointIndex].x;
+ _y += kAsScene1307KeyPoints[_pointIndex].y;
+ processDelta();
+ _pointIndex++;
+ } else {
+ SetSpriteCallback(NULL);
+ }
+}
+
+void AsScene1307Key::suInsertKey() {
+ if (_pointIndex < kAsScene1307KeyPointsCount) {
+ _x -= kAsScene1307KeyPoints[kAsScene1307KeyPointsCount - _pointIndex - 1].x;
+ _y -= kAsScene1307KeyPoints[kAsScene1307KeyPointsCount - _pointIndex - 1].y;
+ processDelta();
+ _pointIndex++;
+ if (_pointIndex == 7)
+ _soundResource1.play();
+ } else {
+ SetSpriteCallback(NULL);
+ _parentScene->sendMessage(0x2002, 0, this);
+ }
+}
+
+void AsScene1307Key::suMoveKey() {
+ if (_pointIndex < kAsScene1307KeyFrameIndicesCount) {
+ _frameIndex += kAsScene1307KeyFrameIndices[_pointIndex];
+ _x = _prevX + (_deltaX * _frameIndex) / kAsScene1307KeyDivValue;
+ _y = _prevY + (_deltaY * _frameIndex) / kAsScene1307KeyDivValue;
+ processDelta();
+ _pointIndex++;
+ } else {
+ NPoint pt = (*_pointList)[getSubVar(0xA010B810, _index)];
+ _x = pt.x + kAsScene1307KeyXDelta;
+ _y = pt.y + kAsScene1307KeyYDelta;
+ stInsertKey();
+ }
+}
+
+void AsScene1307Key::stRemoveKey() {
+ const uint32 *fileHashes = kAsScene1307KeyResourceLists[_index];
+ _pointIndex = 0;
+ SetSpriteCallback(&AsScene1307Key::suRemoveKey);
+ setFileHash(fileHashes[0], 0, -1);
+ _soundResource2.play();
+}
+
+void AsScene1307Key::stInsertKey() {
+ _pointIndex = 0;
+ _parentScene->sendMessage(0x1022, kAsScene1307KeySurfacePriorities[getSubVar(0xA010B810, _index) % 4], this);
+ _surface->getClipRect() = _clipRects[getSubVar(0xA010B810, _index) % 4];
+ SetSpriteCallback(&AsScene1307Key::suInsertKey);
+ _newHashListIndex = -2;
+}
+
+void AsScene1307Key::stMoveKey() {
+ NPoint pt = (*_pointList)[getSubVar(0xA010B810, _index)];
+ int16 newX = pt.x + kAsScene1307KeyXDelta;
+ int16 newY = pt.y + kAsScene1307KeyYDelta;
+ _parentScene->sendMessage(0x1022, 1000, this);
+ _surface->getClipRect().x1 = 0;
+ _surface->getClipRect().y1 = 0;
+ _surface->getClipRect().x2 = 640;
+ _surface->getClipRect().y2 = 480;
+ _prevX = _x;
+ _prevY = _y;
+ if (newX == _x && newY == _y) {
+ stInsertKey();
+ } else {
+ const uint32 *fileHashes = kAsScene1307KeyResourceLists[_index];
+ _pointIndex = 0;
+ _frameIndex = 0;
+ _deltaX = newX - _x;
+ _deltaY = newY - _y;
+ SetSpriteCallback(&AsScene1307Key::suMoveKey);
+ setFileHash(fileHashes[0], 0, -1);
+ }
+}
+
+void AsScene1307Key::stUnlock() {
+ const uint32 *fileHashes = kAsScene1307KeyResourceLists[_index];
+ setFileHash(fileHashes[1], 0, -1);
+ _newHashListIndex = -2;
+}
+
+void AsScene1307Key::stInsert() {
+ const uint32 *fileHashes = kAsScene1307KeyResourceLists[_index];
+ setFileHash(fileHashes[2], 0, -1);
+ _newHashListIndex = -2;
+}
+
+Scene1307::Scene1307(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm), _countdown(0),
+ _asCurrKey(NULL), _isInsertingKey(false), _doLeaveScene(false), _isPuzzleSolved(false) {
+
+ //DEBUG
+ setSubVar(0x08D0AB11, 0, 1);
+ setSubVar(0x08D0AB11, 1, 1);
+ setSubVar(0x08D0AB11, 2, 1);
+
+ Sprite *tempSprite;
+
+ _vm->gameModule()->initScene1307Vars();
+
+ _dataResource.load(0x22102142);
+ _keyHolePoints = _dataResource.getPointArray(0xAC849240);
+
+ for (uint i = 0; i < 16; i++) {
+ NPoint pt = (*_keyHolePoints)[i];
+ _keyHoleRects[i].x1 = pt.x - 15;
+ _keyHoleRects[i].y1 = pt.y - 15;
+ _keyHoleRects[i].x2 = pt.x + 15;
+ _keyHoleRects[i].y2 = pt.y + 15;
+ }
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1307::handleMessage);
+ SetUpdateHandler(&Scene1307::update);
+
+ _background = addBackground(new DirtyBackground(_vm, 0xA8006200, 0, 0));
+ _palette = new Palette(_vm, 0xA8006200);
+ _palette->usePalette();
+ addEntity(_palette);
+ _mouseCursor = addSprite(new Mouse435(_vm, 0x06204A88, 20, 620));
+
+ tempSprite = addSprite(new StaticSprite(_vm, 0x00A3621C, 800));
+ _clipRects[0].x1 = tempSprite->getSurface()->getDrawRect().x;
+ _clipRects[0].y1 = 0;
+ _clipRects[0].x2 = 640;
+ _clipRects[0].y2 = 480;
+
+ tempSprite = addSprite(new StaticSprite(_vm, 0x00A3641C, 600));
+ _clipRects[1].x1 = tempSprite->getSurface()->getDrawRect().x;
+ _clipRects[1].y1 = 0;
+ _clipRects[1].x2 = 640;
+ _clipRects[1].y2 = 480;
+
+ tempSprite = addSprite(new StaticSprite(_vm, 0x00A3681C, 400));
+ _clipRects[2].x1 = tempSprite->getSurface()->getDrawRect().x;
+ _clipRects[2].y1 = 0;
+ _clipRects[2].x2 = 640;
+ _clipRects[2].y2 = 480;
+
+ tempSprite = addSprite(new StaticSprite(_vm, 0x00A3701C, 200));
+ _clipRects[3].x1 = tempSprite->getSurface()->getDrawRect().x;
+ _clipRects[3].y1 = 0;
+ _clipRects[3].x2 = 640;
+ _clipRects[3].y2 = 480;
+
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex)) {
+ _asKeys[keyIndex] = addSprite(new AsScene1307Key(_vm, this, keyIndex, _clipRects));
+ _vm->_collisionMan->addSprite(_asKeys[keyIndex]);
+ } else {
+ _asKeys[keyIndex] = NULL;
+ }
+ }
+
+ _soundResource.load(0x68E25540);
+
+}
+
+void Scene1307::update() {
+ Scene::update();
+ if (_countdown && (--_countdown == 0)) {
+ _doLeaveScene = true;
+ } else if (_countdown == 20) {
+ _palette->startFadeToWhite(40);
+ }
+ if (_doLeaveScene && !_soundResource.isPlaying()) {
+ _parentModule->sendMessage(0x1009, 1, this);
+ setGlobalVar(0x80455A41, 1);
+ }
+}
+
+uint32 Scene1307::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO Debug stuff
+ if (!_isPuzzleSolved) {
+ if (param.asPoint().x > 20 && param.asPoint().x < 620) {
+ if (_asCurrKey && !_isInsertingKey) {
+ int16 mouseX = param.asPoint().x;
+ int16 mouseY = param.asPoint().y;
+ uint clickedKeyHoleIndex;
+ for (clickedKeyHoleIndex = 0; clickedKeyHoleIndex < 16; clickedKeyHoleIndex++) {
+ if (mouseX >= _keyHoleRects[clickedKeyHoleIndex].x1 && mouseX <= _keyHoleRects[clickedKeyHoleIndex].x2 &&
+ mouseY >= _keyHoleRects[clickedKeyHoleIndex].y1 && mouseY <= _keyHoleRects[clickedKeyHoleIndex].y2)
+ break;
+ }
+ if (clickedKeyHoleIndex < 16) {
+ // Check if the clicked keyhole is already occupied with a key
+ bool occupied = false;
+ for (uint keyIndex = 0; keyIndex < 3 && !occupied; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex) && _asKeys[keyIndex] != _asCurrKey) {
+ if (getSubVar(0xA010B810, keyIndex) == clickedKeyHoleIndex)
+ occupied = true;
+ }
+ }
+ if (!occupied) {
+ // If the keyhole is free, insert the current key
+ _asCurrKey->sendMessage(0x2001, clickedKeyHoleIndex, this);
+ _isInsertingKey = true;
+ _mouseClicked = false;
+ }
+ }
+ }
+ } else if (_countdown == 0 && !_asCurrKey && !_isInsertingKey) {
+ _parentModule->sendMessage(0x1009, 0, this);
+ }
+ }
+ break;
+ // TODO Debug stuff
+ case 0x2002:
+ // Check if all keys are in the correct keyholes
+ if (getSubVar(0x08D0AB11, 0) && getSubVar(0xA010B810, 0) == getSubVar(0x0C10A000, 0) &&
+ getSubVar(0x08D0AB11, 1) && getSubVar(0xA010B810, 1) == getSubVar(0x0C10A000, 1) &&
+ getSubVar(0x08D0AB11, 2) && getSubVar(0xA010B810, 2) == getSubVar(0x0C10A000, 2)) {
+ // Play unlock animations for all keys
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (_asKeys[keyIndex])
+ _asKeys[keyIndex]->sendMessage(0x2003, 1, this);
+ }
+ _soundResource.play();
+ _isPuzzleSolved = true;
+ _countdown = 47;
+ } else {
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex) && _asKeys[keyIndex]) {
+ _asKeys[keyIndex]->sendMessage(0x2000, 1, this);
+ }
+ }
+ _asCurrKey->sendMessage(0x2004, 1, this);
+ }
+ _asCurrKey = NULL;
+ _isInsertingKey = false;
+ break;
+ case 0x4826:
+ _asCurrKey = (Sprite*)sender;
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex) && _asKeys[keyIndex]) {
+ _asKeys[keyIndex]->sendMessage(0x2000, 0, this);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
} // End of namespace Neverhood
diff --git a/engines/neverhood/module1300.h b/engines/neverhood/module1300.h
index 33f5fb5c9f..80b2774817 100644
--- a/engines/neverhood/module1300.h
+++ b/engines/neverhood/module1300.h
@@ -208,6 +208,52 @@ protected:
uint32 handleMessage416EB0(int messageNum, const MessageParam &param, Entity *sender);
};
+class AsScene1307Key : public AnimatedSprite {
+public:
+ AsScene1307Key(NeverhoodEngine *vm, Scene *parentScene, uint index, NRect *clipRects);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ SoundResource _soundResource4;
+ NPointArray *_pointList;
+ uint _pointIndex;
+ int _frameIndex;
+ uint _index;
+ NRect *_clipRects;
+ bool _isClickable;
+ int16 _prevX, _prevY;
+ int16 _deltaX, _deltaY;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suRemoveKey();
+ void suInsertKey();
+ void suMoveKey();
+ void stRemoveKey();
+ void stInsertKey();
+ void stMoveKey();
+ void stUnlock();
+ void stInsert();
+};
+
+class Scene1307 : public Scene {
+public:
+ Scene1307(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource;
+ NPointArray *_keyHolePoints;
+ NRect _keyHoleRects[16];
+ NRect _clipRects[4];
+ Sprite *_asKeys[3];
+ int _countdown;
+ Sprite *_asCurrKey;
+ bool _isInsertingKey;
+ bool _doLeaveScene;
+ bool _isPuzzleSolved;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
} // End of namespace Neverhood
#endif /* NEVERHOOD_MODULE1300_H */