aboutsummaryrefslogtreecommitdiff
path: root/engines/neverhood
diff options
context:
space:
mode:
Diffstat (limited to 'engines/neverhood')
-rw-r--r--engines/neverhood/background.cpp88
-rw-r--r--engines/neverhood/background.h57
-rw-r--r--engines/neverhood/blbarchive.cpp116
-rw-r--r--engines/neverhood/blbarchive.h72
-rw-r--r--engines/neverhood/collisionman.cpp114
-rw-r--r--engines/neverhood/collisionman.h57
-rw-r--r--engines/neverhood/detection.cpp282
-rw-r--r--engines/neverhood/diskplayerscene.cpp563
-rw-r--r--engines/neverhood/diskplayerscene.h110
-rw-r--r--engines/neverhood/entity.h146
-rw-r--r--engines/neverhood/gamemodule.cpp509
-rw-r--r--engines/neverhood/gamemodule.h56
-rw-r--r--engines/neverhood/gamevars.cpp114
-rw-r--r--engines/neverhood/gamevars.h57
-rw-r--r--engines/neverhood/graphics.cpp321
-rw-r--r--engines/neverhood/graphics.h134
-rw-r--r--engines/neverhood/klayman.cpp4921
-rw-r--r--engines/neverhood/klayman.h543
-rw-r--r--engines/neverhood/module.cpp117
-rw-r--r--engines/neverhood/module.h70
-rw-r--r--engines/neverhood/module.mk50
-rw-r--r--engines/neverhood/module1000.cpp1898
-rw-r--r--engines/neverhood/module1000.h336
-rw-r--r--engines/neverhood/module1100.cpp719
-rw-r--r--engines/neverhood/module1100.h136
-rw-r--r--engines/neverhood/module1200.cpp1236
-rw-r--r--engines/neverhood/module1200.h234
-rw-r--r--engines/neverhood/module1300.cpp1928
-rw-r--r--engines/neverhood/module1300.h321
-rw-r--r--engines/neverhood/module1400.cpp1737
-rw-r--r--engines/neverhood/module1400.h296
-rw-r--r--engines/neverhood/module1500.cpp147
-rw-r--r--engines/neverhood/module1500.h59
-rw-r--r--engines/neverhood/module1600.cpp1486
-rw-r--r--engines/neverhood/module1600.h194
-rw-r--r--engines/neverhood/module1700.cpp278
-rw-r--r--engines/neverhood/module1700.h72
-rw-r--r--engines/neverhood/module1800.cpp170
-rw-r--r--engines/neverhood/module1800.h45
-rw-r--r--engines/neverhood/module1900.cpp691
-rw-r--r--engines/neverhood/module1900.h150
-rw-r--r--engines/neverhood/module2000.cpp155
-rw-r--r--engines/neverhood/module2000.h55
-rw-r--r--engines/neverhood/module2100.cpp341
-rw-r--r--engines/neverhood/module2100.h95
-rw-r--r--engines/neverhood/module2200.cpp2731
-rw-r--r--engines/neverhood/module2200.h403
-rw-r--r--engines/neverhood/module2300.cpp181
-rw-r--r--engines/neverhood/module2300.h47
-rw-r--r--engines/neverhood/module2600.cpp333
-rw-r--r--engines/neverhood/module2600.h76
-rw-r--r--engines/neverhood/module2700.cpp1038
-rw-r--r--engines/neverhood/module2700.h134
-rw-r--r--engines/neverhood/module3000.cpp1617
-rw-r--r--engines/neverhood/module3000.h269
-rw-r--r--engines/neverhood/mouse.cpp249
-rw-r--r--engines/neverhood/mouse.h62
-rw-r--r--engines/neverhood/navigationscene.cpp217
-rw-r--r--engines/neverhood/navigationscene.h56
-rw-r--r--engines/neverhood/neverhood.cpp248
-rw-r--r--engines/neverhood/neverhood.h135
-rw-r--r--engines/neverhood/palette.cpp177
-rw-r--r--engines/neverhood/palette.h65
-rw-r--r--engines/neverhood/resource.cpp679
-rw-r--r--engines/neverhood/resource.h212
-rw-r--r--engines/neverhood/resourceman.cpp172
-rw-r--r--engines/neverhood/resourceman.h81
-rw-r--r--engines/neverhood/scene.cpp615
-rw-r--r--engines/neverhood/scene.h214
-rw-r--r--engines/neverhood/screen.cpp289
-rw-r--r--engines/neverhood/screen.h61
-rw-r--r--engines/neverhood/smackerplayer.cpp250
-rw-r--r--engines/neverhood/smackerplayer.h83
-rw-r--r--engines/neverhood/smackerscene.cpp122
-rw-r--r--engines/neverhood/smackerscene.h54
-rw-r--r--engines/neverhood/sprite.cpp528
-rw-r--r--engines/neverhood/sprite.h178
-rw-r--r--engines/neverhood/staticdata.cpp200
-rw-r--r--engines/neverhood/staticdata.h116
79 files changed, 33168 insertions, 0 deletions
diff --git a/engines/neverhood/background.cpp b/engines/neverhood/background.cpp
new file mode 100644
index 0000000000..e235eaa1b3
--- /dev/null
+++ b/engines/neverhood/background.cpp
@@ -0,0 +1,88 @@
+/* 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/background.h"
+
+namespace Neverhood {
+
+// Background
+
+Background::Background(NeverhoodEngine *vm, int objectPriority)
+ : Entity(vm, objectPriority), _surface(NULL), _spriteResource(vm) {
+ // Empty
+}
+
+Background::Background(NeverhoodEngine *vm, uint32 fileHash, int objectPriority, int surfacePriority)
+ : Entity(vm, objectPriority), _surface(NULL), _spriteResource(vm) {
+
+ _spriteResource.load(fileHash);
+ createSurface(surfacePriority, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _surface->drawSpriteResource(_spriteResource);
+
+}
+
+Background::~Background() {
+ delete _surface;
+}
+
+void Background::createSurface(int surfacePriority, int16 width, int16 height) {
+ _surface = new BaseSurface(_vm, surfacePriority, width, height);
+ _surface->setTransparent(false);
+ _spriteResource.getPosition().x = width;
+ _spriteResource.getPosition().y = height;
+}
+
+void Background::load(uint32 fileHash) {
+ _spriteResource.load(fileHash);
+ if (_surface)
+ _surface->drawSpriteResource(_spriteResource);
+}
+
+// DirtyBackground
+
+DirtyBackground::DirtyBackground(NeverhoodEngine *vm, const char *fileName, int objectPriority, int surfacePriority)
+ : Background(vm, objectPriority) {
+
+ _spriteResource.load(calcHash(fileName));
+ createSurface(surfacePriority, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _surface->drawSpriteResource(_spriteResource);
+}
+
+DirtyBackground::DirtyBackground(NeverhoodEngine *vm, uint32 fileHash, int objectPriority, int surfacePriority)
+ : Background(vm, objectPriority) {
+
+ _spriteResource.load(fileHash);
+ createSurface(surfacePriority, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _surface->drawSpriteResource(_spriteResource);
+}
+
+void DirtyBackground::createSurface(int surfacePriority, int16 width, int16 height) {
+
+ // TODO: Later use a DirtySurface once it is implemented
+ _surface = new BaseSurface(_vm, surfacePriority, width, height);
+ _surface->setTransparent(false);
+ _spriteResource.getPosition().x = width;
+ _spriteResource.getPosition().y = height;
+
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/background.h b/engines/neverhood/background.h
new file mode 100644
index 0000000000..8ac3581a51
--- /dev/null
+++ b/engines/neverhood/background.h
@@ -0,0 +1,57 @@
+/* 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_BACKGROUND_H
+#define NEVERHOOD_BACKGROUND_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/entity.h"
+#include "neverhood/graphics.h"
+#include "neverhood/resource.h"
+
+namespace Neverhood {
+
+class Background : public Entity {
+public:
+ Background(NeverhoodEngine *vm, int objectPriority);
+ Background(NeverhoodEngine *vm, uint32 fileHash, int objectPriority, int surfacePriority);
+ virtual ~Background();
+ BaseSurface *getSurface() { return _surface; }
+ void createSurface(int surfacePriority, int16 width, int16 height);
+ void load(uint32 fileHash);
+ SpriteResource& getSpriteResource() { return _spriteResource; }
+protected:
+ BaseSurface *_surface;
+ SpriteResource _spriteResource;
+};
+
+class DirtyBackground : public Background {
+public:
+ DirtyBackground(NeverhoodEngine *vm, const char *fileName, int objectPriority, int surfacePriority);
+ DirtyBackground(NeverhoodEngine *vm, uint32 fileHash, int objectPriority, int surfacePriority);
+ void createSurface(int surfacePriority, int16 width, int16 height);
+
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_BACKGROUND_H */
diff --git a/engines/neverhood/blbarchive.cpp b/engines/neverhood/blbarchive.cpp
new file mode 100644
index 0000000000..6a047cab46
--- /dev/null
+++ b/engines/neverhood/blbarchive.cpp
@@ -0,0 +1,116 @@
+/* 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 "common/dcl.h"
+#include "neverhood/blbarchive.h"
+
+namespace Neverhood {
+
+BlbArchive::BlbArchive() : _extData(NULL) {
+}
+
+BlbArchive::~BlbArchive() {
+ delete[] _extData;
+}
+
+void BlbArchive::open(const Common::String &filename) {
+ BlbHeader header;
+
+ _entries.clear();
+
+ if (!_fd.open(filename))
+ error("BlbArchive::open() Could not open %s", filename.c_str());
+
+ header.id1 = _fd.readUint32LE();
+ header.id2 = _fd.readUint16LE();
+ header.extDataSize = _fd.readUint16LE();
+ header.fileSize = _fd.readUint32LE();
+ header.fileCount = _fd.readUint32LE();
+
+ if (header.id1 != 0x2004940 || header.id2 != 7 || header.fileSize != _fd.size())
+ error("BlbArchive::open() %s seems to be corrupt", filename.c_str());
+
+ debug(2, "fileCount = %d", header.fileCount);
+
+ _entries.reserve(header.fileCount);
+
+ // Load file hashes
+ for (uint i = 0; i < header.fileCount; i++) {
+ BlbArchiveEntry entry;
+ entry.fileHash = _fd.readUint32LE();
+ _entries.push_back(entry);
+ }
+
+ // Load file records
+ for (uint i = 0; i < header.fileCount; i++) {
+ BlbArchiveEntry &entry = _entries[i];
+ entry.type = _fd.readByte();
+ entry.comprType = _fd.readByte();
+ entry.extDataOfs = _fd.readUint16LE();
+ entry.timeStamp = _fd.readUint32LE();
+ entry.offset = _fd.readUint32LE();
+ entry.diskSize = _fd.readUint32LE();
+ entry.size = _fd.readUint32LE();
+ debug(2, "%08X: %03d, %02X, %04X, %08X, %08X, %08X, %08X",
+ entry.fileHash, entry.type, entry.comprType, entry.extDataOfs, entry.timeStamp,
+ entry.offset, entry.diskSize, entry.size);
+ }
+
+ // Load ext data
+ if (header.extDataSize > 0) {
+ _extData = new byte[header.extDataSize];
+ _fd.read(_extData, header.extDataSize);
+ }
+
+}
+
+void BlbArchive::load(uint index, byte *buffer, uint32 size) {
+ BlbArchiveEntry &entry = _entries[index];
+
+ _fd.seek(entry.offset);
+
+ switch (entry.comprType) {
+ case 1: // Uncompressed
+ if (size == 0)
+ size = entry.diskSize;
+ _fd.read(buffer, size);
+ break;
+ case 3: // DCL-compressed
+ Common::decompressDCL(&_fd, buffer, entry.diskSize, entry.size);
+ break;
+ default:
+ ;
+ }
+
+}
+
+byte *BlbArchive::getEntryExtData(uint index) {
+ BlbArchiveEntry &entry = _entries[index];
+ return (_extData && entry.extDataOfs != 0) ? &_extData[entry.extDataOfs - 1] : NULL;
+}
+
+Common::SeekableReadStream *BlbArchive::createStream(uint index) {
+ const BlbArchiveEntry &entry = _entries[index];
+ return new Common::SafeSubReadStream(&_fd, entry.offset, entry.offset + entry.diskSize);
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/blbarchive.h b/engines/neverhood/blbarchive.h
new file mode 100644
index 0000000000..ddb3f0196b
--- /dev/null
+++ b/engines/neverhood/blbarchive.h
@@ -0,0 +1,72 @@
+/* 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_BLBARCHIVE_H
+#define NEVERHOOD_BLBARCHIVE_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/substream.h"
+#include "neverhood/neverhood.h"
+
+namespace Neverhood {
+
+struct BlbHeader {
+ uint32 id1;
+ uint16 id2;
+ uint16 extDataSize;
+ int32 fileSize;
+ uint32 fileCount;
+};
+
+struct BlbArchiveEntry {
+ uint32 fileHash;
+ byte type;
+ byte comprType;
+ uint16 extDataOfs;
+ uint32 timeStamp;
+ uint32 offset;
+ uint32 diskSize;
+ uint32 size;
+};
+
+class BlbArchive {
+public:
+ BlbArchive();
+ ~BlbArchive();
+ void open(const Common::String &filename);
+ void load(uint index, byte *buffer, uint32 size);
+ byte *getEntryExtData(uint index);
+ uint32 getSize(uint index) { return _entries[index].size; }
+ BlbArchiveEntry *getEntry(uint index) { return &_entries[index]; }
+ uint getCount() { return _entries.size(); }
+ Common::SeekableReadStream *createStream(uint index);
+private:
+ Common::File _fd;
+ Common::Array<BlbArchiveEntry> _entries;
+ byte *_extData;
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_BLBARCHIVE_H */
diff --git a/engines/neverhood/collisionman.cpp b/engines/neverhood/collisionman.cpp
new file mode 100644
index 0000000000..a1314bfe0f
--- /dev/null
+++ b/engines/neverhood/collisionman.cpp
@@ -0,0 +1,114 @@
+/* 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/collisionman.h"
+
+namespace Neverhood {
+
+static HitRect defaultHitRect = {NRect(), 0x5000};
+
+CollisionMan::CollisionMan(NeverhoodEngine *vm)
+ : _vm(vm), _hitRects(NULL) {
+}
+
+CollisionMan::~CollisionMan() {
+}
+
+void CollisionMan::setHitRects(uint32 id) {
+ setHitRects(_vm->_staticData->getHitRectList(id));
+}
+
+void CollisionMan::setHitRects(HitRectList *hitRects) {
+ _hitRects = hitRects;
+
+ // DEBUG
+ if (_hitRects) {
+ debug("CollisionMan::setHitRects() count = %d", _hitRects->size());
+ for (HitRectList::iterator it = _hitRects->begin(); it != _hitRects->end(); it++) {
+ HitRect *hitRect = &(*it);
+ debug("(%d, %d, %d, %d) -> %04X", hitRect->rect.x1, hitRect->rect.y1, hitRect->rect.x2, hitRect->rect.y2, hitRect->type);
+ }
+ }
+
+}
+
+void CollisionMan::clearHitRects() {
+ _hitRects = NULL;
+}
+
+HitRect *CollisionMan::findHitRectAtPos(int16 x, int16 y) {
+ if (_hitRects) {
+ for (HitRectList::iterator it = _hitRects->begin(); it != _hitRects->end(); it++) {
+ HitRect *hitRect = &(*it);
+ if (x >= hitRect->rect.x1 && x <= hitRect->rect.x2 && y >= hitRect->rect.y1 && y <= hitRect->rect.y2)
+ return hitRect;
+ }
+ }
+ return &defaultHitRect;
+}
+
+void CollisionMan::addSprite(Sprite *sprite) {
+ int index = 0, insertIndex = -1;
+ for (Common::Array<Sprite*>::iterator iter = _sprites.begin(); iter != _sprites.end(); iter++) {
+ if ((*iter)->getPriority() > sprite->getPriority()) {
+ insertIndex = index;
+ break;
+ }
+ index++;
+ }
+ if (insertIndex >= 0)
+ _sprites.insert_at(insertIndex, sprite);
+ else
+ _sprites.push_back(sprite);
+}
+
+void CollisionMan::removeSprite(Sprite *sprite) {
+ for (uint index = 0; index < _sprites.size(); index++) {
+ if (_sprites[index] == sprite) {
+ _sprites.remove_at(index);
+ break;
+ }
+ }
+}
+
+void CollisionMan::clearSprites() {
+ _sprites.clear();
+}
+
+void CollisionMan::checkCollision(Sprite *sprite, uint16 flags, int messageNum, uint32 messageParam) {
+ for (Common::Array<Sprite*>::iterator iter = _sprites.begin(); iter != _sprites.end(); iter++) {
+ Sprite *collSprite = *iter;
+ if ((sprite->getFlags() & flags) && collSprite->checkCollision(sprite->getRect())) {
+ sprite->sendMessage(collSprite, messageNum, messageParam);
+ }
+ }
+}
+
+void CollisionMan::save() {
+ // TODO
+}
+
+void CollisionMan::restore() {
+ // TODO
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/collisionman.h b/engines/neverhood/collisionman.h
new file mode 100644
index 0000000000..86359525b0
--- /dev/null
+++ b/engines/neverhood/collisionman.h
@@ -0,0 +1,57 @@
+/* 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_COLLISIONMAN_H
+#define NEVERHOOD_COLLISIONMAN_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/sprite.h"
+#include "neverhood/staticdata.h"
+
+namespace Neverhood {
+
+class CollisionMan {
+public:
+ CollisionMan(NeverhoodEngine *vm);
+ ~CollisionMan();
+ void setHitRects(uint32 id);
+ void setHitRects(HitRectList *hitRects);
+ void clearHitRects();
+ HitRect *findHitRectAtPos(int16 x, int16 y);
+ void addSprite(Sprite *sprite);
+ void removeSprite(Sprite *sprite);
+ void clearSprites();
+ void checkCollision(Sprite *sprite, uint16 flags, int messageNum, uint32 messageParam);
+ void save();
+ void restore();
+ uint getSpriteCount() const { return _sprites.size(); }
+ Sprite *getSprite(uint index) const { return _sprites[index]; }
+protected:
+ NeverhoodEngine *_vm;
+ HitRectList *_hitRects;
+ Common::Array<Sprite*> _sprites;
+};
+
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_COLLISIONMAN_H */
diff --git a/engines/neverhood/detection.cpp b/engines/neverhood/detection.cpp
new file mode 100644
index 0000000000..df9eca3d7f
--- /dev/null
+++ b/engines/neverhood/detection.cpp
@@ -0,0 +1,282 @@
+/* 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 "base/plugins.h"
+
+#include "engines/advancedDetector.h"
+#include "common/file.h"
+
+#include "neverhood/neverhood.h"
+
+
+namespace Neverhood {
+
+struct NeverhoodGameDescription {
+ ADGameDescription desc;
+
+ int gameID;
+ int gameType;
+ uint32 features;
+ uint16 version;
+};
+
+const char *NeverhoodEngine::getGameId() const {
+ return _gameDescription->desc.gameid;
+}
+
+uint32 NeverhoodEngine::getFeatures() const {
+ return _gameDescription->features;
+}
+
+Common::Platform NeverhoodEngine::getPlatform() const {
+ return _gameDescription->desc.platform;
+}
+
+uint16 NeverhoodEngine::getVersion() const {
+ return _gameDescription->version;
+}
+
+}
+
+static const PlainGameDescriptor neverhoodGames[] = {
+ {"neverhood", "The Neverhood Chronicles"},
+ {0, 0}
+};
+
+namespace Neverhood {
+
+static const NeverhoodGameDescription gameDescriptions[] = {
+
+ {
+ // Neverhood English version
+ // TODO: Maybe additional files are needed to properly detect different versions
+ {
+ "neverhood",
+ 0,
+ AD_ENTRY1s("hd.blb", "22958d968458c9ff221aee38577bb2b2", 4279716),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ },
+
+ { AD_TABLE_END_MARKER, 0, 0, 0, 0 }
+};
+
+/**
+ * The fallback game descriptor used by the Neverhood engine's fallbackDetector.
+ * Contents of this struct are to be overwritten by the fallbackDetector.
+ */
+static NeverhoodGameDescription g_fallbackDesc = {
+ {
+ "",
+ "",
+ AD_ENTRY1(0, 0), // This should always be AD_ENTRY1(0, 0) in the fallback descriptor
+ Common::UNK_LANG,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO_NONE
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+} // End of namespace Neverhood
+
+class NeverhoodMetaEngine : public AdvancedMetaEngine {
+public:
+ NeverhoodMetaEngine() : AdvancedMetaEngine(Neverhood::gameDescriptions, sizeof(Neverhood::NeverhoodGameDescription), neverhoodGames) {
+ _singleid = "neverhood";
+ }
+
+ virtual const char *getName() const {
+ return "Neverhood Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Neverhood Engine (C) Infogrames";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+
+#if 0 // Not used yet but let's keep it for later when it is
+ SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ void removeSaveState(const char *target, int slot) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+#endif
+
+ const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const;
+
+};
+
+bool NeverhoodMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ false; // Nothing yet :(
+// (f == kSupportsListSaves) ||
+// (f == kSupportsLoadingDuringStartup) ||
+// (f == kSupportsDeleteSave) ||
+// (f == kSavesSupportMetaInfo) ||
+// (f == kSavesSupportThumbnail);
+}
+
+bool Neverhood::NeverhoodEngine::hasFeature(EngineFeature f) const {
+ return
+ false; // Nothing yet :(
+// (f == kSupportsRTL) || // TODO: Not yet...
+// (f == kSupportsLoadingDuringRuntime) ||
+// (f == kSupportsSavingDuringRuntime);
+}
+
+bool NeverhoodMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ const Neverhood::NeverhoodGameDescription *gd = (const Neverhood::NeverhoodGameDescription *)desc;
+ if (gd) {
+ *engine = new Neverhood::NeverhoodEngine(syst, gd);
+ }
+ return gd != 0;
+}
+
+const ADGameDescription *NeverhoodMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
+ // Set the default values for the fallback descriptor's ADGameDescription part.
+ Neverhood::g_fallbackDesc.desc.language = Common::UNK_LANG;
+ Neverhood::g_fallbackDesc.desc.platform = Common::kPlatformPC;
+ Neverhood::g_fallbackDesc.desc.flags = ADGF_NO_FLAGS;
+
+ // Set default values for the fallback descriptor's NeverhoodGameDescription part.
+ Neverhood::g_fallbackDesc.gameID = 0;
+ Neverhood::g_fallbackDesc.features = 0;
+ Neverhood::g_fallbackDesc.version = 3;
+
+ return NULL;
+}
+
+#if 0 // Not used yet but let's keep it for later when it is
+
+SaveStateList NeverhoodMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Neverhood::NeverhoodEngine::SaveHeader header;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ Common::StringArray filenames;
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ if (Neverhood::NeverhoodEngine::readSaveHeader(in, false, header) == Neverhood::NeverhoodEngine::kRSHENoError) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.description));
+ }
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+int NeverhoodMetaEngine::getMaximumSaveSlot() const {
+ return 999;
+}
+
+void NeverhoodMetaEngine::removeSaveState(const char *target, int slot) const {
+ // Slot 0 can't be deleted, it's for restarting the game(s)
+ if (slot == 0)
+ return;
+
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::String filename = Neverhood::NeverhoodEngine::getSavegameFilename(target, slot);
+
+ saveFileMan->removeSavefile(filename.c_str());
+
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ // Rename every slot greater than the deleted slot,
+ // Also do not rename quicksaves.
+ if (slotNum > slot && slotNum < 990) {
+ // FIXME: Our savefile renaming done here is inconsitent with what we do in
+ // GUI_v2::deleteMenu. While here we rename every slot with a greater equal
+ // number of the deleted slot to deleted slot, deleted slot + 1 etc.,
+ // we only rename the following slots in GUI_v2::deleteMenu until a slot
+ // is missing.
+ saveFileMan->renameSavefile(file->c_str(), filename.c_str());
+
+ filename = Neverhood::NeverhoodEngine::getSavegameFilename(target, ++slot);
+ }
+ }
+
+}
+
+SaveStateDescriptor NeverhoodMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = Neverhood::NeverhoodEngine::getSavegameFilename(target, slot);
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
+
+ if (in) {
+ Neverhood::NeverhoodEngine::SaveHeader header;
+ Neverhood::NeverhoodEngine::kReadSaveHeaderError error;
+
+ error = Neverhood::NeverhoodEngine::readSaveHeader(in, true, header);
+ delete in;
+
+ if (error == Neverhood::NeverhoodEngine::kRSHENoError) {
+ SaveStateDescriptor desc(slot, header.description);
+
+ desc.setDeletableFlag(false);
+ desc.setWriteProtectedFlag(false);
+ desc.setThumbnail(header.thumbnail);
+
+ return desc;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+#endif
+
+#if PLUGIN_ENABLED_DYNAMIC(NEVERHOOD)
+ REGISTER_PLUGIN_DYNAMIC(NEVERHOOD, PLUGIN_TYPE_ENGINE, NeverhoodMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(NEVERHOOD, PLUGIN_TYPE_ENGINE, NeverhoodMetaEngine);
+#endif
diff --git a/engines/neverhood/diskplayerscene.cpp b/engines/neverhood/diskplayerscene.cpp
new file mode 100644
index 0000000000..4fdc736dc5
--- /dev/null
+++ b/engines/neverhood/diskplayerscene.cpp
@@ -0,0 +1,563 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "neverhood/diskplayerscene.h"
+#include "neverhood/mouse.h"
+
+namespace Neverhood {
+
+// TODO: Maybe move hash tables into neverhood.dat
+
+static const uint32 kDiskplayerPaletteFileHashes[] = {
+ 0x03B78240,
+ 0x34B32B08,
+ 0x4F2569D4,
+ 0x07620590,
+ 0x38422401
+};
+
+static const byte kDiskplayerInitArray[] = {
+ 2, 1, 4, 5, 3, 11, 8, 6, 7, 9, 10, 17, 16, 18, 19, 20, 15, 14, 13, 12
+};
+
+static const uint32 kDiskplayerSmackerFileHashes[] = {
+ 0x010A2810,
+ 0x020A2810,
+ 0x040A2810,
+ 0x080A2810,
+ 0x100A2810,
+ 0x200A2810,
+ 0x400A2810,
+ 0x800A2810,
+ 0x000A2811,
+ 0x010C2810,
+ 0x020C2810,
+ 0x040C2810,
+ 0x080C2810,
+ 0x100C2810,
+ 0x200C2810,
+ 0x400C2810,
+ 0x800C2810,
+ 0x000C2811,
+ 0x000C2812,
+ 0x02002810,
+ 0x04002810
+};
+
+static const uint32 kDiskplayerSlotFileHashes1[] = {
+ 0x81312280,
+ 0x01312281,
+ 0x01312282,
+ 0x01312284,
+ 0x01312288,
+ 0x01312290,
+ 0x013122A0,
+ 0x013122C0,
+ 0x01312200,
+ 0x82312280,
+ 0x02312281,
+ 0x02312282,
+ 0x02312284,
+ 0x02312288,
+ 0x02312290,
+ 0x023122A0,
+ 0x023122C0,
+ 0x02312200,
+ 0x02312380,
+ 0x04312281
+};
+
+static const uint32 kDiskplayerSlotFileHashes2[] = {
+ 0x90443A00,
+ 0x90443A18,
+ 0x90443A28,
+ 0x90443A48,
+ 0x90443A88,
+ 0x90443B08,
+ 0x90443808,
+ 0x90443E08,
+ 0x90443208,
+ 0xA0443A00,
+ 0xA0443A18,
+ 0xA0443A28,
+ 0xA0443A48,
+ 0xA0443A88,
+ 0xA0443B08,
+ 0xA0443808,
+ 0xA0443E08,
+ 0xA0443208,
+ 0xA0442A08,
+ 0xC0443A18
+};
+
+static const uint32 kDiskplayerSlotFileHashes3[] = {
+ 0x10357320,
+ 0x10557320,
+ 0x10957320,
+ 0x11157320,
+ 0x12157320,
+ 0x14157320,
+ 0x18157320,
+ 0x00157320,
+ 0x30157320,
+ 0x1035B320,
+ 0x1055B320,
+ 0x1095B320,
+ 0x1115B320,
+ 0x1215B320,
+ 0x1415B320,
+ 0x1815B320,
+ 0x0015B320,
+ 0x3015B320,
+ 0x5015B320,
+ 0x10543320
+};
+
+static const uint32 kDiskplayerSlotFileHashes4[] = {
+ 0xDC8020E4,
+ 0xDC802164,
+ 0xDC802264,
+ 0xDC802464,
+ 0xDC802864,
+ 0xDC803064,
+ 0xDC800064,
+ 0xDC806064,
+ 0xDC80A064,
+ 0xDC8020E7,
+ 0xDC802167,
+ 0xDC802267,
+ 0xDC802467,
+ 0xDC802867,
+ 0xDC803067,
+ 0xDC800067,
+ 0xDC806067,
+ 0xDC80A067,
+ 0xDC812067,
+ 0xDC802161
+};
+
+Class494::Class494(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100) {
+
+ createSurface1(0x100B90B4, 1200);
+ _x = 211;
+ _y = 195;
+ setFileHash(0x100B90B4, 0, -1);
+ _newHashListIndex = 0;
+ _needRefresh = true;
+ updatePosition();
+ _surface->setVisible(false);
+}
+
+uint32 Class494::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void Class494::sub43BE00() {
+ stopAnimation();
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Sprite::handleMessage);
+ _surface->setVisible(false);
+}
+
+void Class494::sub43BE20() {
+ setFileHash(0x100B90B4, 0, -1);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class494::handleMessage);
+ NextState(&Class494::sub43BE00);
+ _surface->setVisible(true);
+}
+
+DiskplayerPlayButton::DiskplayerPlayButton(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene)
+ : StaticSprite(vm, 1400), _soundResource1(vm), _soundResource2(vm),
+ _diskplayerScene(diskplayerScene), _isPlaying(false) {
+
+ _spriteResource.load2(0x24A4A664);
+ createSurface(400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _deltaRect.x = 0;
+ _deltaRect.y = 0;
+ _deltaRect.width = _spriteResource.getDimensions().width;
+ _deltaRect.height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _surface->setVisible(false);
+ processDelta();
+ _needRefresh = true;
+ StaticSprite::update();
+ _soundResource1.load(0x44043000);
+ _soundResource2.load(0x44045000);
+ SetMessageHandler(&DiskplayerPlayButton::handleMessage);
+}
+
+uint32 DiskplayerPlayButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (!_diskplayerScene->getFlag3()) {
+ if (_isPlaying) {
+ sendMessage(_diskplayerScene, 0x2001, 0);
+ release();
+ } else {
+ sendMessage(_diskplayerScene, 0x2000, 0);
+ press();
+ }
+ }
+ StaticSprite::update();
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+void DiskplayerPlayButton::press() {
+ if (!_isPlaying) {
+ _surface->setVisible(true);
+ StaticSprite::update();
+ _soundResource1.play();
+ _isPlaying = true;
+ }
+}
+
+void DiskplayerPlayButton::release() {
+ if (_isPlaying) {
+ _surface->setVisible(false);
+ StaticSprite::update();
+ _soundResource2.play();
+ _isPlaying = false;
+ }
+}
+
+DiskplayerSlot::DiskplayerSlot(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene, int elementIndex, int value)
+ : Entity(vm, 0), _diskplayerScene(diskplayerScene), _soundResource(vm), _elementIndex(elementIndex),
+ _value(value), _flag2(false), _flag(false), _countdown(0), _initialCountdown(2),
+ _inactiveSlot(NULL), _appearSlot(NULL), _activeSlot(NULL) {
+
+ if (value != 0 && elementIndex < 20) {
+ _inactiveSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes1[_elementIndex], 1100));
+ _appearSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes2[_elementIndex], 1000));
+ _activeSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes3[_elementIndex], 1100));
+ _inactiveSlot->getSurface()->setVisible(false);
+ _appearSlot->getSurface()->setVisible(false);
+ _activeSlot->getSurface()->setVisible(false);
+ _soundResource.load(0x46210074);
+ // TODO sound panning stuff
+ } else if (elementIndex != 20) {
+ _activeSlot = _diskplayerScene->addSprite(new StaticSprite(_vm, kDiskplayerSlotFileHashes4[_elementIndex], 1100));
+ _activeSlot->getSurface()->setVisible(false);
+ }
+ SetUpdateHandler(&DiskplayerSlot::update);
+}
+
+void DiskplayerSlot::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ if (_flag) {
+ if (_inactiveSlot) {
+ _inactiveSlot->getSurface()->setVisible(true);
+ }
+ if (_activeSlot) {
+ _activeSlot->getSurface()->setVisible(false);
+ }
+ _countdown = _initialCountdown / 2;
+ } else {
+ if (_inactiveSlot) {
+ _inactiveSlot->getSurface()->setVisible(false);
+ }
+ if (_activeSlot) {
+ _activeSlot->getSurface()->setVisible(true);
+ }
+ _countdown = _initialCountdown;
+ }
+ _flag = !_flag;
+ }
+}
+
+void DiskplayerSlot::appear() {
+ if (_inactiveSlot) {
+ _inactiveSlot->getSurface()->setVisible(true);
+ }
+ if (_appearSlot) {
+ _appearSlot->getSurface()->setVisible(true);
+ }
+ if (_inactiveSlot) {
+ _soundResource.play();
+ }
+}
+
+void DiskplayerSlot::play() {
+ if (!_flag2) {
+ if (_inactiveSlot) {
+ _inactiveSlot->getSurface()->setVisible(false);
+ }
+ if (_activeSlot) {
+ _activeSlot->getSurface()->setVisible(true);
+ }
+ _flag = true;
+ _countdown = 0;
+ }
+}
+
+void DiskplayerSlot::activate() {
+ if (!_flag2) {
+ _countdown = _initialCountdown;
+ }
+}
+
+void DiskplayerSlot::stop() {
+ if (!_flag2) {
+ if (_inactiveSlot) {
+ _inactiveSlot->getSurface()->setVisible(true);
+ }
+ if (_activeSlot) {
+ _activeSlot->getSurface()->setVisible(false);
+ }
+ _flag = false;
+ _countdown = 0;
+ }
+}
+
+DiskplayerScene::DiskplayerScene(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _which(which), _diskIndex(0), _appearCountdown(0), _tuneInCountdown(0),
+ _fullFlag(false), _flag3(false), _inputDisabled(true), _updateStatus(0) {
+
+ int count = 0;
+
+ _surfaceFlag = true;
+
+ setBackground(0x8A000044);
+ setPalette(kDiskplayerPaletteFileHashes[_which]);
+ _playButton = new DiskplayerPlayButton(_vm, this);
+ addSprite(_playButton);
+ _vm->_collisionMan->addSprite(_playButton);
+ _class494 = new Class494(_vm);
+ addSprite(_class494);
+
+ // DEBUG: Give all disks
+ for (int i = 0; i < 19; i++) {
+ setSubVar(0x02720344, i, 1);
+ }
+
+ for (int i = 0; i < 20; i++) {
+ _diskAvailable[i] = 0;
+ if (getSubVar(0x02720344, i))
+ count++;
+ }
+
+ for (int i = 0; i < count; i++) {
+ _diskAvailable[kDiskplayerInitArray[i] - 1] = 1;
+ }
+
+ for (int i = 0; i < 20; i++) {
+ _diskSlots[i] = new DiskplayerSlot(_vm, this, i, _diskAvailable[i]);
+ addEntity(_diskSlots[i]);
+ }
+
+ _fullFlag = count == 20;
+
+ if (_fullFlag && !getGlobalVar(0xC0780812))
+ _flag3 = true;
+
+ _flag4 = _flag3;
+
+ _class650 = new DiskplayerSlot(_vm, this, 20, 0);
+ addEntity(_class650);
+
+ insertMouse435(0x000408A8, 20, 620);
+ showMouse(false);
+
+ _smackerPlayer = new SmackerPlayer(_vm, this, 0x08288103, false, true);
+ addEntity(_smackerPlayer);
+ addSurface(_smackerPlayer->getSurface());
+ _smackerPlayer->setDrawPos(154, 86);
+ // TODO _smackerPlayer->gotoFrame(0);
+
+ _palette->usePalette();
+
+ SetMessageHandler(&DiskplayerScene::handleMessage);
+ SetUpdateHandler(&DiskplayerScene::update);
+ _appearCountdown = 6;
+
+}
+
+void DiskplayerScene::update() {
+ Scene::update();
+
+ debug("_updateStatus = %d", _updateStatus);
+
+ if (_updateStatus == 1) {
+ if (_smackerPlayer->getFrameNumber() == _smackerPlayer->getFrameCount() - 1) {
+ if (_diskAvailable[_diskIndex]) {
+ playDisk();
+ } else {
+ playStatic();
+ }
+ }
+ } else if (_updateStatus == 2) {
+ if (_smackerPlayer->getFrameNumber() == _smackerPlayer->getFrameCount() - 1) {
+ _diskSlots[_diskIndex]->stop();
+ _diskIndex++;
+ if (_fullFlag) {
+ if (_diskIndex == 20) {
+ if (_flag3) {
+ playDisk();
+ _updateStatus = 3;
+ } else {
+ _diskIndex = 0;
+ stop();
+ }
+ } else {
+ playDisk();
+ }
+ } else {
+ if (_diskIndex == 20) {
+ _diskIndex = 0;
+ stop();
+ } else {
+ tuneIn();
+ }
+ }
+ }
+ } else if (_updateStatus == 3) {
+ if (_smackerPlayer->getFrameNumber() == 133) {
+ _class494->sub43BE20();
+ setGlobalVar(0xC0780812, 1);
+ } else if (_smackerPlayer->getFrameNumber() == _smackerPlayer->getFrameCount() - 1) {
+ for (int i = 0; i < 20; i++) {
+ _diskSlots[i]->setFlag2(false);
+ _diskSlots[i]->stop();
+ }
+ _diskIndex = 0;
+ stop();
+ showMouse(true);
+ _flag3 = false;
+ }
+ }
+
+ if (_appearCountdown != 0 && (--_appearCountdown == 0)) {
+ _diskSlots[_diskIndex]->appear();
+ if (_flag3) {
+ _diskSlots[_diskIndex]->activate();
+ _diskSlots[_diskIndex]->setFlag2(true);
+ }
+ _diskIndex++;
+ while (_diskAvailable[_diskIndex] == 0 && _diskIndex < 19)
+ _diskIndex++;
+ if (_diskIndex < 20) {
+ _appearCountdown = 1;
+ } else {
+ _diskIndex = 0;
+ _inputDisabled = false;
+ if (_flag3) {
+ _playButton->press();
+ _tuneInCountdown = 2;
+ } else {
+ showMouse(true);
+ _diskSlots[_diskIndex]->activate();
+ }
+ }
+ }
+
+ if (_tuneInCountdown != 0 && (--_tuneInCountdown == 0)) {
+ playDisk();
+ }
+
+}
+
+uint32 DiskplayerScene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ if (!_inputDisabled) {
+ switch (messageNum) {
+ case 0x0001:
+ // TODO: Debug/Cheat
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ sendMessage(_parentModule, 0x1009, 0);
+ } else if (!_flag3 &&
+ param.asPoint().x > 38 && param.asPoint().x < 598 &&
+ param.asPoint().y > 400 && param.asPoint().y < 460) {
+
+ _diskSlots[_diskIndex]->stop();
+ _diskIndex = (param.asPoint().x - 38) / 28;
+ _diskSlots[_diskIndex]->activate();
+ if (_updateStatus == 2) {
+ if (_diskAvailable[_diskIndex]) {
+ playDisk();
+ } else {
+ playStatic();
+ }
+ }
+ }
+ break;
+ // case 0x000D: TODO: Debug/Cheat
+ case 0x2000:
+ tuneIn();
+ break;
+ case 0x2001:
+ stop();
+ break;
+ }
+ }
+ return messageResult;
+}
+
+void DiskplayerScene::stop() {
+ _smackerPlayer->open(0x08288103, true);
+ _palette->usePalette();
+ _playButton->release();
+ _updateStatus = 0;
+ _diskSlots[_diskIndex]->activate();
+}
+
+void DiskplayerScene::tuneIn() {
+ _smackerPlayer->open(0x900001C1, false);
+ _palette->usePalette();
+ _playButton->release();
+ _updateStatus = 1;
+ _diskSlots[_diskIndex]->activate();
+}
+
+void DiskplayerScene::playDisk() {
+ _smackerPlayer->open(kDiskplayerSmackerFileHashes[_diskIndex], false);
+ _palette->usePalette();
+ _updateStatus = 2;
+ _diskSlots[_diskIndex]->play();
+}
+
+void DiskplayerScene::playStatic() {
+ _smackerPlayer->open(0x90000101, false);
+ _palette->usePalette();
+ _playButton->release();
+ _updateStatus = 2;
+ _diskSlots[_diskIndex]->activate();
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/diskplayerscene.h b/engines/neverhood/diskplayerscene.h
new file mode 100644
index 0000000000..7969a7a03b
--- /dev/null
+++ b/engines/neverhood/diskplayerscene.h
@@ -0,0 +1,110 @@
+/* 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_DISKPLAYERSCENE_H
+#define NEVERHOOD_DISKPLAYERSCENE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/resourceman.h"
+#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
+
+namespace Neverhood {
+
+class DiskplayerScene;
+
+class Class494 : public AnimatedSprite {
+public:
+ Class494(NeverhoodEngine *vm);
+ void sub43BE20();
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub43BE00();
+};
+
+class DiskplayerPlayButton : public StaticSprite {
+public:
+ DiskplayerPlayButton(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene);
+ void press();
+ void release();
+protected:
+ DiskplayerScene *_diskplayerScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ bool _isPlaying;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class DiskplayerSlot : public Entity {
+public:
+ DiskplayerSlot(NeverhoodEngine *vm, DiskplayerScene *diskplayerScene, int elementIndex, int value);
+ void activate();
+ void stop();
+ void appear();
+ void play();
+ void setFlag2(bool value) { _flag2 = value; }
+protected:
+ DiskplayerScene *_diskplayerScene;
+ SoundResource _soundResource;
+ Sprite *_inactiveSlot;
+ Sprite *_appearSlot;
+ Sprite *_activeSlot;
+ int _elementIndex;
+ int _initialCountdown;
+ int _countdown;
+ bool _flag2;
+ int _value;
+ bool _flag;
+ void update();
+};
+
+class DiskplayerScene : public Scene {
+public:
+ DiskplayerScene(NeverhoodEngine *vm, Module *parentModule, int which);
+ bool getFlag3() const { return _flag3; }
+protected:
+ SmackerPlayer *_smackerPlayer;
+ DiskplayerPlayButton *_playButton;
+ Class494 *_class494;
+ DiskplayerSlot *_diskSlots[20];
+ DiskplayerSlot *_class650;
+ int _updateStatus;
+ byte _diskAvailable[20];
+ bool _flag4;
+ int _which;
+ int _diskIndex;
+ int _appearCountdown;
+ int _tuneInCountdown;
+ bool _fullFlag;
+ bool _inputDisabled;
+ bool _flag3;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stop();
+ void tuneIn();
+ void playDisk();
+ void playStatic();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_DISKPLAYERSCENE_H */
diff --git a/engines/neverhood/entity.h b/engines/neverhood/entity.h
new file mode 100644
index 0000000000..9256c13ba8
--- /dev/null
+++ b/engines/neverhood/entity.h
@@ -0,0 +1,146 @@
+/* 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_ENTITY_H
+#define NEVERHOOD_ENTITY_H
+
+#include "common/str.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/gamevars.h"
+#include "neverhood/graphics.h"
+
+namespace Neverhood {
+
+class Entity;
+
+enum MessageParamType {
+ mptInteger,
+ mptPoint,
+ mptEntity
+};
+
+struct MessageParam {
+public:
+ MessageParam(uint32 value) : _type(mptInteger), _integer(value) {}
+ MessageParam(NPoint value) : _type(mptPoint), _point(value) {}
+ MessageParam(Entity *entity) : _type(mptEntity), _entity(entity) {}
+ uint32 asInteger() const {
+ assert(_type == mptInteger);
+ return _integer;
+ }
+ NPoint asPoint() const {
+ assert(_type == mptInteger || _type == mptPoint);
+ if (_type == mptInteger) {
+ NPoint pt;
+ pt.x = _integer & 0xFFFF;
+ pt.y = (_integer >> 16) & 0xFFFF;
+ return pt;
+ }
+ return _point;
+ }
+ Entity *asEntity() const {
+ assert(_type == mptEntity);
+ return _entity;
+ }
+protected:
+ union {
+ uint32 _integer;
+ NPoint _point;
+ Entity *_entity;
+ // TODO: Other types...
+ };
+ MessageParamType _type;
+ // TODO: Constructors for the param types...
+};
+
+// TODO: Disable heavy debug stuff in release mode
+
+#define SetUpdateHandler(handler) _updateHandlerCb = static_cast <void (Entity::*)(void)> (handler); debug(2, "SetUpdateHandler(" #handler ")"); _updateHandlerCbName = #handler
+#define SetMessageHandler(handler) _messageHandlerCb = static_cast <uint32 (Entity::*)(int messageNum, const MessageParam &param, Entity *sender)> (handler); debug(2, "SetMessageHandler(" #handler ")"); _messageHandlerCbName = #handler
+
+class Entity {
+public:
+ Common::String _name; // Entity name for debugging purposes
+ Common::String _updateHandlerCbName;
+ Common::String _messageHandlerCbName;
+ Entity(NeverhoodEngine *vm, int priority)
+ : _vm(vm), _updateHandlerCb(NULL), _messageHandlerCb(NULL), _priority(priority), _name("Entity") {
+ }
+ virtual ~Entity() {
+ }
+ virtual void draw() {
+ }
+ void handleUpdate() {
+ //debug("Entity(%s).handleUpdate", _name.c_str());
+ debug(2, "handleUpdate() -> [%s]", _updateHandlerCbName.c_str());
+ if (_updateHandlerCb)
+ (this->*_updateHandlerCb)();
+ }
+ bool hasMessageHandler() const { return _messageHandlerCb != NULL; }
+ uint32 receiveMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ debug(2, "receiveMessage(%04X) -> [%s]", messageNum, _messageHandlerCbName.c_str());
+ return _messageHandlerCb ? (this->*_messageHandlerCb)(messageNum, param, sender) : 0;
+ }
+ // NOTE: These were overloaded before for the various message parameter types
+ // it caused some problems so each type gets its own sendMessage variant now
+ uint32 sendMessage(Entity *receiver, int messageNum, const MessageParam &param) {
+ return receiver ? receiver->receiveMessage(messageNum, param, this) : 0;
+ }
+ uint32 sendMessage(Entity *receiver, int messageNum, uint32 param) {
+ return sendMessage(receiver, messageNum, MessageParam(param));
+ }
+ uint32 sendPointMessage(Entity *receiver, int messageNum, const NPoint &param) {
+ return sendMessage(receiver, messageNum, MessageParam(param));
+ }
+ uint32 sendEntityMessage(Entity *receiver, int messageNum, Entity *param) {
+ return sendMessage(receiver, messageNum, MessageParam((Entity*)param));
+ }
+ int getPriority() const { return _priority; }
+ // Shortcuts for game variable access
+ uint32 getGlobalVar(uint32 nameHash) {
+ return _vm->_gameVars->getGlobalVar(nameHash);
+ }
+ void setGlobalVar(uint32 nameHash, uint32 value) {
+ _vm->_gameVars->setGlobalVar(nameHash, value);
+ }
+ uint32 getSubVar(uint32 nameHash, uint32 subNameHash) {
+ return _vm->_gameVars->getSubVar(nameHash, subNameHash);
+ }
+ void setSubVar(uint32 nameHash, uint32 subNameHash, uint32 value) {
+ _vm->_gameVars->setSubVar(nameHash, subNameHash, value);
+ }
+ void incGlobalVar(uint32 nameHash, int incrValue) {
+ setGlobalVar(nameHash, getGlobalVar(nameHash) + incrValue);
+ }
+ void incSubVar(uint32 nameHash, uint32 subNameHash, int incrValue) {
+ setSubVar(nameHash, subNameHash, getSubVar(nameHash, subNameHash) + incrValue);
+ }
+protected:
+ void (Entity::*_updateHandlerCb)();
+ uint32 (Entity::*_messageHandlerCb)(int messageNum, const MessageParam &param, Entity *sender);
+ NeverhoodEngine *_vm;
+ int _priority;
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_ENTITY_H */
diff --git a/engines/neverhood/gamemodule.cpp b/engines/neverhood/gamemodule.cpp
new file mode 100644
index 0000000000..95fe521e23
--- /dev/null
+++ b/engines/neverhood/gamemodule.cpp
@@ -0,0 +1,509 @@
+/* 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/gamemodule.h"
+
+#include "neverhood/graphics.h"
+#include "neverhood/module1000.h"
+#include "neverhood/module1100.h"
+#include "neverhood/module1200.h"
+#include "neverhood/module1300.h"
+#include "neverhood/module1400.h"
+#include "neverhood/module1500.h"
+#include "neverhood/module1600.h"
+#include "neverhood/module1700.h"
+#include "neverhood/module1800.h"
+#include "neverhood/module1900.h"
+#include "neverhood/module2000.h"
+#include "neverhood/module2100.h"
+#include "neverhood/module2200.h"
+#include "neverhood/module2300.h"
+#include "neverhood/module2600.h"
+#include "neverhood/module2700.h"
+#include "neverhood/module3000.h"
+
+namespace Neverhood {
+
+GameModule::GameModule(NeverhoodEngine *vm)
+ : Module(vm, NULL), _moduleNum(-1) {
+
+ // Other initializations moved to actual engine class
+ // TODO
+ // TODO Sound1ChList_sub_407F70(0x2D0031, 0x8861079);
+ SetMessageHandler(&GameModule::handleMessage);
+}
+
+GameModule::~GameModule() {
+
+ // TODO Sound1ChList_sub_407AF0(0x2D0031);
+ delete _childObject;
+ _childObject = NULL;
+ // TODO: Set palette to black but probably not neccessary
+ // TODO Sound1ChList_sub_408480();
+ // TODO Set debug vars (maybe)
+}
+
+void GameModule::handleMouseMove(int16 x, int16 y) {
+ if (_childObject) {
+ NPoint mousePos;
+ mousePos.x = x;
+ mousePos.y = y;
+ debug(2, "GameModule::handleMouseMove(%d, %d)", x, y);
+ sendPointMessage(_childObject, 0, mousePos);
+ }
+}
+
+void GameModule::handleMouseDown(int16 x, int16 y) {
+ if (_childObject) {
+ NPoint mousePos;
+ mousePos.x = x;
+ mousePos.y = y;
+ debug(2, "GameModule::handleMouseDown(%d, %d)", x, y);
+ sendPointMessage(_childObject, 1, mousePos);
+ }
+}
+
+void GameModule::initScene1307Vars() {
+
+ // Exit if it's already initialized
+ 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
+
+ byte array44[3];
+ byte array3C[10];
+ byte array30[48];
+ uint32 index3 = 48;
+ uint32 index2 = 9;
+ uint32 index1 = 2;
+ uint32 rndIndex;
+
+ // Exit if it's already initialized
+ if (getSubVar(0x40050052, 0xC8606803))
+ return;
+
+ for (uint32 i = 0; i < 3; i++)
+ setSubVar(0x61084036, i, 1);
+
+ for (byte i = 0; i < 3; i++)
+ array44[i] = i;
+
+ for (byte i = 0; i < 10; i++)
+ array3C[i] = i;
+
+ for (byte i = 0; i < 48; i++)
+ array30[i] = i;
+
+ rndIndex = _vm->_rnd->getRandomNumber(3 - 1);
+
+ setSubVar(0x13100631, array44[rndIndex], 5);
+
+ for (byte i = 5; i < 9; i++)
+ array3C[i] = array3C[i + 1];
+
+ while (rndIndex < 2) {
+ array44[rndIndex] = array44[rndIndex + 1];
+ rndIndex++;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ uint32 rndIndex1 = _vm->_rnd->getRandomNumber(index2 - 1); // si
+ uint32 rndIndex2 = _vm->_rnd->getRandomNumber(index1 - 1); // di
+ setSubVar(0x13100631, array44[rndIndex2], array3C[rndIndex1]);
+ index2--;
+ while (rndIndex1 < index2) {
+ array3C[rndIndex1] = array3C[rndIndex1 + 1];
+ rndIndex1++;
+ }
+ index1--;
+ while (rndIndex2 < index1) {
+ array44[rndIndex2] = array44[rndIndex2 + 1];
+ rndIndex2++;
+ }
+ }
+
+ for (uint32 i = 0; i < 3; i++) {
+ uint32 rndValue = _vm->_rnd->getRandomNumber(4 - 1) * 2 + 2;
+ uint32 index4 = 0;
+ setSubVar(0x7500993A, i, rndValue);
+ while (index4 < rndValue) {
+ uint32 rndIndex3 = _vm->_rnd->getRandomNumber(index3 - 1);
+ setSubVar(0x0C65F80B, array30[rndIndex3], getSubVar(0x13100631, i));
+ index3--;
+ while (rndIndex3 < index3) {
+ array30[rndIndex3] = array30[rndIndex3 + 1];
+ rndIndex3++;
+ }
+ index4++;
+ }
+ }
+
+ uint32 index5 = 0;
+ while (index3 != 0) {
+ uint32 rndIndex4 = _vm->_rnd->getRandomNumber(index3 - 1);
+ index1 = array3C[index5];
+ setSubVar(0x0C65F80B, array30[rndIndex4], index1);
+ index3--;
+ while (rndIndex4 < index3) {
+ array30[rndIndex4] = array30[rndIndex4 + 1];
+ rndIndex4++;
+ }
+ uint32 rndIndex5 = _vm->_rnd->getRandomNumber(index3 - 1);
+ setSubVar(0x0C65F80B, array30[rndIndex5], index1);
+ index3--;
+ while (rndIndex5 < index3) {
+ array30[rndIndex5] = array30[rndIndex5 + 1];
+ rndIndex5++;
+ }
+ index5++;
+ if (index5 >= index2)
+ index5 = 0;
+
+ }
+
+ setSubVar(0x40050052, 0xC8606803, 1);
+
+}
+
+void GameModule::initScene3009Vars() {
+ if (!getSubVar(0x40050052, 0x8C9819C2)) {
+ for (int i = 0; i < 3; i++) {
+ setSubVar(0x00504B86, i, _vm->_rnd->getRandomNumber(12 - 1));
+ setSubVar(0x0A4C0A9A, i, _vm->_rnd->getRandomNumber(12 - 1));
+ }
+ setSubVar(0x40050052, 0x8C9819C2, 1);
+ }
+}
+
+uint32 GameModule::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Module::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0800:
+ _someFlag1 = true;
+ return messageResult;
+ case 0x1009:
+ _moduleResult = param.asInteger();
+ _done = true;
+ return messageResult;
+ case 0x100A:
+ // Unused resource preloading message
+ return messageResult;
+ case 0x101F:
+ _field2C = true;
+ return messageResult;
+ case 0x1023:
+ // Unused resource preloading message
+ return messageResult;
+ }
+ return messageResult;
+}
+
+void GameModule::startup() {
+ // TODO: Displaying of error text probably not needed in ScummVM
+// createModule(1500, 0); // Logos and intro video //Real
+#if 0
+ _vm->gameState().sceneNum = 0;
+ createModule(1200, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 0;
+ createModule(1800, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 0;
+ createModule(2000, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 4;
+ createModule(2200, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 0;
+ createModule(1000, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 1;
+ createModule(1000, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 8;
+ _vm->gameState().which = 1;
+ createModule(1600, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 6;
+ createModule(1900, -1);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 0;
+ createModule(2100, 3);
+#endif
+#if 0
+ _vm->gameState().sceneNum = 8;
+ createModule(2600, -1);
+#endif
+#if 1
+ _vm->gameState().which = 0;
+ _vm->gameState().sceneNum = 1;
+ createModule(2700, -1);
+#endif
+}
+
+void GameModule::createModule(int moduleNum, int which) {
+ debug("GameModule::createModule(%d, %d)", moduleNum, which);
+ _moduleNum = moduleNum;
+ switch (_moduleNum) {
+ case 1000:
+ setGlobalVar(0x91080831, 0x03294419);
+ _childObject = new Module1000(_vm, this, which);
+ break;
+ case 1100:
+ setGlobalVar(0x91080831, 0x0002C818);
+ _childObject = new Module1100(_vm, this, which);
+ break;
+ case 1200:
+ setGlobalVar(0x91080831, 0x00478311);
+ _childObject = new Module1200(_vm, this, which);
+ break;
+ case 1300:
+ setGlobalVar(0x91080831, 0x0061C090);
+ _childObject = new Module1300(_vm, this, which);
+ break;
+ case 1400:
+ setGlobalVar(0x91080831, 0x00AD0012);
+ _childObject = new Module1400(_vm, this, which);
+ break;
+ case 1500:
+ _someFlag1 = false;
+ setGlobalVar(0x91080831, 0x00F10114);
+ _childObject = new Module1500(_vm, this, which, true);
+ break;
+ case 1600:
+ setGlobalVar(0x91080831, 0x01A008D8);
+ _childObject = new Module1600(_vm, this, which);
+ break;
+ case 1700:
+ setGlobalVar(0x91080831, 0x04212331);
+ _childObject = new Module1700(_vm, this, which);
+ break;
+ case 1800:
+ setGlobalVar(0x91080831, 0x04A14718);
+ _childObject = new Module1800(_vm, this, which);
+ break;
+ case 1900:
+ setGlobalVar(0x91080831, 0x04E1C09C);
+ _childObject = new Module1900(_vm, this, which);
+ break;
+ case 2000:
+ setGlobalVar(0x91080831, 0x08250000);
+ _childObject = new Module2000(_vm, this, which);
+ break;
+ case 2100:
+ setGlobalVar(0x91080831, 0x10A10C14);
+ _childObject = new Module2100(_vm, this, which);
+ break;
+ case 2200:
+ setGlobalVar(0x91080831, 0x11391412);
+ _childObject = new Module2200(_vm, this, which);
+ break;
+ case 2300:
+ setGlobalVar(0x91080831, 0x1A214010);
+ _childObject = new Module2300(_vm, this, which);
+ break;
+ case 2600:
+ setGlobalVar(0x91080831, 0x40271018);
+ _childObject = new Module2600(_vm, this, which);
+ break;
+ case 2700:
+ setGlobalVar(0x91080831, 0x42212411);
+ _childObject = new Module2700(_vm, this, which);
+ break;
+ case 3000:
+ setGlobalVar(0x91080831, 0x81293110);
+ _childObject = new Module3000(_vm, this, which);
+ break;
+ default:
+ error("GameModule::createModule() Could not create module %d", moduleNum);
+ }
+ SetUpdateHandler(&GameModule::updateModule);
+ _childObject->handleUpdate();
+}
+
+void GameModule::updateModule() {
+ if (!updateChild()) {
+ switch (_moduleNum) {
+ case 1000:
+ createModule(2300, 0);
+ break;
+ case 1200:
+ if (_moduleResult == 1) {
+ createModule(2600, 0);
+ } else {
+ createModule(2300, 2);
+ }
+ break;
+ case 1100:
+ if (_moduleResult == 0) {
+ createModule(2900, 2);
+ } else {
+ setGlobalVar(0xD0A14D10, 1);
+ createModule(1300, 0);
+ }
+ break;
+ case 1300:
+ if (_moduleResult == 1) {
+ // TODO _gameState.clear();
+ // TODO GameModule_handleKeyEscape
+ } else {
+ createModule(2900, 0);
+ }
+ break;
+ case 1400:
+ if (_moduleResult == 1) {
+ error("WEIRD!");
+ } else {
+ createModule(1600, 1);
+ }
+ break;
+ case 1500:
+ createModule(1000, 0);
+ break;
+ case 1600:
+ if (_moduleResult == 1) {
+ createModule(1400, 0);
+ } else if (_moduleResult == 2) {
+ createModule(1700, 0);
+ } else {
+ createModule(2100, 0);
+ }
+ break;
+ case 1700:
+ if (_moduleResult == 1) {
+ createModule(2900, 3);
+ } else {
+ createModule(1600, 2);
+ }
+ break;
+ case 1800:
+ if (_moduleResult == 1) {
+ // TODO GameState_clear();
+ // TODO GameModule_handleKeyEscape();
+ } else if (_moduleResult == 2) {
+ createModule(2700, 0);
+ } else if (_moduleResult == 3) {
+ createModule(3000, 3);
+ } else {
+ createModule(2800, 0);
+ }
+ break;
+ case 1900:
+ createModule(3000, 1);
+ break;
+ case 2000:
+ createModule(2900, 4);
+ break;
+ case 2100:
+ if (_moduleResult == 1) {
+ createModule(2900, 1);
+ } else {
+ createModule(1600, 0);
+ }
+ break;
+ case 2200:
+ createModule(2300, 1);
+ break;
+ case 2300:
+ if (_moduleResult == 1) {
+ createModule(2200, 0);
+ } else if (_moduleResult == 2) {
+ createModule(1200, 0);
+ } else if (_moduleResult == 3) {
+ createModule(2400, 0);
+ } else if (_moduleResult == 4) {
+ createModule(3000, 0);
+ } else {
+ createModule(1000, 1);
+ }
+ break;
+ case 2600:
+ if (_moduleResult == 1) {
+ createModule(2500, 0);
+ } else {
+ createModule(1200, 1);
+ }
+ break;
+ case 2700:
+ createModule(1800, 2);
+ break;
+ case 3000:
+ if (_moduleResult == 1) {
+ createModule(1900, 0);
+ } else if (_moduleResult == 2) {
+ // WEIRD: Sets the errorFlag
+ } else if (_moduleResult == 3) {
+ createModule(1800, 3);
+ } else if (_moduleResult == 4) {
+ createModule(3000, 0);
+ } else {
+ createModule(2300, 4);
+ }
+ break;
+ }
+ }
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/gamemodule.h b/engines/neverhood/gamemodule.h
new file mode 100644
index 0000000000..6da7123125
--- /dev/null
+++ b/engines/neverhood/gamemodule.h
@@ -0,0 +1,56 @@
+/* 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.
+ *
+ */
+
+// TODO: I couldn't come up with a better name than 'Module' so far
+
+#ifndef NEVERHOOD_GAMEMODULE_H
+#define NEVERHOOD_GAMEMODULE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+
+namespace Neverhood {
+
+class GameModule : public Module {
+public:
+ GameModule(NeverhoodEngine *vm);
+ virtual ~GameModule();
+ void startup();
+ void handleMouseMove(int16 x, int16 y);
+ void handleMouseDown(int16 x, int16 y);
+ void initScene1307Vars();
+ void initScene1405Vars();
+ void initScene3009Vars();
+protected:
+ Entity *_prevChildObject;
+ bool _someFlag1;
+ bool _field2C;
+ uint32 _counter;
+ int _moduleNum;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createModule(int moduleNum, int which);
+ void updateModule();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE_H */
diff --git a/engines/neverhood/gamevars.cpp b/engines/neverhood/gamevars.cpp
new file mode 100644
index 0000000000..3e4e60438a
--- /dev/null
+++ b/engines/neverhood/gamevars.cpp
@@ -0,0 +1,114 @@
+/* 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/gamevars.h"
+
+namespace Neverhood {
+
+GameVars::GameVars() {
+ addVar(0, 0);
+}
+
+GameVars::~GameVars() {
+}
+
+uint32 GameVars::getGlobalVar(uint32 nameHash) {
+ //debug("GameVars::getGlobalVar(%08X)", nameHash);
+ int16 varIndex = findSubVarIndex(0, nameHash);
+ return varIndex != -1 ? _vars[varIndex].value : 0;
+}
+
+void GameVars::setGlobalVar(uint32 nameHash, uint32 value) {
+ //debug("GameVars::setGlobalVar(%08X, %d)", nameHash, value);
+ _vars[getSubVarIndex(0, nameHash)].value = value;
+}
+
+uint32 GameVars::getSubVar(uint32 nameHash, uint32 subNameHash) {
+ //debug("GameVars::getSubVar(%08X, %08X)", nameHash, subNameHash);
+ uint32 value = 0;
+ int16 varIndex = findSubVarIndex(0, nameHash);
+ if (varIndex != -1) {
+ int16 subVarIndex = findSubVarIndex(varIndex, subNameHash);
+ if (subVarIndex != -1) {
+ value = _vars[subVarIndex].value;
+ }
+ }
+ return value;
+}
+
+void GameVars::setSubVar(uint32 nameHash, uint32 subNameHash, uint32 value) {
+ //debug("GameVars::setSubVar(%08X, %08X, %d)", nameHash, subNameHash, value);
+ int16 varIndex = getSubVarIndex(0, nameHash);
+ //debug(" varIndex = %d", varIndex);
+ int16 subVarIndex = getSubVarIndex(varIndex, subNameHash);
+ //debug(" subVarIndex = %d", subVarIndex);
+ _vars[subVarIndex].value = value;
+ //_vars[getSubVarIndex(getSubVarIndex(0, nameHash), subNameHash)].value = value;
+}
+
+int16 GameVars::addVar(uint32 nameHash, uint32 value) {
+ //debug("GameVars::addVar(%08X, %d)", nameHash, value);
+ GameVar gameVar;
+ gameVar.nameHash = nameHash;
+ gameVar.value = value;
+ gameVar.firstIndex = -1;
+ gameVar.nextIndex = -1;
+ _vars.push_back(gameVar);
+ return _vars.size() - 1;
+}
+
+int16 GameVars::findSubVarIndex(int16 varIndex, uint32 subNameHash) {
+ //debug("GameVars::findSubVarIndex(%d, %08X)", varIndex, subNameHash);
+ for (int16 nextIndex = _vars[varIndex].firstIndex; nextIndex != -1; nextIndex = _vars[nextIndex].nextIndex) {
+ if (_vars[nextIndex].nameHash == subNameHash)
+ return nextIndex;
+ }
+ return -1;
+}
+
+int16 GameVars::addSubVar(int16 varIndex, uint32 subNameHash, uint32 value) {
+ //debug("GameVars::addSubVar(%d, %08X, %d)", varIndex, subNameHash, value);
+ int16 nextIndex = _vars[varIndex].firstIndex;
+ int16 subVarIndex;
+ if (nextIndex == -1) {
+ subVarIndex = addVar(subNameHash, value);
+ _vars[varIndex].firstIndex = subVarIndex;
+ } else {
+ while (_vars[nextIndex].nextIndex != -1)
+ nextIndex = _vars[nextIndex].nextIndex;
+ subVarIndex = addVar(subNameHash, value);
+ _vars[nextIndex].nextIndex = subVarIndex;
+ }
+ return subVarIndex;
+}
+
+int16 GameVars::getSubVarIndex(int16 varIndex, uint32 subNameHash) {
+ //debug("GameVars::getSubVarIndex(%d, %08X)", varIndex, subNameHash);
+ int16 subVarIndex = findSubVarIndex(varIndex, subNameHash);
+ if (subVarIndex == -1) {
+ subVarIndex = addSubVar(varIndex, subNameHash, 0);
+ debug("need to create: subVarIndex = %d", subVarIndex);
+ }
+ return subVarIndex;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/gamevars.h b/engines/neverhood/gamevars.h
new file mode 100644
index 0000000000..863aa1b2c1
--- /dev/null
+++ b/engines/neverhood/gamevars.h
@@ -0,0 +1,57 @@
+/* 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_GAMEVARS_H
+#define NEVERHOOD_GAMEVARS_H
+
+#include "common/array.h"
+#include "neverhood/neverhood.h"
+
+namespace Neverhood {
+
+struct GameVar {
+ uint32 nameHash;
+ uint32 value;
+ int16 firstIndex, nextIndex;
+};
+
+class GameVars {
+public:
+ GameVars();
+ ~GameVars();
+ // TODO void load(???);
+ // TODO void save(???);
+ uint32 getGlobalVar(uint32 nameHash);
+ void setGlobalVar(uint32 nameHash, uint32 value);
+ uint32 getSubVar(uint32 nameHash, uint32 subNameHash);
+ void setSubVar(uint32 nameHash, uint32 subNameHash, uint32 value);
+protected:
+ Common::Array<GameVar> _vars;
+ int16 addVar(uint32 nameHash, uint32 value);
+ int16 findSubVarIndex(int16 varIndex, uint32 subNameHash);
+ int16 addSubVar(int16 varIndex, uint32 subNameHash, uint32 value);
+ int16 getSubVarIndex(int16 varIndex, uint32 subNameHash);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_GAMEVARS_H */
diff --git a/engines/neverhood/graphics.cpp b/engines/neverhood/graphics.cpp
new file mode 100644
index 0000000000..5bb9424f57
--- /dev/null
+++ b/engines/neverhood/graphics.cpp
@@ -0,0 +1,321 @@
+/* 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/graphics.h"
+#include "neverhood/resource.h"
+#include "neverhood/screen.h"
+
+namespace Neverhood {
+
+BaseSurface::BaseSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height)
+ : _vm(vm), _priority(priority), _visible(true), _transparent(true) {
+
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = width;
+ _drawRect.height = height;
+ // TODO: Check if _sysRect is needed at all in the reimplementation...
+ _sysRect.x = 0;
+ _sysRect.y = 0;
+ _sysRect.width = (width + 3) & 0xFFFC; // align by 4 bytes
+ _sysRect.height = height;
+ _clipRect.x1 = 0;
+ _clipRect.y1 = 0;
+ _clipRect.x2 = 640;
+ _clipRect.y2 = 480;
+ _surface = new Graphics::Surface();
+ _surface->create(_sysRect.width, _sysRect.height, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+BaseSurface::~BaseSurface() {
+ delete _surface;
+}
+
+void BaseSurface::draw() {
+ if (_surface && _visible && _drawRect.width > 0 && _drawRect.height > 0) {
+ if (_sysRect.x == 0 && _sysRect.y == 0) {
+ _vm->_screen->drawSurface2(_surface, _drawRect, _clipRect, _transparent);
+ } else {
+ _vm->_screen->drawUnk(_surface, _drawRect, _sysRect, _clipRect, _transparent);
+ }
+ }
+}
+
+void BaseSurface::addDirtyRect() {
+ // TODO
+}
+
+void BaseSurface::clear() {
+ _surface->fillRect(Common::Rect(0, 0, _surface->w, _surface->h), 0);
+}
+
+void BaseSurface::drawSpriteResource(SpriteResource &spriteResource) {
+ if (spriteResource.getDimensions().width <= _drawRect.width &&
+ spriteResource.getDimensions().height <= _drawRect.height) {
+ clear();
+ spriteResource.draw((byte*)_surface->pixels, _surface->pitch, false, false);
+ }
+}
+
+void BaseSurface::drawSpriteResourceEx(SpriteResource &spriteResource, bool flipX, bool flipY, int16 width, int16 height) {
+ if (spriteResource.getDimensions().width <= _sysRect.width &&
+ spriteResource.getDimensions().height <= _sysRect.height) {
+ if (width > 0 && width <= _sysRect.width)
+ _drawRect.width = width;
+ if (height > 0 && height <= _sysRect.height)
+ _drawRect.height = height;
+ if (_surface) {
+ clear();
+ spriteResource.draw((byte*)_surface->pixels, _surface->pitch, flipX, flipY);
+ }
+ }
+}
+
+void BaseSurface::drawAnimResource(AnimResource &animResource, uint frameIndex, bool flipX, bool flipY, int16 width, int16 height) {
+ if (width > 0 && width <= _sysRect.width)
+ _drawRect.width = width;
+ if (height > 0 && height <= _sysRect.height)
+ _drawRect.height = height;
+ if (_surface) {
+ clear();
+ if (frameIndex < animResource.getFrameCount()) {
+ animResource.draw(frameIndex, (byte*)_surface->pixels, _surface->pitch, flipX, flipY);
+ }
+ }
+}
+
+void BaseSurface::drawMouseCursorResource(MouseCursorResource &mouseCursorResource, int frameNum) {
+ if (frameNum < 3) {
+ mouseCursorResource.draw(frameNum, (byte*)_surface->pixels, _surface->pitch);
+ }
+}
+
+void BaseSurface::copyFrom(Graphics::Surface *sourceSurface, int16 x, int16 y, NDrawRect &sourceRect, bool transparent) {
+ // TODO: Clipping
+ byte *source = (byte*)sourceSurface->getBasePtr(sourceRect.x, sourceRect.y);
+ byte *dest = (byte*)_surface->getBasePtr(x, y);
+ int height = sourceRect.height;
+ if (!transparent) {
+ while (height--) {
+ memcpy(dest, source, sourceRect.width);
+ source += sourceSurface->pitch;
+ dest += _surface->pitch;
+ }
+ } else {
+ while (height--) {
+ for (int xc = 0; xc < sourceRect.width; xc++)
+ if (source[xc] != 0)
+ dest[xc] = source[xc];
+ source += sourceSurface->pitch;
+ dest += _surface->pitch;
+ }
+ }
+}
+
+// FontSurface
+
+FontSurface::FontSurface(NeverhoodEngine *vm, NPointArray *tracking, uint16 numRows, byte firstChar, uint16 charWidth, uint16 charHeight)
+ : BaseSurface(vm, 0, charWidth * 16, charHeight * numRows), _tracking(tracking), _numRows(numRows), _firstChar(firstChar),
+ _charWidth(charWidth), _charHeight(charHeight) {
+}
+
+void FontSurface::drawChar(BaseSurface *destSurface, int16 x, int16 y, byte chr) {
+ NDrawRect sourceRect;
+ chr -= _firstChar;
+ sourceRect.x = (chr % 16) * _charWidth;
+ sourceRect.y = (chr / 16) * _charHeight;
+ sourceRect.width = _charWidth;
+ sourceRect.height = _charHeight;
+ destSurface->copyFrom(_surface, x, y, sourceRect, true);
+}
+
+void FontSurface::drawString(BaseSurface *destSurface, int16 x, int16 y, const byte *string) {
+ for (; *string != 0; string++) {
+ drawChar(destSurface, x, y, *string);
+ x += (*_tracking)[*string - _firstChar].x;
+ }
+}
+
+// Misc
+
+void parseBitmapResource(byte *sprite, bool *rle, NDimensions *dimensions, NPoint *position, byte **palette, byte **pixels) {
+
+ uint16 flags;
+
+ flags = READ_LE_UINT16(sprite);
+ sprite += 2;
+
+ if (rle)
+ *rle = flags & 1;
+
+ if (flags & 2) {
+ if (dimensions) {
+ dimensions->width = READ_LE_UINT16(sprite);
+ dimensions->height = READ_LE_UINT16(sprite + 2);
+ }
+ sprite += 4;
+ } else if (dimensions) {
+ dimensions->width = 1;
+ dimensions->height = 1;
+ }
+
+ if (flags & 4) {
+ if (position) {
+ position->x = READ_LE_UINT16(sprite);
+ position->y = READ_LE_UINT16(sprite + 2);
+ }
+ sprite += 4;
+ } else if (position) {
+ position->x = 0;
+ position->y = 0;
+ }
+
+ if (flags & 8) {
+ if (palette)
+ *palette = sprite;
+ sprite += 1024;
+ } else if (palette)
+ *palette = NULL;
+
+ if (flags & 0x10) {
+ if (pixels)
+ *pixels = sprite;
+ } else if (pixels)
+ *pixels = NULL;
+
+}
+
+void unpackSpriteRle(byte *source, int width, int height, byte *dest, int destPitch, bool flipX, bool flipY) {
+
+ // TODO: Flip Y
+
+ int16 rows, chunks;
+ int16 skip, copy;
+
+ rows = READ_LE_UINT16(source);
+ chunks = READ_LE_UINT16(source + 2);
+ source += 4;
+
+ do {
+ if (chunks == 0) {
+ dest += rows * destPitch;
+ } else {
+ while (rows-- > 0) {
+ uint16 rowChunks = chunks;
+ while (rowChunks-- > 0) {
+ skip = READ_LE_UINT16(source);
+ copy = READ_LE_UINT16(source + 2);
+ source += 4;
+ if (!flipX) {
+ memcpy(dest + skip, source, copy);
+ } else {
+ byte *flipDest = dest + width - skip - 1;
+ for (int xc = 0; xc < copy; xc++) {
+ *flipDest-- = source[xc];
+ }
+ }
+ source += copy;
+ }
+ dest += destPitch;
+ }
+ }
+ rows = READ_LE_UINT16(source);
+ chunks = READ_LE_UINT16(source + 2);
+ source += 4;
+ } while (rows > 0);
+
+}
+
+void unpackSpriteRleRepl(byte *source, int width, int height, byte *dest, int destPitch, byte oldColor, byte newColor, bool flipX, bool flipY) {
+
+ // TODO: Flip Y
+
+ int16 rows, chunks;
+ int16 skip, copy;
+
+ rows = READ_LE_UINT16(source);
+ chunks = READ_LE_UINT16(source + 2);
+ source += 4;
+
+ do {
+ if (chunks == 0) {
+ dest += rows * destPitch;
+ } else {
+ while (rows-- > 0) {
+ uint16 rowChunks = chunks;
+ while (rowChunks-- > 0) {
+ skip = READ_LE_UINT16(source);
+ copy = READ_LE_UINT16(source + 2);
+ source += 4;
+ if (!flipX) {
+ for (int xc = 0; xc < copy; xc++) {
+ dest[skip + xc] = source[xc] == oldColor ? newColor : source[xc];
+ }
+ } else {
+ byte *flipDest = dest + width - skip - 1;
+ for (int xc = 0; xc < copy; xc++) {
+ *flipDest-- = source[xc] == oldColor ? newColor : source[xc];
+ }
+ }
+ source += copy;
+ }
+ dest += destPitch;
+ }
+ }
+ rows = READ_LE_UINT16(source);
+ chunks = READ_LE_UINT16(source + 2);
+ source += 4;
+ } while (rows > 0);
+
+}
+
+void unpackSpriteNormal(byte *source, int width, int height, byte *dest, int destPitch, bool flipX, bool flipY) {
+
+ // TODO: Flip Y
+
+ int sourcePitch = (width + 3) & 0xFFFC;
+
+ if (!flipX) {
+ while (height-- > 0) {
+ memcpy(dest, source, width);
+ source += sourcePitch;
+ dest += destPitch;
+ }
+ } else {
+ while (height-- > 0) {
+ dest += width - 1;
+ for (int xc = 0; xc < width; xc++)
+ *dest-- = source[xc];
+ source += sourcePitch;
+ dest += destPitch;
+ }
+ }
+
+}
+
+int calcDistance(int16 x1, int16 y1, int16 x2, int16 y2) {
+ int16 deltaX = ABS(x1 - x2);
+ int16 deltaY = ABS(y1 - y2);
+ return sqrt((double)(deltaX * deltaX + deltaY * deltaY));
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/graphics.h b/engines/neverhood/graphics.h
new file mode 100644
index 0000000000..c2adb11913
--- /dev/null
+++ b/engines/neverhood/graphics.h
@@ -0,0 +1,134 @@
+/* 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_GRAPHICS_H
+#define NEVERHOOD_GRAPHICS_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "graphics/surface.h"
+#include "neverhood/neverhood.h"
+
+namespace Neverhood {
+
+struct NPoint {
+ int16 x, y;
+};
+
+typedef Common::Array<NPoint> NPointArray;
+
+struct NDimensions {
+ int16 width, height;
+};
+
+struct NRect {
+ int16 x1, y1, x2, y2;
+ NRect() : x1(0), y1(0), x2(0), y2(0) {}
+ NRect(int16 x01, int16 y01, int16 x02, int16 y02) : x1(x01), y1(y01), x2(x02), y2(y02) {}
+ void set(int16 x01, int16 y01, int16 x02, int16 y02) {
+ x1 = x01;
+ y1 = y01;
+ x2 = x02;
+ y2 = y02;
+ }
+};
+
+typedef Common::Array<NRect> NRectArray;
+
+// TODO: Use Common::Rect
+struct NDrawRect {
+ int16 x, y, width, height;
+ NDrawRect() : x(0), y(0), width(0), height(0) {}
+ NDrawRect(int16 x0, int16 y0, int16 width0, int16 height0) : x(x0), y(y0), width(width0), height(height0) {}
+ int16 x2() { return x + width; }
+ int16 y2() { return y + height; }
+ void set(int16 x0, int16 y0, int16 width0, int16 height0) {
+ x = x0;
+ y = y0;
+ width = width0;
+ height = height0;
+ }
+};
+
+class AnimResource;
+class SpriteResource;
+class MouseCursorResource;
+
+// NOTE: "Restore" methods aren't need in the reimplementation as they're DirectDraw-specific
+
+class BaseSurface {
+public:
+ BaseSurface(NeverhoodEngine *vm, int priority, int16 width, int16 height);
+ virtual ~BaseSurface();
+ virtual void draw();
+ virtual void addDirtyRect();
+ void clear();
+ void drawSpriteResource(SpriteResource &spriteResource);
+ void drawSpriteResourceEx(SpriteResource &spriteResource, bool flipX, bool flipY, int16 width, int16 height);
+ void drawAnimResource(AnimResource &animResource, uint frameIndex, bool flipX, bool flipY, int16 width, int16 height);
+ void drawMouseCursorResource(MouseCursorResource &mouseCursorResource, int frameNum);
+ void copyFrom(Graphics::Surface *sourceSurface, int16 x, int16 y, NDrawRect &sourceRect, bool transparent);
+ int getPriority() const { return _priority; }
+ void setPriority(int priority) { _priority = priority; }
+ NDrawRect& getDrawRect() { return _drawRect; }
+ NDrawRect& getSysRect() { return _sysRect; }
+ NRect& getClipRect() { return _clipRect; }
+ void setClipRect(NRect clipRect) { _clipRect = clipRect; }
+ bool getVisible() const { return _visible; }
+ void setVisible(bool value) { _visible = value; }
+ void setTransparent(bool value) { _transparent = value; }
+ Graphics::Surface *getSurface() { return _surface; }
+protected:
+ NeverhoodEngine *_vm;
+ int _priority;
+ bool _visible;
+ Graphics::Surface *_surface;
+ NDrawRect _drawRect;
+ NDrawRect _sysRect;
+ NRect _clipRect;
+ bool _transparent;
+};
+
+class FontSurface : public BaseSurface {
+public:
+ FontSurface(NeverhoodEngine *vm, NPointArray *tracking, uint16 numRows, byte firstChar, uint16 charWidth, uint16 charHeight);
+ void drawChar(BaseSurface *destSurface, int16 x, int16 y, byte chr);
+ void drawString(BaseSurface *destSurface, int16 x, int16 y, const byte *string);
+protected:
+ NPointArray *_tracking;
+ uint16 _numRows;
+ byte _firstChar;
+ uint16 _charWidth;
+ uint16 _charHeight;
+};
+
+// Misc
+
+void parseBitmapResource(byte *sprite, bool *rle, NDimensions *dimensions, NPoint *position, byte **palette, byte **pixels);
+void unpackSpriteRle(byte *source, int width, int height, byte *dest, int destPitch, bool flipX, bool flipY);
+void unpackSpriteRleRepl(byte *source, int width, int height, byte *dest, int destPitch, byte oldColor, byte newColor, bool flipX, bool flipY);
+void unpackSpriteNormal(byte *source, int width, int height, byte *dest, int destPitch, bool flipX, bool flipY);
+int calcDistance(int16 x1, int16 y1, int16 x2, int16 y2);
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_GRAPHICS_H */
diff --git a/engines/neverhood/klayman.cpp b/engines/neverhood/klayman.cpp
new file mode 100644
index 0000000000..567788b729
--- /dev/null
+++ b/engines/neverhood/klayman.cpp
@@ -0,0 +1,4921 @@
+/* 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/klayman.h"
+#include "neverhood/collisionman.h"
+#include "neverhood/resourceman.h"
+#include "neverhood/staticdata.h"
+
+namespace Neverhood {
+
+static const KlaymanTableItem klaymanTable1[] = {
+ {1, &Klayman::stDoIdlePickEar},
+ {1, &Klayman::sub41FDA0},
+ {1, &Klayman::sub41FDF0},
+ {1, &Klayman::stDoIdleChest},
+ {1, &Klayman::sub41FEB0}
+};
+
+static const KlaymanTableItem klaymanTable2[] = {
+ {1, &Klayman::stDoIdlePickEar},
+ {1, &Klayman::sub41FDA0},
+ {1, &Klayman::stDoIdleChest},
+ {1, &Klayman::sub41FEB0}
+};
+
+#if 0
+static const KlaymanTableItem klaymanTable3[] = {
+ {1, &Klayman::sub421430},
+ {1, &Klayman::sub421480}
+};
+#endif
+
+static const KlaymanTableItem klaymanTable4[] = {
+ {1, &Klayman::sub41FDA0},
+ {1, &Klayman::stDoIdleChest},
+ {1, &Klayman::sub41FEB0},
+};
+
+// Klayman
+
+Klayman::Klayman(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, int surfacePriority, int objectPriority, NRectArray *clipRects)
+ : AnimatedSprite(vm, objectPriority), _soundResource1(vm), _soundResource2(vm),
+ _counterMax(0), _counter(0), _flagE4(false), _counter3Max(0), _flagF8(false), _counter1(0),
+ _counter2(0), /*_field118(0), */_status2(0), _flagE5(true), _attachedSprite(NULL), _flagE1(false),
+ _status3(1), _parentScene(parentScene), _flagE2(false), _flagE3(false), _flagF6(false), _flagF7(false),
+ _flagFA(false), _statusE0(0), _field114(0), _resourceHandle(-1), _soundFlag(false) {
+
+ // TODO DirtySurface
+ createSurface(surfacePriority, 320, 200);
+ _x = x;
+ _y = y;
+ _x4 = x;
+ _y4 = y;
+ _flags = 2;
+ setKlaymanTable1();
+ stTryStandIdle();
+ SetUpdateHandler(&Klayman::update);
+}
+
+void Klayman::xUpdate() {
+ // Empty
+}
+
+uint32 Klayman::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4818:
+ sub41C930(_dataResource.getPoint(param.asInteger()).x, false);
+ break;
+ }
+ return 0;
+}
+
+void Klayman::update() {
+ AnimatedSprite::update();
+ xUpdate();
+}
+
+void Klayman::setKlaymanTable(const KlaymanTableItem *table, int tableCount) {
+ _table = table;
+ _tableCount = tableCount;
+ _tableMaxValue = 0;
+ for (int i = 0; i < tableCount; i++) {
+ _tableMaxValue += table[i].value;
+ }
+}
+
+void Klayman::setKlaymanTable1() {
+ setKlaymanTable(klaymanTable1, ARRAYSIZE(klaymanTable1));
+}
+
+void Klayman::setKlaymanTable2() {
+ setKlaymanTable(klaymanTable2, ARRAYSIZE(klaymanTable2));
+}
+
+void Klayman::setKlaymanTable3() {
+ // TODO setKlaymanTable(klaymanTable3, ARRAYSIZE(klaymanTable3));
+}
+
+void Klayman::stDoIdlePickEar() {
+ sub41D320(0x5B20C814, AnimationCallback(&Klayman::stIdlePickEar));
+}
+
+void Klayman::stIdlePickEar() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x5B20C814, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmIdlePickEar);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stStandAround);
+ FinalizeState(&Klayman::evIdlePickEarDone);
+}
+
+uint32 Klayman::hmIdlePickEar(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x04DBC02C) {
+ _soundResource1.play(0x44528AA1);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::evIdlePickEarDone() {
+ _soundResource1.stop();
+}
+
+void Klayman::sub41FDA0() {
+ sub41D320(0xD122C137, AnimationCallback(&Klayman::sub41FDB0));
+}
+
+void Klayman::sub41FDB0() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0xD122C137, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E980);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stStandAround);
+}
+
+uint32 Klayman::handleMessage41E980(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x808A0008) {
+ _soundResource1.play(0xD948A340);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub41FDF0() {
+ sub41D320(0x543CD054, AnimationCallback(&Klayman::sub41FE00));
+}
+
+void Klayman::sub41FE00() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x543CD054, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E9E0);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stStandAround);
+ FinalizeState(&Klayman::sub41FE50);
+}
+
+void Klayman::sub41FE50() {
+ _soundResource1.stop();
+}
+
+uint32 Klayman::handleMessage41E9E0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x5A0F0104) {
+ _soundResource1.play(0x7970A100);
+ } else if (param.asInteger() == 0x9A9A0109) {
+ _soundResource1.play(0xD170CF04);
+ } else if (param.asInteger() == 0x989A2169) {
+ _soundResource1.play(0xD073CF14);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stDoIdleChest() {
+ sub41D320(0x40A0C034, AnimationCallback(&Klayman::stIdleChest));
+}
+
+void Klayman::stIdleChest() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x40A0C034, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmIdleChest);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stStandAround);
+}
+
+uint32 Klayman::hmIdleChest(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x0D2A0288) {
+ _soundResource1.play(0xD192A368);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub41FEB0() {
+ sub41D320(0x5120E137, AnimationCallback(&Klayman::sub41FEC0));
+}
+
+void Klayman::sub41FEC0() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x5120E137, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EFE0);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stStandAround);
+}
+
+uint32 Klayman::handleMessage41EFE0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0xC006000C) {
+ _soundResource1.play(0x9D406340);
+ } else if (param.asInteger() == 0x2E4A2940) {
+ _soundResource1.play(0x53A4A1D4);
+ } else if (param.asInteger() == 0xAA0A0860) {
+ _soundResource1.play(0x5BE0A3C6);
+ } else if (param.asInteger() == 0xC0180260) {
+ _soundResource1.play(0x5D418366);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub421350() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x582EC138, 0, -1);
+ _counter = 0;
+ SetSpriteCallback(NULL);
+ SetUpdateHandler(&Klayman::update41D1C0);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ _counter3 = 0;
+ _counterMax = 8;
+ _counter3Max = _vm->_rnd->getRandomNumber(64 - 1) + 24;
+}
+
+void Klayman::update41D1C0() {
+ update();
+ _counter++;
+ if (_counter >= _counterMax) {
+ _counter = 0;
+ if (_table) {
+ int randomValue = _vm->_rnd->getRandomNumber(_tableMaxValue);
+ for (int i = 0; i < _tableCount; i++) {
+ if (randomValue < _table[_tableCount].value) {
+ (this->*(_table[_tableCount].callback))();
+ _counterMax = _vm->_rnd->getRandomNumber(128) + 24;
+ break;
+ }
+ randomValue -= _table[_tableCount].value;
+ }
+ }
+ } else {
+ _counter3++;
+ if (_counter3 >= _counter3Max) {
+ _counter3 = 0;
+ _counter3Max = _vm->_rnd->getRandomNumber(64) + 24;
+ stIdleSitBlink();
+ }
+ }
+}
+
+void Klayman::stIdleSitBlink() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x5C24C018, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stIdleSitBlinkSecond);
+}
+
+void Klayman::stIdleSitBlinkSecond() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x5C24C018, 0, -1);
+ SetUpdateHandler(&Klayman::update41D1C0);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stPickUpNeedle() {
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ if (!stStartAction(AnimationCallback(&Klayman::stPickUpNeedle))) {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x1449C169, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmPickUpGeneric);
+ SetSpriteCallback(NULL);
+ }
+}
+
+void Klayman::sub41FFF0() {
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ if (!stStartAction(AnimationCallback(&Klayman::sub41FFF0))) {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x0018C032, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D640);
+ SetSpriteCallback(NULL);
+ }
+}
+
+uint32 Klayman::handleMessage41D640(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0xC1380080) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x4806, 0);
+ _soundResource1.play(0xC8004340);
+ }
+ } else if (param.asInteger() == 0x02B20220) {
+ _soundResource1.play(0xC5408620);
+ } else if (param.asInteger() == 0x03020231) {
+ _soundResource1.play(0xD4C08010);
+ } else if (param.asInteger() == 0x67221A03) {
+ _soundResource1.play(0x44051000);
+ } else if (param.asInteger() == 0x925A0C1E) {
+ _soundResource1.play(0x40E5884D);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub4214D0() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xD229823D, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::sub421510() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x9A2801E0, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stStepOver() {
+ if (!stStartAction(AnimationCallback(&Klayman::stStepOver))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x004AA310, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EC70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ }
+}
+
+void Klayman::stSitInTeleporter() {
+ if (!stStartAction(AnimationCallback(&Klayman::stSitInTeleporter))) {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x392A0330, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EAB0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ }
+}
+
+uint32 Klayman::handleMessage41EAB0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x001A2832) {
+ _soundResource1.play(0xC0E4884C);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub421310() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x913AB120, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+}
+
+/////////////////////////////////////////////////////////////////
+
+void Klayman::sub41CE70() {
+ _x4 = _x;
+ if (!_flagE1 && !_flagE2 && !_flagE3) {
+ gotoState(NULL);
+ sub41C7B0();
+ }
+}
+
+void Klayman::sub41D320(uint32 fileHash, AnimationCb callback) {
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ if (_resourceHandle != -1) {
+ // TODO _vm->_res->moveToFront(_resourceHandle);
+ NextState(callback);
+ SetUpdateHandler(&Klayman::update41D2B0);
+ }
+}
+
+void Klayman::update41D2B0() {
+ // TODO Check if this odd stuff is needed or just some cache optimization
+ if (_vm->_res->isResourceDataValid(_resourceHandle)) {
+ sub41C7B0();
+ // TODO _vm->_res->moveToBack(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ } else {
+ // TODO _vm->_res->moveToFront(_resourceHandle);
+ }
+ update();
+}
+
+bool Klayman::stStartActionFromIdle(AnimationCb callback) {
+ if (_status2 == 2) {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x9A7020B8, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41F140);
+ SetSpriteCallback(NULL);
+ NextState(callback);
+ return true;
+ }
+ return false;
+}
+
+void Klayman::sub41C7B0() {
+ if (_finalizeStateCb) {
+ AnimationCb cb = _finalizeStateCb;
+ _finalizeStateCb = NULL;
+ (this->*cb)();
+ }
+ if (_nextStateCb) {
+ AnimationCb cb = _nextStateCb;
+ _nextStateCb = NULL;
+ (this->*cb)();
+#if 0 // TODO
+ } else if (_callbackList) {
+ removeCallbackList();
+#endif
+ } else {
+ sendMessage(_parentScene, 0x1006, 0);
+ }
+}
+
+void Klayman::sub41C770() {
+ _flagFA = false;
+ _status3 = 1;
+}
+
+void Klayman::sub41C790() {
+ if (_flagFA)
+ _status3 = 0;
+}
+
+void Klayman::stTryStandIdle() {
+ if (!stStartActionFromIdle(AnimationCallback(&Klayman::stTryStandIdle))) {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x5420E254, 0, -1);
+ _counter = 0;
+ _counter3 = 0;
+ _counter3Max = _vm->_rnd->getRandomNumber(64) + 24;
+ SetUpdateHandler(&Klayman::update41D0F0);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(NULL);
+ }
+}
+
+void Klayman::update41D0F0() {
+ update();
+ _counter++;
+ if (_counter >= 720) {
+ _counter = 0;
+ if (_table) {
+ int randomValue = _vm->_rnd->getRandomNumber(_tableMaxValue);
+ for (int i = 0; i < _tableCount; i++) {
+ if (randomValue < _table[_tableCount].value) {
+ (this->*(_table[_tableCount].callback))();
+ break;
+ }
+ randomValue -= _table[_tableCount].value;
+ }
+ }
+ } else {
+ _counter3++;
+ if (_counter3 >= _counter3Max) {
+ _counter3 = 0;
+ _counter3Max = _vm->_rnd->getRandomNumber(64) + 24;
+ stStand();
+ }
+ }
+}
+
+uint32 Klayman::handleMessage41D360(int messageNum, const MessageParam &param, Entity *sender) {
+ Sprite::handleMessage(messageNum, param, sender);
+ uint32 messageResult = xHandleMessage(messageNum, param);
+ switch (messageNum) {
+ case 0x1008:
+ messageResult = _flagE5;
+ break;
+ case 0x1014:
+ _attachedSprite = (Sprite*)(param.asEntity());
+ break;
+ case 0x1019:
+ sub41C7B0();
+ break;
+ case 0x101C:
+ sub41C770();
+ break;
+ case 0x1021:
+ sub41C790();
+ break;
+ case 0x481C:
+ _status3 = param.asInteger();
+ _flagFA = true;
+ messageResult = 1;
+ break;
+ case 0x482C:
+ if (param.asInteger() != 0) {
+ debug("#################################################");
+ // TODO _rectResource.getRectangle2(param.asInteger(), &_field118, &_field114,);
+ } else {
+ debug("#################################################");
+ // TODO _field114 = 0;
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stStand() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x5900C41E, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+ NextState(&Klayman::stStandAround);
+}
+
+uint32 Klayman::handleMessage41D480(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ sub41C7B0();
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stStandAround() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x5420E254, 0, -1);
+ SetUpdateHandler(&Klayman::update41D0F0);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(NULL);
+}
+
+uint32 Klayman::handleMessage41F140(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x271AA210) {
+ _soundResource1.play(0x4924AAC4);
+ } else if (param.asInteger() == 0x2B22AA81) {
+ _soundResource1.play(0x0A2AA8E0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+
+void Klayman::sub41C930(int16 x, bool flag) {
+ int16 xdiff = ABS(x - _x);
+ if (x == _x) {
+ _x4 = x;
+ if (!_flagE1 && !_flagE2 && !_flagE3) {
+ gotoState(NULL);
+ sub41C7B0();
+ }
+ } else if (xdiff <= 36 && !_flagE1 && !_flagE2 && !_flagE3) {
+ _x4 = x;
+ gotoState(NULL);
+ sub41C7B0();
+ } else if (xdiff <= 42 && _status3 != 3) {
+ if (_flagE2 && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0)) && ABS(_x4 - _x) > xdiff) {
+ _x4 = x;
+ } else {
+ _x4 = x;
+ GotoState(&Klayman::stSneak);
+ }
+ } else if (_flagE1 && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0))) {
+ _x4 = x;
+ } else if (flag) {
+ _x4 = x;
+ error("// TODO AnimatedSprite_GotoState(&Klayman::sub421550));");
+ // TODO AnimatedSprite_GotoState(&Klayman::sub421550);
+ } else {
+ _x4 = x;
+ GotoState(&Klayman::stStartWalking);
+ }
+}
+
+void Klayman::stWakeUp() {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x527AC970, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stSleeping() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x5A38C110, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmSleeping);
+ SetSpriteCallback(NULL);
+}
+
+uint32 Klayman::hmSleeping(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x03060012) {
+ _soundResource1.play(0xC0238244);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+bool Klayman::stStartAction(AnimationCb callback3) {
+ if (_status2 == 1) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x5C7080D4, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41F140);
+ SetSpriteCallback(&Klayman::spriteUpdate41F250);
+ NextState(callback3);
+ return true;
+ } else {
+ _x = _x4;
+ return false;
+ }
+}
+
+void Klayman::spriteUpdate41F250() {
+
+ int16 xdiff = _x4 - _x;
+
+ if (_doDeltaX) {
+ _x -= _deltaX;
+ } else {
+ _x += _deltaX;
+ }
+ _deltaX = 0;
+
+ if (_doDeltaY) {
+ _y -= _deltaY;
+ } else {
+ _y += _deltaY;
+ }
+ _deltaY = 0;
+
+ if (_flag) {
+ if (xdiff > 6)
+ _x += 6;
+ else if (xdiff < -6)
+ _x -= 6;
+ else
+ _x = _x4;
+ }
+
+ processDelta();
+
+}
+
+void Klayman::spriteUpdate41F5F0() {
+
+ int16 xdiff = _x4 - _x;
+
+ if (_frameIndex == 9) {
+ if (xdiff > 26)
+ _deltaX += xdiff - 26;
+ else if (xdiff < -26)
+ _deltaX -= xdiff + 26;
+ }
+
+ if (xdiff > _deltaX)
+ xdiff = _deltaX;
+ else if (xdiff < -_deltaX)
+ xdiff = -_deltaX;
+ _deltaX = 0;
+
+ if (_x4 != _x) {
+ HitRect *hitRectPrev = _vm->_collisionMan->findHitRectAtPos(_x, _y);
+ _x += xdiff;
+ if (_field114) {
+ error("// TODO Klayman_sub_41CF70");
+ // TODO Klayman_sub_41CF70
+ } else {
+ HitRect *hitRectNext = _vm->_collisionMan->findHitRectAtPos(_x, _y);
+ if (hitRectNext->type == 0x5002) {
+ _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (hitRectNext->rect.x2 - _x) / 2);
+ } else if (hitRectNext->type == 0x5003) {
+ _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (_x - hitRectNext->rect.x1) / 2);
+ } else if (hitRectPrev->type == 0x5002) {
+ if (xdiff > 0) {
+ _y = hitRectPrev->rect.y2;
+ } else {
+ _y = hitRectPrev->rect.y1;
+ }
+ } else if (hitRectPrev->type == 0x5003) {
+ if (xdiff < 0) {
+ _y = hitRectPrev->rect.y2;
+ } else {
+ _y = hitRectPrev->rect.y1;
+ }
+ }
+ }
+ processDelta();
+ }
+
+}
+
+void Klayman::stSneak() {
+ _status2 = 1;
+ _flagE2 = true;
+ _flagE5 = true;
+ setDoDeltaX(_x4 < _x ? 1 : 0);
+ setFileHash(0x5C48C506, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41DD80);
+ SetSpriteCallback(&Klayman::spriteUpdate41F5F0);
+ FinalizeState(&Klayman::stSneakDone);
+}
+
+void Klayman::stSneakDone() {
+ _flagE2 = false;
+}
+
+uint32 Klayman::handleMessage41DD80(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x4924AAC4);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0A2AA8E0);
+ } else if (param.asInteger() == 0x32188010) {
+ if (_soundFlag) {
+ _soundResource1.play(0x48498E46);
+ } else {
+ _soundResource1.play(0x405002D8);
+ }
+ } else if (param.asInteger() == 0x02A2909C) {
+ if (_soundFlag) {
+ _soundResource1.play(0x50399F64);
+ } else {
+ _soundResource1.play(0x0460E2FA);
+ }
+ }
+ break;
+ case 0x3002:
+ _x = _x4;
+ sub41C7B0();
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub41CD70(int16 x) {
+ if (x > _x) {
+ if (ABS(x - _x) <= 105) {
+ sub41CAC0(x);
+ } else {
+ sub41C930(x, false);
+ }
+ } else if (x == _x) {
+ _x4 = x;
+ gotoState(NULL);
+ sub41C7B0();
+ } else {
+ sub41C930(x, false);
+ }
+}
+
+void Klayman::stStartWalking() {
+ if (!stStartActionFromIdle(AnimationCallback(&Klayman::stStartWalking))) {
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setDoDeltaX(_x4 < _x ? 1 : 0);
+ setFileHash(0x242C0198, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EC70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F320);
+ FinalizeState(&Klayman::stStartWalkingDone);
+ NextState(&Klayman::stWalking);
+ }
+}
+
+void Klayman::stStartWalkingDone() {
+ _flagE1 = false;
+}
+
+uint32 Klayman::handleMessage41EC70(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x32180101) {
+ if (_soundFlag) {
+ _soundResource1.play(0x48498E46);
+ } else {
+ _soundResource1.play(0x405002D8);
+ }
+ } else if (param.asInteger() == 0x0A2A9098) {
+ if (_soundFlag) {
+ _soundResource1.play(0x50399F64);
+ } else {
+ _soundResource1.play(0x0460E2FA);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stWalking() {
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setFileHash(0x1A249001, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EB70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F300);
+ FinalizeState(&Klayman::stStartWalkingDone);
+ NextState(&Klayman::sub41FA40);
+}
+
+void Klayman::spriteUpdate41F300() {
+ SetSpriteCallback(&Klayman::spriteUpdate41F320);
+ _deltaX = 0;
+}
+
+uint32 Klayman::handleMessage41EB70(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x32180101) {
+ if (_soundFlag) {
+ _soundResource1.play(0x48498E46);
+ } else {
+ _soundResource1.play(0x405002D8);
+ }
+ } else if (param.asInteger() == 0x0A2A9098) {
+ if (_soundFlag) {
+ _soundResource1.play(0x50399F64);
+ } else {
+ _soundResource1.play(0x0460E2FA);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub41FA40() {
+ if (_status3 == 2) {
+ sub41C7B0();
+ } else if (_status3 == 3) {
+ sub420F20();
+ } else {
+ _flagE2 = true;
+ _flagE5 = true;
+ if (ABS(_x4 - _x) <= 42 && _frameIndex >= 5 && _frameIndex <= 11) {
+ if (_status3 == 0) {
+ _status2 = 1;
+ setFileHash(0xF234EE31, 0, -1);
+ } else {
+ _status2 = 2;
+ setFileHash(0xF135CC21, 0, -1);
+ }
+ } else if (ABS(_x4 - _x) <= 10 && (_frameIndex >= 12 || _frameIndex <= 4)) {
+ if (_status3 == 0) {
+ _status2 = 1;
+ setFileHash(0x8604A152, 0, -1);
+ } else {
+ _status2 = 2;
+ setFileHash(0xA246A132, 0, -1);
+ }
+ }
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41DD80);
+ SetSpriteCallback(&Klayman::spriteUpdate41F5F0);
+ FinalizeState(&Klayman::stSneakDone);
+ }
+}
+
+void Klayman::spriteUpdate41F320() {
+ int16 xdiff = ABS(_x4 - _x);
+ int16 xdelta = _x4 - _x;
+
+ if (xdelta > _deltaX)
+ xdelta = _deltaX;
+ else if (xdelta < -_deltaX)
+ xdelta = -_deltaX;
+
+ _deltaX = 0;
+
+ if (xdiff == 0) {
+ sendMessage(this, 0x1019, 0);
+ } else if (_status3 != 2 && _status3 != 3 && xdiff <= 42 && _frameIndex >= 5 && _frameIndex <= 11) {
+ sendMessage(this, 0x1019, 0);
+ } else if (_status3 != 2 && _status3 != 3 && xdiff <= 10 && (_frameIndex >= 12 || _frameIndex <= 4)) {
+ sendMessage(this, 0x1019, 0);
+ } else if (_status3 == 3 && xdiff < 30) {
+ sendMessage(this, 0x1019, 0);
+ } else if (_status3 == 3 && xdiff < 150 && _frameIndex >= 6) {
+ sendMessage(this, 0x1019, 0);
+ } else {
+ HitRect *hitRectPrev = _vm->_collisionMan->findHitRectAtPos(_x, _y);
+ _x += xdelta;
+ if (_field114) {
+ error("_field114");
+ // TODO Klayman_sub_41CF70
+ } else {
+ HitRect *hitRectNext = _vm->_collisionMan->findHitRectAtPos(_x, _y);
+ if (hitRectNext->type == 0x5002) {
+ _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (hitRectNext->rect.x2 - _x) / 2);
+ } else if (hitRectNext->type == 0x5003) {
+ _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (_x - hitRectNext->rect.x1) / 2);
+ } else if (hitRectPrev->type == 0x5002) {
+ if (xdelta > 0) {
+ _y = hitRectPrev->rect.y2;
+ } else {
+ _y = hitRectPrev->rect.y1;
+ }
+ } else if (hitRectPrev->type == 0x5003) {
+ if (xdelta < 0) {
+ _y = hitRectPrev->rect.y2;
+ } else {
+ _y = hitRectPrev->rect.y1;
+ }
+ } else if (_flagF6 && xdelta != 0) {
+ if (hitRectNext->type == 0x5000) {
+ _y++;
+ } else if (hitRectNext->type == 0x5001 && _y > hitRectNext->rect.y1) {
+ _y--;
+ }
+ }
+ }
+ processDelta();
+ }
+
+}
+
+uint32 Klayman::handleMessage41E210(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_attachedSprite, 0x482A, 0);
+ } else if (param.asInteger() == 0x88001184) {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stPickUpGeneric() {
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ if (!stStartAction(AnimationCallback(&Klayman::stPickUpGeneric))) {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x1C28C178, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmPickUpGeneric);
+ SetSpriteCallback(NULL);
+ }
+}
+
+uint32 Klayman::hmPickUpGeneric(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0xC1380080) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x4806, 0);
+ }
+ _soundResource1.play(0x40208200);
+ } else if (param.asInteger() == 0x02B20220) {
+ _soundResource1.play(0xC5408620);
+ } else if (param.asInteger() == 0x03020231) {
+ _soundResource1.play(0xD4C08010);
+ } else if (param.asInteger() == 0x67221A03) {
+ _soundResource1.play(0x44051000);
+ } else if (param.asInteger() == 0x2EAE0303) {
+ _soundResource1.play(0x03630300);
+ } else if (param.asInteger() == 0x61CE4467) {
+ _soundResource1.play(0x03630300);
+ }
+ break;
+ }
+ return messageResult;
+
+}
+
+void Klayman::stTurnPressButton() {
+ if (!stStartAction(AnimationCallback(&Klayman::stTurnPressButton))) {
+ _status2 = 2;
+ _flagE5 = true;
+ setFileHash(0x1C02B03D, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmPressButton);
+ SetSpriteCallback(NULL);
+ }
+}
+
+uint32 Klayman::hmPressButton(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x0D01B294) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x480B, 0);
+ }
+ } else if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x4924AAC4);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0A2AA8E0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stStampFloorButton() {
+ if (!stStartAction(AnimationCallback(&Klayman::stStampFloorButton))) {
+ _status2 = 2;
+ _flagE5 = true;
+ setFileHash(0x1C16B033, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmPressButton);
+ SetSpriteCallback(NULL);
+ }
+}
+
+void Klayman::stPressButtonSide() {
+ if (!stStartActionFromIdle(AnimationCallback(&Klayman::stPressButtonSide))) {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x1CD89029, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmPressButton);
+ SetSpriteCallback(&Klayman::spriteUpdate41F250);
+ }
+}
+
+void Klayman::sub41CD00(int16 x) {
+ if (_x > x) {
+ if (_x - x <= 105) {
+ sub41CAC0(x);
+ } else {
+ sub41C930(x, false);
+ }
+ } else if (_x < x) {
+ sub41C930(x, false);
+ } else {
+ _x4 = x;
+ gotoState(NULL);
+ sub41C7B0();
+ }
+}
+
+void Klayman::sub41CC40(int16 x1, int16 x2) {
+ if (_x > x1) {
+ if (_x == x1 + x2) {
+ _x4 = x1 + x2;
+ gotoState(NULL);
+ sub41C7B0();
+ } else if (_x < x1 + x2) {
+ sub41CAC0(x1 + x2);
+ } else {
+ sub41C930(x1 + x2, false);
+ }
+ } else {
+ if (_x == x1 - x2) {
+ _x4 = x1 - x2;
+ gotoState(NULL);
+ sub41C7B0();
+ } else if (_x > x1 - x2) {
+ sub41CAC0(x1 - x2);
+ } else {
+ sub41C930(x1 - x2, false);
+ }
+ }
+}
+
+void Klayman::sub41CAC0(int16 x) {
+ int16 xdiff = ABS(x - _x);
+ if (x == _x) {
+ _x4 = x;
+ if (!_flagE1 && !_flagE2 && !_flagE3) {
+ gotoState(NULL);
+ sub41C7B0();
+ }
+ } else if (xdiff <= 36 && !_flagE1 && !_flagE2 && !_flagE3) {
+ _x4 = x;
+ gotoState(NULL);
+ sub41C7B0();
+ } else if (xdiff <= 42 && _status3 != 3) {
+ if (_flagE2 && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0)) && ABS(_x4 - _x) > xdiff) {
+ _x4 = x;
+ } else {
+ _x4 = x;
+ GotoState(&Klayman::stSneak);
+ }
+ } else if (_flagE3 && ((!_doDeltaX && x - _x > 0) || (_doDeltaX && x - _x < 0))) {
+ _x4 = x;
+ } else {
+ _x4 = x;
+ GotoState(&Klayman::stLargeStep);
+ }
+}
+
+void Klayman::stLargeStep() {
+ _status2 = 2;
+ _flagE3 = true;
+ _flagE5 = true;
+ setDoDeltaX(_x4 >= _x ? 1 : 0);
+ setFileHash(0x08B28116, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmLargeStep);
+ SetSpriteCallback(&Klayman::suLargeStep);
+ FinalizeState(&Klayman::stLargeStepDone);
+}
+
+void Klayman::stLargeStepDone() {
+ _flagE3 = false;
+}
+
+void Klayman::suLargeStep() {
+ int16 xdiff = _x4 - _x;
+
+ if (_doDeltaX) {
+ _deltaX = -_deltaX;
+ }
+
+ if (_frameIndex == 7) {
+ _deltaX = xdiff;
+ }
+
+ if ((xdiff > 0 && xdiff > _deltaX) || (xdiff < 0 && xdiff < _deltaX))
+ xdiff = _deltaX;
+
+ _deltaX = 0;
+
+ if (_x != _x4) {
+ HitRect *hitRectPrev = _vm->_collisionMan->findHitRectAtPos(_x, _y);
+ _x += xdiff;
+ if (_field114) {
+ error("// TODO Klayman_sub_41CF70();");
+ // TODO Klayman_sub_41CF70();
+ } else {
+ HitRect *hitRectNext = _vm->_collisionMan->findHitRectAtPos(_x, _y);
+ if (hitRectNext->type == 0x5002) {
+ _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (hitRectNext->rect.x2 - _x) / 2);
+ } else if (hitRectNext->type == 0x5003) {
+ _y = MAX<int16>(hitRectNext->rect.y1, hitRectNext->rect.y2 - (_x - hitRectNext->rect.x1) / 2);
+ } else if (hitRectPrev->type == 0x5002) {
+ if (xdiff > 0) {
+ _y = hitRectPrev->rect.y2;
+ } else {
+ _y = hitRectPrev->rect.y1;
+ }
+ } else if (hitRectPrev->type == 0x5003) {
+ if (xdiff < 0) {
+ _y = hitRectPrev->rect.y2;
+ } else {
+ _y = hitRectPrev->rect.y1;
+ }
+ }
+ }
+ processDelta();
+ }
+}
+
+uint32 Klayman::hmLargeStep(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x4924AAC4);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0A2AA8E0);
+ }
+ break;
+ case 0x3002:
+ _x = _x4;
+ sub41C7B0();
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stWonderAboutHalf() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0xD820A114, 0, 10);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stWonderAboutAfter() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0xD820A114, 30, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stTurnToUseHalf() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x9B250AD2, 0, 7);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EEF0);
+ SetSpriteCallback(NULL);
+}
+
+uint32 Klayman::handleMessage41EEF0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x4924AAC4);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0A2AA8E0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::stTurnAwayFromUse() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x98F88391, 4, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EEF0);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stWonderAbout() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0xD820A114, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::stPeekWall() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0xAC20C012, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::hmPeekWall);
+ SetSpriteCallback(NULL);
+}
+
+uint32 Klayman::hmPeekWall(int messageNum, const MessageParam &param, Entity *sender) {
+ int16 speedUpFrameIndex;
+ switch (messageNum) {
+ case 0x1008:
+ speedUpFrameIndex = getFrameIndex(kKlaymanSpeedUpHash);
+ if (_frameIndex < speedUpFrameIndex)
+ setFileHash(0xAC20C012, speedUpFrameIndex, -1);
+ return 0;
+ case 0x100D:
+ if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x405002D8);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0460E2FA);
+ }
+ break;
+ }
+ return handleMessage41D480(messageNum, param, sender);
+}
+
+void Klayman::sub420210() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420210))) {
+ _status2 = 0;
+ setFileHash(0xD82890BA, 0, -1);
+ sub4201C0();
+ }
+}
+
+void Klayman::sub4201C0() {
+ _flagE5 = false;
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D790);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ NextState(&Klayman::sub420340);
+ sendMessage(_attachedSprite, 0x482B, 0);
+}
+
+uint32 Klayman::handleMessage41D790(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x168050A0) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x4806, 0);
+ }
+ _flagE5 = true;
+ } else if (param.asInteger() == 0x320AC306) {
+ _soundResource1.play(0x5860C640);
+ } else if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_attachedSprite, 0x482A, 0);
+ } else if (param.asInteger() == 0x88001184) {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::spriteUpdate41F230() {
+ AnimatedSprite::updateDeltaXY();
+ _x4 = _x;
+}
+
+void Klayman::sub420340() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x4829E0B8, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::sub420250() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420250))) {
+ _status2 = 0;
+ setFileHash(0x900980B2, 0, -1);
+ sub4201C0();
+ }
+}
+
+void Klayman::sub420290() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420290))) {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xBA1910B2, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41D880);
+ NextState(&Klayman::sub420380);
+ sendMessage(_attachedSprite, 0x482B, 0);
+ }
+}
+
+uint32 Klayman::handleMessage41D880(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x168050A0) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x4806, 0);
+ }
+ } else if (param.asInteger() == 0x320AC306) {
+ _soundResource1.play(0x5860C640);
+ } else if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_attachedSprite, 0x482A, 0);
+ } else if (param.asInteger() == 0x88001184) {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub420380() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0x4A293FB0, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41DAA0);
+ SetSpriteCallback(NULL);
+}
+
+uint32 Klayman::handleMessage41DAA0(int messageNum, const MessageParam &param, Entity *sender) {
+ if (messageNum == 0x1008) {
+ sub4203C0();
+ return 0;
+ }
+ return handleMessage41D360(messageNum, param, sender);
+}
+
+void Klayman::sub4203C0() {
+ _status2 = 1;
+ _flagE5 = false;
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x4807, 0);
+ _attachedSprite = NULL;
+ }
+ setFileHash(0xB869A4B9, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(NULL);
+}
+
+void Klayman::sub420300() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420300))) {
+ _status2 = 0;
+ setFileHash(0xB8699832, 0, -1);
+ sub4201C0();
+ }
+}
+
+void Klayman::sub41CCE0(int16 x) {
+ sub41CC40(_attachedSprite->getX(), x);
+}
+
+void Klayman::sub420970() {
+ _status2 = 0;
+ _flagE5 = true;
+ _statusE0 = 3;
+ setFileHash2(0x3A292504, 0x01084280, 0);
+ _fileHash4 = 0x01084280;
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(NULL);
+ sub41C7B0();
+}
+
+void Klayman::sub4209D0() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub4209D0))) {
+ _status2 = 0;
+ if (_y4 < _y) {
+ if (_statusE0 == 1) {
+ _statusE0 = 2;
+ sub420BC0();
+ } else {
+ sub41C7B0();
+ }
+ } else if (_statusE0 == 0) {
+ _statusE0 = 2;
+ _flagE5 = false;
+ setFileHash(0x122D1505, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E0D0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ } else if (_statusE0 == 3) {
+ _statusE0 = 2;
+ _flagE5 = false;
+ setFileHash2(0x122D1505, 0x01084280, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E0D0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ } else if (_statusE0 == 1) {
+ _statusE0 = 2;
+ _flagE5 = true;
+ setFileHash(0x122D1505, 29 - _frameIndex, -1);
+ }
+ }
+}
+
+void Klayman::sub420BC0() {
+ _status2 = 2;
+ if (_statusE0 == 1) {
+ _statusE0 = 0;
+ _flagE5 = false;
+ setFileHash2(0x3A292504, 0x02421405, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41DFD0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ } else if (_statusE0 == 1) {
+ _statusE0 = 0;
+ _flagE5 = false;
+ setFileHash2(0x122D1505, 0x02421405, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41DFD0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ } else {
+ sub41C7B0();
+ }
+}
+
+uint32 Klayman::handleMessage41DFD0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x489B025C) {
+ _soundResource1.play(0x52C4C2D7);
+ } else if (param.asInteger() == 0x400A0E64) {
+ _soundResource1.play(0x50E081D9);
+ } else if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x405002D8);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0460E2FA);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Klayman::handleMessage41E0D0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x01084280) {
+ _flagE5 = true;
+ } else if (param.asInteger() == 0x489B025C) {
+ _soundResource1.play(0x52C4C2D7);
+ } else if (param.asInteger() == 0x400A0E64) {
+ _soundResource1.play(0x50E081D9);
+ } else if (param.asInteger() == 0x02421405) {
+ if (_statusE0 == 1) {
+ setFileHash2(0x3A292504, 0x01084280, 0);
+ } else {
+ setFileHash2(0x122D1505, 0x01084280, 0);
+ }
+ if (_statusE0 == 1) {
+ if (_y4 >= _y - 30) {
+ sendMessage(this, 0x1019, 0);
+ }
+ } else {
+ if (_y4 <= _y) {
+ sendMessage(this, 0x1019, 0);
+ }
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub420AD0() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420AD0))) {
+ _status2 = 0;
+ if (_y4 >= _y - 30) {
+ sub41C7B0();
+ } else if (_statusE0 == 0) {
+ _statusE0 = 1;
+ _flagE5 = false;
+ setFileHash(0x3A292504, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E0D0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ } else if (_statusE0 == 3) {
+ _statusE0 = 1;
+ _flagE5 = true;
+ setFileHash2(0x3A292504, 0x01084280, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E0D0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ } else if (_statusE0 == 2) {
+ _statusE0 = 1;
+ _flagE5 = true;
+ setFileHash(0x3A292504, 29 - _frameIndex, -1);
+ }
+ }
+}
+
+void Klayman::sub421030() {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash2(0xF229C003, 0x14884392, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E490);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+}
+
+uint32 Klayman::handleMessage41E490(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x80C110B5) {
+ sendMessage(_parentScene, 0x482A, 0);
+ } else if (param.asInteger() == 0x110010D1) {
+ sendMessage(_parentScene, 0x482B, 0);
+ } else if (param.asInteger() == 0x32180101) {
+ if (_soundFlag) {
+ _soundResource1.play(0x48498E46);
+ } else {
+ _soundResource1.play(0x405002D8);
+ }
+ } else if (param.asInteger() == 0x0A2A9098) {
+ if (_soundFlag) {
+ _soundResource1.play(0x50399F64);
+ } else {
+ _soundResource1.play(0x0460E2FA);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub420FE0() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420FE0))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0xF229C003, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E490);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ }
+}
+
+void Klayman::sub4210C0() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub4210C0))) {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash2(0xCA221107, 0x8520108C, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E490);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ }
+}
+
+void Klayman::sub421070() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub421070))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0xCA221107, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E490);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ }
+}
+
+void Klayman::stLandOnFeet() {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x18118554, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E290);
+ SetSpriteCallback(NULL);
+}
+
+uint32 Klayman::handleMessage41E290(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x320AC306) {
+ _soundResource1.play(0x5860C640);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub420ED0() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420ED0))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x91540140, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41E2F0);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ }
+}
+
+uint32 Klayman::handleMessage41E2F0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0xC61A0119) {
+ _soundResource1.play(0x402338C2);
+ } else if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x4924AAC4);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0A2AA8E0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Klayman::sub420750() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420750))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x5CCCB330, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41DD20);
+ }
+}
+
+void Klayman::stTurnToUse() {
+ if (!stStartAction(AnimationCallback(&Klayman::stTurnToUse))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x9B250AD2, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41EEF0);
+ }
+}
+
+void Klayman::sub4207F0() {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x98F88391, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41EEF0);
+}
+
+void Klayman::sub420F20() {
+ _flagF8 = false;
+ _flagE5 = false;
+ setFileHash(0x11A8E012, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F5A0);
+ SetMessageHandler(&Klayman::handleMessage41EC70);
+}
+
+void Klayman::spriteUpdate41F5A0() {
+ if (!_flagF8 && ABS(_x4 - _x) < 80) {
+ sendMessage(_parentScene, 0x4829, 0);
+ _flagF8 = true;
+ }
+ AnimatedSprite::updateDeltaXY();
+}
+
+void Klayman::stMoveObjectSkipTurnFaceObject() {
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ _flagE4 = false;
+ _flagE5 = true;
+ setFileHash2(0x0C1CA072, 0x01084280, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41D970);
+}
+
+void Klayman::sub420660() {
+ sendMessage(_attachedSprite, 0x4807, 0);
+}
+
+uint32 Klayman::handleMessage41D970(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x01084280) {
+ if (_attachedSprite)
+ sendMessage(_attachedSprite, 0x480B, _doDeltaX ? 1 : 0);
+ } else if (param.asInteger() == 0x02421405) {
+ if (_flagE4 && sendMessage(_attachedSprite, 0x480C, _doDeltaX ? 1 : 0) != 0) {
+ stMoveObjectSkipTurn();
+ } else {
+ FinalizeState(&Klayman::sub420660);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ }
+ } else if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x405002D8);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0460E2FA);
+ }
+ break;
+ case 0x480A:
+ _flagE4 = true;
+ return 0;
+ }
+ return handleMessage41D480(messageNum, param, sender);
+}
+
+void Klayman::stMoveObjectSkipTurn() {
+ _flagE4 = false;
+ _flagE5 = true;
+ setFileHash2(0x0C1CA072, 0x01084280, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41D970);
+}
+
+void Klayman::stMoveObjectFaceObject() {
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ if (!stStartAction(AnimationCallback(&Klayman::stMoveObjectFaceObject))) {
+ _status2 = 2;
+ _flagE4 = false;
+ _flagE5 = true;
+ setFileHash(0x0C1CA072, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41D970);
+ }
+}
+
+void Klayman::sub420C50() {
+ if (!stStartAction(AnimationCallback(&Klayman::sub420C50))) {
+ _status2 = 0;
+ if (_flagF7) {
+ stReleaseLeverUp();
+ } else {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ setFileHash(0x0C303040, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41E210);
+ NextState(&Klayman::stPullLeverDown);
+ _flagE5 = false;
+ }
+ }
+}
+
+// Exactly the same code as sub420DA0 which was removed
+void Klayman::stPullLeverDown() {
+ setFileHash(0x0D318140, 0, -1);
+ sendMessage(_attachedSprite, 0x480F, 0);
+ NextState(&Klayman::stHoldLeverDown);
+}
+
+void Klayman::stHoldLeverDown() {
+ setFileHash(0x4464A440, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ _flagF7 = true;
+ _flagE5 = true;
+}
+
+void Klayman::stReleaseLeverUp() {
+ setFileHash(0x09018068, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41E210);
+ sendMessage(_attachedSprite, 0x4807, 0);
+ NextState(&Klayman::stPullLeverDown);
+ _flagE5 = false;
+}
+
+void Klayman::sub420E20() {
+ if (_flagF7) {
+ _status2 = 2;
+ setFileHash(0x09018068, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41E210);
+ sendMessage(_attachedSprite, 0x4807, 0);
+ NextState(&Klayman::sub420E90);
+ _flagE5 = false;
+ _flagF7 = false;
+ } else {
+ sub41C7B0();
+ }
+}
+
+void Klayman::sub420E90() {
+ setFileHash(0x0928C048, 0, -1);
+ FinalizeState(&Klayman::sub420EB0);
+}
+
+void Klayman::sub420EB0() {
+ sendMessage(_attachedSprite, 0x482A, 0);
+}
+
+void Klayman::sub420680() {
+ if (!stStartActionFromIdle(AnimationCallback(&Klayman::sub420680))) {
+ _status2 = 2;
+ _counter2 = 0;
+ for (uint32 i = 0; i < 20; i++) {
+ if (getSubVar(0x02038314, i)) {
+ setSubVar(0x02720344, i, 1);
+ setSubVar(0x02038314, i, 0);
+ _counter2++;
+ }
+ }
+ if (_counter2 == 0) {
+ gotoState(NULL);
+ sub41C7B0();
+ } else {
+ setFileHash(0xD8C8D100, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F250);
+ SetMessageHandler(&Klayman::handleMessage41DB90);
+ _flagE5 = false;
+ _counter2--;
+ }
+ }
+}
+
+uint32 Klayman::handleMessage41DB90(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x06040580) {
+ if (_counter2 == 0) {
+ // TODO: Calc calcHash value somewhere else
+ setFileHash3(0xD8C8D100, calcHash("GoToStartLoop/Finish"), 0);
+ }
+ } else if (_counter2 != 0 && param.asInteger() == calcHash("GoToStartLoop/Finish")) {
+ _counter2--;
+ setFileHash2(0xD8C8D100, 0x01084280, 0);
+ } else if (param.asInteger() == 0x062A1510) {
+ _soundResource1.play(0x41688704);
+ } else if (param.asInteger() == 0x02B20220) {
+ _soundResource1.play(0xC5408620);
+ } else if (param.asInteger() == 0x0A720138) {
+ _soundResource1.play(0xD4C08010);
+ } else if (param.asInteger() == 0xB613A180) {
+ _soundResource1.play(0x44051000);
+ } else if (param.asInteger() == 0x0E040501) {
+ _soundResource1.play(0xC6A129C1);
+ }
+ }
+ return handleMessage41D480(messageNum, param, sender);
+}
+
+uint32 Klayman::handleMessage41DD20(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x040D4186) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x4808, 0);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+//##############################################################################
+
+// KmScene1001
+
+KmScene1001::KmScene1001(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+}
+
+uint32 KmScene1001::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ if (param.asInteger() == 2)
+ GotoState(&Klayman::stSleeping);
+ break;
+ case 0x480D:
+ GotoState(&KmScene1001::sub44FA50);
+ break;
+ case 0x4812:
+ GotoState(&Klayman::stPickUpGeneric);
+ 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());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ // TODO: It's not really a point but an x1/x2 pair
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481F:
+ if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x4836:
+ if (param.asInteger() == 1) {
+ sendMessage(_parentScene, 0x2002, 0);
+ GotoState(&Klayman::stWakeUp);
+ }
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void KmScene1001::sub44FA50() {
+ if (!stStartAction(AnimationCallback(&KmScene1001::sub44FA50))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x00648953, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1001::handleMessage44FA00);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ }
+}
+
+uint32 KmScene1001::handleMessage44FA00(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Klayman::handleMessage41E210(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_attachedSprite, 0x480F, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+// KmScene1002
+
+KmScene1002::KmScene1002(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, Sprite *class599, Sprite *ssLadderArch)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _otherSprite(NULL), _class599(class599), _ssLadderArch(ssLadderArch),
+ _status(0) {
+
+ setKlaymanTable1();
+
+}
+
+void KmScene1002::xUpdate() {
+ if (_x >= 250 && _x <= 435 && _y >= 420) {
+ if (_status == 0) {
+ // TODO setKlaymanTable(stru_4B44C8);
+ _status = 1;
+ }
+ } else if (_status == 1) {
+ setKlaymanTable1();
+ _status = 0;
+ }
+}
+
+uint32 KmScene1002::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x2001:
+ GotoState(&KmScene1002::sub449E90);
+ break;
+ case 0x2007:
+ _otherSprite = (Sprite*)param.asEntity();
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4803:
+ if (param.asInteger() == 1) {
+ GotoState(&KmScene1002::stJumpAndFall);
+ } else if (param.asInteger() == 2) {
+ GotoState(&KmScene1002::stDropFromRing);
+ }
+ break;
+ case 0x4804:
+ GotoState(&Klayman::stPeekWall);
+ break;
+ case 0x4805:
+ switch (param.asInteger()) {
+ case 1:
+ GotoState(&Klayman::sub420210);
+ break;
+ case 2:
+ GotoState(&Klayman::sub420250);
+ break;
+ case 3:
+ GotoState(&Klayman::sub420290);
+ break;
+ case 4:
+ GotoState(&Klayman::sub420300);
+ break;
+ }
+ break;
+ case 0x480A:
+ GotoState(&KmScene1002::stMoveVenusFlyTrap);
+ break;
+ case 0x480D:
+ GotoState(&KmScene1002::sub449E20);
+ break;
+ case 0x4816:
+ if (param.asInteger() == 0) {
+ GotoState(&KmScene1002::stPressDoorButton);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ sub41CCE0(param.asInteger());
+ break;
+ case 0x4820:
+ sendMessage(_parentScene, 0x2005, 0);
+ GotoState(&Klayman::sub420970);
+ break;
+ case 0x4821:
+ sendMessage(_parentScene, 0x2005, 0);
+ _y4 = param.asInteger();
+ GotoState(&Klayman::sub4209D0);
+ break;
+ case 0x4822:
+ sendMessage(_parentScene, 0x2005, 0);
+ _y4 = param.asInteger();
+ GotoState(&Klayman::sub420AD0);
+ break;
+ case 0x4823:
+ sendMessage(_parentScene, 0x2006, 0);
+ GotoState(&Klayman::sub420BC0);
+ break;
+ case 0x482E:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub421030);
+ } else {
+ GotoState(&Klayman::sub420FE0);
+ }
+ break;
+ case 0x482F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub4210C0);
+ } else {
+ GotoState(&Klayman::sub421070);
+ }
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void KmScene1002::update4497D0() {
+ Klayman::update();
+ if (_counter1 != 0 && (--_counter1 == 0)) {
+ _surface->setVisible(true);
+ SetUpdateHandler(&Klayman::update);
+ }
+}
+
+uint32 KmScene1002::handleMessage449800(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x168050A0) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x480F, 0);
+ }
+ } else if (param.asInteger() == 0x586B0300) {
+ if (_otherSprite) {
+ sendMessage(_otherSprite, 0x480E, 1);
+ }
+ } else if (param.asInteger() == 0x4AB28209) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x482A, 0);
+ }
+ } else if (param.asInteger() == 0x88001184) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene1002::handleMessage4498E0(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x4811:
+ _soundResource1.play(0x5252A0E4);
+ setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0);
+ if (_doDeltaX) {
+ _x = ((Sprite*)sender)->getX() - 75;
+ } else {
+ _x = ((Sprite*)sender)->getX() + 75;
+ }
+ _y = ((Sprite*)sender)->getY() - 200;
+ if (param.asInteger() == 0) {
+ sub449EF0();
+ } else if (param.asInteger() == 1) {
+ sub44A0D0();
+ } else if (param.asInteger() == 2) {
+ stSpitOutFall();
+ }
+ break;
+ }
+ return 0;
+}
+
+uint32 KmScene1002::hmPressDoorButton(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x942D2081) {
+ _flagE5 = false;
+ sendMessage(_attachedSprite, 0x2003, 0);
+ } else if (param.asInteger() == 0xDA600012) {
+ stHitByBoxingGlove();
+ } else if (param.asInteger() == 0x0D01B294) {
+ _flagE5 = false;
+ sendMessage(_attachedSprite, 0x480B, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene1002::hmMoveVenusFlyTrap(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x01084280) {
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x480B, (uint32)_doDeltaX);
+ }
+ } else if (param.asInteger() == 0x02421405) {
+ if (_flagE4) {
+ if (_attachedSprite) {
+ if (sendMessage(_attachedSprite, 0x480C, (uint32)_doDeltaX) != 0) {
+ stContinueMovingVenusFlyTrap();
+ }
+ }
+ } else {
+ SetMessageHandler(&KmScene1002::handleMessage449BA0);
+ }
+ } else if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_attachedSprite, 0x482A, 0);
+ } else if (param.asInteger() == 0x88001184) {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ } else if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x405002D8);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0460E2FA);
+ }
+ break;
+ case 0x480A:
+ _flagE4 = true;
+ return 0;
+ }
+ return handleMessage41D480(messageNum, param, sender);
+}
+
+uint32 KmScene1002::handleMessage449BA0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_attachedSprite, 0x482A, 0);
+ } else if (param.asInteger() == 0x88001184) {
+ sendMessage(_attachedSprite, 0x482B, 0);
+ } else if (param.asInteger() == 0x32180101) {
+ _soundResource1.play(0x405002D8);
+ } else if (param.asInteger() == 0x0A2A9098) {
+ _soundResource1.play(0x0460E2FA);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene1002::handleMessage449C90(int messageNum, const MessageParam &param, Entity *sender) {
+ int16 speedUpFrameIndex;
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1008:
+ speedUpFrameIndex = getFrameIndex(kKlaymanSpeedUpHash);
+ if (_frameIndex < speedUpFrameIndex) {
+ setFileHash(0x35AA8059, speedUpFrameIndex, -1);
+ _y = 435;
+ }
+ messageResult = 0;
+ break;
+ case 0x100D:
+ if (param.asInteger() == 0x1A1A0785) {
+ _soundResource1.play(0x40F0A342);
+ } else if (param.asInteger() == 0x60428026) {
+ _soundResource1.play(0x40608A59);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene1002::handleMessage449D60(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D360(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x1307050A) {
+ _soundResource1.play(0x40428A09);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1002::suFallDown() {
+ AnimatedSprite::updateDeltaXY();
+ HitRect *hitRect = _vm->_collisionMan->findHitRectAtPos(_x, _y + 10);
+ if (hitRect->type == 0x5001) {
+ _y = hitRect->rect.y1;
+ processDelta();
+ sendMessage(this, 0x1019, 0);
+ }
+ _vm->_collisionMan->checkCollision(this, 0xFFFF, 0x4810, 0);
+}
+
+void KmScene1002::sub449E20() {
+ if (!stStartAction(AnimationCallback(&KmScene1002::sub449E20))) {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x584984B4, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ SetMessageHandler(&KmScene1002::handleMessage449800);
+ NextState(&Klayman::stLandOnFeet);
+ sendMessage(_attachedSprite, 0x482B, 0);
+ }
+}
+
+void KmScene1002::sub449E90() {
+ _soundResource1.play(0x56548280);
+ _status2 = 0;
+ _flagE5 = false;
+ _surface->setVisible(false);
+ setFileHash(0x5420E254, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1002::handleMessage4498E0);
+}
+
+void KmScene1002::sub449EF0() {
+ _counter1 = 1;
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x000BAB02, 0, -1);
+ SetUpdateHandler(&KmScene1002::update4497D0);
+ // Weird stuff happening
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ //SetMessageHandler(&Klayman::handleMessage41D480);
+ SetSpriteCallback(&KmScene1002::suFallDown);
+ NextState(&KmScene1002::sub449F70);
+ sendMessage(_class599, 0x482A, 0);
+ sendMessage(_ssLadderArch, 0x482A, 0);
+}
+
+void KmScene1002::sub449F70() {
+ sendMessage(_parentScene, 0x1024, 1);
+ _soundResource1.play(0x41648271);
+ _status2 = 1;
+ _flagE5 = false;
+ _flagE1 = false;
+ setFileHash2(0x000BAB02, 0x88003000, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1002::handleMessage41D480);
+ NextState(&KmScene1002::sub44A230);
+ sendMessage(_parentScene, 0x2002, 0);
+ // TODO _callbackList = NULL;
+ _attachedSprite = NULL;
+ sendMessage(_class599, 0x482B, 0);
+ sendMessage(_ssLadderArch, 0x482B, 0);
+}
+
+void KmScene1002::stSpitOutFall() {
+ _counter1 = 1;
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x9308C132, 0, -1);
+ SetUpdateHandler(&KmScene1002::update4497D0);
+ SetSpriteCallback(&KmScene1002::suFallDown);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ NextState(&KmScene1002::sub449F70);
+ sendMessage(_class599, 0x482A, 0);
+ sendMessage(_ssLadderArch, 0x482A, 0);
+}
+
+void KmScene1002::sub44A0D0() {
+ _counter1 = 1;
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x0013A206, 0, -1);
+ SetUpdateHandler(&KmScene1002::update4497D0);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(&KmScene1002::suFallDown);
+ NextState(&KmScene1002::sub44A150);
+ sendMessage(_class599, 0x482A, 0);
+ sendMessage(_ssLadderArch, 0x482A, 0);
+}
+
+void KmScene1002::sub44A150() {
+ sendMessage(_parentScene, 0x1024, 1);
+ _soundResource1.play(0x41648271);
+ _status2 = 1;
+ _flagE5 = false;
+ _flagE1 = false;
+ setFileHash2(0x0013A206, 0x88003000, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::handleMessage41D480);
+ SetSpriteCallback(NULL);
+ NextState(&KmScene1002::sub44A230);
+ sendMessage(_parentScene, 0x2002, 0);
+ // TODO _callbackList = NULL;
+ _attachedSprite = NULL;
+ sendMessage(_class599, 0x482B, 0);
+ sendMessage(_ssLadderArch, 0x482B, 0);
+}
+
+void KmScene1002::sub44A230() {
+ setDoDeltaX(2);
+ stTryStandIdle();
+}
+
+void KmScene1002::stJumpAndFall() {
+ if (!stStartAction(AnimationCallback(&KmScene1002::stJumpAndFall))) {
+ sendMessage(_parentScene, 0x1024, 3);
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0xB93AB151, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::handleMessage449D60);
+ SetSpriteCallback(&KmScene1002::suFallDown);
+ NextState(&Klayman::stLandOnFeet);
+ }
+}
+
+void KmScene1002::stDropFromRing() {
+ if (_attachedSprite) {
+ _x = _attachedSprite->getX();
+ sendMessage(_attachedSprite, 0x4807, 0);
+ _attachedSprite = NULL;
+ }
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x586984B1, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::handleMessage41D360);
+ SetSpriteCallback(&KmScene1002::suFallDown);
+ NextState(&Klayman::stLandOnFeet);
+}
+
+void KmScene1002::stPressDoorButton() {
+ _status2 = 2;
+ _flagE5 = true;
+ setDoDeltaX(0);
+ setFileHash(0x1CD89029, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::hmPressDoorButton);
+ SetSpriteCallback(&Klayman::spriteUpdate41F250);
+}
+
+void KmScene1002::stHitByBoxingGlove() {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x35AA8059, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::handleMessage449C90);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ FinalizeState(&KmScene1002::stHitByBoxingGloveDone);
+}
+
+void KmScene1002::stHitByBoxingGloveDone() {
+ sendMessage(_parentScene, 0x1024, 1);
+}
+
+void KmScene1002::stMoveVenusFlyTrap() {
+ if (!stStartAction(AnimationCallback(&KmScene1002::stMoveVenusFlyTrap))) {
+ _status2 = 2;
+ _flagE4 = false;
+ _flagE5 = true;
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ setFileHash(0x5C01A870, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::hmMoveVenusFlyTrap);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ FinalizeState(&KmScene1002::stMoveVenusFlyTrapDone);
+ }
+}
+
+void KmScene1002::stContinueMovingVenusFlyTrap() {
+ _flagE4 = false;
+ _flagE5 = true;
+ setFileHash2(0x5C01A870, 0x01084280, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1002::hmMoveVenusFlyTrap);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ FinalizeState(&KmScene1002::stMoveVenusFlyTrapDone);
+}
+
+void KmScene1002::stMoveVenusFlyTrapDone() {
+ sendMessage(_attachedSprite, 0x482A, 0);
+}
+
+// KmScene1004
+
+KmScene1004::KmScene1004(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ _dataResource.load(0x01900A04);
+}
+
+uint32 KmScene1004::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x4818:
+ sub41C930(_dataResource.getPoint(param.asInteger()).x, false);
+ break;
+ case 0x481E:
+ GotoState(&KmScene1004::stReadNote);
+ break;
+ case 0x4820:
+ sendMessage(_parentScene, 0x2000, 0);
+ GotoState(&Klayman::sub420970);
+ break;
+ case 0x4821:
+ sendMessage(_parentScene, 0x2000, 0);
+ _y4 = param.asInteger();
+ GotoState(&Klayman::sub4209D0);
+ break;
+ case 0x4822:
+ sendMessage(_parentScene, 0x2000, 0);
+ _y4 = param.asInteger();
+ GotoState(&Klayman::sub420AD0);
+ break;
+ case 0x4823:
+ sendMessage(_parentScene, 0x2001, 0);
+ GotoState(&Klayman::sub420BC0);
+ break;
+ case 0x4824:
+ sendMessage(_parentScene, 0x2000, 0);
+ _y4 = _dataResource.getPoint(param.asInteger()).y;
+ GotoState(&Klayman::sub4209D0);
+ break;
+ case 0x4825:
+ sendMessage(_parentScene, 0x2000, 0);
+ _y4 = _dataResource.getPoint(param.asInteger()).y;
+ GotoState(&Klayman::sub420AD0);
+ break;
+ case 0x4828:
+ GotoState(&Klayman::sub420ED0);
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+uint32 KmScene1004::hmReadNote(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x04684052) {
+ _flagE5 = true;
+ sendMessage(_parentScene, 0x2002, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1004::stReadNote() {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash(0x123E9C9F, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&KmScene1004::hmReadNote);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+}
+
+KmScene1109::KmScene1109(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _flag1(false) {
+
+ // Empty
+}
+
+uint32 KmScene1109::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x2000:
+ _flag1 = param.asInteger() != 0;
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ if (_flag1)
+ GotoState(&Klayman::sub421350);
+ else
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&Klayman::stWalking);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481D:
+ if (_flag1)
+ GotoState(&Klayman::sub4214D0);
+ break;
+ case 0x481E:
+ if (_flag)
+ GotoState(&Klayman::sub421510);
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x4835:
+ sendMessage(_parentScene, 0x2000, 1);
+ _flag1 = true;
+ GotoState(&Klayman::stSitInTeleporter);
+ break;
+ case 0x4836:
+ sendMessage(_parentScene, 0x2000, 0);
+ _flag1 = false;
+ GotoState(&Klayman::sub421310);
+ break;
+ case 0x483D:
+ sub461F30();
+ break;
+ case 0x483E:
+ sub461F70();
+ break;
+ }
+ return 0;
+}
+
+uint32 KmScene1109::handleMessage461EA0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Klayman::handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4E0A2C24) {
+ _soundResource1.play(0x85B10BB8);
+ } else if (param.asInteger() == 0x4E6A0CA0) {
+ _soundResource1.play(0xC5B709B0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1109::sub461F30() {
+ _status2 = 0;
+ _flagE5 = false;
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1109::handleMessage461EA0);
+ setFileHash(0x2C2A4A1C, 0, -1);
+}
+
+void KmScene1109::sub461F70() {
+ _status2 = 0;
+ _flagE5 = false;
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1109::handleMessage461EA0);
+ setFileHash(0x3C2E4245, 0, -1);
+}
+
+// KmScene1201
+
+KmScene1201::KmScene1201(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, Entity *class464)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _class464(class464), _countdown(0) {
+
+ // TODO setKlaymanTable(dword_4AEF10, 3);
+ _flagF6 = true;
+
+}
+
+uint32 KmScene1201::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480A:
+ GotoState(&KmScene1201::sub40DF00);
+ break;
+ case 0x4812:
+ GotoState(&Klayman::stPickUpGeneric);
+ break;
+ case 0x4813:
+ GotoState(&KmScene1201::stFetchMatch);
+ break;
+ case 0x4814:
+ GotoState(&KmScene1201::stTumbleHeadless);
+ break;
+ case 0x4815:
+ GotoState(&KmScene1201::sub40E040);
+ break;
+ case 0x4816:
+ if (param.asInteger() == 0) {
+ GotoState(&Klayman::stPressButtonSide);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x481F:
+ GotoState(&Klayman::stWonderAbout);
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void KmScene1201::update40DBE0() {
+ if (_x >= 380)
+ sub41C7B0();
+ Klayman::update();
+}
+
+uint32 KmScene1201::hmMatch(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Klayman::handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x51281850) {
+ setGlobalVar(0x20A0C516, 1);
+ } else if (param.asInteger() == 0x43000538) {
+ _soundResource1.play(0x21043059);
+ } else if (param.asInteger() == 0x02B20220) {
+ _soundResource1.play(0xC5408620);
+ } else if (param.asInteger() == 0x0A720138) {
+ _soundResource1.play(0xD4C08010);
+ } else if (param.asInteger() == 0xB613A180) {
+ _soundResource1.play(0x44051000);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1201::stFetchMatch() {
+ if (!stStartAction(AnimationCallback(&KmScene1201::stFetchMatch))) {
+ _status2 = 0;
+ _flagE5 = false;
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ setFileHash(0x9CAA0218, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1201::hmMatch);
+ NextState(&KmScene1201::stLightMatch);
+ }
+}
+
+void KmScene1201::stLightMatch() {
+ _status2 = 1;
+ _flagE5 = false;
+ setDoDeltaX(_attachedSprite->getX() < _x ? 1 : 0);
+ setFileHash(0x1222A513, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1201::hmMatch);
+}
+
+uint32 KmScene1201::handleMessage40DDF0(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x01084280) {
+ _soundResource1.play(0x405002D8);
+ if (_attachedSprite) {
+ sendMessage(_attachedSprite, 0x480B, 0);
+ }
+ } else if (param.asInteger() == 0x02421405) {
+ if (_countdown != 0) {
+ _countdown--;
+ stMoveObjectSkipTurn();
+ } else {
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ }
+ }
+ break;
+ }
+ return Klayman::handleMessage41D480(messageNum, param, sender);
+}
+
+uint32 KmScene1201::hmTumbleHeadless(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Klayman::handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x000F0082) {
+ _soundResource1.play(0x74E2810F);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1201::sub40DF00() {
+ if (!stStartAction(AnimationCallback(&KmScene1201::sub40DF00))) {
+ _status2 = 2;
+ _flagE5 = false;
+ _countdown = 8;
+ setDoDeltaX(0);
+ setFileHash(0x0C1CA072, 0, -1);
+ SetUpdateHandler(&KmScene1201::update40DBE0);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ SetMessageHandler(&KmScene1201::handleMessage40DDF0);
+ }
+}
+
+void KmScene1201::stMoveObjectSkipTurn() {
+ _flagE5 = false;
+ setFileHash2(0x0C1CA072, 0x01084280, 0);
+ SetUpdateHandler(&KmScene1201::update40DBE0);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ SetMessageHandler(&KmScene1201::handleMessage40DDF0);
+}
+
+void KmScene1201::stTumbleHeadless() {
+ if (!stStartActionFromIdle(AnimationCallback(&KmScene1201::stTumbleHeadless))) {
+ _status2 = 1;
+ _flagE5 = false;
+ setDoDeltaX(0);
+ setFileHash(0x2821C590, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ SetMessageHandler(&KmScene1201::hmTumbleHeadless);
+ NextState(&Klayman::stTryStandIdle);
+ sendMessage(_class464, 0x2006, 0);
+ _soundResource1.play(0x62E0A356);
+ }
+}
+
+void KmScene1201::sub40E040() {
+ if (!stStartActionFromIdle(AnimationCallback(&KmScene1201::sub40E040))) {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x5420E254, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ }
+}
+
+KmScene1303::KmScene1303(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // Empty
+}
+
+uint32 KmScene1303::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4804:
+ GotoState(&KmScene1303::stPeekWall1);
+ break;
+ case 0x483B:
+ GotoState(&KmScene1303::stPeekWallReturn);
+ break;
+ case 0x483C:
+ GotoState(&KmScene1303::stPeekWall2);
+ break;
+ }
+ return 0;
+}
+
+uint32 KmScene1303::hmPeekWallReturn(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == calcHash("PopBalloon")) {
+ sendMessage(_parentScene, 0x2000, 0);
+ } else if (param.asInteger() == 0x02B20220) {
+ _soundResource1.play(0xC5408620);
+ } else if (param.asInteger() == 0x0A720138) {
+ _soundResource1.play(0xD4C08010);
+ } else if (param.asInteger() == 0xB613A180) {
+ _soundResource1.play(0x44051000);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1303::update4161A0() {
+ Klayman::update();
+ _counter3++;
+ if (_counter3 >= _counter3Max)
+ stPeekWall3();
+}
+
+void KmScene1303::stPeekWall1() {
+ _status2 = 0;
+ _flagE5 = true;
+ setFileHash(0xAC20C012, 8, 37);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ NextState(&KmScene1303::stPeekWall3);
+}
+
+void KmScene1303::stPeekWall2() {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0xAC20C012, 43, 49);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+}
+
+void KmScene1303::stPeekWall3() {
+ _counter3 = 0;
+ _status2 = 0;
+ _flagE5 = true;
+ _counter3Max = _vm->_rnd->getRandomNumber(64) + 24;
+ setFileHash(0xAC20C012, 38, 42);
+ SetUpdateHandler(&KmScene1303::update4161A0);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ _newHashListIndex = 42;
+}
+
+void KmScene1303::stPeekWallReturn() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x2426932E, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1303::hmPeekWallReturn);
+}
+
+KmScene1304::KmScene1304(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // Empty
+}
+
+uint32 KmScene1304::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ 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 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+KmScene1305::KmScene1305(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // Empty
+}
+
+uint32 KmScene1305::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ GotoState(&KmScene1305::stCrashDown);
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ }
+ return 0;
+}
+
+void KmScene1305::stCrashDown() {
+ _soundResource1.play(0x41648271);
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash2(0x000BAB02, 0x88003000, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Klayman::handleMessage41D480);
+ NextState(&KmScene1305::cbCrashDownEvent);
+}
+
+void KmScene1305::cbCrashDownEvent() {
+ setDoDeltaX(2);
+ stTryStandIdle();
+}
+
+KmScene1306::KmScene1306(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ _flag1 = false;
+}
+
+uint32 KmScene1306::xHandleMessage(int messageNum, const MessageParam &param) {
+ uint32 messageResult = 0;
+ switch (messageNum) {
+ case 0x2000:
+ _flag1 = param.asInteger() != 0;
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ if (_flag1)
+ GotoState(&Klayman::sub421350);
+ else
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ 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());
+ sub41C7B0();
+ break;
+ case 0x481A:
+ GotoState(&Klayman::sub420680);
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ if (_flag1)
+ GotoState(&Klayman::sub4214D0);
+ else
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ if (_flag1)
+ GotoState(&Klayman::sub421510);
+ else
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x481F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x482E:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub421030);
+ } else {
+ GotoState(&Klayman::sub420FE0);
+ }
+ break;
+ case 0x482F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub4210C0);
+ } else {
+ GotoState(&Klayman::sub421070);
+ }
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x4835:
+ sendMessage(_parentScene, 0x2000, 1);
+ _flag1 = true;
+ GotoState(&Klayman::stSitInTeleporter);
+ break;
+ case 0x4836:
+ sendMessage(_parentScene, 0x2000, 0);
+ _flag1 = false;
+ GotoState(&Klayman::sub421310);
+ break;
+ case 0x483D:
+ sub417D40();
+ break;
+ case 0x483E:
+ sub417D80();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1306::sub417D40() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xEE084A04, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1306::handleMessage417CB0);
+}
+
+void KmScene1306::sub417D80() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xB86A4274, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1306::handleMessage417CB0);
+}
+
+uint32 KmScene1306::handleMessage417CB0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4E0A2C24) {
+ _soundResource1.play(0x85B10BB8);
+ } else if (param.asInteger() == 0x4E6A0CA0) {
+ _soundResource1.play(0xC5B709B0);
+ }
+ }
+ return messageResult;
+}
+
+KmScene1308::KmScene1308(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ _flag1 = false;
+}
+
+uint32 KmScene1308::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480A:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stMoveObjectSkipTurnFaceObject);
+ } else {
+ GotoState(&Klayman::stMoveObjectFaceObject);
+ }
+ break;
+ case 0x480D:
+ GotoState(&KmScene1001::sub420C50);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481A:
+ if (param.asInteger() == 1) {
+ GotoState(&KmScene1308::sub456150);
+ } else {
+ GotoState(&Klayman::sub420680);
+ }
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x4827:
+ GotoState(&Klayman::sub420E20);
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+uint32 KmScene1308::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Klayman::handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (!_flag1 && param.asInteger() == 0x06040580) {
+ setFileHash3(0xDC409440, 0x46431401, 0);
+ } else if (_flag1 && param.asInteger() == 0x46431401) {
+ _flag1 = false;
+ setFileHash2(0xDC409440, 0x01084280, 0);
+ } else if (param.asInteger() == 0x062A1510) {
+ _soundResource1.play(0x41688704);
+ } else if (param.asInteger() == 0x02B20220) {
+ _soundResource1.play(0xC5408620);
+ } else if (param.asInteger() == 0x0A720138) {
+ _soundResource1.play(0xD4C08010);
+ } else if (param.asInteger() == 0xB613A180) {
+ _soundResource1.play(0x44051000);
+ } else if (param.asInteger() == 0x0E4C8141) {
+ _soundResource1.play(0xDC4A1280);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1308::sub456150() {
+ if (!stStartActionFromIdle(AnimationCallback(&KmScene1308::sub456150))) {
+ _status2 = 2;
+ _flag1 = false;
+ for (uint i = 0; i < 3; i++) {
+ if (getSubVar(0x0090EA95, i)) {
+ bool more;
+ setSubVar(0x08D0AB11, i, 1);
+ setSubVar(0x0090EA95, i, 0);
+ do {
+ more = false;
+ setSubVar(0xA010B810, i, _vm->_rnd->getRandomNumber(16 - 1));
+ for (uint j = 0; j < i && !more; j++) {
+ if (getSubVar(0x08D0AB11, j) && getSubVar(0xA010B810, j) == getSubVar(0xA010B810, i))
+ more = true;
+ }
+ if (getSubVar(0xA010B810, i) == getSubVar(0x0C10A000, i))
+ more = true;
+ } while (more);
+ _flag1 = true;
+ }
+ }
+ if (!_flag1) {
+ gotoState(NULL);
+ sub41C7B0();
+ } else {
+ _flagE5 = false;
+ setFileHash(0xDC409440, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F250);
+ SetMessageHandler(&KmScene1308::handleMessage);
+ _flag1 = false;
+ }
+ }
+}
+
+// KmScene1401
+
+KmScene1401::KmScene1401(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // Empty
+}
+
+uint32 KmScene1401::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480A:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stMoveObjectSkipTurnFaceObject);
+ } else {
+ GotoState(&Klayman::stMoveObjectFaceObject);
+ }
+ 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());
+ sub41C7B0();
+ 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);
+ sub41C7B0();
+ break;
+ case 0x482E:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub421030);
+ } else {
+ GotoState(&Klayman::sub420FE0);
+ }
+ break;
+ case 0x482F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub4210C0);
+ } else {
+ GotoState(&Klayman::sub421070);
+ }
+ break;
+ }
+ return 0;
+}
+
+// KmScene1402
+
+KmScene1402::KmScene1402(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ SetFilterY(&Sprite::defFilterY);
+}
+
+uint32 KmScene1402::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480A:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stMoveObjectSkipTurnFaceObject);
+ } else {
+ GotoState(&Klayman::stMoveObjectFaceObject);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ }
+ return 0;
+}
+
+// KmScene1403
+
+KmScene1403::KmScene1403(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ setKlaymanTable(klaymanTable4, ARRAYSIZE(klaymanTable4));
+}
+
+uint32 KmScene1403::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480A:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stMoveObjectSkipTurnFaceObject);
+ } else {
+ GotoState(&Klayman::stMoveObjectFaceObject);
+ }
+ break;
+ case 0x480D:
+ GotoState(&KmScene1001::sub420C50);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x4827:
+ GotoState(&Klayman::sub420E20);
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+// KmScene1404
+
+KmScene1404::KmScene1404(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // Empty
+}
+
+uint32 KmScene1404::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480A:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stMoveObjectSkipTurnFaceObject);
+ } else {
+ GotoState(&Klayman::stMoveObjectFaceObject);
+ }
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481A:
+ GotoState(&Klayman::sub420680);
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x481F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+KmScene1608::KmScene1608(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _flag1(false) {
+}
+
+uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x2032:
+ _flag1 = param.asInteger() != 0;
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ if (_flag1)
+ GotoState(&Klayman::sub421350);
+ else
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ if (_flag1)
+ GotoState(&Klayman::sub4214D0);
+ break;
+ case 0x481E:
+ if (_flag)
+ GotoState(&Klayman::sub421510);
+ break;
+ case 0x481F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x4835:
+ sendMessage(_parentScene, 0x2032, 1);
+ _flag1 = true;
+ GotoState(&Klayman::stSitInTeleporter);
+ break;
+ case 0x4836:
+ sendMessage(_parentScene, 0x2032, 0);
+ _flag1 = false;
+ GotoState(&Klayman::sub421310);
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+// KmScene1705
+
+KmScene1705::KmScene1705(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _flag(false) {
+
+ // Empty
+}
+
+uint32 KmScene1705::xHandleMessage(int messageNum, const MessageParam &param) {
+ uint32 messageResult = 0;
+ switch (messageNum) {
+ case 0x2000:
+ _flag = param.asInteger() != 0;
+ messageResult = 1;
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ if (_flag) {
+ GotoState(&Klayman::sub421350);
+ } else {
+ GotoState(&Klayman::stTryStandIdle);
+ }
+ break;
+ case 0x4803:
+ GotoState(&KmScene1705::stFallSkipJump);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ if (_flag) {
+ GotoState(&Klayman::sub4214D0);
+ }
+ break;
+ case 0x481E:
+ if (_flag) {
+ GotoState(&Klayman::sub421510);
+ }
+ break;
+ case 0x481F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x4835:
+ sendMessage(_parentScene, 0x2000, 1);
+ _flag = true;
+ GotoState(&Klayman::stSitInTeleporter);
+ break;
+ case 0x4836:
+ sendMessage(_parentScene, 0x2000, 0);
+ _flag = false;
+ GotoState(&Klayman::sub421310);
+ break;
+ case 0x483D:
+ sub468AD0();
+ break;
+ case 0x483E:
+ sub468B10();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene1705::handleMessage4689A0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4E0A2C24) {
+ _soundResource1.play(0x85B10BB8);
+ } else if (param.asInteger() == 0x4E6A0CA0) {
+ _soundResource1.play(0xC5B709B0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene1705::spriteUpdate468A30() {
+ updateDeltaXY();
+ HitRect *hitRect = _vm->_collisionMan->findHitRectAtPos(_x, _y + 10);
+ if (hitRect->type == 0x5001) {
+ _y = hitRect->rect.y1;
+ processDelta();
+ sendMessage(this, 0x1019, 0);
+ }
+}
+
+void KmScene1705::stFallSkipJump() {
+ _status2 = 2;
+ _flagE5 = false;
+ setFileHash2(0xB93AB151, 0x40A100F8, 0);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&KmScene1705::spriteUpdate468A30);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ NextState(&Klayman::stLandOnFeet);
+}
+
+void KmScene1705::sub468AD0() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x5E0A4905, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1705::handleMessage4689A0);
+}
+
+void KmScene1705::sub468B10() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xD86E4477, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene1705::handleMessage4689A0);
+}
+
+KmScene1901::KmScene1901(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // Empty
+}
+
+uint32 KmScene1901::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+KmScene2001::KmScene2001(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _flag(false) {
+
+ // Empty
+}
+
+uint32 KmScene2001::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x2000:
+ _flag = param.asInteger() != 0;
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ if (_flag) {
+ GotoState(&Klayman::sub421350);
+ } else {
+ GotoState(&Klayman::stTryStandIdle);
+ }
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&Klayman::stWalking);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481D:
+ if (_flag) {
+ GotoState(&Klayman::sub4214D0);
+ }
+ break;
+ case 0x481E:
+ if (_flag) {
+ GotoState(&Klayman::sub421510);
+ }
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x4835:
+ sendMessage(_parentScene, 0x2000, 1);
+ _flag = true;
+ GotoState(&Klayman::stSitInTeleporter);
+ break;
+ case 0x4836:
+ sendMessage(_parentScene, 0x2000, 0);
+ _flag = false;
+ GotoState(&Klayman::sub421310);
+ break;
+ case 0x483D:
+ sub440230();
+ break;
+ case 0x483E:
+ stDoTeleport();
+ break;
+ }
+ return 0;
+}
+
+uint32 KmScene2001::handleMessage4401A0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4E0A2C24) {
+ _soundResource1.play(0x85B10BB8);
+ } if (param.asInteger() == 0x4E6A0CA0) {
+ _soundResource1.play(0xC5B709B0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene2001::sub440230() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xBE68CC54, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene2001::handleMessage4401A0);
+}
+
+void KmScene2001::stDoTeleport() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x18AB4ED4, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene2001::handleMessage4401A0);
+}
+
+KmScene2101::KmScene2101(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000), _flag1(false) {
+
+ // Empty
+}
+
+uint32 KmScene2101::xHandleMessage(int messageNum, const MessageParam &param) {
+ uint32 messageResult = 0;
+ switch (messageNum) {
+ case 0x2000:
+ _flag1 = param.asInteger() != 0;
+ messageResult = 1;
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ if (_flag1)
+ GotoState(&Klayman::sub421350);
+ else
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4811:
+ GotoState(&KmScene2101::sub4862C0);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ 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());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ if (_flag1)
+ GotoState(&Klayman::sub4214D0);
+ break;
+ case 0x481E:
+ if (_flag)
+ GotoState(&Klayman::sub421510);
+ break;
+ case 0x4834:
+ GotoState(&Klayman::stStepOver);
+ break;
+ case 0x4835:
+ sendMessage(_parentScene, 0x2000, 1);
+ _flag1 = true;
+ GotoState(&Klayman::stSitInTeleporter);
+ break;
+ case 0x4836:
+ sendMessage(_parentScene, 0x2000, 0);
+ _flag1 = false;
+ GotoState(&Klayman::sub421310);
+ break;
+ case 0x483D:
+ sub486320();
+ break;
+ case 0x483E:
+ sub486360();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene2101::handleMessage486160(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ int16 speedUpFrameIndex;
+ switch (messageNum) {
+ case 0x1008:
+ speedUpFrameIndex = getFrameIndex(kKlaymanSpeedUpHash);
+ if (_frameIndex < speedUpFrameIndex) {
+ setFileHash(0x35AA8059, speedUpFrameIndex, -1);
+ _y = 438;
+ }
+ messageResult = 0;
+ break;
+ case 0x100D:
+ if (param.asInteger() == 0x1A1A0785) {
+ _soundResource1.play(0x40F0A342);
+ } else if (param.asInteger() == 0x60428026) {
+ _soundResource1.play(0x40608A59);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 KmScene2101::handleMessage486230(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage41D480(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4E0A2C24) {
+ _soundResource1.play(0x85B10BB8);
+ } else if (param.asInteger() == 0x4E6A0CA0) {
+ _soundResource1.play(0xC5B709B0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void KmScene2101::sub4862C0() {
+ _status2 = 1;
+ _flagE5 = false;
+ setFileHash(0x35AA8059, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ SetMessageHandler(&KmScene2101::handleMessage486160);
+ _soundResource1.play(0x402E82D4);
+}
+
+void KmScene2101::sub486320() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0xFF290E30, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene2101::handleMessage486230);
+}
+
+void KmScene2101::sub486360() {
+ _status2 = 0;
+ _flagE5 = false;
+ setFileHash(0x9A28CA1C, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&KmScene2101::handleMessage486230);
+}
+
+KmScene2201::KmScene2201(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount)
+ // TODO: NRect *rect1, int16 unk in Klayman ctor
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ _dataResource.load(0x04104242);
+ _flagF6 = false;
+}
+
+uint32 KmScene2201::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4812:
+ GotoState(&Klayman::stPickUpGeneric);
+ break;
+ case 0x4816:
+ if (param.asInteger() == 0) {
+ GotoState(&Klayman::stPressButtonSide);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x4818:
+ sub41C930(_dataResource.getPoint(param.asInteger()).x, false);
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x482E:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub421030);
+ } else {
+ GotoState(&Klayman::sub420FE0);
+ }
+ break;
+ case 0x482F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub4210C0);
+ } else {
+ GotoState(&Klayman::sub421070);
+ }
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+KmScene2203::KmScene2203(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+ // Empty
+}
+
+uint32 KmScene2203::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ 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());
+ sub41C7B0();
+ break;
+ case 0x4818:
+ sub41C930(_dataResource.getPoint(param.asInteger()).x, false);
+ break;
+ case 0x4819:
+ GotoState(&Klayman::sub420750);
+ break;
+ case 0x481A:
+ GotoState(&Klayman::sub420680);
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x481D:
+ GotoState(&Klayman::stTurnToUse);
+ break;
+ case 0x481E:
+ GotoState(&Klayman::sub4207F0);
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+KmScene2205::KmScene2205(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+ // Empty
+}
+
+void KmScene2205::xUpdate() {
+ setGlobalVar(0x18288913, _frameIndex);
+}
+
+uint32 KmScene2205::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&KmScene2205::sub423980);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4816:
+ if (param.asInteger() == 0) {
+ GotoState(&Klayman::stPressButtonSide);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x4818:
+ sub41C930(_dataResource.getPoint(param.asInteger()).x, false);
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void KmScene2205::sub423980() {
+ int16 frameIndex = getGlobalVar(0x18288913);
+ if (frameIndex < 0 || frameIndex > 13)
+ frameIndex = 0;
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setFileHash(0x1A249001, frameIndex, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EB70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F300);
+ NextState(&Klayman::sub41FA40);
+ FinalizeState(&Klayman::stStartWalkingDone);
+}
+
+KmScene2206::KmScene2206(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+
+ // TODO Sound1ChList_addSoundResource(0x80101800, 0xD3B02847);
+}
+
+KmScene2206::~KmScene2206() {
+ // TODO Sound1ChList_sub_407AF0(0x80101800);
+}
+
+void KmScene2206::xUpdate() {
+ setGlobalVar(0x18288913, _frameIndex);
+}
+
+uint32 KmScene2206::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4803:
+ GotoState(&KmScene2206::sub482490);
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&KmScene2206::sub482530);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4812:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ 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());
+ sub41C7B0();
+ 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() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x482E:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub421030);
+ } else {
+ GotoState(&Klayman::sub420FE0);
+ }
+ break;
+ case 0x482F:
+ if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub4210C0);
+ } else {
+ GotoState(&Klayman::sub421070);
+ }
+ break;
+ case 0x4837:
+ sub41CE70();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void KmScene2206::spriteUpdate482450() {
+ _yDelta++;
+ _y += _yDelta;
+ if (_y > 600) {
+ sendMessage(this, 0x1019, 0);
+ }
+}
+
+void KmScene2206::sub482490() {
+ if (!stStartActionFromIdle(AnimationCallback(&KmScene2206::sub482490))) {
+ _status2 = 1;
+ sendMessage(_parentScene, 0x4803, 0);
+ _flagE5 = false;
+ _yDelta = 0;
+ setFileHash(0x5420E254, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ SetSpriteCallback(&KmScene2206::spriteUpdate482450);
+ // TODO Sound1ChList_playLooping(0xD3B02847);
+ }
+}
+
+void KmScene2206::sub482530() {
+ int16 frameIndex = getGlobalVar(0x18288913) + 1;
+ if (frameIndex < 0 || frameIndex > 13)
+ frameIndex = 0;
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setFileHash(0x1A249001, frameIndex, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EB70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F300);
+ NextState(&Klayman::sub41FA40);
+ FinalizeState(&Klayman::stStartWalkingDone);
+}
+
+KmScene2207::KmScene2207(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+ // Empty
+}
+
+uint32 KmScene2207::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x2001:
+ GotoState(&KmScene2207::sub442460);
+ break;
+ case 0x2005:
+ spriteUpdate442430();
+ GotoState(&KmScene2207::stTryStandIdle);
+ break;
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x480D:
+ GotoState(&KmScene2207::sub4424B0);
+ break;
+ case 0x4812:
+ GotoState(&Klayman::stPickUpGeneric);
+ 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());
+ sub41C7B0();
+ break;
+ case 0x481B:
+ if (param.asPoint().y != 0) {
+ sub41CC40(param.asPoint().y, param.asPoint().x);
+ } else {
+ sub41CCE0(param.asPoint().x);
+ }
+ break;
+ case 0x4827:
+ GotoState(&Klayman::sub420E20);
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x483F:
+ sub41CD00(param.asInteger());
+ break;
+ case 0x4840:
+ sub41CD70(param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void KmScene2207::spriteUpdate442430() {
+ _x = _attachedSprite->getX() - 20;
+ _y = _attachedSprite->getY() + 46;
+ processDelta();
+}
+
+void KmScene2207::sub442460() {
+ if (!stStartActionFromIdle(AnimationCallback(&KmScene2207::sub442460))) {
+ _status2 = 1;
+ _flagE5 = true;
+ setFileHash(0x5420E254, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&KmScene2207::spriteUpdate442430);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ }
+}
+
+void KmScene2207::sub4424B0() {
+ if (!stStartAction(AnimationCallback(&KmScene2207::sub4424B0))) {
+ _status2 = 0;
+ if (_flagF7) {
+ stReleaseLeverUp();
+ } else {
+ _flagE5 = false;
+ setFileHash(0x0C303040, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&KmScene2207::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41E210);
+ NextState(&KmScene2207::sub442520);
+ }
+ }
+}
+
+void KmScene2207::sub442520() {
+ setFileHash(0x0D318140, 0, -1);
+ sendMessage(_attachedSprite, 0x480F, 0);
+ NextState(&KmScene2207::sub442560);
+}
+
+void KmScene2207::sub442560() {
+ setFileHash(0x1564A2C0, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ NextState(&KmScene2207::sub4425A0);
+ _flagE5 = true;
+ _flagF7 = true;
+}
+
+void KmScene2207::sub4425A0() {
+ setFileHash(0x4464A440, 0, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetSpriteCallback(&Klayman::spriteUpdate41F230);
+ SetMessageHandler(&Klayman::handleMessage41D360);
+ _flagE5 = true;
+ _flagF7 = true;
+}
+
+KmScene2242::KmScene2242(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+ // Empty
+}
+
+void KmScene2242::xUpdate() {
+ setGlobalVar(0x18288913, _frameIndex);
+}
+
+uint32 KmScene2242::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&KmScene2242::sub444D20);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4812:
+ if (param.asInteger() == 2) {
+ GotoState(&Klayman::stPickUpNeedle);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::sub41FFF0);
+ } else {
+ GotoState(&Klayman::stPickUpGeneric);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ 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() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x4837:
+ sub41CE70();
+ break;
+ }
+ return 0;
+}
+
+void KmScene2242::sub444D20() {
+ int16 frameIndex = (int16)getGlobalVar(0x18288913);
+ if (frameIndex < 0 || frameIndex > 13)
+ frameIndex = 0;
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setFileHash(0x1A249001, frameIndex, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EB70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F300);
+ NextState(&Klayman::sub41FA40);
+ FinalizeState(&Klayman::stStartWalkingDone);
+}
+
+KmHallOfRecords::KmHallOfRecords(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+ // Empty
+}
+
+void KmHallOfRecords::xUpdate() {
+ setGlobalVar(0x18288913, _frameIndex);
+}
+
+uint32 KmHallOfRecords::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&KmHallOfRecords::sub43B130);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481F:
+ if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x4837:
+ sub41CE70();
+ break;
+ }
+ return 0;
+}
+
+void KmHallOfRecords::sub43B130() {
+ int16 frameIndex = (int16)getGlobalVar(0x18288913);
+ if (frameIndex < 0 || frameIndex > 13)
+ frameIndex = 0;
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setFileHash(0x1A249001, frameIndex, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EB70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F300);
+ NextState(&Klayman::sub41FA40);
+ FinalizeState(&Klayman::stStartWalkingDone);
+}
+
+KmScene2247::KmScene2247(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y)
+ : Klayman(vm, parentScene, x, y, 1000, 1000) {
+ // Empty
+}
+
+void KmScene2247::xUpdate() {
+ setGlobalVar(0x18288913, _frameIndex);
+}
+
+uint32 KmScene2247::xHandleMessage(int messageNum, const MessageParam &param) {
+ switch (messageNum) {
+ case 0x4001:
+ case 0x4800:
+ sub41C930(param.asPoint().x, false);
+ break;
+ case 0x4004:
+ GotoState(&Klayman::stTryStandIdle);
+ break;
+ case 0x4804:
+ if (param.asInteger() != 0) {
+ _x4 = param.asInteger();
+ GotoState(&KmScene2247::sub453520);
+ } else {
+ GotoState(&Klayman::stPeekWall);
+ }
+ break;
+ case 0x4817:
+ setDoDeltaX(param.asInteger());
+ sub41C7B0();
+ break;
+ case 0x481F:
+ if (param.asInteger() == 0) {
+ GotoState(&Klayman::stWonderAboutHalf);
+ } else if (param.asInteger() == 1) {
+ GotoState(&Klayman::stWonderAboutAfter);
+ } else if (param.asInteger() == 3) {
+ GotoState(&Klayman::stTurnToUseHalf);
+ } else if (param.asInteger() == 4) {
+ GotoState(&Klayman::stTurnAwayFromUse);
+ } else {
+ GotoState(&Klayman::stWonderAbout);
+ }
+ break;
+ case 0x482D:
+ setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
+ sub41C7B0();
+ break;
+ case 0x4837:
+ sub41CE70();
+ break;
+ }
+ return 0;
+}
+
+void KmScene2247::sub453520() {
+ int16 frameIndex = (int16)getGlobalVar(0x18288913);
+ if (frameIndex < 0 || frameIndex > 13)
+ frameIndex = 0;
+ _status2 = 0;
+ _flagE1 = true;
+ _flagE5 = true;
+ setFileHash(0x1A249001, frameIndex, -1);
+ SetUpdateHandler(&Klayman::update);
+ SetMessageHandler(&Klayman::handleMessage41EB70);
+ SetSpriteCallback(&Klayman::spriteUpdate41F300);
+ NextState(&Klayman::sub41FA40);
+ FinalizeState(&Klayman::stStartWalkingDone);
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/klayman.h b/engines/neverhood/klayman.h
new file mode 100644
index 0000000000..645ed74226
--- /dev/null
+++ b/engines/neverhood/klayman.h
@@ -0,0 +1,543 @@
+/* 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_KLAYMAN_H
+#define NEVERHOOD_KLAYMAN_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/sprite.h"
+#include "neverhood/graphics.h"
+#include "neverhood/resource.h"
+
+namespace Neverhood {
+
+// TODO: This code is horrible and weird and a lot of stuff needs renaming once a better name is found
+
+class Klayman;
+
+const uint32 kKlaymanSpeedUpHash = 0x004A2148;
+
+struct KlaymanTableItem {
+ int value;
+ void (Klayman::*callback)();
+};
+
+class Klayman : public AnimatedSprite {
+public:
+ Klayman(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, int surfacePriority = 1000, int objectPriority = 1000, NRectArray *clipRects = NULL);
+
+ void update();
+
+ void stDoIdlePickEar();
+ void sub41FDA0();
+ void sub41FDF0();
+ void stDoIdleChest();
+ void sub41FEB0();
+ void stTryStandIdle();
+ void stWakeUp();
+ void stSleeping();
+ void stPickUpGeneric();
+ void stTurnPressButton();
+ void stStampFloorButton();
+ void stPressButtonSide();
+ void stLargeStep();
+ void stWonderAboutHalf();
+ void stWonderAboutAfter();
+ void stTurnToUseHalf();
+ void stTurnAwayFromUse();
+ void stWonderAbout();
+ void stPeekWall();
+ void sub420210();
+ void sub4201C0();
+ void sub420340();
+ void sub420250();
+ void sub420290();
+ void sub420380();
+ void sub4203C0();
+ void sub420300();
+ void sub420970();
+ void sub4209D0();
+ void sub420BC0();
+ void sub420AD0();
+ void sub421030();
+ void sub420FE0();
+ void sub4210C0();
+ void sub421070();
+ void stLandOnFeet();
+ void sub420ED0();
+ void sub420750();
+ void stTurnToUse();
+ void sub4207F0();
+ void sub420F20();
+ void sub421350();
+ void stIdleSitBlink();
+ void stIdleSitBlinkSecond();
+ void stPickUpNeedle();
+ void sub41FFF0();
+ void sub4214D0();
+ void sub421510();
+ void stStepOver();
+ void stSitInTeleporter();
+ void sub421310();
+ void stMoveObjectSkipTurnFaceObject();
+ void sub420660();
+ void stMoveObjectSkipTurn();
+ void stMoveObjectFaceObject();
+ void sub420C50();
+ void stPullLeverDown();
+ void stHoldLeverDown();
+ void stReleaseLeverUp();
+ void sub420E20();
+ void sub420E90();
+ void sub420EB0();
+ void sub420680();
+ void stWalking();
+ void sub41FA40();
+ void stStartWalkingDone();
+
+ void sub41CE70();
+
+ void spriteUpdate41F250();
+ void spriteUpdate41F5F0();
+ void suLargeStep();
+ void spriteUpdate41F230();
+ void spriteUpdate41F5A0();
+ void spriteUpdate41F300();
+ void spriteUpdate41F320();
+
+ uint32 handleMessage41D360(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41D480(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41EB70(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41E210(int messageNum, const MessageParam &param, Entity *sender);
+
+ void setKlaymanTable(const KlaymanTableItem *table, int tableCount);
+ void setKlaymanTable1();
+ void setKlaymanTable2();
+ void setKlaymanTable3();
+
+ void setSoundFlag(bool value) { _soundFlag = value; }
+
+protected:
+ Entity *_parentScene;
+ Sprite *_attachedSprite;
+ int _statusE0;
+ bool _flagE1;
+ bool _flagE2;
+ bool _flagE3;
+ bool _flagE4;
+ bool _flagE5;
+ int16 _x4, _y4;
+ int16 _counter, _counterMax;
+ int16 _counter3, _counter3Max;
+ int16 _counter1;
+ int16 _counter2;
+ bool _flagF6;
+ bool _flagF7;
+ bool _flagF8;
+ int _status2;
+ bool _flagFA;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ int _status3;
+ const KlaymanTableItem *_table;
+ int _tableCount;
+ int _tableMaxValue;
+ uint32 _field114;
+ /*
+ 00000118 field118 dw ?
+ */
+ bool _soundFlag;
+ int _resourceHandle;
+ virtual void xUpdate();
+ virtual uint32 xHandleMessage(int messageNum, const MessageParam &param);
+
+ void stIdlePickEar();
+ void evIdlePickEarDone();
+ uint32 hmIdlePickEar(int messageNum, const MessageParam &param, Entity *sender);
+
+ void sub41FDB0();
+ uint32 handleMessage41E980(int messageNum, const MessageParam &param, Entity *sender);
+
+ void sub41FE00();
+ void sub41FE50();
+ uint32 handleMessage41E9E0(int messageNum, const MessageParam &param, Entity *sender);
+
+ void stIdleChest();
+ uint32 hmIdleChest(int messageNum, const MessageParam &param, Entity *sender);
+
+ void sub41FEC0();
+ uint32 handleMessage41EFE0(int messageNum, const MessageParam &param, Entity *sender);
+
+ void sub41D320(uint32 fileHash, AnimationCb callback);
+ void update41D2B0();
+
+ bool stStartActionFromIdle(AnimationCb callback);
+ void sub41C7B0();
+ void sub41C770();
+ void sub41C790();
+
+ void update41D0F0();
+
+ void stStand();
+ void stStandAround();
+
+ uint32 handleMessage41F140(int messageNum, const MessageParam &param, Entity *sender);
+
+ void sub41C930(int16 x, bool flag);
+
+ uint32 hmSleeping(int messageNum, const MessageParam &param, Entity *sender);
+
+ bool stStartAction(AnimationCb callback3);
+
+ void stSneak();
+ void stSneakDone();
+ uint32 handleMessage41DD80(int messageNum, const MessageParam &param, Entity *sender);
+ void sub41CD70(int16 x);
+ void stStartWalking();
+ uint32 handleMessage41EC70(int messageNum, const MessageParam &param, Entity *sender);
+
+ uint32 hmPickUpGeneric(int messageNum, const MessageParam &param, Entity *sender);
+
+ uint32 hmPressButton(int messageNum, const MessageParam &param, Entity *sender);
+
+ void sub41CD00(int16 x);
+ void sub41CC40(int16 x1, int16 x2);
+ void sub41CAC0(int16 x);
+ void sub41CCE0(int16 x);
+ void stLargeStepDone();
+
+ uint32 hmLargeStep(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41EEF0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmPeekWall(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41D790(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41D880(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41DAA0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41DFD0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41E0D0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41E490(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41E290(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41E2F0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41D640(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41EAB0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41D970(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage41DD20(int messageNum, const MessageParam &param, Entity *sender);
+
+ void update41D1C0();
+
+ uint32 handleMessage41DB90(int messageNum, const MessageParam &param, Entity *sender);
+
+};
+
+class KmScene1001 : public Klayman {
+public:
+ KmScene1001(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void sub44FA50();
+ uint32 handleMessage44FA00(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class KmScene1002 : public Klayman {
+public:
+ KmScene1002(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, Sprite *class599, Sprite *ssLadderArch);
+protected:
+ Sprite *_class599;
+ Sprite *_ssLadderArch;
+ Sprite *_otherSprite;
+ int _status;
+ void xUpdate();
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void update4497D0();
+ uint32 handleMessage449800(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage4498E0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmPressDoorButton(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmMoveVenusFlyTrap(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage449BA0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage449C90(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage449D60(int messageNum, const MessageParam &param, Entity *sender);
+ void suFallDown();
+ void sub449E20();
+ void sub449E90();
+ void sub449EF0();
+ void sub449F70();
+ void stSpitOutFall();
+ void sub44A0D0();
+ void sub44A150();
+ void sub44A230();
+ void stJumpAndFall();
+ void stDropFromRing();
+ void stPressDoorButton();
+ void stHitByBoxingGlove();
+ void stHitByBoxingGloveDone();
+ void stMoveVenusFlyTrap();
+ void stContinueMovingVenusFlyTrap();
+ void stMoveVenusFlyTrapDone();
+};
+
+class KmScene1004 : public Klayman {
+public:
+ KmScene1004(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 hmReadNote(int messageNum, const MessageParam &param, Entity *sender);
+ void stReadNote();
+};
+
+class KmScene1109 : public Klayman {
+public:
+ KmScene1109(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag1;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage461EA0(int messageNum, const MessageParam &param, Entity *sender);
+ void sub461F30();
+ void sub461F70();
+};
+
+class KmScene1201 : public Klayman {
+public:
+ KmScene1201(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, Entity *class464);
+protected:
+ Entity *_class464;
+ int _countdown;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void update40DBE0();
+ uint32 hmMatch(int messageNum, const MessageParam &param, Entity *sender);
+ void stFetchMatch();
+ void stLightMatch();
+ uint32 handleMessage40DDF0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmTumbleHeadless(int messageNum, const MessageParam &param, Entity *sender);
+ void sub40DF00();
+ void stMoveObjectSkipTurn();
+ void stTumbleHeadless();
+ void sub40E040();
+};
+
+class KmScene1303 : public Klayman {
+public:
+ KmScene1303(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 hmPeekWallReturn(int messageNum, const MessageParam &param, Entity *sender);
+ void update4161A0();
+ void stPeekWall1();
+ void stPeekWall2();
+ void stPeekWall3();
+ void stPeekWallReturn();
+};
+
+class KmScene1304 : public Klayman {
+public:
+ KmScene1304(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene1305 : public Klayman {
+public:
+ KmScene1305(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void stCrashDown();
+ void cbCrashDownEvent();
+};
+
+class KmScene1306 : public Klayman {
+public:
+ KmScene1306(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag1;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage417CB0(int messageNum, const MessageParam &param, Entity *sender);
+ void sub417D40();
+ void sub417D80();
+};
+
+class KmScene1308 : public Klayman {
+public:
+ KmScene1308(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag1;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub456150();
+};
+
+class KmScene1401 : public Klayman {
+public:
+ KmScene1401(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene1402 : public Klayman {
+public:
+ KmScene1402(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene1403 : public Klayman {
+public:
+ KmScene1403(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene1404 : public Klayman {
+public:
+ KmScene1404(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene1608 : public Klayman {
+public:
+ KmScene1608(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag1;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene1705 : public Klayman {
+public:
+ KmScene1705(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage4689A0(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate468A30();
+ void stFallSkipJump();
+ void sub468AD0();
+ void sub468B10();
+};
+
+class KmScene1901 : public Klayman {
+public:
+ KmScene1901(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene2001 : public Klayman {
+public:
+ KmScene2001(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage4401A0(int messageNum, const MessageParam &param, Entity *sender);
+ void sub440230();
+ void stDoTeleport();
+};
+
+class KmScene2101 : public Klayman {
+public:
+ KmScene2101(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ bool _flag1;
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ uint32 handleMessage486160(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage486230(int messageNum, const MessageParam &param, Entity *sender);
+ void sub4862C0();
+ void sub486320();
+ void sub486360();
+};
+
+class KmScene2201 : public Klayman {
+public:
+ KmScene2201(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y, NRect *clipRects, int clipRectsCount);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene2203 : public Klayman {
+public:
+ KmScene2203(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene2205 : public Klayman {
+public:
+ KmScene2205(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+ void sub423980();
+protected:
+ void xUpdate();
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+};
+
+class KmScene2206 : public Klayman {
+public:
+ KmScene2206(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+ ~KmScene2206();
+protected:
+ int16 _yDelta;
+ void xUpdate();
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void spriteUpdate482450();
+ void sub482490();
+ void sub482530();
+};
+
+class KmScene2207 : public Klayman {
+public:
+ KmScene2207(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void spriteUpdate442430();
+ void sub442460();
+ void sub4424B0();
+ void sub442520();
+ void sub442560();
+ void sub4425A0();
+};
+
+class KmScene2242 : public Klayman {
+public:
+ KmScene2242(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ void xUpdate();
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void sub444D20();
+};
+
+class KmHallOfRecords : public Klayman {
+public:
+ KmHallOfRecords(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ void xUpdate();
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void sub43B130();
+};
+
+class KmScene2247 : public Klayman {
+public:
+ KmScene2247(NeverhoodEngine *vm, Entity *parentScene, int16 x, int16 y);
+protected:
+ void xUpdate();
+ uint32 xHandleMessage(int messageNum, const MessageParam &param);
+ void sub453520();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_KLAYMAN_H */
diff --git a/engines/neverhood/module.cpp b/engines/neverhood/module.cpp
new file mode 100644
index 0000000000..5be9a6321f
--- /dev/null
+++ b/engines/neverhood/module.cpp
@@ -0,0 +1,117 @@
+/* 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/module.h"
+#include "neverhood/navigationscene.h"
+#include "neverhood/smackerscene.h"
+
+namespace Neverhood {
+
+Module::Module(NeverhoodEngine *vm, Module *parentModule)
+ : Entity(vm, 0), _parentModule(parentModule), _childObject(NULL),
+ _done(false), _sceneType(kSceneTypeNormal) {
+
+ SetMessageHandler(&Module::handleMessage);
+
+}
+
+Module::~Module() {
+ delete _childObject;
+}
+
+void Module::draw() {
+ if (_childObject)
+ _childObject->draw();
+}
+
+uint32 Module::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x0008:
+ if (_parentModule)
+ sendMessage(_parentModule, 8, 0);
+ return 0;
+ case 0x1009:
+ _moduleResult = param.asInteger();
+ _done = true;
+ return 0;
+ case 0x100A:
+ case 0x1023:
+ case 0x1024:
+ // Unused resource preloading messages
+ return 0;
+ default:
+ if (_childObject && sender == _parentModule)
+ return sender->sendMessage(_childObject, messageNum, param);
+ }
+ return 0;
+}
+
+NavigationScene *Module::navigationScene() {
+ // Not so nice
+ return (NavigationScene*)_childObject;
+}
+
+void Module::createNavigationScene(uint32 navigationListId, int navigationIndex, const byte *itemsTypes) {
+ _sceneType = kSceneTypeNavigation;
+ _childObject = new NavigationScene(_vm, this, navigationListId, navigationIndex, itemsTypes);
+}
+
+void Module::createSmackerScene(uint32 fileHash, bool doubleSurface, bool flag1, bool canAbort) {
+ SmackerScene *smackerScene;
+ _sceneType = kSceneTypeSmacker;
+ smackerScene = new SmackerScene(_vm, this, doubleSurface, flag1, canAbort);
+ smackerScene->setFileHash(fileHash);
+ smackerScene->nextVideo();
+ _childObject = smackerScene;
+}
+
+void Module::createSmackerScene(const uint32 *fileHashList, bool doubleSurface, bool flag1, bool canAbort) {
+ SmackerScene *smackerScene;
+ _sceneType = kSceneTypeSmacker;
+ smackerScene = new SmackerScene(_vm, this, doubleSurface, flag1, canAbort);
+ smackerScene->setFileHashList(fileHashList);
+ smackerScene->nextVideo();
+ _childObject = smackerScene;
+}
+
+bool Module::updateChild() {
+ if (_childObject) {
+ _childObject->handleUpdate();
+ if (_done) {
+ _done = false;
+ // Save the last area type if it's a NavigationScene for further processing
+ if (_sceneType == kSceneTypeNavigation)
+ _navigationAreaType = navigationScene()->getNavigationAreaType();
+ delete _childObject;
+ _childObject = NULL;
+ _sceneType = kSceneTypeNormal;
+ return false;
+ }
+ }
+ return true;
+}
+
+void Module::leaveModule(uint32 result) {
+ sendMessage(_parentModule, 0x1009, result);
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module.h b/engines/neverhood/module.h
new file mode 100644
index 0000000000..57a42c623b
--- /dev/null
+++ b/engines/neverhood/module.h
@@ -0,0 +1,70 @@
+/* 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.
+ *
+ */
+
+// TODO: I couldn't come up with a better name than 'Module' so far
+
+#ifndef NEVERHOOD_MODULE_H
+#define NEVERHOOD_MODULE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/background.h"
+#include "neverhood/collisionman.h"
+#include "neverhood/entity.h"
+#include "neverhood/graphics.h"
+#include "neverhood/mouse.h"
+#include "neverhood/palette.h"
+#include "neverhood/screen.h"
+
+namespace Neverhood {
+
+class NavigationScene;
+
+enum SceneType {
+ kSceneTypeNormal,
+ kSceneTypeSmacker,
+ kSceneTypeNavigation
+};
+
+class Module : public Entity {
+public:
+ Module(NeverhoodEngine *vm, Module *parentModule);
+ virtual ~Module();
+ virtual void draw();
+protected:
+ Module *_parentModule;
+ Entity *_childObject;
+ bool _done;
+ uint32 _moduleResult;
+ SceneType _sceneType;
+ int _navigationAreaType;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ NavigationScene *navigationScene();
+ void createNavigationScene(uint32 navigationListId, int navigationIndex, const byte *itemsTypes = NULL);
+ void createSmackerScene(uint32 fileHash, bool doubleSurface, bool flag1, bool canAbort);
+ void createSmackerScene(const uint32 *fileHashList, bool doubleSurface, bool flag1, bool canAbort);
+ bool updateChild();
+ void leaveModule(uint32 result);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE_H */
diff --git a/engines/neverhood/module.mk b/engines/neverhood/module.mk
new file mode 100644
index 0000000000..adf58b1225
--- /dev/null
+++ b/engines/neverhood/module.mk
@@ -0,0 +1,50 @@
+MODULE := engines/neverhood
+
+MODULE_OBJS = \
+ background.o \
+ blbarchive.o \
+ collisionman.o \
+ detection.o \
+ diskplayerscene.o \
+ gamemodule.o \
+ gamevars.o \
+ graphics.o \
+ klayman.o \
+ module.o \
+ module1000.o \
+ module1100.o \
+ module1200.o \
+ module1300.o \
+ module1400.o \
+ module1500.o \
+ module1600.o \
+ module1700.o \
+ module1800.o \
+ module1900.o \
+ module2000.o \
+ module2100.o \
+ module2200.o \
+ module2300.o \
+ module2600.o \
+ module2700.o \
+ module3000.o \
+ mouse.o \
+ navigationscene.o \
+ neverhood.o \
+ palette.o \
+ resource.o \
+ resourceman.o \
+ scene.o \
+ screen.o \
+ smackerscene.o \
+ smackerplayer.o \
+ sprite.o \
+ staticdata.o
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/neverhood/module1000.cpp b/engines/neverhood/module1000.cpp
new file mode 100644
index 0000000000..b60c3182d0
--- /dev/null
+++ b/engines/neverhood/module1000.cpp
@@ -0,0 +1,1898 @@
+/* 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/module1000.h"
+
+namespace Neverhood {
+
+Module1000::Module1000(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ debug("Create Module1000(%d)", which);
+
+ _musicFileHash = getGlobalVar(0xD0A14D10) ? 0x81106480 : 0x00103144;
+
+ // TODO Music18hList_add(0x03294419, 0x061880C6);
+ // TODO Music18hList_add(0x03294419, _musicFileHash);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 0) {
+ createScene(0, 0);
+ } else if (which == 1) {
+ createScene(1, 1);
+ }
+
+}
+
+Module1000::~Module1000() {
+ // TODO Music18hList_deleteGroup(0x03294419);
+}
+
+void Module1000::createScene(int sceneNum, int which) {
+ debug("Module1000::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ // TODO Music18hList_play(0x061880C6, 0, 0, 1);
+ _childObject = new Scene1001(_vm, this, which);
+ break;
+ case 1:
+ // TODO Music18hList_play(0x061880C6, 0, 0, 1);
+ _childObject = new Scene1002(_vm, this, which);
+ break;
+ case 2:
+ // TODO Music18hList_play(0x061880C6, 0, 0);
+ _childObject = new Class152(_vm, this, 0xC084110C, 0x41108C00);
+ break;
+ case 3:
+ // TODO Music18hList_stop(0x061880C6, 0, 2);
+ _childObject = new Scene1004(_vm, this, which);
+ break;
+ case 4:
+ // TODO Music18hList_stop(0x061880C6, 0, 0);
+ // TODO Music18hList_play(_musicFileHash, 0, 0, 1);
+ _childObject = new Scene1005(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module1000::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1000::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 2)
+ createScene(2, 0);
+ else
+ createScene(1, 0);
+ break;
+ case 1:
+ if (_moduleResult == 1)
+ leaveModule(0);
+ else if (_moduleResult == 2)
+ createScene(3, 0);
+ else
+ createScene(0, 1);
+ break;
+ case 2:
+ createScene(0, 2);
+ break;
+ case 3:
+ if (_moduleResult == 1)
+ createScene(4, 0);
+ else
+ createScene(1, 2);
+ break;
+ case 4:
+ // TODO Music18hList_stop(_musicFileHash, 0, 1);
+ createScene(3, 1);
+ break;
+ }
+ }
+}
+
+// Scene1001
+
+AsScene1001Door::AsScene1001Door(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm) {
+
+ createSurface(800, 137, 242);
+ _x = 726;
+ _y = 440;
+ callback1();
+ _soundResource2.load(0xED403E03);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1001Door::handleMessage);
+}
+
+uint32 AsScene1001Door::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ handleMessage2000h();
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return 0;
+}
+
+void AsScene1001Door::handleMessage2000h() {
+ switch (getGlobalVar(0x52371C95)) {
+ case 0:
+ case 1:
+ _soundResource1.play(0x65482F03);
+ setFileHash(0x624C0498, 1, 3);
+ NextState(&AsScene1001Door::callback1);
+ break;
+ case 2:
+ _soundResource2.play();
+ setFileHash(0x624C0498, 6, 6);
+ NextState(&AsScene1001Door::callback2);
+ break;
+ default:
+ // Nothing
+ break;
+ }
+ incGlobalVar(0x52371C95, 1);
+}
+
+void AsScene1001Door::callback1() {
+ switch (getGlobalVar(0x52371C95)) {
+ case 1:
+ setFileHash(0x624C0498, 4, -1);
+ _newHashListIndex = 4;
+ break;
+ case 2:
+ setFileHash(0x624C0498, 1, -1);
+ _newHashListIndex = 1;
+ break;
+ case 3:
+ stopAnimation();
+ setVisible(false);
+ break;
+ default:
+ setFileHash(0x624C0498, 0, -1);
+ _newHashListIndex = 0;
+ break;
+ }
+}
+
+void AsScene1001Door::callback2() {
+ setGlobalVar(0xD217189D, 1);
+ setFileHash(0x624C0498, 6, 6);
+ NextState(&AsScene1001Door::callback3);
+ _x = 30;
+}
+
+void AsScene1001Door::callback3() {
+ _soundResource1.play();
+ stopAnimation();
+ setVisible(false);
+}
+
+AsScene1001Hammer::AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _asDoor(asDoor) {
+
+ _x = 547;
+ _y = 206;
+ createSurface(900, 177, 192);
+ setFileHash(0x022C90D4, -1, -1);
+ _newHashListIndex = -2;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1001Hammer::handleMessage);
+}
+
+uint32 AsScene1001Hammer::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x00352100) {
+ sendMessage(_asDoor, 0x2000, 0);
+ } else if (param.asInteger() == 0x0A1A0109) {
+ _soundResource.play(0x66410886);
+ }
+ break;
+ case 0x2000:
+ setFileHash(0x022C90D4, 1, -1);
+ _soundResource.play(0xE741020A);
+ _newHashListIndex = -2;
+ break;
+ }
+ return 0;
+}
+
+AsScene1001Window::AsScene1001Window(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1200), _soundResource(vm) {
+
+ _x = 320;
+ _y = 240;
+ createSurface(100, 66, 129);
+ setFileHash(0xC68C2299, 0, -1);
+ _newHashListIndex = 0;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1001Window::handleMessage);
+}
+
+uint32 AsScene1001Window::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x0E0A1410) {
+ _soundResource.play(0x60803F10);
+ }
+ break;
+ case 0x2001:
+ setFileHash(0xC68C2299, 0, -1);
+ break;
+ case 0x3002:
+ SetMessageHandler(NULL);
+ setGlobalVar(0x03C698DA, 1);
+ setVisible(false);
+ break;
+ }
+ return 0;
+}
+
+AsScene1001Lever::AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene) {
+
+ createSurface(1010, 71, 73);
+ setDoDeltaX(deltaXType);
+ setFileHash(0x04A98C36, 0, -1);
+ _newHashListIndex = 0;
+ _x = x;
+ _y = y;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1001Lever::handleMessage);
+}
+
+uint32 AsScene1001Lever::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x00C0C444) {
+ sendMessage(_parentScene, 0x480F, 0);
+ } else if (param.asInteger() == 0xC41A02C0) {
+ _soundResource.play(0x40581882);
+ }
+ break;
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x3002:
+ setFileHash(0x04A98C36, 0, -1);
+ _newHashListIndex = 0;
+ break;
+ case 0x480F:
+ setFileHash(0x04A98C36, 0, -1);
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+SsCommonButtonSprite::SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash)
+ : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene), _soundResource(vm), _countdown(0) {
+
+ _priority = 1100;
+ _soundFileHash = soundFileHash ? soundFileHash : 0x44141000;
+ setVisible(false);
+ SetUpdateHandler(&SsCommonButtonSprite::update);
+ SetMessageHandler(&SsCommonButtonSprite::handleMessage);
+}
+
+void SsCommonButtonSprite::update() {
+ if (_countdown != 0 && (--_countdown) == 0) {
+ setVisible(false);
+ }
+}
+
+uint32 SsCommonButtonSprite::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x480B:
+ sendMessage(_parentScene, 0x480B, 0);
+ setVisible(true);
+ _countdown = 8;
+ _soundResource.play(_soundFileHash);
+ break;
+ }
+ return messageResult;
+}
+
+Scene1001::Scene1001(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _fieldE4(-1), _fieldE6(-1) {
+
+ _name = "Scene1001";
+
+ Sprite *tempSprite;
+
+ SetMessageHandler(&Scene1001::handleMessage);
+
+ setHitRects(0x004B4860);
+ _surfaceFlag = false;
+ setBackground(0x4086520E);
+ setPalette(0x4086520E);
+ insertMouse433(0x6520A400);
+
+ if (which < 0) {
+ setRectList(0x004B49F0);
+ insertKlayman<KmScene1001>(200, 433);
+ setMessageList(0x004B4888);
+ } else if (which == 1) {
+ setRectList(0x004B49F0);
+ insertKlayman<KmScene1001>(640, 433);
+ setMessageList(0x004B4898);
+ } else if (which == 2) {
+ setRectList(0x004B49F0);
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene1001>(390, 433);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene1001>(300, 433);
+ }
+ setMessageList(0x004B4970);
+ } else {
+ setRectList(0x004B4A00);
+ insertKlayman<KmScene1001>(200, 433);
+ setMessageList(0x004B4890);
+ }
+
+ tempSprite = insertStaticSprite(0x2080A3A8, 1300);
+
+ _klayman->setClipRect(0, 0, tempSprite->getDrawRect().x2(), 480);
+
+ if (getGlobalVar(0xD217189D) == 0) {
+ _asDoor = insertSprite<AsScene1001Door>();
+ _asDoor->setClipRect(0, 0, tempSprite->getDrawRect().x2(), 480);
+ } else {
+ _asDoor = NULL;
+ }
+
+ _asLever = insertSprite<AsScene1001Lever>(this, 150, 433, 1);
+
+ insertStaticSprite(0x809861A6, 950);
+ insertStaticSprite(0x89C03848, 1100);
+
+ _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x15288120, 100, 0);
+
+ if (getGlobalVar(0x03C698DA) == 0) {
+ tempSprite = insertStaticSprite(0x8C066150, 200);
+ _asWindow = insertSprite<AsScene1001Window>();
+ _asWindow->setClipRect(tempSprite->getDrawRect());
+ } else {
+ _asWindow = NULL;
+ }
+
+ _asHammer = insertSprite<AsScene1001Hammer>(_asDoor);
+
+}
+
+Scene1001::~Scene1001() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX());
+}
+
+uint32 Scene1001::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ debug("Scene1001::handleMessage(%04X)", messageNum);
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x == 0 && getGlobalVar(0xA4014072)) {
+ leaveScene(0);
+ }
+ break;
+ case 0x000D:
+ if (param.asInteger() == 0x188B2105) {
+ leaveScene(0);
+ messageResult = 1;
+ }
+ break;
+ case 0x100D:
+ if (param.asInteger() == 0x00342624) {
+ sendEntityMessage(_klayman, 0x1014, _asLever);
+ setMessageList2(0x004B4910);
+ messageResult = 1;
+ } else if (param.asInteger() == 0x21E64A00) {
+ if (getGlobalVar(0xD217189D)) {
+ setMessageList(0x004B48A8);
+ } else {
+ setMessageList(0x004B48C8);
+ }
+ messageResult = 1;
+ } else if (param.asInteger() == 0x040424D0) {
+ sendEntityMessage(_klayman, 0x1014, _ssButton);
+ } else if (param.asInteger() == 0x80006358) {
+ if (getGlobalVar(0x03C698DA)) {
+ setMessageList(0x004B4938);
+ } else {
+ setMessageList(0x004B4960);
+ }
+ }
+ break;
+ case 0x2002:
+ setRectList(0x004B49F0);
+ break;
+ case 0x480B:
+ if (_asWindow) {
+ sendMessage(_asWindow, 0x2001, 0);
+ }
+ break;
+ case 0x480F:
+ if (_asHammer) {
+ sendMessage(_asHammer, 0x2000, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+// Scene1002
+
+SsScene1002LadderArch::SsScene1002LadderArch(NeverhoodEngine *vm, Scene *parentScene)
+ : StaticSprite(vm, 0x152C1313, 1015), _parentScene(parentScene) {
+
+ SetMessageHandler(&SsScene1002LadderArch::handleMessage);
+}
+
+uint32 SsScene1002LadderArch::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 995);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1015);
+ break;
+ }
+ return messageResult;
+}
+
+Class599::Class599(NeverhoodEngine *vm, Scene *parentScene)
+ : StaticSprite(vm, 0x316C4BB4, 1015), _parentScene(parentScene) {
+
+ SetMessageHandler(&Class599::handleMessage);
+}
+
+uint32 Class599::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 995);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1015);
+ break;
+ }
+ return messageResult;
+}
+
+AsScene1002Ring::AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool flag1, int16 x, int16 y, int16 clipY1, bool flag2)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene), _flag1(flag1) {
+
+ SetUpdateHandler(&AsScene1002Ring::update);
+
+ if (flag1) {
+ createSurface(990, 68, 314);
+ if (flag2) {
+ setFileHash(0x04103090, 0, -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447930);
+ } else {
+ setFileHash(0xA85C4011, _vm->_rnd->getRandomNumber(15), -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage4475E0);
+ }
+ } else {
+ createSurface(990, 68, 138);
+ setFileHash(0xA85C4011, _vm->_rnd->getRandomNumber(15), -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage4475E0);
+ }
+
+ setClipRect(0, clipY1, 640, 480);
+
+ _x = x;
+ _y = y;
+
+ setDoDeltaX(_vm->_rnd->getRandomNumber(1));
+
+}
+
+void AsScene1002Ring::update() {
+ AnimatedSprite::updateAnim();
+ AnimatedSprite::updatePosition();
+}
+
+uint32 AsScene1002Ring::handleMessage4475E0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4806:
+ setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0);
+ sendMessage(_parentScene, 0x4806, 0);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447760);
+ if (_flag1) {
+ setFileHash(0x87502558, 0, -1);
+ } else {
+ setFileHash(0x80DD4010, 0, -1);
+ }
+ break;
+ case 0x480F:
+ setDoDeltaX(((Sprite*)sender)->isDoDeltaX() ? 1 : 0);
+ sendMessage(_parentScene, 0x480F, 0);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447890);
+ setFileHash(0x861A2020, 0, -1);
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002Ring::handleMessage447760(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ if (_flag1) {
+ setFileHash(0x78D0A812, 0, -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447930);
+ } else {
+ setFileHash(0xB85D2A10, 0, -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447930);
+ }
+ break;
+ case 0x4807:
+ sendMessage(_parentScene, 0x4807, 0);
+ setDoDeltaX(_vm->_rnd->getRandomNumber(1));
+ setFileHash(0x8258A030, 0, -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447A00);
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002Ring::handleMessage447890(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ setFileHash(0x04103090, 0, -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447930);
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002Ring::handleMessage447930(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4807:
+ sendMessage(_parentScene, 0x4807, 0);
+ setDoDeltaX(_vm->_rnd->getRandomNumber(1));
+ setFileHash(0x8258A030, 0, -1);
+ SetMessageHandler(&AsScene1002Ring::handleMessage447A00);
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002Ring::handleMessage447A00(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage4475E0(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x05410F72) {
+ _soundResource.play(0x21EE40A9);
+ }
+ break;
+ case 0x3002:
+ setFileHash(0xA85C4011, 0, -1);
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+AsScene1002Door::AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect)
+ : StaticSprite(vm, 1200) {
+
+ _spriteResource.load2(0x1052370F);
+ createSurface(800, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ setClipRect(clipRect);
+
+ _x = 526;
+
+ if (getGlobalVar(0x8306F218)) {
+ _y = 49;
+ } else {
+ _y = 239;
+ }
+
+ _surface->getDrawRect().x = 0;
+ _surface->getDrawRect().y = 0;
+ _surface->getDrawRect().width = _spriteResource.getDimensions().width;
+ _surface->getDrawRect().height = _spriteResource.getDimensions().height;
+
+ _needRefresh = true;
+
+ SetUpdateHandler(&AsScene1002Door::update);
+ SetMessageHandler(&AsScene1002Door::handleMessage);
+ SetSpriteCallback(NULL);
+ StaticSprite::update();
+
+}
+
+void AsScene1002Door::update() {
+ handleSpriteUpdate();
+ StaticSprite::update();
+}
+
+uint32 AsScene1002Door::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4808:
+ setGlobalVar(0x8306F218, 1);
+ SetSpriteCallback(&AsScene1002Door::suOpenDoor);
+ break;
+ case 0x4809:
+ setGlobalVar(0x8306F218, 0);
+ SetSpriteCallback(&AsScene1002Door::suCloseDoor);
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1002Door::suOpenDoor() {
+ if (_y > 49) {
+ _y -= 8;
+ if (_y < 49) {
+ SetSpriteCallback(NULL);
+ _y = 49;
+ }
+ _needRefresh = true;
+ }
+}
+
+void AsScene1002Door::suCloseDoor() {
+ if (_y < 239) {
+ _y += 8;
+ if (_y > 239) {
+ SetSpriteCallback(NULL);
+ _y = 239;
+ }
+ _needRefresh = true;
+ }
+}
+
+Class505::Class505(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1400) {
+
+ createSurface(1025, 88, 165);
+ setVisible(false);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class505::handleMessage);
+}
+
+uint32 Class505::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2004:
+ _x = ((Sprite*)sender)->getX() - 98;
+ _y = ((Sprite*)sender)->getY() - 111;
+ setFileHash(0x0422255A, 0, -1);
+ setVisible(true);
+ break;
+ case 0x3002:
+ stopAnimation();
+ setVisible(false);
+ break;
+ }
+ return messageResult;
+}
+
+AsScene1002DoorSpy::AsScene1002DoorSpy(NeverhoodEngine *vm, NRect &clipRect, Scene *parentScene, Sprite *asDoor, Sprite *class505)
+ : AnimatedSprite(vm, 1300), _rect(clipRect), _parentScene(parentScene), _asDoor(asDoor), _class505(class505),
+ _soundResource(vm) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1002DoorSpy::handleMessage4489D0);
+ SetSpriteCallback(&AsScene1002DoorSpy::spriteUpdate448AA0);
+ createSurface(800, 136, 147);
+ setClipRect(clipRect);
+ spriteUpdate448AA0();
+ _soundResource.load(0xC0C40298);
+ setFileHash(0x586C1D48, 0, 0);
+}
+
+uint32 AsScene1002DoorSpy::handleMessage4489D0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0xA61CA1C2) {
+ sendMessage(_class505, 0x2004, 0);
+ } else if (param.asInteger() == 0x14CE0620) {
+ _soundResource.play();
+ }
+ break;
+ case 0x2003:
+ sub448B10();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002DoorSpy::handleMessage448A60(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage4489D0(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1002DoorSpy::spriteUpdate448AA0() {
+ _x = _asDoor->getX() + 34;
+ _y = _asDoor->getY() + 175;
+}
+
+void AsScene1002DoorSpy::sub448AC0() {
+ setClipRect(_rect);
+ _parentScene->setSurfacePriority(getSurface(), 800);
+ setFileHash(0x586C1D48, 0, 0);
+ SetMessageHandler(&AsScene1002DoorSpy::handleMessage4489D0);
+}
+
+void AsScene1002DoorSpy::sub448B10() {
+ setClipRect(0, 0, 640, 480);
+ _parentScene->setSurfacePriority(getSurface(), 1200);
+ setFileHash(0x586C1D48, 1, -1);
+ SetMessageHandler(&AsScene1002DoorSpy::handleMessage448A60);
+ NextState(&AsScene1002DoorSpy::sub448AC0);
+}
+
+Class426::Class426(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash)
+ : StaticSprite(vm, 1100), _parentScene(parentScene), _soundResource(vm), _status(0) {
+
+ _soundFileHash = soundFileHash != 0 ? soundFileHash : 0x44141000;
+
+ _fileHashes[0] = fileHash1;
+ _fileHashes[1] = fileHash2;
+
+ _spriteResource.load2(fileHash1);
+ createSurface(surfacePriority, 40, 40);
+
+ _surface->getDrawRect().x = 0;
+ _surface->getDrawRect().y = 0;
+ _surface->getDrawRect().width = _spriteResource.getDimensions().width;
+ _surface->getDrawRect().height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+
+ setVisible(false);
+ _needRefresh = true;
+
+ SetUpdateHandler(&Class426::update);
+ SetMessageHandler(&Class426::handleMessage);
+
+}
+
+void Class426::setFileHashes(uint32 fileHash1, uint32 fileHash2) {
+ _fileHashes[0] = fileHash1;
+ _fileHashes[1] = fileHash2;
+ if (_status == 2) {
+ _spriteResource.load2(fileHash2);
+ _surface->getDrawRect().x = 0;
+ _surface->getDrawRect().y = 0;
+ _surface->getDrawRect().width = _spriteResource.getDimensions().width;
+ _surface->getDrawRect().height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _needRefresh = true;
+ StaticSprite::update();
+ } else {
+ _spriteResource.load2(fileHash1);
+ _surface->getDrawRect().x = 0;
+ _surface->getDrawRect().y = 0;
+ _surface->getDrawRect().width = _spriteResource.getDimensions().width;
+ _surface->getDrawRect().height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _needRefresh = true;
+ StaticSprite::update();
+ }
+}
+
+void Class426::update() {
+ if (_countdown != 0 && (--_countdown) == 0) {
+ if (_status == 1) {
+ _status = 2;
+ _spriteResource.load2(_fileHashes[1]);
+ _surface->getDrawRect().x = 0;
+ _surface->getDrawRect().y = 0;
+ _surface->getDrawRect().width = _spriteResource.getDimensions().width;
+ _surface->getDrawRect().height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _needRefresh = true;
+ StaticSprite::update();
+ _countdown = 4;
+ } else if (_status == 2) {
+ _status = 3;
+ _spriteResource.load2(_fileHashes[0]);
+ _surface->getDrawRect().x = 0;
+ _surface->getDrawRect().y = 0;
+ _surface->getDrawRect().width = _spriteResource.getDimensions().width;
+ _surface->getDrawRect().height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _needRefresh = true;
+ StaticSprite::update();
+ _countdown = 4;
+ } else if (_status == 3) {
+ _status = 0;
+ setVisible(false);
+ }
+ }
+}
+
+uint32 Class426::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x480B:
+ sendMessage(_parentScene, 0x480B, 0);
+ _status = 1;
+ _countdown = 4;
+ setVisible(true);
+ _soundResource.play(_soundFileHash);
+ break;
+ }
+ return messageResult;
+}
+
+AsScene1002VenusFlyTrap::AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman, bool flag)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene), _klayman(klayman),
+ _flag(flag), _countdown(0) {
+
+ createSurface(995, 175, 195);
+
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448000);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+
+ if (!_flag) {
+ if (getGlobalVar(0x8306F218)) {
+ setDoDeltaX(1);
+ _x = 366;
+ _y = 435;
+ sub4485F0();
+ } else {
+ _x = 174 + getGlobalVar(0x1B144052) * 32;
+ _y = 435;
+ sub448660();
+ }
+ } else {
+ _x = 186 + getGlobalVar(0x86341E88) * 32;
+ _y = 364;
+ if (getGlobalVar(0x13206309) || getGlobalVar(0x80101B1E)) {
+ sub4485F0();
+ } else {
+ sub448660();
+ }
+ }
+
+ _flags = 4;
+}
+
+void AsScene1002VenusFlyTrap::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ removeCallbacks();
+ }
+ AnimatedSprite::update();
+}
+
+void AsScene1002VenusFlyTrap::update447FB0() {
+ if (_countdown == 0 && _klayman->getX() - 20 > _x) {
+ setDoDeltaX(1);
+ } else if (_klayman->getX() + 20 < _x) {
+ setDoDeltaX(0);
+ }
+ update();
+}
+
+uint32 AsScene1002VenusFlyTrap::handleMessage448000(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x000890C4) {
+ _soundResource.play(0xC21190D8);
+ } else if (param.asInteger() == 0x522200A0) {
+ _soundResource.play(0x931080C8);
+ }
+ break;
+ case 0x1011:
+ if (_flag) {
+ if (_x >= 154 && _x <= 346) {
+ sendMessage(_parentScene, 0x2000, 0);
+ messageResult = 1;
+ }
+ } else {
+ if (_x >= 174 && _x <= 430) {
+ sendMessage(_parentScene, 0x2000, 0);
+ messageResult = 1;
+ }
+ }
+ break;
+ case 0x480B:
+ setDoDeltaX(param.asInteger() != 0 ? 1 : 0);
+ if (!_flag) {
+ if (getGlobalVar(0x8306F218)) {
+ sub448560();
+ } else {
+ sub448530();
+ }
+ } else {
+ if (getGlobalVar(0x13206309) || getGlobalVar(0x80101B1E)) {
+ sub448560();
+ } else {
+ sub448530();
+ }
+ }
+ break;
+ case 0x480C:
+ if (_flag) {
+ if (_x >= 154 && _x <= 346)
+ messageResult = 1;
+ else
+ messageResult = 0;
+ } else {
+ if (_x >= 174 && _x <= 430)
+ messageResult = 1;
+ else
+ messageResult = 0;
+ }
+ break;
+ case 0x480E:
+ if (param.asInteger() == 1) {
+ sub4485B0();
+ }
+ break;
+ case 0x4810:
+ sub448780();
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 995);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1015);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002VenusFlyTrap::handleMessage4482E0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage448000(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1002VenusFlyTrap::handleMessage448320(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x000890C4) {
+ _soundResource.play(0xC21190D8);
+ } else if (param.asInteger() == 0x41881801) {
+ if (_flag) {
+ if (_x > 330) {
+ sendMessage(_klayman, 0x4811, 2);
+ } else if (_x > 265) {
+ sendMessage(_klayman, 0x4811, 0);
+ } else {
+ sendMessage(_klayman, 0x4811, 0);
+ }
+ } else {
+ sendMessage(_klayman, 0x4811, 0);
+ }
+ } else if (param.asInteger() == 0x522200A0) {
+ _soundResource.play(0x931080C8);
+ }
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 995);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1015);
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1002VenusFlyTrap::sub4484F0() {
+ setDoDeltaX(2);
+ setFileHash(0xC4080034, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448320);
+ NextState(&AsScene1002VenusFlyTrap::sub448660);
+}
+
+void AsScene1002VenusFlyTrap::sub448530() {
+ setFileHash(0xC4080034, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage4482E0);
+ NextState(&AsScene1002VenusFlyTrap::sub448660);
+}
+
+void AsScene1002VenusFlyTrap::sub448560() {
+ sendMessage(_parentScene, 0x4807, 0);
+ setFileHash(0x82292851, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage4482E0);
+ NextState(&AsScene1002VenusFlyTrap::sub448660);
+}
+
+void AsScene1002VenusFlyTrap::sub4485B0() {
+ setDoDeltaX(1);
+ setFileHash(0x86A82A11, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage4482E0);
+ NextState(&AsScene1002VenusFlyTrap::sub4485F0);
+}
+
+void AsScene1002VenusFlyTrap::sub4485F0() {
+ setFileHash(0xB5A86034, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448000);
+}
+
+void AsScene1002VenusFlyTrap::sub448620() {
+ setFileHash(0x31303094, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(NULL);
+ NextState(&AsScene1002VenusFlyTrap::sub448720);
+ _countdown = 24;
+}
+
+void AsScene1002VenusFlyTrap::sub448660() {
+ setFileHash(0xC8204250, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update447FB0);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448000);
+ if (_flag) {
+ if (_x >= 154 && _x <= 346) {
+ setGlobalVar(0x86341E88, (_x - 186) / 32);
+ } else {
+ NextState(&AsScene1002VenusFlyTrap::sub4484F0);
+ _countdown = 12;
+ }
+ } else {
+ if (_x >= 174 && _x <= 430) {
+ setGlobalVar(0x1B144052, (_x - 174) / 32);
+ } else {
+ NextState(&AsScene1002VenusFlyTrap::sub4484F0);
+ _countdown = 12;
+ }
+ }
+}
+
+void AsScene1002VenusFlyTrap::sub448720() {
+ setFileHash(0x152920C4, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448320);
+ NextState(&AsScene1002VenusFlyTrap::sub448750);
+}
+
+void AsScene1002VenusFlyTrap::sub448750() {
+ setFileHash(0x84001117, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448320);
+ NextState(&AsScene1002VenusFlyTrap::sub448660);
+}
+
+void AsScene1002VenusFlyTrap::sub448780() {
+ if (_x - 15 < _klayman->getX() && _x + 15 > _klayman->getX()) {
+ if (_flag) {
+ setDoDeltaX(_x > 265 && _x < 330 ? 1 : 0);
+ } else {
+ setDoDeltaX(_x > 320 ? 1 : 0);
+ }
+ sendMessage(_klayman, 0x2001, 0);
+ setFileHash(0x8C2C80D4, 0, -1);
+ SetUpdateHandler(&AsScene1002VenusFlyTrap::update);
+ SetMessageHandler(&AsScene1002VenusFlyTrap::handleMessage448320);
+ NextState(&AsScene1002VenusFlyTrap::sub448620);
+ }
+}
+
+Class506::Class506(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1200), _countdown(0) {
+
+ createSurface(850, 186, 212);
+ _x = 320;
+ _y = 240;
+ if (getGlobalVar(0x8306F218)) {
+ setFileHash(0x004A4495, -1, -1);
+ _newHashListIndex = -2;
+ } else {
+ setVisible(false);
+ }
+ SetUpdateHandler(&Class506::update);
+ SetMessageHandler(&Class506::handleMessage4491B0);
+}
+
+void Class506::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ if (_flag) {
+ sub449280();
+ } else {
+ sub449250();
+ }
+ }
+ AnimatedSprite::update();
+}
+
+uint32 Class506::handleMessage4491B0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageResult) {
+ case 0x4808:
+ _flag = false;
+ _countdown = 2;
+ break;
+ case 0x4809:
+ _flag = true;
+ _countdown = 2;
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Class506::handleMessage449210(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage4491B0(messageNum, param, sender);
+ switch (messageResult) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void Class506::sub449250() {
+ setFileHash(0x004A4495, 0, -1);
+ SetMessageHandler(&Class506::handleMessage4491B0);
+ _newHashListIndex = -2;
+ setVisible(true);
+}
+
+void Class506::sub449280() {
+ setFileHash(0x004A4495, -1, -1);
+ _playBackwards = true;
+ SetMessageHandler(&Class506::handleMessage449210);
+ NextState(&Class506::sub4492C0);
+ setVisible(true);
+}
+
+void Class506::sub4492C0() {
+ setVisible(false);
+ stopAnimation();
+}
+
+Class478::Class478(NeverhoodEngine *vm, Klayman *klayman)
+ : AnimatedSprite(vm, 1200), _klayman(klayman) {
+
+ createSurface(1200, 40, 163);
+ SetUpdateHandler(&Class478::update);
+ SetMessageHandler(&Sprite::handleMessage);
+ setVisible(false);
+}
+
+void Class478::update() {
+ if (_klayman->getCurrAnimFileHash() == 0x3A292504) {
+ setFileHash(0xBA280522, _frameIndex, -1);
+ _newHashListIndex = _klayman->getFrameIndex();
+ setVisible(true);
+ _x = _klayman->getX();
+ _y = _klayman->getY();
+ setDoDeltaX(_klayman->isDoDeltaX() ? 1 : 0);
+ } else if (_klayman->getCurrAnimFileHash() == 0x122D1505) {
+ setFileHash(0x1319150C, _frameIndex, -1);
+ _newHashListIndex = _klayman->getFrameIndex();
+ setVisible(true);
+ _x = _klayman->getX();
+ _y = _klayman->getY();
+ setDoDeltaX(_klayman->isDoDeltaX() ? 1 : 0);
+ } else {
+ setVisible(false);
+ }
+ AnimatedSprite::update();
+}
+
+Class479::Class479(NeverhoodEngine *vm, Scene *parentScene, Klayman *klayman)
+ : AnimatedSprite(vm, 1200), _parentScene(parentScene), _klayman(klayman),
+ _flag1(false) {
+
+ SetUpdateHandler(&Class479::update);
+ SetMessageHandler(&Class479::handleMessage);
+ createSurface(1000, 33, 41);
+ setVisible(false);
+}
+
+void Class479::update() {
+ if (_klayman->getCurrAnimFileHash() == 0xAC20C012 && _klayman->getFrameIndex() < 50) {
+ setFileHash(0x9820C913, _klayman->getFrameIndex(), -1);
+ _newHashListIndex = _klayman->getFrameIndex();
+ setVisible(true);
+ _x = _klayman->getX();
+ _y = _klayman->getY();
+ setDoDeltaX(_klayman->isDoDeltaX() ? 1 : 0);
+ } else {
+ setVisible(false);
+ }
+ AnimatedSprite::update();
+}
+
+uint32 Class479::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4AB28209) {
+ sendMessage(_parentScene, 0x1022, 1200);
+ _flag1 = true;
+ _savedClipRect = _surface->getClipRect();
+ setClipRect(0, 0, 640, 480);
+ } else if (param.asInteger() == 0x88001184) {
+ sendMessage(_parentScene, 0x1022, 1000);
+ if (_flag1) {
+ setClipRect(_savedClipRect);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+Scene1002::Scene1002(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource1(vm), _soundResource2(vm), _soundResource3(vm),
+ _flag1B4(false), _flag1BE(false) {
+
+ NRect tempClipRect;
+ Sprite *tempSprite;
+
+ SetUpdateHandler(&Scene1002::update);
+ SetMessageHandler(&Scene1002::handleMessage);
+
+ setHitRects(0x004B4138);
+
+ _surfaceFlag = true;
+
+ setBackground(0x12C23307);
+ setPalette(0x12C23307);
+
+ _flag = false;
+
+ insertStaticSprite(0x06149428, 1100);
+ insertStaticSprite(0x312C8774, 1100);
+
+ _ssLadderArch = insertSprite<SsScene1002LadderArch>(this);
+ _ssLadderArchPart1 = insertStaticSprite(0x060000A0, 1200);
+ _ssLadderArchPart2 = insertStaticSprite(0xB2A423B0, 1100);
+ _ssLadderArchPart3 = insertStaticSprite(0x316E0772, 1100);
+
+ _class599 = insertSprite<Class599>(this);
+
+ if (which < 0) {
+ if (_vm->_gameState.field2 == 0) {
+ insertKlayman<KmScene1002>(90, 226, _class599, _ssLadderArch);
+ _class478 = insertSprite<Class478>(_klayman);
+ setMessageList(0x004B4270);
+ _klayman->setClipRect(31, 0, _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart3->getDrawRect().y2());
+ _class478->getSurface()->getClipRect() = _klayman->getSurface()->getClipRect();
+ _klayman->setRepl(64, 0);
+ } else {
+ insertKlayman<KmScene1002>(379, 435, _class599, _ssLadderArch);
+ _class478 = insertSprite<Class478>(_klayman);
+ setMessageList(0x004B4270);
+ _klayman->setClipRect(_ssLadderArch->getDrawRect().x, 0, _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart1->getDrawRect().y2());
+ _class478->setClipRect(_klayman->getClipRect());
+ }
+ } else if (which == 1) {
+ insertKlayman<KmScene1002>(650, 435, _class599, _ssLadderArch);
+ _class478 = insertSprite<Class478>(_klayman);
+ setMessageList(0x004B4478);
+ _klayman->setClipRect(_ssLadderArch->getDrawRect().x, 0, _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart1->getDrawRect().y2());
+ _class478->setClipRect(_klayman->getClipRect());
+ _vm->_gameState.field2 = 1;
+ } else if (which == 2) {
+ insertKlayman<KmScene1002>(68, 645, _class599, _ssLadderArch);
+ _class478 = insertSprite<Class478>(_klayman);
+ setMessageList(0x004B4298);
+ _klayman->setClipRect(_ssLadderArch->getDrawRect().x, 0, _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart1->getDrawRect().y2());
+ _class478->setClipRect(_klayman->getClipRect());
+ _vm->_gameState.field2 = 1;
+ sendMessage(_klayman, 0x4820, 0);
+ } else {
+ insertKlayman<KmScene1002>(90, 226, _class599, _ssLadderArch);
+ _class478 = insertSprite<Class478>(_klayman);
+ setMessageList(0x004B4470);
+ _klayman->setClipRect(31, 0, _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart3->getDrawRect().y2());
+ _class478->setClipRect(_klayman->getClipRect());
+ _class479 = insertSprite<Class479>(this, _klayman);
+ _class479->setClipRect(_klayman->getClipRect());
+ _klayman->setRepl(64, 0);
+ _vm->_gameState.field2 = 0;
+ }
+
+ insertMouse433(0x23303124);
+
+ tempSprite = insertStaticSprite(0xB3242310, 825);
+ tempClipRect.set(tempSprite->getDrawRect().x, tempSprite->getDrawRect().y,
+ _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart2->getDrawRect().y2());
+
+ _asRing1 = insertSprite<AsScene1002Ring>(this, false, 258, 191, _class599->getDrawRect().y, false);
+ _asRing2 = insertSprite<AsScene1002Ring>(this, false, 297, 189, _class599->getDrawRect().y, false);
+ _asRing3 = insertSprite<AsScene1002Ring>(this, true, 370, 201, _class599->getDrawRect().y, getGlobalVar(0x8306F218) != 0);
+ _asRing4 = insertSprite<AsScene1002Ring>(this, false, 334, 191, _class599->getDrawRect().y, false);
+ _asRing5 = insertSprite<AsScene1002Ring>(this, false, 425, 184, _class599->getDrawRect().y, false);
+
+ _asDoor = insertSprite<AsScene1002Door>(tempClipRect);
+ tempSprite = insertSprite<Class505>();
+ _asDoorSpy = insertSprite<AsScene1002DoorSpy>(tempClipRect, this, _asDoor, tempSprite);
+ _class426 = insertSprite<Class426>(this, 0x00412692, 0x140B60BE, 800, 0);
+ _asVenusFlyTrap = insertSprite<AsScene1002VenusFlyTrap>(this, _klayman, false);
+ _vm->_collisionMan->addSprite(_asVenusFlyTrap);
+
+ sendEntityMessage(_klayman, 0x2007, _asVenusFlyTrap);
+
+ _class506 = insertSprite<Class506>();
+
+ setRectList(0x004B43A0);
+
+ _soundResource2.load(0x60755842);
+ _soundResource3.load(0x616D5821);
+
+}
+
+Scene1002::~Scene1002() {
+}
+
+void Scene1002::update() {
+ Scene::update();
+ if (!_flag1B4 && _klayman->getY() > 230) {
+ _klayman->setClipRect(_ssLadderArch->getDrawRect().x, 0, _ssLadderArchPart2->getDrawRect().x2(), _ssLadderArchPart1->getDrawRect().y2());
+ _class478->setClipRect(_klayman->getClipRect());
+ deleteSprite(&_ssLadderArchPart3);
+ _klayman->clearRepl();
+ _flag1B4 = true;
+ _vm->_gameState.field2 = 1;
+ }
+
+ if (_flag1BE && _klayman->getY() > 422) {
+ sendMessage(_parentModule, 0x1024, 1);
+ _flag1BE = false;
+ }
+
+}
+
+uint32 Scene1002::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ debug("Scene1002::handleMessage(%04X)", messageNum);
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // Debug stuff (original)
+ if (param.asPoint().x == 0 && getGlobalVar(0xA4014072)) {
+ setGlobalVar(0x8306F218, 1);
+ setGlobalVar(0x1B144052, 3);
+ leaveScene(1);
+ }
+ break;
+ case 0x000D:
+ // Debug stuff (original)
+ if (param.asInteger() == 0x48848178) {
+ setGlobalVar(0x8306F218, 1);
+ setGlobalVar(0x1B144052, 3);
+ leaveScene(1);
+ }
+ messageResult = 1;
+ break;
+ case 0x100D:
+ if (param.asInteger() == 0xE6EE60E1) {
+ if (getGlobalVar(0x8306F218)) {
+ setMessageList(0x004B4428);
+ } else {
+ setMessageList(0x004B4448);
+ }
+ messageResult = 1;
+ } else if (param.asInteger() == 0x4A845A00) {
+ sendEntityMessage(_klayman, 0x1014, _asRing1);
+ } else if (param.asInteger() == 0x43807801) {
+ sendEntityMessage(_klayman, 0x1014, _asRing2);
+ } else if (param.asInteger() == 0x46C26A01) {
+ if (getGlobalVar(0x8306F218)) {
+ setMessageList(0x004B44B8);
+ } else {
+ sendEntityMessage(_klayman, 0x1014, _asRing3);
+ if (_asVenusFlyTrap->getX() - 10 < 366 && _asVenusFlyTrap->getX() + 10 > 366) {
+ setGlobalVar(0x2B514304, 1);
+ setMessageList(0x004B44A8);
+ } else {
+ setMessageList(0x004B44A0);
+ }
+ }
+ messageResult = 1;
+ } else if (param.asInteger() == 0x468C7B11) {
+ sendEntityMessage(_klayman, 0x1014, _asRing4);
+ } else if (param.asInteger() == 0x42845B19) {
+ sendEntityMessage(_klayman, 0x1014, _asRing5);
+ } else if (param.asInteger() == 0xC0A07458) {
+ sendEntityMessage(_klayman, 0x1014, _class426);
+ }
+ break;
+ case 0x1024:
+ sendMessage(_parentModule, 0x1024, param.asInteger());
+ break;
+ case 0x2000:
+ if (_flag) {
+ setMessageList2(0x004B43D0);
+ } else {
+ if (_klayman->getY() > 420) {
+ sendEntityMessage(_klayman, 0x1014, _asVenusFlyTrap);
+ setMessageList2(0x004B4480);
+ } else if (_klayman->getY() > 227) {
+ setMessageList2(0x004B41E0);
+ } else {
+ setMessageList2(0x004B4148);
+ }
+ }
+ break;
+ case 0x2002:
+ _messageList = NULL;
+ break;
+ case 0x2005:
+ _flag = true;
+ setRectList(0x004B4418);
+ break;
+ case 0x2006:
+ _flag = false;
+ setRectList(0x004B43A0);
+ break;
+ case 0x4806:
+ sendMessage(_parentModule, 0x1024, 2);
+ _flag1BE = true;
+ if (sender == _asRing1) {
+ setGlobalVar(0x4DE80AC0, 0);
+ _soundResource1.play(0x665198C0);
+ } else if (sender == _asRing2) {
+ setGlobalVar(0x4DE80AC0, 0);
+ _soundResource1.play(0xE2D389C0);
+ } else if (sender == _asRing3) {
+ setGlobalVar(0x4DE80AC0, 0);
+ _soundResource2.play();
+ sendMessage(_asDoor, 0x4808, 0);
+ sendMessage(_class506, 0x4808, 0);
+ } else if (sender == _asRing4) {
+ setGlobalVar(0x4DE80AC0, 0);
+ _soundResource1.play(0xE0558848);
+ } else if (sender == _asRing5) {
+ setGlobalVar(0x4DE80AC0, 1);
+ _soundResource1.play(0x44014282);
+ }
+ break;
+ case 0x4807:
+ if (sender == _asRing3) {
+ _soundResource3.play();
+ sendMessage(_asDoor, 0x4809, 0);
+ sendMessage(_class506, 0x4809, 0);
+ } else if (sender == _asVenusFlyTrap) {
+ if (getGlobalVar(0x8306F218)) {
+ sendMessage(_asRing3, 0x4807, 0);
+ }
+ }
+ break;
+ case 0x480B:
+ sendEntityMessage(_klayman, 0x1014, _asDoorSpy);
+ break;
+ case 0x480F:
+ setGlobalVar(0x4DE80AC0, 0);
+ _soundResource2.play();
+ sendMessage(_asDoor, 0x4808, 0);
+ sendMessage(_class506, 0x4808, 0);
+ break;
+ }
+ return messageResult;
+}
+
+// Class152
+
+Class152::Class152(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash)
+ : Scene(vm, parentModule, true), _fieldD0(-1), _fieldD2(-1) {
+
+ _surfaceFlag = false;
+
+ SetMessageHandler(&Class152::handleMessage);
+
+ setBackground(backgroundFileHash);
+ setPalette(backgroundFileHash);
+ insertMouse435(cursorFileHash, 20, 620);
+}
+
+uint32 Class152::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ leaveScene(0);
+ }
+ break;
+ }
+ return 0;
+}
+
+// Scene1004
+
+AsScene1004TrashCan::AsScene1004TrashCan(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100), _soundResource(vm) {
+
+ _x = 330;
+ _y = 327;
+ createSurface(800, 56, 50);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1004TrashCan::handleMessage);
+ setVisible(false);
+}
+
+uint32 AsScene1004TrashCan::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x225A8587) {
+ _soundResource.play(0x109AFC4C);
+ }
+ break;
+ case 0x2002:
+ setFileHash(0xEB312C11, 0, -1);
+ setVisible(true);
+ break;
+ case 0x3002:
+ stopAnimation();
+ setVisible(false);
+ break;
+ }
+ return 0;
+}
+
+Scene1004::Scene1004(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _paletteAreaStatus(-1) {
+
+ Sprite *tempSprite;
+
+ _surfaceFlag = true;
+
+ SetUpdateHandler(&Scene1004::update);
+ SetMessageHandler(&Scene1004::handleMessage);
+
+ setBackground(0x50C03005);
+
+ if (getGlobalVar(0x0D0A14D10)) {
+ setPalette(0xA30BA329);
+ _palette->addBasePalette(0xA30BA329, 0, 256, 0);
+ } else {
+ setPalette(0x50C03005);
+ _palette->addBasePalette(0x50C03005, 0, 256, 0);
+ }
+ addEntity(_palette);
+
+ insertMouse433(0x03001504);
+
+ if (which < 0) {
+ setRectList(0x004B7C70);
+ insertKlayman<KmScene1004>(330, 327);
+ setMessageList(0x004B7C18);
+ } else if (which == 1) {
+ setRectList(0x004B7C70);
+ insertKlayman<KmScene1004>(330, 327);
+ setMessageList(0x004B7C08);
+ } else {
+ loadDataResource(0x01900A04);
+ insertKlayman<KmScene1004>(_dataResource.getPoint(0x80052A29).x, 27);
+ setMessageList(0x004B7BF0);
+ }
+
+ updatePaletteArea();
+
+ _class478 = insertSprite<Class478>(_klayman);
+
+ insertStaticSprite(0x800034A0, 1100);
+ insertStaticSprite(0x64402020, 1100);
+ insertStaticSprite(0x3060222E, 1300);
+ tempSprite = insertStaticSprite(0x0E002004, 1300);
+
+ _klayman->setClipRect(0, tempSprite->getDrawRect().y, 640, 480);
+ _class478->setClipRect(_klayman->getClipRect());
+
+ _asTrashCan = insertSprite<AsScene1004TrashCan>();
+
+}
+
+void Scene1004::update() {
+ Scene::update();
+ updatePaletteArea();
+}
+
+uint32 Scene1004::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x926500A1) {
+ setMessageList(0x004B7C20);
+ messageResult = 1;
+ }
+ break;
+ case 0x2000:
+ loadDataResource(0x01900A04);
+ break;
+ case 0x2001:
+ setRectList(0x004B7C70);
+ break;
+ case 0x2002:
+ sendMessage(_asTrashCan, 0x2002, 0);
+ break;
+ }
+ return messageResult;
+}
+
+void Scene1004::updatePaletteArea() {
+ if (_klayman->getY() < 150) {
+ if (_paletteAreaStatus != 0) {
+ _paletteAreaStatus = 0;
+ _palette->addBasePalette(0x406B0D10, 0, 64, 0);
+ _palette->startFadeToPalette(12);
+ }
+ } else {
+ if (_paletteAreaStatus != 1) {
+ _paletteAreaStatus = 1;
+ _palette->addBasePalette(0x24332243, 0, 64, 0);
+ _palette->startFadeToPalette(12);
+ }
+ }
+}
+
+// Scene1005
+
+Scene1005::Scene1005(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ SetMessageHandler(&Scene1005::handleMessage);
+
+ _surfaceFlag = true;
+
+ if (getGlobalVar(0xD0A14D10)) {
+ setBackground(0x2800E011);
+ setPalette(0x2800E011);
+ insertStaticSprite(0x492D5AD7, 100);
+ insertMouse435(0x0E015288, 20, 620);
+ } else {
+ setBackground(0x8870A546);
+ setPalette(0x8870A546);
+ insertStaticSprite(0x40D1E0A9, 100);
+ insertStaticSprite(0x149C00A6, 100);
+ insertMouse435(0x0A54288F, 20, 620);
+ }
+
+ drawTextToBackground();
+
+}
+
+uint32 Scene1005::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ leaveScene(0);
+ }
+ break;
+ }
+ return 0;
+}
+
+void Scene1005::drawTextToBackground() {
+ TextResource textResource(_vm);
+ const char *textStart, *textEnd;
+ int16 y = 36;
+ uint32 textIndex = getTextIndex();
+ FontSurface *fontSurface = createFontSurface();
+ textResource.load(0x80283101);
+ textStart = textResource.getString(textIndex, textEnd);
+ while (textStart < textEnd) {
+ fontSurface->drawString(_background->getSurface(), 188, y, (const byte*)textStart);
+ y += 36;
+ textStart += strlen(textStart) + 1;
+ }
+ delete fontSurface;
+}
+
+FontSurface *Scene1005::createFontSurface() {
+ FontSurface *fontSurface;
+ DataResource fontData(_vm);
+ SpriteResource fontSprite(_vm);
+ fontData.load(calcHash("asRecFont"));
+ uint16 numRows = fontData.getPoint(calcHash("meNumRows")).x;
+ uint16 firstChar = fontData.getPoint(calcHash("meFirstChar")).x;
+ uint16 charWidth = fontData.getPoint(calcHash("meCharWidth")).x;
+ uint16 charHeight = fontData.getPoint(calcHash("meCharHeight")).x;
+ NPointArray *tracking = fontData.getPointArray(calcHash("meTracking"));
+ fontSurface = new FontSurface(_vm, tracking, numRows, firstChar, charWidth, charHeight);
+ if (getGlobalVar(0xD0A14D10)) {
+ fontSprite.load2(0x283CE401);
+ } else {
+ fontSprite.load2(0xC6604282);
+ }
+ fontSurface->drawSpriteResourceEx(fontSprite, false, false, 0, 0);
+ return fontSurface;
+}
+
+uint32 Scene1005::getTextIndex() {
+ uint32 textIndex;
+ textIndex = getTextIndex1();
+ if (getGlobalVar(0xD0A14D10)) {
+ textIndex = getTextIndex2();
+ }
+ if (getGlobalVar(0x8440001F) && getGlobalVar(0x01830201) == textIndex) {
+ textIndex = getTextIndex3();
+ } else {
+ setGlobalVar(0x8440001F, 1);
+ setGlobalVar(0x01830201, textIndex);
+ }
+ return textIndex;
+}
+
+uint32 Scene1005::getTextIndex1() {
+ uint32 textIndex;
+ if (getGlobalVar(0x98109F12)) {
+ if (!getGlobalVar(0x2090590C))
+ textIndex = 18;
+ else if (!getGlobalVar(0x610210B7))
+ textIndex = 19;
+ else if (getGlobalVar(0x0C0288F4)) {
+ if (!getGlobalVar(0xD0A14D10))
+ textIndex = 23;
+ else if (!getSubVar(0x0090EA95, 0) && !getSubVar(0x08D0AB11, 0))
+ textIndex = 24;
+ else if (!getGlobalVar(0xC0780812))
+ textIndex = 26;
+ else if (!getSubVar(0x0090EA95, 1) && !getSubVar(0x08D0AB11, 1))
+ textIndex = 27;
+ else if (!getGlobalVar(0xC0780812))
+ textIndex = 28;
+ else
+ textIndex = 29;
+ } else if (!getGlobalVar(0xE7498218))
+ textIndex = 20;
+ else if (!getGlobalVar(0x081890D14))
+ textIndex = 21;
+ else
+ textIndex = 22;
+ } else if (getGlobalVar(0x00040153)) {
+ if (!getGlobalVar(0x10938830))
+ textIndex = 12;
+ else if (!getGlobalVar(0x2050861A))
+ textIndex = 13;
+ else if (!getGlobalVar(0x4DE80AC0))
+ textIndex = 50;
+ else if (!getGlobalVar(0x89C669AA))
+ textIndex = 14;
+ else if (!getGlobalVar(0x1C1B8A9A))
+ textIndex = 15;
+ else if (!getGlobalVar(0xCB45DE03))
+ textIndex = 16;
+ else
+ textIndex = 17;
+ } else if (!getGlobalVar(0x2B514304)) {
+ textIndex = 0;
+ } else if (getGlobalVar(0x0A18CA33)) {
+ if (!getGlobalVar(0x404290D5))
+ textIndex = 4;
+ else if (!getGlobalVar(0x45080C38))
+ textIndex = 5;
+ else if (!getSubVar(0x14800353, 0x40119852))
+ textIndex = 6;
+ else if (!getGlobalVar(0x4E0BE910))
+ textIndex = 7;
+ else if (!getGlobalVar(0x86615030))
+ textIndex = 8;
+ else if (!getSubVar(0x14800353, 0x304008D2))
+ textIndex = 9;
+ else if (!getSubVar(0x14800353, 0x01180951))
+ textIndex = 10;
+ else
+ textIndex = 11;
+ } else if (!getGlobalVar(0x0A310817)) {
+ textIndex = 1;
+ } else if (getGlobalVar(0x000CF819)) {
+ textIndex = 3;
+ } else {
+ textIndex = 2;
+ }
+ return textIndex;
+}
+
+uint32 Scene1005::getTextIndex2() {
+ uint32 textIndex = getGlobalVar(0x29408F00);
+ if (textIndex + 1 >= 10) {
+ setGlobalVar(0x29408F00, 0);
+ textIndex = 0;
+ } else {
+ setGlobalVar(0x29408F00, textIndex + 1);
+ }
+ return textIndex + 40;
+}
+
+uint32 Scene1005::getTextIndex3() {
+ uint32 textIndex = getGlobalVar(0x8A140C21);
+ if (textIndex + 1 >= 10) {
+ setGlobalVar(0x8A140C21, 0);
+ textIndex = 0;
+ } else {
+ setGlobalVar(0x8A140C21, textIndex + 1);
+ }
+ return textIndex + 30;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1000.h b/engines/neverhood/module1000.h
new file mode 100644
index 0000000000..47b1a91229
--- /dev/null
+++ b/engines/neverhood/module1000.h
@@ -0,0 +1,336 @@
+/* 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_MODULE1000_H
+#define NEVERHOOD_MODULE1000_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module1000
+
+class Module1000 : public Module {
+public:
+ Module1000(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1000();
+protected:
+ uint32 _musicFileHash;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene1001
+
+class AsScene1001Door : public AnimatedSprite {
+public:
+ AsScene1001Door(NeverhoodEngine *vm);
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void handleMessage2000h();
+ void callback1();
+ void callback2();
+ void callback3();
+};
+
+class AsScene1001Hammer : public AnimatedSprite {
+public:
+ AsScene1001Hammer(NeverhoodEngine *vm, Sprite *asDoor);
+protected:
+ Sprite *_asDoor;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1001Window : public AnimatedSprite {
+public:
+ AsScene1001Window(NeverhoodEngine *vm);
+protected:
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1001Lever : public AnimatedSprite {
+public:
+ AsScene1001Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int deltaXType);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsCommonButtonSprite : public StaticSprite {
+public:
+ SsCommonButtonSprite(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, int surfacePriority, uint32 soundFileHash);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 _soundFileHash;
+ int16 _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1001 : public Scene {
+public:
+ Scene1001(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Scene1001();
+protected:
+ Sprite *_asHammer;
+ Sprite *_asDoor;
+ Sprite *_asWindow;
+ Sprite *_asLever;
+ Sprite *_ssButton;
+ int16 _fieldE4;
+ int16 _fieldE6;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// TODO: Move this to some common file since it's used several times
+
+class Class152 : public Scene {
+public:
+ Class152(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 cursorFileHash);
+protected:
+ // TODO: Are these used?
+ int16 _fieldD0;
+ int16 _fieldD2;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1002
+
+class SsScene1002LadderArch : public StaticSprite {
+public:
+ SsScene1002LadderArch(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Class599 : public StaticSprite {
+public:
+ Class599(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1002Ring : public AnimatedSprite {
+public:
+ AsScene1002Ring(NeverhoodEngine *vm, Scene *parentScene, bool flag1, int16 x, int16 y, int16 clipY1, bool flag2);
+protected:
+ Scene *_parentScene;
+ bool _flag1;
+ SoundResource _soundResource;
+ void update();
+ uint32 handleMessage4475E0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage447760(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage447890(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage447930(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage447A00(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1002Door : public StaticSprite {
+public:
+ AsScene1002Door(NeverhoodEngine *vm, NRect &clipRect);
+protected:
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suOpenDoor();
+ void suCloseDoor();
+};
+
+class Class505 : public AnimatedSprite {
+public:
+ Class505(NeverhoodEngine *vm);
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1002DoorSpy : public AnimatedSprite {
+public:
+ AsScene1002DoorSpy(NeverhoodEngine *vm, NRect &clipRect, Scene *parentScene, Sprite *asDoor, Sprite *class505);
+protected:
+ Scene *_parentScene;
+ Sprite *_asDoor;
+ Sprite *_class505;
+ SoundResource _soundResource;
+ NRect _rect;
+ uint32 handleMessage4489D0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage448A60(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate448AA0();
+ void sub448AC0();
+ void sub448B10();
+};
+
+class Class426 : public StaticSprite {
+public:
+ Class426(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash);
+ void setFileHashes(uint32 fileHash1, uint32 fileHash2);
+protected:
+ Scene *_parentScene;
+ int _countdown;
+ uint32 _fileHashes[2];
+ int _status;
+ SoundResource _soundResource;
+ uint32 _soundFileHash;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1002VenusFlyTrap : public AnimatedSprite {
+public:
+ AsScene1002VenusFlyTrap(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman, bool flag);
+protected:
+ Scene *_parentScene;
+ Sprite *_klayman;
+ int _countdown;
+ SoundResource _soundResource;
+ bool _flag;
+ void update();
+ void update447FB0();
+ uint32 handleMessage448000(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage4482E0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage448320(int messageNum, const MessageParam &param, Entity *sender);
+ void sub4484F0();
+ void sub448530();
+ void sub448560();
+ void sub4485B0();
+ void sub4485F0();
+ void sub448620();
+ void sub448660();
+ void sub448720();
+ void sub448750();
+ void sub448780();
+};
+
+class Class506 : public AnimatedSprite {
+public:
+ Class506(NeverhoodEngine *vm);
+protected:
+ int _countdown;
+ bool _flag;
+ void update();
+ uint32 handleMessage4491B0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage449210(int messageNum, const MessageParam &param, Entity *sender);
+ void sub449250();
+ void sub449280();
+ void sub4492C0();
+};
+
+class Class478 : public AnimatedSprite {
+public:
+ Class478(NeverhoodEngine *vm, Klayman *klayman);
+protected:
+ Klayman *_klayman;
+ void update();
+};
+
+class Class479 : public AnimatedSprite {
+public:
+ Class479(NeverhoodEngine *vm, Scene *parentScene, Klayman *klayman);
+protected:
+ Scene *_parentScene;
+ Klayman *_klayman;
+ bool _flag1;
+ NRect _savedClipRect;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1002 : public Scene {
+public:
+ Scene1002(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Scene1002();
+protected:
+ Sprite *_asRing1;
+ Sprite *_asRing2;
+ Sprite *_asRing3;
+ Sprite *_asRing4;
+ Sprite *_asRing5;
+ Sprite *_asDoor;
+ Sprite *_asDoorSpy;
+ Sprite *_asVenusFlyTrap;
+ Sprite *_ssLadderArch;
+ Sprite *_ssLadderArchPart1;
+ Sprite *_ssLadderArchPart2;
+ Sprite *_ssLadderArchPart3;
+ Sprite *_class599;
+ Sprite *_class478;
+ Sprite *_class479;
+ Sprite *_class506;
+ Sprite *_class426;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ bool _flag1B4;
+ bool _flag1BE;
+ bool _flag;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1004
+
+class AsScene1004TrashCan : public AnimatedSprite {
+public:
+ AsScene1004TrashCan(NeverhoodEngine *vm);
+protected:
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1004 : public Scene {
+public:
+ Scene1004(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_class478;
+ Sprite *_asTrashCan;
+ int _paletteAreaStatus;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void updatePaletteArea();
+};
+
+// Scene1005
+
+class Scene1005 : public Scene {
+public:
+ Scene1005(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void drawTextToBackground();
+ FontSurface *createFontSurface();
+ uint32 getTextIndex();
+ uint32 getTextIndex1();
+ uint32 getTextIndex2();
+ uint32 getTextIndex3();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1000_H */
diff --git a/engines/neverhood/module1100.cpp b/engines/neverhood/module1100.cpp
new file mode 100644
index 0000000000..52c9d92a33
--- /dev/null
+++ b/engines/neverhood/module1100.cpp
@@ -0,0 +1,719 @@
+/* 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/module1100.h"
+#include "neverhood/gamemodule.h"
+
+namespace Neverhood {
+
+Module1100::Module1100(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 1) {
+ createScene(9, 1);
+ } else {
+ createScene(9, 3);
+ }
+
+ // TODO Sound1ChList_addSoundResources(0x2C818, dword_4B85B0, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B85B0, true, 50, 600, 20, 250);
+ // TODO Sound1ChList_setSoundValues(0x74E01054, false, 100, 200, 10, 20);
+ // TODO Sound1ChList_setVolume(0x74E01054, 60);
+ // TODO Sound1ChList_sub_407C70(0x2C818, 0x41861371, 0x43A2507F);
+
+}
+
+Module1100::~Module1100() {
+ // TODO Sound1ChList_sub_407A50(0x2C818);
+}
+
+void Module1100::createScene(int sceneNum, int which) {
+ static const uint32 kSmackerFileHashList06[] = {0x10880805, 0x1088081D, 0};
+ static const uint32 kSmackerFileHashList07[] = {0x00290321, 0x01881000, 0};
+ debug("Module1100::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _countdown = 65;
+ createNavigationScene(0x004B8430, which);
+ break;
+ case 1:
+ _countdown = 50;
+ createNavigationScene(0x004B8460, which);
+ break;
+ case 2:
+ if (getGlobalVar(0x610210B7)) {
+ createNavigationScene(0x004B84F0, which);
+ } else {
+ createNavigationScene(0x004B8490, which);
+ }
+ break;
+ case 3:
+ if (getGlobalVar(0x610210B7)) {
+ createNavigationScene(0x004B8580, which);
+ } else {
+ createNavigationScene(0x004B8550, which);
+ }
+ break;
+ case 4:
+ _childObject = new Scene1105(_vm, this, which);
+ break;
+ case 5:
+ if (getGlobalVar(0x610210B7))
+ createSmackerScene(0x04180001, true, false, false);
+ else
+ createSmackerScene(0x04180007, true, false, false);
+ break;
+ case 6:
+ // TODO Sound1ChList_sub_407AF0(0x2C818);
+ createSmackerScene(kSmackerFileHashList06, true, true, false);
+ break;
+ case 7:
+ // TODO Sound1ChList_setSoundValues(0x74E01054, false, 0, 0, 0, 0);
+ createSmackerScene(kSmackerFileHashList07, true, true, false);
+ break;
+ case 8:
+ _childObject = new Scene1109(_vm, this, which);
+ break;
+ case 1002:
+ _countdown = 40;
+ // TODO Sound1ChList_sub_4080B0(true);
+ createSmackerScene(0x00012211, true, true, false);
+ break;
+ }
+ SetUpdateHandler(&Module1100::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1100::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _countdown = 0;
+ // TODO Sound1ChList_sub_407C70(0x2C818, 0x48498E46, 0x50399F64);
+ // TODO Sound1ChList_setVolume(0x48498E46, 65);
+ // TODO Sound1ChList_setVolume(0x50399F64, 65);
+ if (_moduleResult == 0) {
+ createScene(1, 0);
+ } else if (_moduleResult == 1) {
+ createScene(8, 0);
+ }
+ break;
+ case 1:
+ // TODO Sound1ChList_sub_407C70(0x2C818, 0x41861371, 0x43A2507F);
+ if (getGlobalVar(0x0C0288F4)) {
+ if (_moduleResult == 0) {
+ createScene(6, -1);
+ } else if (_moduleResult == 1) {
+ createScene(0, 1);
+ }
+ } else {
+ if (_moduleResult == 0) {
+ createScene(2, 0);
+ } else if (_moduleResult == 1) {
+ createScene(0, 1);
+ }
+ }
+ break;
+ case 2:
+ // TODO Sound1ChList_setSoundValues(0x74E01054, false, 0, 0, 0, 0);
+ if (_navigationAreaType == 3) {
+ createScene(7, -1);
+ } else if (_moduleResult == 1) {
+ createScene(3, 0);
+ } else if (_moduleResult == 2) {
+ createScene(1002, -1);
+ }
+ break;
+ case 3:
+ if (_moduleResult == 0) {
+ createScene(4, 0);
+ } else if (_moduleResult == 1) {
+ createScene(2, 3);
+ }
+ break;
+ case 4:
+ if (_moduleResult == 0) {
+ createScene(3, 0);
+ } else if (_moduleResult == 1) {
+ createScene(5, -1);
+ }
+ break;
+ case 5:
+ if (getGlobalVar(0x610210B7)) {
+ createScene(3, 0);
+ } else {
+ createScene(4, 0);
+ }
+ break;
+ case 6:
+ leaveModule(1);
+ break;
+ case 7:
+ createScene(2, 2);
+ break;
+ case 8:
+ if (_moduleResult == 0) {
+ createScene(0, 0);
+ } else if (_moduleResult == 1) {
+ leaveModule(0);
+ }
+ break;
+ case 1002:
+ _countdown = 0;
+ // TODO Sound1ChList_sub_407C70(0x2C818, 0x48498E46, 0x50399F64, 0);
+ createScene(1, 1);
+ break;
+ }
+ } else {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+#if 0 // TODO
+ if (navigationScene()->soundFlag1 && _countdown != 0 && (--_countdown == 0)) {
+ Sound1ChList_sub_407C70(0x2C818, 0x48498E46, 0x50399F64);
+ Sound1ChList_setVolume(0x48498E46, 65);
+ Sound1ChList_setVolume(0x50399F64, 65);
+ }
+#endif
+ break;
+ case 1:
+#if 0 // TODO
+ if (navigationScene()->soundFlag1 && _countdown != 0 && (--_countdown == 0)) {
+ Sound1ChList_sub_407C70(0x2C818, 0x41861371, 0x43A2507F);
+ }
+#endif
+ break;
+ case 2:
+ // TODO Sound1ChList_setSoundValues(0x74E01054, !navigationScene()->soundFlag1, 0, 0, 0, 0);
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 1002:
+ if (_countdown != 0 && (--_countdown == 0)) {
+ // TODO Sound1ChList_sub_407C70(0x2C818, 0x48498E46, 0x50399F64);
+ // TODO Sound1ChList_setVolume(0x48498E46, 65);
+ // TODO Sound1ChList_setVolume(0x50399F64, 65);
+ }
+ break;
+ }
+ }
+}
+
+static const uint32 kScene1105FileHashes[] = {
+ 0x00028006,
+ 0x0100A425,
+ 0x63090415,
+ 0x082100C4,
+ 0x0068C607,
+ 0x00018344,
+ 0x442090E4,
+ 0x0400E004,
+ 0x5020A054,
+ 0xB14A891E
+};
+
+static const uint32 kScene1105BackgroundFileHashes[] = {
+ 0x20018662,
+ 0x20014202,
+ 0x20012202,
+ 0x20010002 // CHECKME: This used ??
+};
+
+static const uint32 kSsScene1105SymbolDieFileHashes[] = {
+ 0,
+ 0x90898414,
+ 0x91098414,
+ 0x92098414,
+ 0x94098414,
+ 0x98098414,
+ 0x80098414,
+ 0xB0098414,
+ 0xD0098414,
+ 0x10098414
+};
+
+SsScene1105Button::SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &rect)
+ : StaticSprite(vm, fileHash, 200), _soundResource(vm), _parentScene(parentScene),
+ _countdown(0) {
+
+ _rect = rect;
+ SetMessageHandler(&SsScene1105Button::handleMessage);
+ SetUpdateHandler(&SsScene1105Button::update);
+ setVisible(false);
+}
+
+void SsScene1105Button::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ sendMessage(_parentScene, 0x4807, 0);
+ setVisible(false);
+ }
+}
+
+uint32 SsScene1105Button::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_countdown == 0) {
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ }
+ break;
+ case 0x480B:
+ _countdown = 8;
+ setVisible(true);
+ _soundResource.play(0x44141000);
+ break;
+ }
+ return messageResult;
+}
+
+SsScene1105Symbol::SsScene1105Symbol(NeverhoodEngine *vm, uint32 fileHash, int16 x, int16 y)
+ : StaticSprite(vm, fileHash, 200) {
+
+ _x = x;
+ _y = y;
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -(_spriteResource.getDimensions().height / 2);
+ StaticSprite::update();
+}
+
+void SsScene1105Symbol::hide() {
+ setVisible(false);
+ _needRefresh = true;
+ StaticSprite::update();
+}
+
+SsScene1105SymbolDie::SsScene1105SymbolDie(NeverhoodEngine *vm, uint index, int16 x, int16 y)
+ : StaticSprite(vm, 1100), _index(index) {
+
+ SetMessageHandler(&SsScene1105SymbolDie::handleMessage);
+ _x = x;
+ _y = y;
+ createSurface(200, 50, 50);
+ loadSymbolSprite();
+}
+
+uint32 SsScene1105SymbolDie::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ loadSymbolSprite();
+ break;
+ }
+ return messageResult;
+}
+
+void SsScene1105SymbolDie::loadSymbolSprite() {
+ load(kSsScene1105SymbolDieFileHashes[getSubVar(0x61084036, _index)], true, false);
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -(_spriteResource.getDimensions().height / 2);
+ StaticSprite::update();
+}
+
+void SsScene1105SymbolDie::hide() {
+ setVisible(false);
+ _needRefresh = true;
+ StaticSprite::update();
+}
+
+AsScene1105TeddyBear::AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm),
+ _parentScene(parentScene) {
+
+ // TODO createSurface3(100, dword_4AF4C0);
+ createSurface(100, 640, 480); //TODO: Remeove once the line above is done
+ _x = 320;
+ _y = 240;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1105TeddyBear::handleMessage);
+ setFileHash(0x65084002, 0, -1);
+ _newHashListIndex = 0;
+ setVisible(false);
+ _needRefresh = true;
+ updatePosition();
+ _soundResource1.load(0xCE840261);
+ _soundResource2.load(0xCCA41A62);
+}
+
+uint32 AsScene1105TeddyBear::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2002:
+ if (getGlobalVar(0x610210B7)) {
+ setFileHash(0x6B0C0432, 0, -1);
+ _soundResource1.play();
+ } else {
+ setFileHash(0x65084002, 0, -1);
+ _soundResource2.play();
+ }
+ break;
+ case 0x3002:
+ sendMessage(_parentScene, 0x2003, 0);
+ stopAnimation();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1105TeddyBear::show() {
+ setVisible(true);
+ _needRefresh = true;
+ updatePosition();
+}
+
+void AsScene1105TeddyBear::hide() {
+ setVisible(false);
+ _needRefresh = true;
+ updatePosition();
+}
+
+SsScene1105OpenButton::SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene)
+ : StaticSprite(vm, 900), _soundResource(vm), _parentScene(parentScene),
+ _countdown(0), _flag1(false) {
+
+ _spriteResource.load2(0x8228A46C);
+ createSurface(400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _deltaRect = _drawRect;
+ _needRefresh = true;
+ processDelta();
+ setVisible(false);
+ _soundResource.load(0x44045140);
+ SetUpdateHandler(&SsScene1105OpenButton::update);
+ SetMessageHandler(&SsScene1105OpenButton::handleMessage);
+}
+
+void SsScene1105OpenButton::update() {
+ StaticSprite::update();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ setVisible(false);
+ sendMessage(_parentScene, 0x2001, 0);
+ }
+}
+
+uint32 SsScene1105OpenButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_countdown == 0 && !_flag1) {
+ _soundResource.play();
+ setVisible(true);
+ _flag1 = true;
+ _countdown = 4;
+ }
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+Scene1105::Scene1105(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource1(vm), _soundResource2(vm),
+ _soundResource3(vm), _countdown(0), _flag1(false), _flag2(false), _flag3(false),
+ _flag4(false), _flag5(false), _backgroundIndex(0) {
+
+ Sprite *ssOpenButton;
+
+ _vm->gameModule()->initScene1405Vars();
+
+ _surfaceFlag = true;
+ SetUpdateHandler(&Scene1105::update);
+ SetMessageHandler(&Scene1105::handleMessage);
+
+ setBackground(0x20010002);
+ setPalette(0x20010002);
+
+ _asTeddyBear = insertSprite<AsScene1105TeddyBear>(this);
+ ssOpenButton = insertSprite<SsScene1105OpenButton>(this);
+ _vm->_collisionMan->addSprite(ssOpenButton);
+ insertMouse435(0x10006208, 20, 620);
+
+ _soundResource1.load(0x48442057);
+ _soundResource2.load(0xC025014F);
+ _soundResource3.load(0x68E25540);
+
+}
+
+uint32 Scene1105::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO Debug stuff
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ if (!_flag2 && _backgroundIndex == 0) {
+ if (_flag1) {
+ _flag1 = false;
+ _backgroundIndex = 15;
+ SetUpdateHandler(&Scene1105::upClosePanel);
+ } else
+ _flag1 = true;
+ _flag5 = false;
+ }
+ }
+ break;
+ // TODO Debug stuff
+ case 0x2001:
+ showMouse(false);
+ _backgroundIndex = 24;
+ SetUpdateHandler(&Scene1105::upOpenPanel);
+ break;
+ case 0x2003:
+ _backgroundIndex = 24;
+ _flag5 = true;
+ SetUpdateHandler(&Scene1105::upClosePanel);
+ break;
+ case 0x4807:
+ if (sender == _ssActionButton) {
+ if (getSubVar(0x7500993A, 0) == getSubVar(0x61084036, 0) &&
+ getSubVar(0x7500993A, 1) == getSubVar(0x61084036, 1) &&
+ getSubVar(0x7500993A, 2) == getSubVar(0x61084036, 2)) {
+ setGlobalVar(0x610210B7, 1);
+ _soundResource3.play();
+ _flag3 = true;
+ } else {
+ sendMessage(_asTeddyBear, 0x2002, 0);
+ }
+ showMouse(false);
+ _flag2 = true;
+ }
+ break;
+ case 0x4826:
+ if (_flag1) {
+ if (sender == _ssActionButton) {
+ sendMessage(_ssActionButton, 0x480B, 0);
+ _flag1 = false;
+ } else if (!getGlobalVar(0x610210B7)) {
+ if (sender == _ssSymbol1UpButton) {
+ if (getSubVar(0x61084036, 0) < 9) {
+ incSubVar(0x61084036, 0, +1);
+ sendMessage(_ssSymbol1UpButton, 0x480B, 0);
+ sendMessage(_ssSymbolDice[0], 0x2000, 0);
+ }
+ } else if (sender == _ssSymbol1DownButton) {
+ if (getSubVar(0x61084036, 0) > 1) {
+ incSubVar(0x61084036, 0, -1);
+ sendMessage(_ssSymbol1DownButton, 0x480B, 0);
+ sendMessage(_ssSymbolDice[0], 0x2000, 0);
+ }
+ } else if (sender == _ssSymbol2UpButton) {
+ if (getSubVar(0x61084036, 1) < 9) {
+ incSubVar(0x61084036, 1, +1);
+ sendMessage(_ssSymbol2UpButton, 0x480B, 0);
+ sendMessage(_ssSymbolDice[1], 0x2000, 0);
+ }
+ } else if (sender == _ssSymbol2DownButton) {
+ if (getSubVar(0x61084036, 1) > 1) {
+ incSubVar(0x61084036, 1, -1);
+ sendMessage(_ssSymbol2DownButton, 0x480B, 0);
+ sendMessage(_ssSymbolDice[1], 0x2000, 0);
+ }
+ } else if (sender == _ssSymbol3UpButton) {
+ if (getSubVar(0x61084036, 2) < 9) {
+ incSubVar(0x61084036, 2, +1);
+ sendMessage(_ssSymbol3UpButton, 0x480B, 0);
+ sendMessage(_ssSymbolDice[2], 0x2000, 0);
+ }
+ } else if (sender == _ssSymbol3DownButton) {
+ if (getSubVar(0x61084036, 2) > 1) {
+ incSubVar(0x61084036, 2, -1);
+ sendMessage(_ssSymbol3DownButton, 0x480B, 0);
+ sendMessage(_ssSymbolDice[2], 0x2000, 0);
+ }
+ }
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Scene1105::createObjects() {
+ _ssSymbols[0] = insertSprite<SsScene1105Symbol>(kScene1105FileHashes[getSubVar(0x13100631, 0)], 161, 304);
+ _ssSymbols[1] = insertSprite<SsScene1105Symbol>(kScene1105FileHashes[getSubVar(0x13100631, 1)], 294, 304);
+ _ssSymbols[2] = insertSprite<SsScene1105Symbol>(kScene1105FileHashes[getSubVar(0x13100631, 2)], 440, 304);
+
+ _ssSymbolDice[0] = insertSprite<SsScene1105SymbolDie>(0, 206, 304);
+ _ssSymbolDice[1] = insertSprite<SsScene1105SymbolDie>(1, 339, 304);
+ _ssSymbolDice[2] = insertSprite<SsScene1105SymbolDie>(2, 485, 304);
+
+ _ssSymbol1UpButton = insertSprite<SsScene1105Button>(this, 0x08002860, NRect(146, 362, 192, 403));
+ _vm->_collisionMan->addSprite(_ssSymbol1UpButton);
+ _ssSymbol1DownButton = insertSprite<SsScene1105Button>(this, 0x42012460, NRect(147, 404, 191, 442));
+ _vm->_collisionMan->addSprite(_ssSymbol1DownButton);
+ _ssSymbol2UpButton = insertSprite<SsScene1105Button>(this, 0x100030A0, NRect(308, 361, 355, 402));
+ _vm->_collisionMan->addSprite(_ssSymbol2UpButton);
+ _ssSymbol2DownButton = insertSprite<SsScene1105Button>(this, 0x840228A0, NRect(306, 406, 352, 445));
+ _vm->_collisionMan->addSprite(_ssSymbol2DownButton);
+ _ssSymbol3UpButton = insertSprite<SsScene1105Button>(this, 0x20000120, NRect(476, 358, 509, 394));
+ _vm->_collisionMan->addSprite(_ssSymbol3UpButton);
+ _ssSymbol3DownButton = insertSprite<SsScene1105Button>(this, 0x08043121, NRect(463, 401, 508, 438));
+ _vm->_collisionMan->addSprite(_ssSymbol3DownButton);
+ _ssActionButton = insertSprite<SsScene1105Button>(this, 0x8248AD35, NRect(280, 170, 354, 245));
+ _vm->_collisionMan->addSprite(_ssActionButton);
+
+ _flag1 = true;
+
+ _asTeddyBear->show();
+
+ // TODO: Find a nicer way
+ deleteSprite((Sprite**)&_mouseCursor);
+ insertMouse435(0x18666208, 20, 620);
+
+}
+
+void Scene1105::upOpenPanel() {
+ Scene::update();
+ if (_backgroundIndex != 0) {
+ _backgroundIndex--;
+ if (_backgroundIndex < 6 && _backgroundIndex % 2 == 0) {
+ uint32 backgroundFileHash = kScene1105BackgroundFileHashes[_backgroundIndex / 2];
+ changeBackground(backgroundFileHash);
+ _palette->addPalette(backgroundFileHash, 0, 256, 0);
+ }
+ if (_backgroundIndex == 10) {
+ _soundResource1.play();
+ }
+ if (_backgroundIndex == 0) {
+ SetUpdateHandler(&Scene1105::update);
+ _countdown = 2;
+ }
+ }
+}
+
+void Scene1105::upClosePanel() {
+ Scene::update();
+ if (_backgroundIndex != 0) {
+ _backgroundIndex--;
+ if (_backgroundIndex == 14) {
+ showMouse(false);
+ _ssSymbols[0]->hide();
+ _ssSymbols[1]->hide();
+ _ssSymbols[2]->hide();
+ _ssSymbolDice[0]->hide();
+ _ssSymbolDice[1]->hide();
+ _ssSymbolDice[2]->hide();
+ }
+ if (_backgroundIndex < 6 && _backgroundIndex % 2 == 0) {
+ uint32 backgroundFileHash = kScene1105BackgroundFileHashes[3 - _backgroundIndex / 2]; // CHECKME
+ if (_backgroundIndex == 4) {
+ _soundResource2.play();
+ _asTeddyBear->hide();
+ }
+ changeBackground(backgroundFileHash);
+ _palette->addPalette(backgroundFileHash, 0, 256, 0);
+ }
+ if (_backgroundIndex == 0) {
+ SetUpdateHandler(&Scene1105::update);
+ _flag4 = true;
+ }
+ }
+}
+
+void Scene1105::update() {
+
+ // DEBUG: Show the correct code
+ debug("(%d, %d) (%d, %d) (%d, %d)",
+ getSubVar(0x7500993A, 0), getSubVar(0x61084036, 0),
+ getSubVar(0x7500993A, 1), getSubVar(0x61084036, 1),
+ getSubVar(0x7500993A, 2), getSubVar(0x61084036, 2));
+
+ Scene::update();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ createObjects();
+ }
+ if (_flag4 && !_soundResource2.isPlaying()) {
+ leaveScene(_flag5);
+ }
+ if (_flag3 && !_soundResource3.isPlaying()) {
+ sendMessage(_asTeddyBear, 0x2002, 0);
+ _flag3 = false;
+ }
+}
+
+Scene1109::Scene1109(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, which) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1109::handleMessage);
+
+ setBackground(0x8449E02F);
+ setPalette(0x8449E02F);
+ insertMouse433(0x9E02B84C);
+
+ _sprite1 = insertStaticSprite(0x600CEF01, 1100);
+
+ if (which < 0) {
+ insertKlayman<KmScene1109>(140, 436);
+ setMessageList(0x004B6260);
+ sendMessage(this, 0x2000, 0);
+ } else if (which == 1) {
+ insertKlayman<KmScene1109>(450, 436);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B6268, false);
+ sendMessage(this, 0x2000, 1);
+ } else if (which == 2) {
+ insertKlayman<KmScene1109>(450, 436);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B6318, false);
+ sendMessage(this, 0x2000, 1);
+ } else if (which == 3) {
+ insertKlayman<KmScene1109>(450, 436);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B6278, false);
+ sendMessage(this, 0x2000, 1);
+ } else {
+ insertKlayman<KmScene1109>(0, 436);
+ setMessageList(0x004B6258);
+ sendMessage(this, 0x2000, 0);
+ }
+
+ _klayman->setClipRect(0, 0, _sprite1->getDrawRect().x2(), 480);
+
+}
+
+uint32 Scene1109::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ if (param.asInteger()) {
+ setRectList(0x004B63A8);
+ _klayman->setKlaymanTable3();
+ } else {
+ setRectList(0x004B6398);
+ _klayman->setKlaymanTable1();
+ }
+ break;
+ }
+ return 0;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1100.h b/engines/neverhood/module1100.h
new file mode 100644
index 0000000000..c46c1dfbca
--- /dev/null
+++ b/engines/neverhood/module1100.h
@@ -0,0 +1,136 @@
+/* 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_MODULE1100_H
+#define NEVERHOOD_MODULE1100_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module1100
+
+class Module1100 : public Module {
+public:
+ Module1100(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1100();
+protected:
+ int _countdown;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+class SsScene1105Button : public StaticSprite {
+public:
+ SsScene1105Button(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash, NRect &rect);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene1105Symbol : public StaticSprite {
+public:
+ SsScene1105Symbol(NeverhoodEngine *vm, uint32 fileHash, int16 x, int16 y);
+ void hide();
+};
+
+class SsScene1105SymbolDie : public StaticSprite {
+public:
+ SsScene1105SymbolDie(NeverhoodEngine *vm, uint index, int16 x, int16 y);
+ void hide();
+protected:
+ uint _index;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void loadSymbolSprite();
+};
+
+class AsScene1105TeddyBear : public AnimatedSprite {
+public:
+ AsScene1105TeddyBear(NeverhoodEngine *vm, Scene *parentScene);
+ void show();
+ void hide();
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene1105OpenButton : public StaticSprite {
+public:
+ SsScene1105OpenButton(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ int _countdown;
+ bool _flag1;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1105 : public Scene {
+public:
+ Scene1105(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ int _countdown;
+ int _backgroundIndex;
+ bool _flag1;
+ bool _flag2;
+ bool _flag3;
+ bool _flag4;
+ bool _flag5;
+ AsScene1105TeddyBear *_asTeddyBear;
+ SsScene1105Symbol *_ssSymbols[3];
+ SsScene1105SymbolDie *_ssSymbolDice[3];
+ Sprite *_ssSymbol1UpButton;
+ Sprite *_ssSymbol1DownButton;
+ Sprite *_ssSymbol2UpButton;
+ Sprite *_ssSymbol2DownButton;
+ Sprite *_ssSymbol3UpButton;
+ Sprite *_ssSymbol3DownButton;
+ Sprite *_ssActionButton;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createObjects();
+ void upOpenPanel();
+ void upClosePanel();
+ void update();
+};
+
+class Scene1109 : public Scene {
+public:
+ Scene1109(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_sprite1;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1100_H */
diff --git a/engines/neverhood/module1200.cpp b/engines/neverhood/module1200.cpp
new file mode 100644
index 0000000000..25abf95643
--- /dev/null
+++ b/engines/neverhood/module1200.cpp
@@ -0,0 +1,1236 @@
+/* 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/module1200.h"
+
+namespace Neverhood {
+
+Module1200::Module1200(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ SetMessageHandler(&Module1200::handleMessage);
+
+ debug("Module1200: which = %d", which);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 1) {
+ createScene(0, 2);
+ } else {
+ createScene(0, 0);
+ }
+
+ // TODO Music18hList_add(0x00478311, 0x62222CAE);
+ // TODO Music18hList_play(0x62222CAE, 0, 0, 1);
+}
+
+Module1200::~Module1200() {
+ // TODO Music18hList_deleteGroup(0x00478311);
+}
+
+void Module1200::createScene(int sceneNum, int which) {
+ debug("Module1200::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _childObject = new Scene1201(_vm, this, which);
+ break;
+ case 1:
+ _childObject = new Scene1202(_vm, this, which);
+ break;
+ case 2:
+ // TODO Music18hList_stop(0x62222CAE, 0, 0);
+ createSmackerScene(0x31890001, true, true, false);
+ setGlobalVar(0x2A02C07B, 1);
+ break;
+ }
+ SetUpdateHandler(&Module1200::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1200::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(1, 0);
+ } else if (_moduleResult == 2) {
+ if (getGlobalVar(0x0A18CA33) && !getGlobalVar(0x2A02C07B)) {
+ createScene(2, -1);
+ } else {
+ leaveModule(1);
+ }
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 1:
+ createScene(0, 1);
+ break;
+ case 2:
+ // TODO Music18hList_play(0x62222CAE, 0, 0, 1);
+ createScene(0, 3);
+ break;
+ }
+ }
+}
+
+// Scene1201
+
+static const uint32 kScene1201InitArray[] = {
+ 1, 0, 2, 4, 5, 3, 6, 7, 8, 10, 9, 11, 13, 14, 12, 16, 17, 15
+};
+
+static const NPoint kScene1201PointArray[] = {
+ {218, 193},
+ {410, 225},
+ {368, 277},
+ {194, 227},
+ {366, 174},
+ {458, 224},
+ {242, 228},
+ {512, 228},
+ {458, 277},
+ {217, 233},
+ {458, 173},
+ {410, 276},
+ {203, 280},
+ {371, 226},
+ {508, 279},
+ {230, 273},
+ {410, 171},
+ {493, 174}
+};
+
+static const uint32 kScene1201TntFileHashList1[] = {
+ 0x2098212D,
+ 0x1600437E,
+ 0x1600437E,
+ 0x00A840E3,
+ 0x1A1830F6,
+ 0x1A1830F6,
+ 0x00212062,
+ 0x384010B6,
+ 0x384010B6,
+ 0x07A01080,
+ 0xD80C2837,
+ 0xD80C2837,
+ 0x03A22092,
+ 0xD8802CB6,
+ 0xD8802CB6,
+ 0x03A93831,
+ 0xDA460476,
+ 0xDA460476
+};
+
+static const uint32 kScene1201TntFileHashList2[] = {
+ 0x3040C676,
+ 0x10914448,
+ 0x10914448,
+ 0x3448A066,
+ 0x1288C049,
+ 0x1288C049,
+ 0x78C0E026,
+ 0x3098D05A,
+ 0x3098D05A,
+ 0x304890E6,
+ 0x1284E048,
+ 0x1284E048,
+ 0xB140A1E6,
+ 0x5088A068,
+ 0x5088A068,
+ 0x74C4C866,
+ 0x3192C059,
+ 0x3192C059
+};
+
+SsScene1201Tnt::SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2)
+ : StaticSprite(vm, 900), _field7A(-1) {
+
+ int16 x = kScene1201PointArray[pointIndex].x;
+ int16 y = kScene1201PointArray[pointIndex].y;
+ if (x < 300) {
+ _spriteResource.load2(kScene1201TntFileHashList1[elemIndex]);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ } else {
+ _spriteResource.load2(kScene1201TntFileHashList2[elemIndex]);
+ _x = x;
+ _y = y;
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -_spriteResource.getDimensions().height;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+
+ }
+ createSurface(50, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ setClipRect(0, 0, 640, clipY2);
+ _needRefresh = true;
+ StaticSprite::update();
+}
+
+AsScene1201Tape::AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash)
+ : AnimatedSprite(vm, fileHash, surfacePriority, x, y), _parentScene(parentScene), _nameHash(nameHash) {
+
+ if (!getSubVar(0x02038314, _nameHash) && !getSubVar(0x02720344, _nameHash)) {
+ SetMessageHandler(&AsScene1201Tape::handleMessage);
+ } else {
+ setVisible(false);
+ SetMessageHandler(NULL);
+ }
+}
+
+uint32 AsScene1201Tape::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x4806:
+ setSubVar(0x02038314, _nameHash, 1);
+ setVisible(false);
+ SetMessageHandler(NULL);
+ break;
+ }
+ return messageResult;
+}
+
+Class466::Class466(NeverhoodEngine *vm, bool flag)
+ : AnimatedSprite(vm, 1200), _soundResource(vm) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class466::handleMessage);
+ createSurface(10, 34, 149);
+ _x = 202;
+ _y = -32;
+ if (flag) {
+ sub40D380();
+ } else {
+ sub40D340();
+ }
+}
+
+uint32 Class466::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x02060018) {
+ _soundResource.play(0x47900E06);
+ }
+ break;
+ case 0x2006:
+ sub40D360();
+ break;
+ }
+ return messageResult;
+}
+
+void Class466::sub40D340() {
+ setFileHash(0x928F0C10, 0, -1);
+ _newHashListIndex = 0;
+}
+
+void Class466::sub40D360() {
+ setFileHash(0x928F0C10, 1, -1);
+ _newHashListIndex = -2;
+}
+
+void Class466::sub40D380() {
+ setFileHash(0x928F0C10, 15, -1);
+ _newHashListIndex = -2;
+}
+
+AsScene1201RightDoor::AsScene1201RightDoor(NeverhoodEngine *vm, Sprite *klayman, bool flag)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _klayman(klayman), _countdown(0) {
+
+ createSurface1(0xD088AC30, 100);
+ _x = 320;
+ _y = 240;
+ SetUpdateHandler(&AsScene1201RightDoor::update);
+ SetMessageHandler(&AsScene1201RightDoor::handleMessage);
+ _newHashListIndex = -2;
+ if (flag) {
+ setFileHash(0xD088AC30, -1, -1);
+ _newHashListIndex = -2;
+ _countdown = 25;
+ } else {
+ stopAnimation();
+ setVisible(false);
+ }
+}
+
+void AsScene1201RightDoor::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ sub40D830();
+ }
+ AnimatedSprite::update();
+}
+
+uint32 AsScene1201RightDoor::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4829:
+ sub40D7E0();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1201RightDoor::sub40D7E0() {
+ setFileHash(0xD088AC30, 0, -1);
+ _newHashListIndex = -2;
+ setVisible(true);
+ _soundResource.play(calcHash("fxDoorOpen20"));
+}
+
+void AsScene1201RightDoor::sub40D830() {
+ setFileHash(0xD088AC30, -1, -1);
+ _playBackwards = true;
+ setVisible(true);
+ _soundResource.play(calcHash("fxDoorClose20"));
+ NextState(&AsScene1201RightDoor::sub40D880);
+}
+
+void AsScene1201RightDoor::sub40D880() {
+ stopAnimation();
+ setVisible(false);
+}
+
+Class464::Class464(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1200) {
+
+ createSurface(1200, 69, 98);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class464::handleMessage);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ setVisible(false);
+}
+
+uint32 Class464::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2006:
+ _x = 436;
+ _y = 339;
+ setFileHash(0xA060C599, 0, -1);
+ setVisible(true);
+ break;
+ case 0x3002:
+ stopAnimation();
+ setVisible(false);
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+AsScene1201TntMan::AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sprite *class466, bool flag)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene), _class466(class466),
+ _flag(false) {
+
+ flag = false;
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1201TntMan::handleMessage);
+ createSurface(990, 106, 181);
+ _x = 201;
+ if (flag) {
+ _y = 297;
+ sub40CD60();
+ } else {
+ _y = 334;
+ sub40CD30();
+ }
+}
+
+AsScene1201TntMan::~AsScene1201TntMan() {
+ // TODO Sound1ChList_sub_407AF0(0x01D00560);
+}
+
+uint32 AsScene1201TntMan::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x092870C0) {
+ sendMessage(_class466, 0x2006, 0);
+ } else if (param.asInteger() == 0x11CA0144) {
+ _soundResource.play(0x51800A04);
+ }
+ break;
+ case 0x1011:
+ sendMessage(_parentScene, 0x2002, 0);
+ messageResult = 1;
+ case 0x480B:
+ if (!_flag) {
+ _sprite = (Sprite*)sender;
+ sub40CD90();
+ }
+ break;
+ }
+ return messageResult;
+
+}
+
+uint32 AsScene1201TntMan::handleMessage40CCD0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = AsScene1201TntMan::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1201TntMan::spriteUpdate40CD10() {
+ _x = _sprite->getX() + 100;
+}
+
+void AsScene1201TntMan::sub40CD30() {
+ setFileHash(0x654913D0, 0, -1);
+ SetMessageHandler(&AsScene1201TntMan::handleMessage);
+ SetSpriteCallback(NULL);
+}
+
+void AsScene1201TntMan::sub40CD60() {
+ setFileHash(0x356803D0, 0, -1);
+ SetMessageHandler(&AsScene1201TntMan::handleMessage40CCD0);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ NextState(&AsScene1201TntMan::sub40CD30);
+}
+
+void AsScene1201TntMan::sub40CD90() {
+ // TODO Sound1ChList_addSoundResource(0x01D00560, 0x4B044624, true);
+ // TODO Sound1ChList_playLooping(0x4B044624);
+ _flag = true;
+ setFileHash(0x85084190, 0, -1);
+ SetMessageHandler(&AsScene1201TntMan::handleMessage);
+ SetSpriteCallback(&AsScene1201TntMan::spriteUpdate40CD10);
+ _newHashListIndex = -2;
+}
+
+Class465::Class465(NeverhoodEngine *vm, Sprite *asTntMan)
+ : AnimatedSprite(vm, 1200), _asTntMan(asTntMan) {
+
+ createSurface1(0x828C0411, 995);
+ SetUpdateHandler(&Class465::update);
+ SetMessageHandler(&Sprite::handleMessage);
+ SetSpriteCallback(&Class465::spriteUpdate40D150);
+ setFileHash(0x828C0411, 0, -1);
+ setVisible(false);
+}
+
+Class465::~Class465() {
+ // TODO Sound1ChList_sub_407AF0(0x041080A4);
+}
+
+void Class465::update() {
+ AnimatedSprite::update();
+ if (getGlobalVar(0x20A0C516)) {
+ setVisible(true);
+ SetUpdateHandler(&AnimatedSprite::update);
+ // TODO Sound1ChList_addSoundResource(0x041080A4, 0x460A1050, true);
+ // TODO Sound1ChList_playLooping(0x460A1050);
+ }
+}
+
+void Class465::spriteUpdate40D150() {
+ _x = _asTntMan->getX() - 18;
+ _y = _asTntMan->getY() - 158;
+}
+
+AsScene1201Match::AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene) {
+
+ createSurface(1100, 57, 60);
+ SetUpdateHandler(&AsScene1201Match::update);
+ SetMessageHandler(&AsScene1201Match::handleMessage40C2D0);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+
+ switch (getGlobalVar(0x0112090A)) {
+ case 0:
+ _x = 521;
+ _y = 112;
+ _status = 0;
+ sub40C4C0();
+ break;
+ case 1:
+ _x = 521;
+ _y = 112;
+ _status = 2;
+ sub40C470();
+ _soundResource.load(0xD00230CD);
+ break;
+ case 2:
+ setDoDeltaX(1);
+ _x = 403;
+ _y = 337;
+ _status = 0;
+ sub40C4F0();
+ break;
+ }
+}
+
+void AsScene1201Match::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ removeCallbacks();
+ }
+ updateAnim();
+ handleSpriteUpdate();
+ updatePosition();
+}
+
+uint32 AsScene1201Match::handleMessage40C2D0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x86668011) {
+ _soundResource.play();
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1201Match::handleMessage40C320(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage40C2D0(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1201Match::handleMessage40C360(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage40C2D0(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x2001, 0);
+ messageResult = 1;
+ break;
+ case 0x4806:
+ setVisible(false);
+ setGlobalVar(0x0112090A, 3);
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1201Match::sub40C3E0() {
+ setFileHash(0x00842374, 0, -1);
+ SetMessageHandler(&AsScene1201Match::handleMessage40C320);
+ if (_status == 0) {
+ NextState(&AsScene1201Match::sub40C420);
+ } else {
+ NextState(&AsScene1201Match::sub40C470);
+ }
+}
+
+void AsScene1201Match::sub40C420() {
+ setGlobalVar(0x0112090A, 2);
+ _x -= 199;
+ _y += 119;
+ setFileHash(0x018D0240, 0, -1);
+ SetMessageHandler(&AsScene1201Match::handleMessage40C320);
+ NextState(&AsScene1201Match::sub40C4F0);
+}
+
+void AsScene1201Match::sub40C470() {
+ setFileHash(0x00842374, 0, -1);
+ SetMessageHandler(&AsScene1201Match::handleMessage40C2D0);
+ _newHashListIndex = 0;
+ if (_status != 0) {
+ _countdown = 36;
+ _status--;
+ NextState(&AsScene1201Match::sub40C3E0);
+ }
+}
+
+void AsScene1201Match::sub40C4C0() {
+ setFileHash(0x00842374, 0, -1);
+ SetMessageHandler(&AsScene1201Match::handleMessage40C360);
+ _newHashListIndex = 0;
+}
+
+void AsScene1201Match::sub40C4F0() {
+ setDoDeltaX(1);
+ _x = 403;
+ _y = 337;
+ setFileHash(0x00842374, 0, -1);
+ SetMessageHandler(&AsScene1201Match::handleMessage40C360);
+ _newHashListIndex = 0;
+}
+
+AsScene1201Creature::AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman)
+ : AnimatedSprite(vm, 900), _soundResource(vm), _parentScene(parentScene), _klayman(klayman),
+ _flag(false) {
+
+ createSurface(1100, 203, 199);
+ SetUpdateHandler(&AsScene1201Creature::update);
+ SetMessageHandler(&AsScene1201Creature::handleMessage40C710);
+ _x = 540;
+ _y = 320;
+ sub40C8E0();
+ _countdown3 = 2;
+}
+
+void AsScene1201Creature::update() {
+ bool oldFlag = _flag;
+ _flag = _x >= 385;
+ if (_flag != oldFlag)
+ sub40C8E0();
+ if (_countdown1 != 0 && (--_countdown1 == 0)) {
+ removeCallbacks();
+ }
+ updateAnim();
+ handleSpriteUpdate();
+ updatePosition();
+}
+
+uint32 AsScene1201Creature::handleMessage40C710(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x02060018) {
+ _soundResource.play(0xCD298116);
+ }
+ break;
+ case 0x2004:
+ GotoState(&AsScene1201Creature::sub40C960);
+ break;
+ case 0x2006:
+ GotoState(&AsScene1201Creature::sub40C9B0);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1201Creature::handleMessage40C7B0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = handleMessage40C710(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x02421405) {
+ if (_countdown2 != 0 && (--_countdown2 == 0)) {
+ sub40C990();
+ }
+ }
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1201Creature::handleMessage40C830(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x02060018) {
+ _soundResource.play(0xCD298116);
+ sendMessage(_parentScene, 0x4814, 0);
+ sendMessage(_klayman, 0x4814, 0);
+ }
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1201Creature::sub40C8E0() {
+ _countdown3--;
+ if (_countdown3 == 0)
+ _countdown3 = 3;
+ setFileHash(0x08081513, 0, -1);
+ SetMessageHandler(&AsScene1201Creature::handleMessage40C710);
+ NextState(&AsScene1201Creature::sub40C930);
+ _countdown1 = 36;
+}
+
+void AsScene1201Creature::sub40C930() {
+ if (!_flag) {
+ setFileHash(0xCA287133, 0, -1);
+ SetMessageHandler(&AsScene1201Creature::handleMessage40C7B0);
+ NextState(&AsScene1201Creature::sub40C8E0);
+ }
+}
+
+void AsScene1201Creature::sub40C960() {
+ setFileHash(0x08081513, 0, -1);
+ SetMessageHandler(&AsScene1201Creature::handleMessage40C710);
+ NextState(&AsScene1201Creature::sub40C9E0);
+ _countdown1 = 48;
+}
+
+void AsScene1201Creature::sub40C990() {
+ setFileHash2(0x0B6E13FB, 0x01084280, 0);
+}
+
+void AsScene1201Creature::sub40C9B0() {
+ setFileHash(0xCA287133, 0, -1);
+ SetMessageHandler(&AsScene1201Creature::handleMessage40C830);
+ NextState(&AsScene1201Creature::sub40C8E0);
+ _countdown1 = 0;
+}
+
+void AsScene1201Creature::sub40C9E0() {
+ setFileHash(0x5A201453, 0, -1);
+ SetMessageHandler(&AsScene1201Creature::handleMessage40C710);
+ _countdown1 = 0;
+}
+
+AsScene1201LeftDoor::AsScene1201LeftDoor(NeverhoodEngine *vm, Sprite *klayman)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _klayman(klayman) {
+
+ _x = 320;
+ _y = 240;
+ createSurface(800, 55, 199);
+ if (_klayman->getX() < 100) {
+ setFileHash(0x508A111B, 0, -1);
+ _newHashListIndex = -2;
+ _soundResource.play(calcHash("fxDoorOpen03"));
+ } else {
+ setFileHash(0x508A111B, -1, -1);
+ _newHashListIndex = -2;
+ }
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1201LeftDoor::handleMessage);
+}
+
+uint32 AsScene1201LeftDoor::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4809:
+ sub40D590();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1201LeftDoor::sub40D590() {
+ setFileHash(0x508A111B, -1, -1);
+ _playBackwards = true;
+ _newHashListIndex = 0;
+}
+
+Scene1201::Scene1201(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _flag(false), _asMatch(NULL), _asTntMan(NULL),
+ _asCreature(NULL), _class466(NULL), _asLeftDoor(NULL), _asRightDoor(NULL), _asTape(NULL) {
+
+ int16 topY1, topY2, topY3, topY4;
+ int16 x1, x2;
+ Sprite *tempSprite, *class464;
+
+ SetUpdateHandler(&Scene1201::update);
+ SetMessageHandler(&Scene1201::handleMessage);
+
+ setHitRects(0x004AEBD0);
+
+ _surfaceFlag = true;
+
+ if (!getSubVar(0x40050052, 0xE8058B52)) {
+ setSubVar(0x40050052, 0xE8058B52, 1);
+ for (uint32 index = 0; index < 18; index++) {
+ setSubVar(0x10055D14, index, kScene1201InitArray[index]);
+ }
+ }
+
+ insertMouse433(0x9A2C0409);
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 3, 1100, 243, 340, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ tempSprite = insertStaticSprite(0x03C82530, 100);
+ topY1 = tempSprite->getY() + tempSprite->getDrawRect().height;
+
+ tempSprite = insertStaticSprite(0x88182069, 200);
+ topY2 = tempSprite->getY() + tempSprite->getDrawRect().height;
+
+ tempSprite = insertStaticSprite(0x476014E0, 300);
+ topY3 = tempSprite->getY() + tempSprite->getDrawRect().height;
+
+ tempSprite = insertStaticSprite(0x04063110, 500);
+ topY4 = tempSprite->getY() + 1;
+
+ _class466 = insertSprite<Class466>(getGlobalVar(0x000CF819) && which != 1);
+ _class466->setClipRect(0, topY4, 640, 480);
+
+ insertStaticSprite(0x400B04B0, 1200);
+
+ tempSprite = insertStaticSprite(0x40295462, 1200);
+ x1 = tempSprite->getX();
+
+ tempSprite = insertStaticSprite(0xA29223FA, 1200);
+ x2 = tempSprite->getX() + tempSprite->getDrawRect().width;
+
+ class464 = insertSprite<Class464>();
+
+ debug("Scene1201: which = %d", which);
+
+ if (which < 0) {
+ insertKlayman<KmScene1201>(364, 333, class464);
+ setMessageList(0x004AEC08);
+ } else if (which == 3) {
+ insertKlayman<KmScene1201>(400, 329, class464);
+ setMessageList(0x004AEC08);
+ } else if (which == 2) {
+ if (getGlobalVar(0x0A310817) && !getGlobalVar(0x0A18CA33)) {
+ insertKlayman<KmScene1201>(374, 333, class464);
+ setMessageList(0x004AEC08);
+ } else {
+ insertKlayman<KmScene1201>(640, 329, class464);
+ setMessageList(0x004AEC20);
+ }
+ } else if (which == 1) {
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene1201>(364, 333, class464);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene1201>(246, 333, class464);
+ }
+ setMessageList(0x004AEC30);
+ } else {
+ insertKlayman<KmScene1201>(0, 336, class464);
+ setMessageList(0x004AEC10);
+ }
+
+ _klayman->setClipRect(x1, 0, x2, 480);
+ _klayman->setRepl(64, 0);
+
+ if (getGlobalVar(0x0A310817) && !getGlobalVar(0x0A18CA33)) {
+ setBackground(0x4019A2C4);
+ setPalette(0x4019A2C4);
+ _asRightDoor = NULL;
+ } else {
+ setBackground(0x40206EC5);
+ setPalette(0x40206EC5);
+ _asRightDoor = insertSprite<AsScene1201RightDoor>(_klayman, which == 2);
+ }
+
+ if (getGlobalVar(0x000CF819)) {
+ insertStaticSprite(0x10002ED8, 500);
+ if (!getGlobalVar(0x0A18CA33)) {
+ _asTntMan = insertSprite<AsScene1201TntMan>(this, _class466, which == 1);
+ _asTntMan->setClipRect(x1, 0, x2, 480);
+ _asTntMan->setRepl(64, 0);
+ _vm->_collisionMan->addSprite(_asTntMan);
+ tempSprite = insertSprite<Class465>(_asTntMan);
+ tempSprite->setClipRect(x1, 0, x2, 480);
+ }
+
+ uint32 tntIndex = 1;
+ while (tntIndex < 18) {
+ uint32 elemIndex = getSubVar(0x10055D14, tntIndex);
+ int16 clipY2;
+ if (kScene1201PointArray[elemIndex].y < 175)
+ clipY2 = topY1;
+ else if (kScene1201PointArray[elemIndex].y < 230)
+ clipY2 = topY2;
+ else
+ clipY2 = topY3;
+ insertSprite<SsScene1201Tnt>(tntIndex, getSubVar(0x10055D14, tntIndex), clipY2);
+ elemIndex = getSubVar(0x10055D14, tntIndex + 1);
+ if (kScene1201PointArray[elemIndex].y < 175)
+ clipY2 = topY1;
+ else if (kScene1201PointArray[elemIndex].y < 230)
+ clipY2 = topY2;
+ else
+ clipY2 = topY3;
+ insertSprite<SsScene1201Tnt>(tntIndex + 1, getSubVar(0x10055D14, tntIndex + 1), clipY2);
+ tntIndex += 3;
+ }
+
+ if (getGlobalVar(0x0A310817) && !getGlobalVar(0x0A18CA33)) {
+ setRectList(0x004AEE58);
+ } else {
+ setRectList(0x004AEDC8);
+ }
+
+ } else {
+
+ insertStaticSprite(0x8E8A1981, 900);
+
+ uint32 tntIndex = 0;
+ while (tntIndex < 18) {
+ uint32 elemIndex = getSubVar(0x10055D14, tntIndex);
+ int16 clipY2;
+ if (kScene1201PointArray[elemIndex].x < 300) {
+ clipY2 = 480;
+ } else {
+ if (kScene1201PointArray[elemIndex].y < 175)
+ clipY2 = topY1;
+ else if (kScene1201PointArray[elemIndex].y < 230)
+ clipY2 = topY2;
+ else
+ clipY2 = topY3;
+ }
+ insertSprite<SsScene1201Tnt>(tntIndex, getSubVar(0x10055D14, tntIndex), clipY2);
+ tntIndex++;
+ }
+
+ if (getGlobalVar(0x0A310817) && !getGlobalVar(0x0A18CA33)) {
+ setRectList(0x004AEE18);
+ } else {
+ setRectList(0x004AED88);
+ }
+
+ }
+
+ tempSprite = insertStaticSprite(0x63D400BC, 900);
+
+ _asLeftDoor = insertSprite<AsScene1201LeftDoor>(_klayman);
+ _asLeftDoor->setClipRect(x1, tempSprite->getDrawRect().y, tempSprite->getDrawRect().x2(), 480);
+
+ if (getGlobalVar(0x0A310817) && ! getGlobalVar(0x0112090A)) {
+ setGlobalVar(0x0112090A, 1);
+ }
+
+ _asMatch = NULL;
+
+ if (getGlobalVar(0x0112090A) < 3) {
+ _asMatch = insertSprite<AsScene1201Match>(this);
+ _vm->_collisionMan->addSprite(_asMatch);
+ }
+
+ if (getGlobalVar(0x0A310817) && !getGlobalVar(0x0A18CA33)) {
+ _asCreature = insertSprite<AsScene1201Creature>(this, _klayman);
+ _asCreature->setClipRect(x1, 0, x2, 480);
+ }
+
+}
+
+Scene1201::~Scene1201() {
+}
+
+void Scene1201::update() {
+ Scene::update();
+ if (_asMatch && getGlobalVar(0x0112090A)) {
+ deleteSprite(&_asMatch);
+ }
+}
+
+uint32 Scene1201::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x07053000) {
+ _flag = true;
+ sendMessage(_asCreature, 0x2004, 0);
+ } else if (param.asInteger() == 0x140E5744) {
+ sendMessage(_asCreature, 0x2005, 0);
+ } else if (param.asInteger() == 0x40253C40) {
+ _messageListFlag = false;
+ sendMessage(_asCreature, 0x2006, 0);
+ } else if (param.asInteger() == 0x090EB048) {
+ if (_klayman->getX() < 572) {
+ setMessageList2(0x004AEC90);
+ } else {
+ setMessageList2(0x004AEC20);
+ }
+ }
+ break;
+ case 0x2001:
+ if (!getGlobalVar(0x0112090A)) {
+ setMessageList2(0x004AECB0);
+ } else {
+ sendEntityMessage(_klayman, 0x1014, _asMatch);
+ setMessageList2(0x004AECC0);
+ }
+ break;
+ case 0x2002:
+ if (getGlobalVar(0x20A0C516)) {
+ sendEntityMessage(_klayman, 0x1014, _asTntMan);
+ setMessageList2(0x004AECF0, false);
+ } else if (getGlobalVar(0x0112090A) == 3) {
+ sendEntityMessage(_klayman, 0x1014, _asTntMan);
+ if (_klayman->getX() > _asTntMan->getX()) {
+ setMessageList(0x004AECD0);
+ } else {
+ setMessageList(0x004AECE0);
+ }
+ }
+ break;
+ case 0x4814:
+ messageList402220();
+ break;
+ case 0x4826:
+ if (sender == _asTape) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList(0x004AED38);
+ }
+ break;
+ case 0x4829:
+ sendMessage(_asRightDoor, 0x4829, 0);
+ break;
+ }
+ return messageResult;
+}
+
+// Scene1202
+
+static const uint32 kScene1202Table[] = {
+ 1, 2, 0, 4, 5, 3, 7, 8, 6, 10, 11, 9, 13, 14, 12, 16, 17, 15
+};
+
+static const NPoint kScene1202Points[] = {
+ {203, 140},
+ {316, 212},
+ {277, 264},
+ {176, 196},
+ {275, 159},
+ {366, 212},
+ {230, 195},
+ {412, 212},
+ {368, 263},
+ {204, 192},
+ {365, 164},
+ {316, 262},
+ {191, 255},
+ {280, 213},
+ {406, 266},
+ {214, 254},
+ {316, 158},
+ {402, 161}
+};
+
+static const uint32 kScene1202FileHashes[] = {
+ 0x1AC00B8,
+ 0x1AC14B8,
+ 0x1AC14B8,
+ 0x1AC30B8,
+ 0x1AC14B8,
+ 0x1AC14B8,
+ 0x1AC00B8,
+ 0x1AC14B8,
+ 0x1AC14B8,
+ 0x1AC90B8,
+ 0x1AC18B8,
+ 0x1AC18B8,
+ 0x1AC30B8,
+ 0x1AC14B8,
+ 0x1AC14B8,
+ 0x1AC50B8,
+ 0x1AC14B8,
+ 0x1AC14B8
+};
+
+AsScene1202TntItem::AsScene1202TntItem(NeverhoodEngine *vm, Scene *parentScene, int index)
+ : AnimatedSprite(vm, 900), _parentScene(parentScene), _index(index) {
+
+ int positionIndex;
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1202TntItem::handleMessage453FE0);
+ positionIndex = getSubVar(0x10055D14, _index);
+ createSurface(900, 37, 67);
+ _x = kScene1202Points[positionIndex].x;
+ _y = kScene1202Points[positionIndex].y;
+ sub4540A0();
+}
+
+uint32 AsScene1202TntItem::handleMessage453FE0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x2000, _index);
+ messageResult = 1;
+ break;
+ case 0x2001:
+ _index2 = (int)param.asInteger();
+ sub4540D0();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1202TntItem::handleMessage454060(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1202TntItem::sub4540A0() {
+ setFileHash(kScene1202FileHashes[_index], 0, -1);
+ SetMessageHandler(&AsScene1202TntItem::handleMessage453FE0);
+ _newHashListIndex = 0;
+}
+
+void AsScene1202TntItem::sub4540D0() {
+ setFileHash(kScene1202FileHashes[_index], 0, -1);
+ SetMessageHandler(&AsScene1202TntItem::handleMessage454060);
+ NextState(&AsScene1202TntItem::sub454100);
+}
+
+void AsScene1202TntItem::sub454100() {
+ _x = kScene1202Points[_index2].x;
+ _y = kScene1202Points[_index2].y;
+ setFileHash(kScene1202FileHashes[_index], 6, -1);
+ SetMessageHandler(&AsScene1202TntItem::handleMessage454060);
+ NextState(&AsScene1202TntItem::sub454160);
+ _playBackwards = true;
+}
+
+void AsScene1202TntItem::sub454160() {
+ sendMessage(_parentScene, 0x2002, _index);
+ sub4540A0();
+}
+
+Scene1202::Scene1202(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _paletteResource(vm), _soundResource1(vm),
+ _soundResource2(vm), _soundResource3(vm), _soundResource4(vm),
+ _flag(true), _soundFlag(false), _counter(0), _index(-1) {
+
+ SetMessageHandler(&Scene1202::handleMessage453C10);
+ SetUpdateHandler(&Scene1202::update);
+
+ _surfaceFlag = true;
+
+ setBackground(0x60210ED5);
+
+ setPalette(0x60210ED5);
+ addEntity(_palette);
+
+ _paletteResource.load(0x60250EB5);
+ _paletteResource.copyPalette(_paletteData);
+
+ insertMouse435(0x10ED160A, 20, 620);
+
+ for (int i = 0; i < 18; i++) {
+ _asTntItems[i] = insertSprite<AsScene1202TntItem>(this, i);
+ _vm->_collisionMan->addSprite(_asTntItems[i]);
+ }
+
+ insertStaticSprite(0x8E8419C1, 1100);
+
+ if (getGlobalVar(0x000CF819)) {
+ SetMessageHandler(&Scene1202::handleMessage453D90);
+ }
+
+ _soundResource1.play(0x40106542);
+ _soundResource2.load(0x40005446);
+ _soundResource2.load(0x40005446);
+ _soundResource2.load(0x68E25540);
+
+}
+
+Scene1202::~Scene1202() {
+ if (isSolved()) {
+ setGlobalVar(0x000CF819, 1);
+ }
+}
+
+void Scene1202::update() {
+ Scene::update();
+ if (_soundFlag) {
+ if (!_soundResource4.isPlaying())
+ leaveScene(0);
+ } else if (_counter == 0 && isSolved()) {
+ SetMessageHandler(&Scene1202::handleMessage453D90);
+ setGlobalVar(0x000CF819, 1);
+ doPaletteEffect();
+ _soundResource4.play();
+ _soundFlag = true;
+ } else if (_index >= 0 && _counter == 0) {
+ int index2 = kScene1202Table[_index];
+ sendMessage(_asTntItems[_index], 0x2001, getSubVar(0x10055D14, index2));
+ sendMessage(_asTntItems[index2], 0x2001, getSubVar(0x10055D14, _index));
+ int temp = getSubVar(0x10055D14, index2);
+ setSubVar(0x10055D14, index2, getSubVar(0x10055D14, _index));
+ setSubVar(0x10055D14, _index, temp);
+ _counter = 2;
+ _index = -1;
+ if (_flag) {
+ _soundResource2.play();
+ } else {
+ _soundResource3.play();
+ }
+ _flag = !_flag;
+ }
+}
+
+uint32 Scene1202::handleMessage453C10(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO: Debug/Cheat stuff
+ if ((param.asPoint().x <= 20 || param.asPoint().x >= 620) && !_soundFlag) {
+ leaveScene(0);
+ }
+ break;
+ case 0x000D:
+ if (param.asInteger() == 0x14210006) {
+ // TODO: Debug/Cheat stuff
+ messageResult = 1;
+ }
+ break;
+ case 0x2000:
+ _index = (int)param.asInteger();
+ break;
+ case 0x2002:
+ _counter--;
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene1202::handleMessage453D90(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ leaveScene(0);
+ }
+ break;
+ }
+ return 0;
+}
+
+bool Scene1202::isSolved() {
+ return
+ getSubVar(0x10055D14, 0) == 0 && getSubVar(0x10055D14, 3) == 3 &&
+ getSubVar(0x10055D14, 6) == 6 && getSubVar(0x10055D14, 9) == 9 &&
+ getSubVar(0x10055D14, 12) == 12 && getSubVar(0x10055D14, 15) == 15;
+}
+
+void Scene1202::doPaletteEffect() {
+#if 0 // TODO
+ Palette2 *palette2 = (Palette2*)_palette;
+ palette2->startFadeToPalette(24);
+#endif
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1200.h b/engines/neverhood/module1200.h
new file mode 100644
index 0000000000..dc8e903472
--- /dev/null
+++ b/engines/neverhood/module1200.h
@@ -0,0 +1,234 @@
+/* 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_MODULE1200_H
+#define NEVERHOOD_MODULE1200_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module1200
+
+class Module1200 : public Module {
+public:
+ Module1200(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1200();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene1201
+
+class AsScene1201Tape : public AnimatedSprite {
+public:
+ AsScene1201Tape(NeverhoodEngine *vm, Scene *parentScene, uint32 nameHash, int surfacePriority, int16 x, int16 y, uint32 fileHash);
+protected:
+ Scene *_parentScene;
+ uint32 _nameHash;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Class466 : public AnimatedSprite {
+public:
+ Class466(NeverhoodEngine *vm, bool flag);
+protected:
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub40D340();
+ void sub40D360();
+ void sub40D380();
+};
+
+class AsScene1201RightDoor : public AnimatedSprite {
+public:
+ AsScene1201RightDoor(NeverhoodEngine *vm, Sprite *klayman, bool flag);
+protected:
+ SoundResource _soundResource;
+ Sprite *_klayman;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub40D7E0();
+ void sub40D830();
+ void sub40D880();
+};
+
+class Class464 : public AnimatedSprite {
+public:
+ Class464(NeverhoodEngine *vm);
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1201TntMan : public AnimatedSprite {
+public:
+ AsScene1201TntMan(NeverhoodEngine *vm, Scene *parentScene, Sprite *class466, bool flag);
+ virtual ~AsScene1201TntMan();
+protected:
+ Scene *_parentScene;
+ Sprite *_class466;
+ Sprite *_sprite;
+ SoundResource _soundResource;
+ bool _flag;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage40CCD0(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate40CD10();
+ void sub40CD30();
+ void sub40CD60();
+ void sub40CD90();
+};
+
+class Class465 : public AnimatedSprite {
+public:
+ Class465(NeverhoodEngine *vm, Sprite *asTntMan);
+ ~Class465();
+protected:
+ Sprite *_asTntMan;
+ void update();
+ void spriteUpdate40D150();
+};
+
+class AsScene1201Match : public AnimatedSprite {
+public:
+ AsScene1201Match(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ int _countdown;
+ int _status;
+ void update();
+ uint32 handleMessage40C2D0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage40C320(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage40C360(int messageNum, const MessageParam &param, Entity *sender);
+ void sub40C3E0();
+ void sub40C420();
+ void sub40C470();
+ void sub40C4C0();
+ void sub40C4F0();
+};
+
+class AsScene1201Creature : public AnimatedSprite {
+public:
+ AsScene1201Creature(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman);
+protected:
+ Scene *_parentScene;
+ Sprite *_klayman;
+ SoundResource _soundResource;
+ int _countdown1;
+ int _countdown2;
+ int _countdown3;
+ bool _flag;
+ void update();
+ uint32 handleMessage40C710(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage40C7B0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage40C830(int messageNum, const MessageParam &param, Entity *sender);
+ void sub40C8E0();
+ void sub40C930();
+ void sub40C960();
+ void sub40C990();
+ void sub40C9B0();
+ void sub40C9E0();
+};
+
+class AsScene1201LeftDoor : public AnimatedSprite {
+public:
+ AsScene1201LeftDoor(NeverhoodEngine *vm, Sprite *klayman);
+protected:
+ Sprite *_klayman;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub40D590();
+};
+
+class SsScene1201Tnt : public StaticSprite {
+public:
+ SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2);
+protected:
+ uint32 _elemIndex;
+ int16 _field7A;
+};
+
+class Scene1201 : public Scene {
+public:
+ Scene1201(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Scene1201();
+protected:
+ // TODO ResourceTable _resourceTable1;
+ // TODO ResourceTable _resourceTable2;
+ Sprite *_asMatch;
+ AsScene1201TntMan *_asTntMan;
+ Sprite *_asCreature;
+ Sprite *_class466;
+ Sprite *_asLeftDoor;
+ Sprite *_asRightDoor;
+ Sprite *_asTape;
+ bool _flag;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1202
+
+class AsScene1202TntItem : public AnimatedSprite {
+public:
+ AsScene1202TntItem(NeverhoodEngine *vm, Scene *parentScene, int index);
+protected:
+ Scene *_parentScene;
+ int _index, _index2;
+ uint32 handleMessage453FE0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage454060(int messageNum, const MessageParam &param, Entity *sender);
+ void sub4540A0();
+ void sub4540D0();
+ void sub454100();
+ void sub454160();
+};
+
+class Scene1202 : public Scene {
+public:
+ Scene1202(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Scene1202();
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ SoundResource _soundResource4;
+ PaletteResource _paletteResource;
+ Sprite *_asTntItems[18];
+ int _counter;
+ int _index;
+ byte _paletteData[1024];
+ bool _soundFlag;
+ bool _flag;
+ void update();
+ uint32 handleMessage453C10(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage453D90(int messageNum, const MessageParam &param, Entity *sender);
+ bool isSolved();
+ void doPaletteEffect();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1200_H */
diff --git a/engines/neverhood/module1300.cpp b/engines/neverhood/module1300.cpp
new file mode 100644
index 0000000000..cb5ed15d99
--- /dev/null
+++ b/engines/neverhood/module1300.cpp
@@ -0,0 +1,1928 @@
+/* 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/module1300.h"
+#include "neverhood/module1000.h"
+#include "neverhood/module1200.h"
+#include "neverhood/module1400.h"
+#include "neverhood/module2200.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/diskplayerscene.h"
+#include "neverhood/navigationscene.h"
+#include "neverhood/smackerscene.h"
+
+namespace Neverhood {
+
+Module1300::Module1300(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ // TODO Music18hList_add(0x61C090, 0x203197);
+ // TODO Sound1ChList_addSoundResources(0x61C090, dword_4B2868, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, 0, 50, 600, 20, 150);
+ // TODO Sound1ChList_sub_407C70(0x61C090, 0x48498E46, 0x50399F64, 0);
+ // TODO Sound1ChList_setVolume(0x48498E46, 70);
+ // TODO Sound1ChList_setVolume(0x50399F64, 70);
+
+ if (which < 0) {
+ if (_vm->gameState().sceneNum >= 1 && _vm->gameState().sceneNum <= 17)
+ createScene(_vm->gameState().sceneNum, -1);
+ else
+ createScene(11, 0);
+ } else {
+ switch (which) {
+ case 0:
+ createScene(11, 0);
+ break;
+ case 1:
+ createScene(13, 0);
+ break;
+ case 2:
+ createScene(14, 0);
+ break;
+ case 3:
+ createScene(15, 0);
+ break;
+ case 4:
+ createScene(7, 0);
+ break;
+ case 5:
+ createScene(5, 1);
+ break;
+ case 6:
+ createScene(5, 5);
+ break;
+ case 7:
+ createScene(3, 0);
+ break;
+ case 8:
+ createScene(1, 0);
+ break;
+ case 9:
+ createScene(2, 0);
+ break;
+ case 10:
+ createScene(6, 0);
+ break;
+ case 11:
+ createScene(4, 0);
+ break;
+ default:
+ createScene(12, 0);
+ break;
+ }
+ }
+
+}
+
+Module1300::~Module1300() {
+ // TODO Sound1ChList_sub_407A50(0x61C090);
+}
+
+void Module1300::createScene(int sceneNum, int which) {
+ debug("Module1300::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 1:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x203197, 0, 2, 1);
+ _childObject = new Scene1302(_vm, this, which);
+ break;
+ case 2:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ _childObject = new Scene1303(_vm, this, which);
+ break;
+ case 3:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ _childObject = new Scene1304(_vm, this, which);
+ break;
+ case 4:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x203197, 0, 2, 1);
+ _childObject = new Scene1305(_vm, this, which);
+ break;
+ case 5:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x203197, 0, 2, 1);
+ _childObject = new Scene1306(_vm, this, which);
+ break;
+ case 6:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x203197, 0, 2, 1);
+ _childObject = new Scene1307(_vm, this, which);
+ break;
+ case 7:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x203197, 0, 2, 1);
+ _childObject = new Scene1308(_vm, this, which);
+ break;
+ case 8:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ _childObject = new DiskplayerScene(_vm, this, 1);
+ break;
+ case 9:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createSmackerScene(0x20082818, true, true, false);
+ break;
+ case 10:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createSmackerScene(0x20082828, true, true, false);
+ break;
+ case 11:
+ // TODO Sound1ChList_setSoundValuesMulti(0xdword_4B2868, true, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createNavigationScene(0x004B27A8, which);
+ break;
+ case 12:
+ // TODO Sound1ChList_setSoundValuesMulti(0xdword_4B2868, true, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createNavigationScene(0x004B2718, which);
+ break;
+ case 13:
+ // TODO Sound1ChList_setSoundValuesMulti(0xdword_4B2868, true, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createNavigationScene(0x004B27D8, which);
+ break;
+ case 14:
+ // TODO Sound1ChList_setSoundValuesMulti(0xdword_4B2868, true, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createNavigationScene(0x004B2808, which);
+ break;
+ case 15:
+ // TODO Sound1ChList_setSoundValuesMulti(0xdword_4B2868, true, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ createNavigationScene(0x004B2838, which);
+ break;
+ case 16:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B2868, false, 0, 0, 0, 0);
+ // TODO Music18hList_stop(0x203197, 0, 2);
+ _childObject = new Scene1317(_vm, this, which);
+ break;
+ case 17:
+ // TODO: Credits scene
+ break;
+ }
+ SetUpdateHandler(&Module1300::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1300::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 1:
+ if (_moduleResult == 1) {
+ createScene(4, 0);
+ } else {
+ createScene(7, 1);
+ }
+ break;
+ case 2:
+ createScene(5, 3);
+ break;
+ case 3:
+ createScene(15, 0);
+ break;
+ case 4:
+ createScene(16, -1);
+ break;
+ case 5:
+ if (_moduleResult == 2) {
+ createScene(8, 0);
+ } else if (_moduleResult == 3) {
+ createScene(2, 0);
+ } else if (_moduleResult == 0) {
+ leaveModule(0);
+ } else if (_moduleResult == 1) {
+ createScene(10, -1);
+ }
+ break;
+ case 6:
+ createScene(7, 2);
+ break;
+ case 7:
+ if (_moduleResult == 0) {
+ createScene(13, 0);
+ } else if (_moduleResult == 1) {
+ createScene(1, 0);
+ } else if (_moduleResult == 2) {
+ createScene(6, 0);
+ }
+ break;
+ case 8:
+ createScene(5, 2);
+ break;
+ case 9:
+ createScene(5, 0);
+ break;
+ case 10:
+ createScene(14, 0);
+ break;
+ case 11:
+ if (_moduleResult == 0)
+ createScene(12, 0);
+ else if (_moduleResult == 1)
+ createScene(11, 1);
+ break;
+ case 12:
+ if (_moduleResult == 0)
+ createScene(14, 1);
+ else if (_moduleResult == 1)
+ createScene(15, 1);
+ else if (_moduleResult == 3)
+ createScene(11, 1);
+ else if (_moduleResult == 5)
+ createScene(13, 1);
+ break;
+ case 13:
+ if (_moduleResult == 0) {
+ createScene(12, 2);
+ } else if (_moduleResult == 1) {
+ createScene(7, 0);
+ }
+ break;
+ case 14:
+ if (_moduleResult == 0) {
+ createScene(12, 3);
+ } else if (_moduleResult == 1) {
+ createScene(9, -1);
+ }
+ break;
+ case 15:
+ if (_moduleResult == 0) {
+ createScene(12, 4);
+ } else if (_moduleResult == 1) {
+ createScene(3, 0);
+ }
+ break;
+ case 16:
+ createScene(17, -1);
+ break;
+ case 17:
+ // TODO
+ break;
+ }
+ }
+}
+
+AsScene1302Bridge::AsScene1302Bridge(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm), _parentScene(parentScene) {
+
+ _x = 320;
+ _y = 240;
+ createSurface1(0x88148150, 500);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1302Bridge::handleMessage);
+ if (!getGlobalVar(0x13206309)) {
+ setFileHash(0x88148150, 0, -1);
+ _newHashListIndex = 0;
+ } else {
+ setFileHash(0x88148150, -1, -1);
+ _newHashListIndex = -2;
+ }
+ _soundResource1.load(0x68895082);
+ _soundResource2.load(0x689BD0C1);
+}
+
+uint32 AsScene1302Bridge::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ stLowerBridge();
+ break;
+ case 0x4809:
+ stRaiseBridge();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1302Bridge::stLowerBridge() {
+ setFileHash(0x88148150, 0, -1);
+ NextState(&AsScene1302Bridge::cbLowerBridgeEvent);
+ _soundResource2.play();
+}
+
+void AsScene1302Bridge::stRaiseBridge() {
+ setFileHash(0x88148150, 7, -1);
+ _playBackwards = true;
+ _newHashListIndex = 0;
+ _soundResource1.play();
+}
+
+void AsScene1302Bridge::cbLowerBridgeEvent() {
+ sendMessage(_parentScene, 0x2032, 0);
+ setFileHash(0x88148150, -1, -1);
+ _newHashListIndex = -2;
+}
+
+SsScene1302Fence::SsScene1302Fence(NeverhoodEngine *vm)
+ : StaticSprite(vm, 0x11122122, 200), _soundResource1(vm), _soundResource2(vm) {
+
+ SetUpdateHandler(&SsScene1302Fence::update);
+ SetMessageHandler(&SsScene1302Fence::handleMessage);
+ SetSpriteCallback(NULL);
+ _firstY = _y;
+ if (getGlobalVar(0x80101B1E))
+ _y += 152;
+ _soundResource1.load(0x7A00400C);
+ _soundResource2.load(0x78184098);
+}
+
+void SsScene1302Fence::update() {
+ handleSpriteUpdate();
+ StaticSprite::update();
+}
+
+uint32 SsScene1302Fence::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4808:
+ _soundResource1.play();
+ SetSpriteCallback(&SsScene1302Fence::suMoveDown);
+ SetMessageHandler(NULL);
+ break;
+ case 0x4809:
+ _soundResource2.play();
+ SetSpriteCallback(&SsScene1302Fence::suMoveUp);
+ SetMessageHandler(NULL);
+ break;
+ }
+ return messageResult;
+}
+
+void SsScene1302Fence::suMoveDown() {
+ if (_y < _firstY + 152)
+ _y += 8;
+ else {
+ SetMessageHandler(&SsScene1302Fence::handleMessage);
+ SetSpriteCallback(NULL);
+ }
+}
+
+void SsScene1302Fence::suMoveUp() {
+ if (_y > _firstY)
+ _y -= 8;
+ else {
+ SetMessageHandler(&SsScene1302Fence::handleMessage);
+ SetSpriteCallback(NULL);
+ }
+}
+
+Class595::Class595(NeverhoodEngine *vm, Scene *parentScene)
+ : StaticSprite(vm, 0xB0420130, 1015), _parentScene(parentScene) {
+
+ SetMessageHandler(&Class595::handleMessage);
+}
+
+uint32 Class595::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 995);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1015);
+ break;
+ }
+ return messageResult;
+}
+
+Scene1302::Scene1302(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm) {
+
+ SetMessageHandler(&Scene1302::handleMessage);
+ setHitRects(0x004B0858);
+ setRectList(0x004B0A38);
+
+ setBackground(0x420643C4);
+ setPalette(0x420643C4);
+ insertMouse433(0x643C0428);
+
+ _class595 = insertSprite<Class595>(this);
+ _sprite1 = insertStaticSprite(0x942FC224, 300);
+ _sprite2 = insertStaticSprite(0x70430830, 1200);
+ _sprite2->setVisible(false);
+ _sprite3 = insertStaticSprite(0x16E01E20, 1100);
+
+ _asRing1 = insertSprite<AsScene1002Ring>(this, false, 218, 122, _class595->getDrawRect().y, false);
+ _asRing2 = insertSprite<AsScene1002Ring>(this, true, 218 + 32, 132, _class595->getDrawRect().y, getGlobalVar(0x13206309));
+ _asRing3 = insertSprite<AsScene1002Ring>(this, false, 218 + 32 + 32, 122, _class595->getDrawRect().y, false);
+ _asRing4 = insertSprite<AsScene1002Ring>(this, true, 218 + 32 + 32 + 32, 132, _class595->getDrawRect().y, getGlobalVar(0x80101B1E));
+ _asRing5 = insertSprite<AsScene1002Ring>(this, false, 218 + 32 + 32 + 32 + 32, 115, _class595->getDrawRect().y, false);
+
+ _asBridge = insertSprite<AsScene1302Bridge>(this);
+ _ssFence = insertSprite<SsScene1302Fence>();
+ _ssFence->setClipRect(0, 0, 640, _sprite1->getDrawRect().y2());
+
+ if (which < 0) {
+ insertKlayman<KmScene1002>(380, 364, _class595, (Sprite*)NULL);
+ setMessageList(0x004B0868);
+ } else {
+ insertKlayman<KmScene1002>(293, 330, _class595, (Sprite*)NULL);
+ setMessageList(0x004B0870);
+ }
+
+ _klayman->setClipRect(0, 0, _sprite3->getDrawRect().x2(), 480);
+
+ _asVenusFlyTrap = insertSprite<AsScene1002VenusFlyTrap>(this, _klayman, true);
+ _vm->_collisionMan->addSprite(_asVenusFlyTrap);
+
+ sendEntityMessage(_klayman, 0x2007, _asVenusFlyTrap);
+
+}
+
+uint32 Scene1302::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = 0;
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x4A845A00) {
+ sendEntityMessage(_klayman, 0x1014, _asRing1);
+ } else if (param.asInteger() == 0x43807801) {
+ if (!getGlobalVar(0x13206309)) {
+ sendEntityMessage(_klayman, 0x1014, _asRing2);
+ if (_asVenusFlyTrap->getX() - 10 < 218 + 32 && _asVenusFlyTrap->getX() + 10 > 218 + 32) {
+ setMessageList(0x004B0940);
+ } else {
+ setMessageList(0x004B0938);
+ }
+ } else {
+ setMessageList(0x004B0950);
+ }
+ messageResult = 1;
+ } else if (param.asInteger() == 0x46C26A01) {
+ sendEntityMessage(_klayman, 0x1014, _asRing3);
+ } else if (param.asInteger() == 0x468C7B11) {
+ if (!getGlobalVar(0x80101B1E)) {
+ sendEntityMessage(_klayman, 0x1014, _asRing4);
+ if (_asVenusFlyTrap->getX() - 10 < 218 + 32 + 32 + 32 && _asVenusFlyTrap->getX() + 10 > 218 + 32 + 32 + 32) {
+ setMessageList(0x004B0940);
+ } else {
+ setMessageList(0x004B0938);
+ }
+ } else {
+ setMessageList(0x004B0950);
+ }
+ messageResult = 1;
+ } else if (param.asInteger() == 0x42845B19) {
+ sendEntityMessage(_klayman, 0x1014, _asRing5);
+ } else if (param.asInteger() == 0x430A6060) {
+ if (getGlobalVar(0x13206309)) {
+ setMessageList2(0x004B0910);
+ } else {
+ messageList402220();
+ }
+ } else if (param.asInteger() == 0x012E2070) {
+ if (getGlobalVar(0x13206309)) {
+ setMessageList2(0x004B0968);
+ } else {
+ messageList402220();
+ }
+ } else if (param.asInteger() == 0x11C40840) {
+ if (_asVenusFlyTrap->getX() >= 260 && _asVenusFlyTrap->getX() <= 342) {
+ setMessageList(0x004B0878);
+ } else {
+ setMessageList(0x004B0978);
+ }
+ }
+ break;
+ case 0x2000:
+ if (_klayman->getY() > 360) {
+ sendEntityMessage(_klayman, 0x1014, _asVenusFlyTrap);
+ setMessageList2(0x004B08F0);
+ } else {
+ setMessageList2(0x004B0920);
+ }
+ break;
+ case 0x2002:
+ if (_klayman->getX() > 545) {
+ leaveScene(1);
+ }
+ break;
+ case 0x2032:
+ _sprite2->setVisible(true);
+ break;
+ case 0x4806:
+ sendMessage(_parentModule, 0x1024, 2);
+ if (sender == _asRing1) {
+ _soundResource.play(0x665198C0);
+ } else if (sender == _asRing2) {
+ sendMessage(_asBridge, 0x4808, 0);
+ setGlobalVar(0x13206309, 1);
+ } else if (sender == _asRing3) {
+ _soundResource.play(0xE2D389C0);
+ } else if (sender == _asRing4) {
+ sendMessage(_ssFence, 0x4808, 0);
+ setGlobalVar(0x80101B1E, 1);
+ } else if (sender == _asRing5) {
+ _soundResource.play(0x40428A09);
+ }
+ break;
+ case 0x4807:
+ if (sender == _asRing2) {
+ sendMessage(_asBridge, 0x4809, 0);
+ setGlobalVar(0x13206309, 0);
+ _sprite2->setVisible(false);
+ } else if (sender == _asRing4) {
+ sendMessage(_ssFence, 0x4809, 0);
+ setGlobalVar(0x80101B1E, 0);
+ } else if (sender == _asVenusFlyTrap) {
+ if (getGlobalVar(0x13206309)) {
+ sendMessage(_asRing2, 0x4807, 0);
+ } else {
+ sendMessage(_asRing4, 0x4807, 0);
+ }
+ }
+ break;
+ case 0x480F:
+ if (sender == _asRing2) {
+ _soundResource.play(0x60755842);
+ sendMessage(_asBridge, 0x4808, 0);
+ setGlobalVar(0x13206309, 1);
+ } else if (sender == _asRing4) {
+ _soundResource.play(0x60755842);
+ sendMessage(_ssFence, 0x4808, 0);
+ setGlobalVar(0x80101B1E, 1);
+ }
+ break;
+ case 0x482A:
+ sendMessage(_asVenusFlyTrap, 0x482B, 0);
+ break;
+ case 0x482B:
+ sendMessage(_asVenusFlyTrap, 0x482A, 0);
+ break;
+ }
+ return messageResult;
+}
+
+AsScene1303Balloon::AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene) {
+
+ // TODO createSurface3(200, dword_4AF9F8);
+ createSurface(200, 640, 480); //TODO: Remeove once the line above is done
+ _x = 289;
+ _y = 390;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1303Balloon::handleMessage);
+ SetSpriteCallback(&AnimatedSprite::updateDeltaXY);
+ setFileHash(0x800278D2, 0, -1);
+}
+
+uint32 AsScene1303Balloon::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x2000:
+ stPopBalloon();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1303Balloon::hmBalloonPopped(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x020B0003) {
+ _soundResource.play(0x742B0055);
+ }
+ break;
+ case 0x3002:
+ _soundResource.play(0x470007EE);
+ stopAnimation();
+ SetMessageHandler(NULL);
+ setVisible(false);
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1303Balloon::stPopBalloon() {
+ setFileHash(0xAC004CD0, 0, -1);
+ SetMessageHandler(&AsScene1303Balloon::hmBalloonPopped);
+}
+
+Scene1303::Scene1303(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1303::handleMessage);
+ setRectList(0x004AF9E8);
+
+ setBackground(0x01581A9C);
+ setPalette(0x01581A9C);
+ insertMouse433(0x81A9801D);
+
+ if (!getGlobalVar(0xAC00C0D0)) {
+ _asBalloon = insertSprite<AsScene1303Balloon>(this);
+ _vm->_collisionMan->addSprite(_asBalloon);
+ }
+
+ _sprite1 = insertStaticSprite(0xA014216B, 1100);
+
+ insertKlayman<KmScene1303>(207, 332);
+ setMessageList(0x004AF9A0);
+
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+
+}
+
+uint32 Scene1303::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ setGlobalVar(0xAC00C0D0, 1);
+ sendMessage(_asBalloon, 0x2000, 0);
+ break;
+ case 0x4826:
+ if (sender == _asBalloon && getGlobalVar(0x31C63C51)) {
+ setMessageList(0x004AF9B8);
+ }
+ break;
+ }
+ return 0;
+}
+
+Class544::Class544(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y)
+ : AnimatedSprite(vm, 0x548E9411, surfacePriority, x, y), _parentScene(parentScene) {
+
+ if (getGlobalVar(0x31C63C51)) {
+ setVisible(false);
+ SetMessageHandler(NULL);
+ } else {
+ SetMessageHandler(&Class544::handleMessage);
+ }
+}
+
+uint32 Class544::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x4806:
+ setGlobalVar(0x31C63C51, 1);
+ setVisible(false);
+ SetMessageHandler(NULL);
+ break;
+ }
+ return messageResult;
+}
+
+Scene1304::Scene1304(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1304::handleMessage);
+ setRectList(0x004B91A8);
+
+ setBackground(0x062C0214);
+ setPalette(0x062C0214);
+ insertMouse433(0xC021006A);
+
+ if (getGlobalVar(0xAC00C0D0)) {
+ _class545 = insertSprite<Class545>(this, 0, 1100, 278, 347);
+ _vm->_collisionMan->addSprite(_class545);
+ } else {
+ _class545 = insertSprite<AnimatedSprite>(0x80106018, 100, 279, 48);
+ // TODO _class545->setUpdateDeltaXY();
+ }
+
+ if (!getGlobalVar(0x31C63C51)) {
+ _class544 = insertSprite<Class544>(this, 1100, 278, 347);
+ _vm->_collisionMan->addSprite(_class544);
+ } else {
+ _class544 = NULL;
+ }
+
+ _sprite1 = insertStaticSprite(0x0562E621, 1100);
+ insertStaticSprite(0x012AE033, 1100);
+ insertStaticSprite(0x090AF033, 1100);
+
+ if (which < 0) {
+ insertKlayman<KmScene1304>(217, 347);
+ setMessageList(0x004B90E8);
+ } else {
+ insertKlayman<KmScene1304>(100, 347);
+ setMessageList(0x004B90F0);
+ }
+
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+
+}
+
+uint32 Scene1304::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x415634A4) {
+ if (getGlobalVar(0xAC00C0D0)) {
+ messageList402220();
+ } else {
+ setMessageList(0x004B9158);
+ }
+ }
+ break;
+ case 0x4826:
+ if (sender == _class544) {
+ sendEntityMessage(_klayman, 0x1014, _class544);
+ setMessageList(0x004B9130);
+ } else if (sender == _class545) {
+ sendEntityMessage(_klayman, 0x1014, _class545);
+ setMessageList(0x004B9140);
+ }
+ break;
+ }
+ return 0;
+}
+
+Scene1305::Scene1305(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1305::handleMessage);
+ setRectList(0x004B6E98);
+
+ setBackground(0x28801B64);
+ setPalette(0x28801B64);
+ insertMouse433(0x01B60280);
+
+ if (which < 0) {
+ insertKlayman<KmScene1305>(212, 441);
+ setMessageList(0x004B6E40);
+ } else {
+ insertKlayman<KmScene1305>(212, 441);
+ setMessageList(0x004B6E48);
+ }
+
+}
+
+uint32 Scene1305::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ return Scene::handleMessage(messageNum, param, sender);
+}
+
+AsScene1306Elevator::AsScene1306Elevator(NeverhoodEngine *vm, Scene *parentScene, AnimatedSprite *asElevatorDoor)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm), _soundResource3(vm),
+ _parentScene(parentScene), _asElevatorDoor(asElevatorDoor), _isUp(false), _isDown(true),
+ _countdown(0) {
+
+ _x = 320;
+ _y = 240;
+ createSurface1(0x043B0270, 100);
+ setFileHash(0x043B0270, 0, -1);
+ _newHashListIndex = 0;
+ SetMessageHandler(&AsScene1306Elevator::handleMessage);
+ _soundResource1.load(0x1C100E83);
+ _soundResource2.load(0x1C08CEC5);
+ _soundResource3.load(0x5D011E87);
+}
+
+void AsScene1306Elevator::update() {
+ if (_isUp && _countdown != 0 && (--_countdown == 0)) {
+ stGoingDown();
+ }
+ AnimatedSprite::update();
+ if (_frameIndex == 7) {
+ _soundResource3.play();
+ _asElevatorDoor->setVisible(false);
+ }
+}
+
+void AsScene1306Elevator::upGoingDown() {
+ AnimatedSprite::update();
+ if (_frameIndex == 5) {
+ _asElevatorDoor->setVisible(true);
+ }
+}
+
+uint32 AsScene1306Elevator::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2001:
+ if (_isUp)
+ _countdown = 144;
+ messageResult = _isUp ? 1 : 0;
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ if (_isDown)
+ stGoingUp();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1306Elevator::stGoingUp() {
+ setVisible(true);
+ _isDown = false;
+ SetUpdateHandler(&AsScene1306Elevator::update);
+ setFileHash(0x043B0270, 0, -1);
+ NextState(&AsScene1306Elevator::cbGoingUpEvent);
+ _soundResource1.play();
+}
+
+void AsScene1306Elevator::cbGoingUpEvent() {
+ SetUpdateHandler(&AsScene1306Elevator::update);
+ sendMessage(_parentScene, 0x4808, 0);
+ _isUp = true;
+ _countdown = 144;
+ stopAnimation();
+ setVisible(false);
+}
+
+void AsScene1306Elevator::stGoingDown() {
+ SetUpdateHandler(&AsScene1306Elevator::upGoingDown);
+ _isUp = false;
+ setVisible(true);
+ setFileHash(0x043B0270, -1, -1);
+ _playBackwards = true;
+ NextState(&AsScene1306Elevator::cbGoingDownEvent);
+ _soundResource2.play();
+}
+
+void AsScene1306Elevator::cbGoingDownEvent() {
+ _isDown = true;
+ sendMessage(_parentScene, 0x4809, 0);
+ SetUpdateHandler(&AsScene1306Elevator::update);
+ stopAnimation();
+}
+
+Scene1306::Scene1306(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ if (getGlobalVar(0xC0780812) && !getGlobalVar(0x13382860))
+ setGlobalVar(0x13382860, 4);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1306::handleMessage);
+
+ setBackground(0x05303114);
+ setPalette(0x05303114);
+ insertMouse433(0x0311005B);
+
+ if (!getGlobalVar(0x13382860)) {
+ _class545 = insertSprite<Class545>(this, 2, 1100, 435, 445);
+ _vm->_collisionMan->addSprite(_class545);
+ }
+
+ _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x404A36A0, 100, 0x440C1000);
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 19, 1100, 359, 445, 0x9148A011);
+
+ _asElevatorDoor = insertSprite<AnimatedSprite>(0x043B0270, 90, 320, 240);
+ _asElevatorDoor->setFileHash(0x043B0270, 6, -1);
+ _asElevatorDoor->setNewHashListIndex(6);
+
+ _asElevator = insertSprite<AsScene1306Elevator>(this, _asElevatorDoor);
+
+ _sprite1 = insertStaticSprite(0x036A1EE0, 80);
+
+ insertStaticSprite(0x00042313, 1100);
+
+ if (which < 0) {
+ insertKlayman<KmScene1306>(380, 440);
+ setMessageList(0x004AFAD0);
+ sendMessage(this, 0x2000, 0);
+ _vm->_collisionMan->addSprite(_asTape);
+ } else if (which == 1) {
+ insertKlayman<KmScene1306>(136, 440);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004AFAF0);
+ sendMessage(this, 0x2000, 1);
+ _vm->_collisionMan->addSprite(_asTape);
+ } else if (which == 2) {
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene1306>(515, 440);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene1306>(355, 440);
+ }
+ setMessageList(0x004AFBC8);
+ sendMessage(this, 0x2000, 0);
+ _vm->_collisionMan->addSprite(_asTape);
+ } else if (which == 3) {
+ insertKlayman<KmScene1306>(534, 440);
+ setMessageList(0x004AFC30);
+ sendMessage(this, 0x2000, 0);
+ _vm->_collisionMan->addSprite(_asTape);
+ } else if (which == 4) {
+ insertKlayman<KmScene1306>(136, 440);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004AFC38);
+ sendMessage(this, 0x2000, 1);
+ _vm->_collisionMan->addSprite(_asTape);
+ } else if (which == 5) {
+ insertKlayman<KmScene1306>(136, 440);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004AFB00);
+ sendMessage(this, 0x2000, 1);
+ _vm->_collisionMan->addSprite(_asTape);
+ } else {
+ insertKlayman<KmScene1306>(286, 408);
+ setSurfacePriority(_asElevator->getSurface(), 1100);
+ setSurfacePriority(_asElevatorDoor->getSurface(), 1090);
+ setSurfacePriority(_sprite1->getSurface(), 1080);
+ sendMessage(this, 0x2000, 0);
+ SetMessageHandler(&Scene1306::handleMessage416EB0);
+ clearRectList();
+ sendMessage(_asElevator, 0x4808, 0);
+ }
+
+}
+
+Scene1306::~Scene1306() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+uint32 Scene1306::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x402064D8) {
+ sendEntityMessage(_klayman, 0x1014, _ssButton);
+ } else if (param.asInteger() == 0x01C66840) {
+ if (sendMessage(_asElevator, 0x2001, 0) != 0) {
+ setMessageList(0x004AFBD8);
+ } else {
+ setMessageList(0x004AFAE0);
+ }
+ } else if (param.asInteger() == 0x8E646E00) {
+ setMessageList(0x004AFAD8);
+ clearRectList();
+ SetMessageHandler(&Scene1306::handleMessage416EB0);
+ }
+ break;
+ case 0x2000:
+ if (param.asInteger() != 0) {
+ setRectList(0x004AFD28);
+ _klayman->setKlaymanTable3();
+ } else {
+ setRectList(0x004AFD18);
+ _klayman->setKlaymanTable1();
+ }
+ break;
+ case 0x480B:
+ if (sender == _ssButton) {
+ sendMessage(_asElevator, 0x4808, 0);
+ }
+ break;
+ case 0x4826:
+ if (sender == _class545) {
+ if (_klayman->getX() >= 249) {
+ sendEntityMessage(_klayman, 0x1014, _class545);
+ setMessageList(0x004AFC58);
+ }
+ } else if (sender == _asTape) {
+ if (_klayman->getX() >= 249) {
+ sendEntityMessage(_klayman, 0x1014, _class545);
+ setMessageList(0x004AFC68);
+ }
+ }
+ break;
+ case 0x482A:
+ setSurfacePriority(_asElevator->getSurface(), 1100);
+ setSurfacePriority(_asElevatorDoor->getSurface(), 1090);
+ setSurfacePriority(_sprite1->getSurface(), 1080);
+ break;
+ case 0x482B:
+ setSurfacePriority(_asElevator->getSurface(), 100);
+ setSurfacePriority(_asElevatorDoor->getSurface(), 90);
+ setSurfacePriority(_sprite1->getSurface(), 80);
+ sendMessage(this, 0x2000, 0);
+ _vm->_collisionMan->addSprite(_asTape);
+ break;
+ }
+ return 0;
+}
+
+uint32 Scene1306::handleMessage416EB0(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4808:
+ setMessageList(0x004AFBD0);
+ SetMessageHandler(&Scene1306::handleMessage);
+ break;
+ case 0x4809:
+ leaveScene(1);
+ break;
+ case 0x482A:
+ setSurfacePriority(_asElevator->getSurface(), 1100);
+ setSurfacePriority(_asElevatorDoor->getSurface(), 1090);
+ setSurfacePriority(_sprite1->getSurface(), 1080);
+ break;
+ case 0x482B:
+ setSurfacePriority(_asElevator->getSurface(), 100);
+ setSurfacePriority(_asElevatorDoor->getSurface(), 90);
+ setSurfacePriority(_sprite1->getSurface(), 80);
+ sendMessage(this, 0x2000, 0);
+ _vm->_collisionMan->addSprite(_asTape);
+ break;
+ }
+ 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) {
+ sendMessage(_parentScene, 0x4826, 0);
+ 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);
+ sendMessage(_parentScene, 0x2002, 0);
+ }
+}
+
+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;
+ sendMessage(_parentScene, 0x1022, kAsScene1307KeySurfacePriorities[getSubVar(0xA010B810, _index) % 4]);
+ setClipRect(_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;
+ sendMessage(_parentScene, 0x1022, 1000);
+ setClipRect(0, 0, 640, 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);
+
+ setBackground(0xA8006200);
+ setPalette(0xA8006200);
+ addEntity(_palette);
+ insertMouse435(0x06204A88, 20, 620);
+
+ tempSprite = insertStaticSprite(0x00A3621C, 800);
+ _clipRects[0].set(tempSprite->getDrawRect().x, 0, 640, 480);
+
+ tempSprite = insertStaticSprite(0x00A3641C, 600);
+ _clipRects[1].set(tempSprite->getDrawRect().x, 0, 640, 480);
+
+ tempSprite = insertStaticSprite(0x00A3681C, 400);
+ _clipRects[2].set(tempSprite->getDrawRect().x, 0, 640, 480);
+
+ tempSprite = insertStaticSprite(0x00A3701C, 200);
+ _clipRects[3].set(tempSprite->getDrawRect().x, 0, 640, 480);
+
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex)) {
+ _asKeys[keyIndex] = insertSprite<AsScene1307Key>(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()) {
+ leaveScene(1);
+ 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
+ sendMessage(_asCurrKey, 0x2001, clickedKeyHoleIndex);
+ _isInsertingKey = true;
+ _mouseClicked = false;
+ }
+ }
+ }
+ } else if (_countdown == 0 && !_asCurrKey && !_isInsertingKey) {
+ leaveScene(0);
+ }
+ }
+ 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])
+ sendMessage(_asKeys[keyIndex], 0x2003, 1);
+ }
+ _soundResource.play();
+ _isPuzzleSolved = true;
+ _countdown = 47;
+ } else {
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex) && _asKeys[keyIndex]) {
+ sendMessage(_asKeys[keyIndex], 0x2000, 1);
+ }
+ }
+ sendMessage(_asCurrKey, 0x2004, 1);
+ }
+ _asCurrKey = NULL;
+ _isInsertingKey = false;
+ break;
+ case 0x4826:
+ _asCurrKey = (Sprite*)sender;
+ for (uint keyIndex = 0; keyIndex < 3; keyIndex++) {
+ if (getSubVar(0x08D0AB11, keyIndex) && _asKeys[keyIndex]) {
+ sendMessage(_asKeys[keyIndex], 0x2000, 0);
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+static const uint32 kScene1308FileHashes[] = {
+ 0x08006320,
+ 0x10006320,
+ 0x20006320,
+ 0x40006320,
+ 0x80006320,
+ 0x00006321,
+ 0x00006322,
+ 0x00006324,
+ 0x00006328,
+ 0x08306320,
+ 0x10306320,
+ 0x20306320,
+ 0x40306320,
+ 0x80306320,
+ 0x00306321,
+ 0x00306322
+};
+
+Class549::Class549(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 0xBA0AE050, 1100, 320, 240), _soundResource(vm),
+ _parentScene(parentScene) {
+
+ SetMessageHandler(&Class549::handleMessage);
+ setVisible(false);
+ stopAnimation();
+}
+
+uint32 Class549::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ sub455470();
+ break;
+ case 0x4809:
+ sub4554F0();
+ break;
+ }
+ return messageResult;
+}
+
+void Class549::sub455470() {
+ setFileHash(0xBA0AE050, 0, -1);
+ setVisible(true);
+ NextState(&Class549::hide);
+ _soundResource.play(calcHash("fxDoorOpen38"));
+}
+
+void Class549::hide() {
+ sendMessage(_parentScene, 0x2000, 0);
+ stopAnimation();
+ setVisible(false);
+}
+
+void Class549::sub4554F0() {
+ setFileHash(0xBA0AE050, -1, -1);
+ _playBackwards = true;
+ setVisible(true);
+ NextState(&Class549::sub455550);
+ _soundResource.play(calcHash("fxDoorClose38"));
+}
+
+void Class549::sub455550() {
+ sendMessage(_parentScene, 0x2001, 0);
+ stopAnimation();
+}
+
+Class592::Class592(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 0xA08A0851, 1100, 320, 240), _soundResource(vm),
+ _parentScene(parentScene) {
+
+ SetMessageHandler(&Class592::handleMessage);
+ NextState(&Class592::sub455710);
+ _soundResource.play(0x51456049);
+}
+
+uint32 Class592::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void Class592::sub455710() {
+ setFileHash(0x6238B191, 0, -1);
+ NextState(&Class592::sub455740);
+ _x = 580;
+ _y = 383;
+}
+
+void Class592::sub455740() {
+ sendMessage(_parentScene, 0x2004, 0);
+ stopAnimation();
+ setVisible(false);
+}
+
+Class593::Class593(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 0x80180A10, 100, 320, 240), _parentScene(parentScene) {
+
+ SetMessageHandler(&Class593::handleMessage);
+ setVisible(false);
+ stopAnimation();
+ Entity::_priority = 1200;
+}
+
+uint32 Class593::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2002:
+ sub4558F0();
+ break;
+ case 0x2003:
+ sub455920();
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void Class593::sub4558F0() {
+ setFileHash(0x80180A10, 0, -1);
+ setVisible(false);
+ _newHashListIndex = -2;
+}
+
+void Class593::sub455920() {
+ setFileHash(0x80180A10, -1, -1);
+ _playBackwards = true;
+ NextState(&Class593::sub455950);
+}
+
+void Class593::sub455950() {
+ sendMessage(_parentScene, 0x2003, 0);
+ stopAnimation();
+ setVisible(false);
+}
+
+Class601::Class601(NeverhoodEngine *vm, uint32 fileHash, int index)
+ : StaticSprite(vm, fileHash, 100) {
+
+ setVisible(false);
+ _x = _spriteResource.getPosition().x + index * 20;
+ StaticSprite::update();
+}
+
+Class513::Class513(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100), _soundResource(vm) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class513::handleMessage);
+ _x = 286;
+ _y = 429;
+ createSurface1(0xA282C472, 100);
+ setFileHash(0xA282C472, 0, -1);
+}
+
+uint32 Class513::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x66382026) {
+ _soundResource.play(0x0CD84468);
+ } else if (param.asInteger() == 0x6E28061C) {
+ _soundResource.play(0x78C8402C);
+ } else if (param.asInteger() == 0x462F0410) {
+ _soundResource.play(0x60984E28);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+Scene1308::Scene1308(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _flag1(false) {
+
+ _vm->gameModule()->initScene1307Vars();
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1308::handleMessage);
+
+ setBackground(0x41024202);
+ setPalette(0x41024202);
+ insertMouse433(0x24206418);
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 17, 1100, 502, 445, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ if (getGlobalVar(0x01023818)) {
+ insertSprite<Class513>();
+ insertSprite<AnimatedSprite>(0x461A1490, 200, 235, 429);
+ }
+
+ _sprite1 = insertStaticSprite(0x0A042060, 1100);
+ _class549 = insertSprite<Class549>(this);
+ _class593 = insertSprite<Class593>(this);
+
+ _class601_1 = insertSprite<Class601>(kScene1308FileHashes[getSubVar(0x0C10A000, 1)], 0);
+ _class601_2 = insertSprite<Class601>(kScene1308FileHashes[getSubVar(0x0C10A000, 0)], 1);
+ _class601_2 = insertSprite<Class601>(kScene1308FileHashes[getSubVar(0x0C10A000, 2)], 2);
+
+ _sprite2 = insertStaticSprite(0x40043120, 995);
+ _sprite3 = insertStaticSprite(0x43003100, 995);
+ _sprite4 = NULL;
+
+ if (which < 0) {
+ insertKlayman<KmScene1308>(380, 440);
+ setMessageList(0x004B57C0);
+ if (getGlobalVar(0x80455A41)) {
+ _sprite4 = insertStaticSprite(0x0101A624, 1100);
+ setRectList(0x004B5990);
+ } else {
+ _sprite5 = insertStaticSprite(0x080811A0, 100);
+ setRectList(0x004B5980);
+ }
+ } else if (which == 1) {
+ insertKlayman<KmScene1308>(640, 440);
+ setMessageList(0x004B57C8);
+ if (getGlobalVar(0x80455A41)) {
+ _sprite4 = insertStaticSprite(0x0101A624, 1100);
+ setRectList(0x004B5990);
+ } else {
+ _sprite5 = insertStaticSprite(0x080811A0, 100);
+ setRectList(0x004B5980);
+ }
+ } else if (which == 2) {
+ insertKlayman<KmScene1308>(475, 440);
+ setMessageList(0x004B58B0);
+ if (getGlobalVar(0x80455A41)) {
+ _sprite5 = insertSprite<Class592>(this);
+ _sprite4 = insertStaticSprite(0x0101A624, 1100);
+ _sprite4->setVisible(false);
+ } else {
+ _sprite5 = insertStaticSprite(0x080811A0, 100);
+ setRectList(0x004B5980);
+ }
+ } else {
+ insertKlayman<KmScene1308>(41, 440);
+ setMessageList(0x004B57D0);
+ sendMessage(_class549, 0x4808, 0);
+ _sprite1->setVisible(false);
+ if (getGlobalVar(0x80455A41)) {
+ _sprite4 = insertStaticSprite(0x0101A624, 1100);
+ _klayman->setVisible(false);
+ } else {
+ _sprite5 = insertStaticSprite(0x080811A0, 100);
+ _klayman->setVisible(false);
+ }
+ }
+
+ if (_sprite4) {
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, _sprite4->getDrawRect().x2(), 480);
+ } else {
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+ }
+
+ if (getGlobalVar(0x04A105B3) == 4) {
+ _class489 = insertSprite<Class489>(this, _klayman, (Sprite*)NULL);
+ _vm->_collisionMan->addSprite(_class489);
+ _class489->setClipRect(0, 0, 640, _sprite2->getDrawRect().y2());
+ _class489->setRepl(64, 0);
+ } else {
+ _class489 = NULL;
+ }
+
+}
+
+uint32 Scene1308::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x88C11390) {
+ setRectList(0x004B59A0);
+ _flag1 = true;
+ } else if (param.asInteger() == 0x08821382) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ if (getGlobalVar(0x80455A41)) {
+ setRectList(0x004B5990);
+ } else {
+ setRectList(0x004B5980);
+ }
+ _flag1 = false;
+ } else if (param.asInteger() == 0x4AC68808) {
+ clearRectList();
+ sendMessage(_class549, 0x4809, 0);
+ _sprite1->setVisible(false);
+ _klayman->setVisible(false);
+ }
+ break;
+ case 0x1022:
+ if (sender == _class489) {
+ if (param.asInteger() >= 1000)
+ setSurfacePriority(_sprite3->getSurface(), 1100);
+ else
+ setSurfacePriority(_sprite3->getSurface(), 995);
+ }
+ break;
+ case 0x2000:
+ if (getGlobalVar(0x80455A41)) {
+ setRectList(0x004B5990);
+ } else {
+ setRectList(0x004B5980);
+ }
+ setMessageList(0x004B57E8, false);
+ _sprite1->setVisible(true);
+ _klayman->setVisible(true);
+ break;
+ case 0x2001:
+ leaveScene(0);
+ break;
+ case 0x2003:
+ _class601_1->setVisible(false);
+ _class601_2->setVisible(false);
+ _class601_3->setVisible(false);
+ break;
+ case 0x2004:
+ _sprite4->setVisible(true);
+ setRectList(0x004B5990);
+ break;
+ case 0x4807:
+ sendMessage(_class593, 0x2003, 0);
+ break;
+ case 0x480F:
+ sendMessage(_class593, 0x2002, 0);
+ _class601_1->setVisible(true);
+ _class601_2->setVisible(true);
+ _class601_3->setVisible(true);
+ break;
+ case 0x4826:
+ if (sender == _class489) {
+ if (_flag1) {
+ setMessageList2(0x004B5868);
+ } else {
+ if (param.asInteger() == 1) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B5848);
+ } else if (sendMessage(_class489, 0x480C, _klayman->getX() <= _class489->getX() ? 0 : 1) != 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B5830);
+ } else {
+ setMessageList2(0x004B5800);
+ }
+ }
+ } else if (sender == _asTape) {
+ if (_flag1) {
+ setMessageList2(0x004B5868);
+ } else if (_messageListStatus != 2) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList2(0x004B58E0);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+Scene1317::Scene1317(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ SetMessageHandler(&Scene1317::handleMessage);
+ _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, 0x08982841, true, false));
+ insertMouse433(0x08284011);
+ showMouse(false);
+ _smackerFileHash = 0;
+ _smackerFlag1 = false;
+}
+
+void Scene1317::update() {
+ if (_smackerFileHash) {
+ _smackerPlayer->open(_smackerFileHash, _smackerFlag1);
+ _smackerFileHash = 0;
+ }
+ Scene::update();
+}
+
+void Scene1317::upChooseKing() {
+ if (!_klaymanBlinks && _klaymanBlinkCountdown != 0 && (--_klaymanBlinkCountdown == 0))
+ _klaymanBlinks = true;
+
+ if (!_klaymanBlinks && _smackerPlayer->getFrameNumber() + 1 >= 2) {
+ _smackerPlayer->rewind();
+ } else if (_klaymanBlinks && _smackerPlayer->getFrameNumber() + 1 >= 6) {
+ _smackerPlayer->rewind();
+ _klaymanBlinks = false;
+ _klaymanBlinkCountdown = _vm->_rnd->getRandomNumber(30 - 1) + 15;
+ }
+
+ if (!_klaymanBlinks && _decisionCountdown != 0 && (--_decisionCountdown == 0))
+ stNoDecisionYet();
+
+ if (_smackerFileHash) {
+ _smackerPlayer->open(_smackerFileHash, _smackerFlag1);
+ _smackerFileHash = 0;
+ }
+
+ Scene::update();
+
+}
+
+uint32 Scene1317::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ stChooseKing();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene1317::hmChooseKing(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x >= 21 && param.asPoint().y >= 24 &&
+ param.asPoint().x <= 261 && param.asPoint().y <= 280) {
+ stHoborgAsKing();
+ } else if (param.asPoint().x >= 313 && param.asPoint().y >= 184 &&
+ param.asPoint().x <= 399 && param.asPoint().y <= 379) {
+ stKlaymanAsKing();
+ } else if (param.asPoint().x >= 347 && param.asPoint().y >= 380 &&
+ param.asPoint().x <= 418 && param.asPoint().y <= 474) {
+ stKlaymanAsKing();
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene1317::hmNoDecisionYet(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ stChooseKing();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene1317::hmHoborgAsKing(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ stEndMovie();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene1317::hmKlaymanAsKing(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ leaveScene(0);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene1317::hmEndMovie(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ leaveScene(0);
+ break;
+ }
+ return messageResult;
+}
+
+void Scene1317::stChooseKing() {
+ showMouse(true);
+ SetMessageHandler(&Scene1317::hmChooseKing);
+ SetUpdateHandler(&Scene1317::upChooseKing);
+ _smackerFileHash = 0x10982841;
+ _smackerFlag1 = true;
+ _decisionCountdown = 450;
+ _klaymanBlinks = false;
+ _klaymanBlinkCountdown = _vm->_rnd->getRandomNumber(30 - 1) + 15;
+}
+
+void Scene1317::stNoDecisionYet() {
+ showMouse(false);
+ SetMessageHandler(&Scene1317::hmNoDecisionYet);
+ SetUpdateHandler(&Scene1317::update);
+ _smackerFileHash = 0x20982841;
+ _smackerFlag1 = false;
+}
+
+void Scene1317::stHoborgAsKing() {
+ showMouse(false);
+ SetMessageHandler(&Scene1317::hmHoborgAsKing);
+ SetUpdateHandler(&Scene1317::update);
+ _smackerFileHash = 0x40982841;
+ _smackerFlag1 = false;
+}
+
+void Scene1317::stKlaymanAsKing() {
+ showMouse(false);
+ SetMessageHandler(&Scene1317::hmKlaymanAsKing);
+ SetUpdateHandler(&Scene1317::update);
+ _smackerFileHash = 0x80982841;
+ _smackerFlag1 = false;
+}
+
+void Scene1317::stEndMovie() {
+ showMouse(false);
+ SetMessageHandler(&Scene1317::hmEndMovie);
+ SetUpdateHandler(&Scene1317::update);
+ _smackerFileHash = 0x40800711;
+ _smackerFlag1 = false;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1300.h b/engines/neverhood/module1300.h
new file mode 100644
index 0000000000..27e2540407
--- /dev/null
+++ b/engines/neverhood/module1300.h
@@ -0,0 +1,321 @@
+/* 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_MODULE1300_H
+#define NEVERHOOD_MODULE1300_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/smackerplayer.h"
+
+namespace Neverhood {
+
+// Module1300
+
+class Module1300 : public Module {
+public:
+ Module1300(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1300();
+protected:
+ uint32 _musicFileHash;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+class AsScene1302Bridge : public AnimatedSprite {
+public:
+ AsScene1302Bridge(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stLowerBridge();
+ void stRaiseBridge();
+ void cbLowerBridgeEvent();
+};
+
+class SsScene1302Fence : public StaticSprite {
+public:
+ SsScene1302Fence(NeverhoodEngine *vm);
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ int16 _firstY;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suMoveDown();
+ void suMoveUp();
+};
+
+class Class595 : public StaticSprite {
+public:
+ Class595(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1302 : public Scene {
+public:
+ Scene1302(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource;
+ Sprite *_asVenusFlyTrap;
+ Sprite *_asBridge;
+ Sprite *_ssFence;
+ Sprite *_asRing1;
+ Sprite *_asRing2;
+ Sprite *_asRing3;
+ Sprite *_asRing4;
+ Sprite *_asRing5;
+ Sprite *_class595;
+ Sprite *_sprite1;
+ Sprite *_sprite2;
+ Sprite *_sprite3;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1303Balloon : public AnimatedSprite {
+public:
+ AsScene1303Balloon(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmBalloonPopped(int messageNum, const MessageParam &param, Entity *sender);
+ void stPopBalloon();
+};
+
+class Scene1303 : public Scene {
+public:
+ Scene1303(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_sprite1;
+ Sprite *_asBalloon;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Class544 : public AnimatedSprite {
+public:
+ Class544(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, int16 x, int16 y);
+protected:
+ Scene *_parentScene;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1304 : public Scene {
+public:
+ Scene1304(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_sprite1;
+ Sprite *_class545;
+ Sprite *_class544;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1305 : public Scene {
+public:
+ Scene1305(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene1306Elevator : public AnimatedSprite {
+public:
+ AsScene1306Elevator(NeverhoodEngine *vm, Scene *parentScene, AnimatedSprite *asElevatorDoor);
+protected:
+ Scene *_parentScene;
+ AnimatedSprite *_asElevatorDoor;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ bool _isUp;
+ bool _isDown;
+ int _countdown;
+ void update();
+ void upGoingDown();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stGoingUp();
+ void cbGoingUpEvent();
+ void stGoingDown();
+ void cbGoingDownEvent();
+};
+
+class Scene1306 : public Scene {
+public:
+ Scene1306(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene1306();
+protected:
+ Sprite *_ssButton;
+ Sprite *_asTape;
+ AnimatedSprite *_asElevatorDoor;
+ Sprite *_asElevator;
+ Sprite *_sprite1;
+ Sprite *_class545;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ 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);
+};
+
+class Class549 : public AnimatedSprite {
+public:
+ Class549(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub455470();
+ void hide();
+ void sub4554F0();
+ void sub455550();
+};
+
+class Class592 : public AnimatedSprite {
+public:
+ Class592(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub455710();
+ void sub455740();
+};
+
+class Class593 : public AnimatedSprite {
+public:
+ Class593(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub4558F0();
+ void sub455920();
+ void sub455950();
+};
+
+class Class601 : public StaticSprite {
+public:
+ Class601(NeverhoodEngine *vm, uint32 fileHash, int index);
+};
+
+class Class513 : public AnimatedSprite {
+public:
+ Class513(NeverhoodEngine *vm);
+protected:
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1308 : public Scene {
+public:
+ Scene1308(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_asTape;
+ Sprite *_class549;
+ Sprite *_class593;
+ Sprite *_class601_1;
+ Sprite *_class601_2;
+ Sprite *_class601_3;
+ AnimatedSprite *_class489;
+ Sprite *_sprite1;
+ Sprite *_sprite2;
+ Sprite *_sprite3;
+ Sprite *_sprite4;
+ Sprite *_sprite5;
+ bool _flag1;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1317 : public Scene {
+public:
+ Scene1317(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SmackerPlayer *_smackerPlayer;
+ bool _klaymanBlinks;
+ int _klaymanBlinkCountdown;
+ int _decisionCountdown;
+ uint32 _smackerFileHash;
+ bool _smackerFlag1;
+ void update();
+ void upChooseKing();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmChooseKing(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmNoDecisionYet(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmHoborgAsKing(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmKlaymanAsKing(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmEndMovie(int messageNum, const MessageParam &param, Entity *sender);
+ void stChooseKing();
+ void stNoDecisionYet();
+ void stHoborgAsKing();
+ void stKlaymanAsKing();
+ void stEndMovie();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1300_H */
diff --git a/engines/neverhood/module1400.cpp b/engines/neverhood/module1400.cpp
new file mode 100644
index 0000000000..42dfdb3d5b
--- /dev/null
+++ b/engines/neverhood/module1400.cpp
@@ -0,0 +1,1737 @@
+/* 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/module1400.h"
+#include "neverhood/module1000.h"
+#include "neverhood/module2100.h"
+#include "neverhood/module2200.h"
+#include "neverhood/diskplayerscene.h"
+#include "neverhood/gamemodule.h"
+
+namespace Neverhood {
+
+Module1400::Module1400(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ // TODO Music18hList_add(0x00AD0012, 0x06333232);
+ // TODO Music18hList_add(0x00AD0012, 0x624A220E);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else {
+ createScene(0, 0);
+ }
+
+}
+
+Module1400::~Module1400() {
+ // TODO Music18hList_deleteGroup(0x00AD0012);
+}
+
+void Module1400::createScene(int sceneNum, int which) {
+ debug("Module1400::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ // TODO Music18hList_play(0x06333232, 0, 2, 1);
+ _childObject = new Scene1401(_vm, this, which);
+ break;
+ case 1:
+ // TODO Music18hList_stop(0x06333232, 0, 2);
+ // TODO Music18hList_stop(0x624A220E, 0, 2);
+ _childObject = new Scene1402(_vm, this, which);
+ break;
+ case 2:
+ // TODO Music18hList_stop(0x06333232, 0, 2);
+ // TODO Music18hList_play(0x624A220E, 0, 2, 1);
+ _childObject = new Scene1403(_vm, this, which);
+ break;
+ case 3:
+ // TODO Music18hList_play(0x06333232, 0, 2, 1);
+ _childObject = new Scene1404(_vm, this, which);
+ break;
+ case 4:
+ // TODO Music18hList_play(0x06333232, 0, 2, 1);
+ _childObject = new Scene1405(_vm, this, which);
+ break;
+ case 5:
+ // TODO Music18hList_stop(0x06333232, 0, 2);
+ _childObject = new DiskplayerScene(_vm, this, 2);
+ break;
+ case 6:
+ // TODO Music18hList_stop(0x06333232, 0, 2);
+ _childObject = new Scene1407(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module1400::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1400::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(1, 0);
+ } else if (_moduleResult == 2) {
+ createScene(3, 0);
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 1:
+ if (_moduleResult == 1) {
+ createScene(2, 0);
+ } else if (_moduleResult == 2) {
+ createScene(6, -1);
+ } else {
+ createScene(0, 1);
+ }
+ break;
+ case 2:
+ createScene(1, 1);
+ break;
+ case 3:
+ if (_moduleResult == 1) {
+ createScene(4, 0);
+ } else if (_moduleResult == 2) {
+ createScene(5, -1);
+ } else {
+ createScene(0, 2);
+ }
+ break;
+ case 4:
+ createScene(3, 1);
+ break;
+ case 5:
+ createScene(3, 2);
+ break;
+ case 6:
+ createScene(1, 2);
+ break;
+ }
+ }
+}
+
+// Scene1401
+
+Class525::Class525(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm),
+ _countdown1(0), _countdown2(0) {
+
+ // TODO createSurface3(900, dword_4B6768);
+ createSurface(900, 640, 480); //TODO: Remeove once the line above is done
+ _x = 454;
+ _y = 217;
+ SetUpdateHandler(&Class525::update4662A0);
+ SetMessageHandler(&Class525::handleMessage466320);
+ setFileHash(0x4C210500, 0, -1);
+}
+
+Class525::~Class525() {
+ // TODO Sound1ChList_sub_407AF0(0x01104C08);
+}
+
+void Class525::update4662A0() {
+ AnimatedSprite::update();
+ if (_countdown1 != 0 && (--_countdown1 == 0)) {
+ sub466460();
+ }
+ if (_countdown2 != 0 && (--_countdown2 == 0)) {
+ // TODO Sound1ChList_addSoundResource(0x01104C08, 0x4A116437, true);
+ // TODO Sound1ChList_playLooping(0x4A116437);
+ }
+}
+
+void Class525::update466300() {
+ AnimatedSprite::update();
+ if (_countdown1 != 0) {
+ _countdown1--;
+ }
+}
+
+uint32 Class525::handleMessage466320(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x0A8A1490) {
+ _soundResource2.play(0x6AB6666F);
+ }
+ break;
+ case 0x2000:
+ _countdown1 = 70;
+ _countdown2 = 8;
+ sub466420();
+ break;
+ case 0x483A:
+ sub4664B0();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Class525::handleMessage4663C0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ if (_countdown1 != 0) {
+ sub466420();
+ } else {
+ sub466460();
+ }
+ SetMessageHandler(&Class525::handleMessage466320);
+ SetUpdateHandler(&Class525::update4662A0);
+ break;
+ }
+ return messageResult;
+}
+
+void Class525::sub466420() {
+ setFileHash(0x4C240100, 0, -1);
+ _soundResource1.play(0x4A30063F);
+}
+
+void Class525::sub466460() {
+ // TODO Sound1ChList_deleteSoundByHash(0x4A116437);
+ _soundResource1.play(0x4A120435);
+ setFileHash(0x4C210500, 0, -1);
+}
+
+void Class525::sub4664B0() {
+ setFileHash(0x6C210810, 0, -1);
+ SetMessageHandler(&Class525::handleMessage4663C0);
+ SetUpdateHandler(&Class525::update466300);
+}
+
+Class526::Class526(NeverhoodEngine *vm, Sprite *class525)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _class525(class525) {
+
+ // TODO createSurface3(100, dword_4B6778);
+ createSurface(100, 640, 480); //TODO: Remeove once the line above is done
+ _x = 478;
+ _y = 433;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class526::handleMessage);
+ setFileHash(0xA282C472, 0, -1);
+}
+
+uint32 Class526::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x66382026) {
+ _soundResource.play(0x0CD84468);
+ } else if (param.asInteger() == 0x6E28061C) {
+ _soundResource.play(0x78C8402C);
+ } else if (param.asInteger() == 0x462F0410) {
+ _soundResource.play(0x60984E28);
+ }
+ break;
+ case 0x4839:
+ sub466770();
+ break;
+ }
+ return messageResult;
+}
+
+void Class526::spriteUpdate466720() {
+ AnimatedSprite::updateDeltaXY();
+ if (_rect.y1 <= 150) {
+ _soundResource.play(0x0E32247F);
+ stopAnimation();
+ SetSpriteCallback(NULL);
+ SetMessageHandler(NULL);
+ setVisible(false);
+ }
+}
+
+void Class526::sub466770() {
+ setFileHash(0x34880040, 0, -1);
+ SetSpriteCallback(&Class526::spriteUpdate466720);
+}
+
+Class527::Class527(NeverhoodEngine *vm, Sprite *class526)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _class526(class526) {
+
+ // TODO createSurface3(200, dword_4B6768);
+ createSurface(200, 640, 480); //TODO: Remeove once the line above is done
+ _x = 427;
+ _y = 433;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class527::handleMessage);
+ setFileHash(0x461A1490, 0, -1);
+}
+
+uint32 Class527::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4839:
+ sub466970();
+ break;
+ }
+ return messageResult;
+}
+
+void Class527::spriteUpdate466920() {
+ AnimatedSprite::updateDeltaXY();
+ if (_rect.y1 <= 150) {
+ _soundResource.play(0x18020439);
+ stopAnimation();
+ SetSpriteCallback(NULL);
+ SetMessageHandler(NULL);
+ setVisible(false);
+ }
+}
+
+void Class527::sub466970() {
+ setFileHash(0x103B8020, 0, -1);
+ SetSpriteCallback(&Class527::spriteUpdate466920);
+}
+
+Class528::Class528(NeverhoodEngine *vm, Sprite *klayman, bool flag)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _klayman(klayman), _countdown(0) {
+
+ _x = 320;
+ _y = 240;
+ createSurface1(0x04551900, 100);
+ SetUpdateHandler(&Class528::update);
+ SetMessageHandler(&Class528::handleMessage);
+ _newHashListIndex = -2;
+ if (flag) {
+ _flag = true;
+ setFileHash(0x04551900, -1,- 1);
+ _countdown = 48;
+ } else {
+ _flag = false;
+ stopAnimation();
+ setVisible(false);
+ }
+}
+
+void Class528::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ sub466C50();
+ }
+ AnimatedSprite::update();
+}
+
+
+uint32 Class528::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2001:
+ if (_flag)
+ _countdown = 168;
+ messageResult = _flag ? 1 : 0;
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ _countdown = 168;
+ if (_flag)
+ sub466BF0();
+ break;
+ }
+ return messageResult;
+}
+
+void Class528::sub466BF0() {
+ _flag = true;
+ setVisible(true);
+ setFileHash(0x04551900, 0, -1);
+ _newHashListIndex = -2;
+ _soundResource.play(calcHash("fxDoorOpen24"));
+}
+
+void Class528::sub466C50() {
+ _flag = false;
+ setVisible(true);
+ setFileHash(0x04551900, -1, -1);
+ _soundResource.play(calcHash("fxDoorClose24"));
+ _playBackwards = true;
+ NextState(&Class528::sub466CB0);
+}
+
+void Class528::sub466CB0() {
+ stopAnimation();
+ setVisible(false);
+}
+
+static const Class489Item kClass489Items[] = {
+ {{154, 453}, 4, 2, 0, -1, 0, 1},
+ {{104, 391}, 4, -1, -1, -1, 1, 1},
+ {{ 22, 447}, 6, -1, -1, -1, 1, 1},
+ {{112, 406}, 2, -1, -1, -1, 1, 0},
+ {{262, 433}, 1, 1, 0, -1, 0, 0}
+};
+
+Class489::Class489(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman, Sprite *class525)
+ : AnimatedSprite(vm, 1100), _parentScene(parentScene), _klayman(klayman), _class525(class525),
+ _soundResource1(vm), _soundResource2(vm), _soundResource3(vm) {
+
+ _class489Item = &kClass489Items[getGlobalVar(0x04A105B3)];
+ // TODO createSurface3(990, dword_4B26D8);
+ createSurface(990, 640, 480); //TODO: Remeove once the line above is done
+ setFileHash(0x10E3042B, 0, -1);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class489::handleMessage);
+ _x = getGlobalVar(0x04A10F33) * 108 + _class489Item->point.x;
+ _flag = true;
+ sub434C80();
+ setDoDeltaX(1);
+ if ((int8)getGlobalVar(0x04A10F33) == _class489Item->varIndex2) {
+ sub434E90();
+ }
+ _soundResource3.load(0xC8C2507C);
+}
+
+Class489::~Class489() {
+ // TODO Sound1ChList_sub_407AF0(0x05331081);
+}
+
+uint32 Class489::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x4807:
+ setGlobalVar(0x04A10F33, (_x - _class489Item->point.x) / 108);
+ if ((int8)getGlobalVar(0x04A10F33) == _class489Item->varIndex2) {
+ sub434E60();
+ } else {
+ sub434DD0();
+ }
+ break;
+ case 0x480B:
+ if (param.asInteger() != 1) {
+ if ((int8)getGlobalVar(0x04A10F33) < _class489Item->varIndex1) {
+ incGlobalVar(0x04A10F33, 1);
+ }
+ } else if (getGlobalVar(0x04A10F33) > 0) {
+ incGlobalVar(0x04A10F33, -1);
+ }
+ sub434DF0();
+ break;
+ case 0x480C:
+ if (param.asInteger() != 1) {
+ messageResult = (int8)getGlobalVar(0x04A10F33) < _class489Item->varIndex1 ? 1 : 0;
+ } else {
+ messageResult = getGlobalVar(0x04A10F33) > 0 ? 1 : 0;
+ }
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ case 0x4828:
+ sub435040();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Class489::handleMessage4348E0(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (param.asPoint().x - _x >= 17 && param.asPoint().x - _x <= 56 &&
+ param.asPoint().y - _y >= -120 && param.asPoint().y - _y <= -82) {
+ sendMessage(_parentScene, 0x4826, 1);
+ } else {
+ sendMessage(_parentScene, 0x4826, 0);
+ }
+ messageResult = 1;
+ break;
+ case 0x4807:
+ sendMessage(_parentScene, 0x4807, 0);
+ sub434F80();
+ break;
+ case 0x480B:
+ if (param.asInteger() != 1) {
+ if ((int8)getGlobalVar(0x04A10F33) < _class489Item->varIndex1) {
+ incGlobalVar(0x04A10F33, 1);
+ }
+ } else if (getGlobalVar(0x04A10F33) > 0) {
+ incGlobalVar(0x04A10F33, -1);
+ }
+ sub434FF0();
+ break;
+ case 0x480C:
+ if (param.asInteger() != 1) {
+ messageResult = (int8)getGlobalVar(0x04A10F33) < _class489Item->varIndex1 ? 1 : 0;
+ } else {
+ messageResult = getGlobalVar(0x04A10F33) > 0 ? 1 : 0;
+ }
+ break;
+ case 0x480F:
+ sub434EC0();
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Class489::handleMessage434B20(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void Class489::spriteUpdate434B60() {
+ if (_x <= _klayman->getX())
+ _x = _klayman->getX() - 100;
+ else
+ _x = _klayman->getX() + 100;
+ sub434C80();
+ if (_remX == _x) {
+ if (getGlobalVar(0x04A10F33) == 0 && _class489Item->flag4 != 0) {
+ sendMessage(_parentScene, 0x1019, 0);
+ incGlobalVar(0x04A105B3, -1);
+ setGlobalVar(0x04A10F33, kClass489Items[getGlobalVar(0x04A105B3)].varIndex1);
+ } else if ((int8)getGlobalVar(0x04A10F33) == _class489Item->varIndex1 && _class489Item->flag != 0) {
+ sendMessage(_parentScene, 0x1019, 1);
+ incGlobalVar(0x04A105B3, +1);
+ setGlobalVar(0x04A10F33, 0);
+ }
+ }
+ Sprite::processDelta();
+}
+
+void Class489::sub434C80() {
+
+ bool soundFlag = false;
+
+ _y = _class489Item->point.y;
+
+ if (_class489Item->index1 != -1) {
+ int16 elX = _class489Item->index1 * 108 + _class489Item->point.x;
+ if (elX - 20 < _x && elX + 20 > _x) {
+ soundFlag = true;
+ _y = _class489Item->point.y + 10;
+ }
+ }
+
+ if (_class489Item->flag2 != -1) {
+ int16 elX = _class489Item->index1 * 108 + _class489Item->point.x;
+ if (elX - 20 < _x && elX + 20 > _x) {
+ soundFlag = true;
+ _y = _class489Item->point.y + 10;
+ }
+ }
+
+ if (_class489Item->varIndex2 != -1) {
+ int16 elX = _class489Item->varIndex2 * 108 + _class489Item->point.x;
+ if (elX - 20 < _x && elX + 20 > _x) {
+ soundFlag = true;
+ _y = _class489Item->point.y + 10;
+ }
+ }
+
+ if (_flag) {
+ if (!soundFlag) {
+ _flag = false;
+ }
+ } else if (soundFlag) {
+ _soundResource2.play(0x5440E474);
+ _flag = true;
+ }
+
+}
+
+void Class489::sub434D80() {
+ AnimatedSprite::updateDeltaXY();
+ if (_rect.y1 <= 150) {
+ sendMessage(_class525, 0x483A, 0);
+ stopAnimation();
+ SetMessageHandler(&Sprite::handleMessage);
+ SetSpriteCallback(NULL);
+ setVisible(false);
+ }
+}
+
+void Class489::sub434DD0() {
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Class489::handleMessage);
+ setFileHash(0x10E3042B, 0, -1);
+}
+
+void Class489::sub434DF0() {
+ _remX = getGlobalVar(0x04A10F33) * 108 + _class489Item->point.x;
+ setFileHash(0x14A10137, 0, -1);
+ SetSpriteCallback(&Class489::spriteUpdate434B60);
+ SetMessageHandler(&Class489::handleMessage);
+ _soundResource2.play(0xEC008474);
+}
+
+void Class489::sub434E60() {
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Class489::handleMessage434B20);
+ setFileHash(0x80C32213, 0, -1);
+ NextState(&Class489::sub434E90);
+}
+
+void Class489::sub434E90() {
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Class489::handleMessage4348E0);
+ setFileHash(0xD23B207F, 0, -1);
+}
+
+void Class489::sub434EC0() {
+ setFileHash(0x50A80517, 0, -1);
+ SetMessageHandler(&Class489::handleMessage434B20);
+ SetSpriteCallback(NULL);
+ NextState(&Class489::sub434F40);
+ setGlobalVar(0x12A10DB3, 1);
+ _soundResource1.play(0xCC4A8456);
+ // TODO Sound1ChList_addSoundResource(0x05331081, 0xCE428854, true);
+ // TODO Sound1ChList_playLooping(0xCE428854);
+}
+
+void Class489::sub434F40() {
+ sendMessage(_parentScene, 0x480F, 0);
+ setFileHash(0xD833207F, 0, -1);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Class489::handleMessage4348E0);
+}
+
+void Class489::sub434F80() {
+ setFileHash(0x50A94417, 0, -1);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&Class489::handleMessage434B20);
+ NextState(&Class489::sub434E90);
+ setGlobalVar(0x12A10DB3, 0);
+ _soundResource1.play(0xCC4A8456);
+ // TODO Sound1ChList_deleteSoundByHash(0xCE428854);
+}
+
+void Class489::sub434FF0() {
+ _remX = getGlobalVar(0x04A10F33) * 108 + _class489Item->point.x;
+ setFileHash(0x22CB4A33, 0, -1);
+ SetSpriteCallback(&Class489::spriteUpdate434B60);
+ SetMessageHandler(&Class489::handleMessage434B20);
+ NextState(&Class489::sub434DF0);
+}
+
+void Class489::sub435040() {
+ setGlobalVar(0x04A105B3, 4);
+ setGlobalVar(0x04A10F33, 0);
+ SetSpriteCallback(&Class489::sub434D80);
+ SetMessageHandler(&Sprite::handleMessage);
+ setFileHash(0x708D4712, 0, -1);
+ _soundResource3.play();
+}
+
+Scene1401::Scene1401(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _flag(false), _class427(NULL), _class489(NULL),
+ _class525(NULL), _class526(NULL), _class527(NULL), _class528(NULL),
+ _sprite1(NULL), _sprite2(NULL), _sprite3(NULL), _ssButton(NULL) {
+
+ SetMessageHandler(&Scene1401::handleMessage);
+ SetUpdateHandler(&Scene1401::update);
+ setRectList(0x004B6758);
+ _surfaceFlag = true;
+
+ setBackground(0x08221FA5);
+ setPalette(0x08221FA5);
+ insertMouse433(0x21FA108A);
+
+ _class427 = insertSprite<Class427>(this, 0x980F3124, 0x12192892, 100, 0);
+ _class525 = insertSprite<Class525>();
+
+ if (!getGlobalVar(0x01023818)) {
+ _class526 = insertSprite<Class526>(_class525);
+ _class527 = insertSprite<Class527>(_class525);
+ }
+
+ _sprite3 = insertStaticSprite(0xA82BA811, 1100);
+ insertStaticSprite(0x0A116C60, 1100);
+ _ssButton = insertSprite<SsCommonButtonSprite>(this, 0xB84B1100, 100, 0);
+ _sprite1 = insertStaticSprite(0x38EA100C, 1005);
+ _sprite2 = insertStaticSprite(0x98D0223C, 1200);
+ _sprite2->setVisible(false);
+
+ if (which < 0) {
+ insertKlayman<KmScene1401>(380, 447);
+ setMessageList(0x004B65C8);
+ _sprite1->setVisible(false);
+ } else if (which == 1) {
+ insertKlayman<KmScene1401>(0, 447);
+ setMessageList(0x004B65D0);
+ _sprite1->setVisible(false);
+ } else if (which == 2) {
+ insertKlayman<KmScene1401>(660, 447);
+ setMessageList(0x004B65D8);
+ _sprite1->setVisible(false);
+ } else {
+ insertKlayman<KmScene1401>(290, 413);
+ setMessageList(0x004B65E8);
+ _sprite1->setVisible(false);
+ }
+
+ if (getGlobalVar(0x04A105B3) == 2) {
+ _class489 = insertSprite<Class489>(this, _klayman, _class525);
+ _vm->_collisionMan->addSprite(_class489);
+ if (getGlobalVar(0x04A10F33) == 6) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ _klayman->setX(_class489->getX() + 100);
+ _klayman->processDelta();
+ setMessageList(0x004B6670);
+ } else if (getGlobalVar(0x04A10F33) == 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ _klayman->setX(_class489->getX() - 100);
+ _klayman->processDelta();
+ setMessageList(0x004B6670);
+ }
+ _class489->setClipRect(_sprite3->getDrawRect().x, _sprite2->getDrawRect().y, 640, 480);
+ }
+
+ _klayman->setClipRect(_sprite3->getDrawRect().x, 0, 640, 480);
+
+ if (which == 0 && _class489) {
+ sendMessage(_class489, 0x482B, 0);
+ }
+
+ _class528 = insertSprite<Class528>(_klayman, which == 1);
+
+}
+
+void Scene1401::update() {
+ Scene::update();
+ if (_class489 && !_flag && _class489->getY() < 360) {
+ _sprite2->setVisible(true);
+ _flag = true;
+ } else {
+ _sprite2->setVisible(false);
+ }
+}
+
+uint32 Scene1401::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x02144CB1) {
+ sendEntityMessage(_klayman, 0x1014, _class427);
+ } else if (param.asInteger() == 0x402064D8) {
+ sendEntityMessage(_klayman, 0x1014, _ssButton);
+ } else if (param.asInteger() == 0x01C66840) {
+ if (sendMessage(_class528, 0x2001, 0) != 0) {
+ setMessageList(0x004B6690);
+ } else {
+ setMessageList(0x004B66B0);
+ }
+ }
+ break;
+ case 0x1019:
+ if (param.asInteger() != 0) {
+ leaveScene(2);
+ } else {
+ leaveScene(1);
+ }
+ break;
+ case 0x480B:
+ if (sender == _class427) {
+ sendMessage(_class525, 0x2000, 0);
+ if (!getGlobalVar(0x01023818)) {
+ sendMessage(_class526, 0x4839, 0);
+ sendMessage(_class527, 0x4839, 0);
+ setGlobalVar(0x01023818, 1);
+ }
+ if (_class489 && _class489->getX() > 404 && _class489->getX() < 504) {
+ sendMessage(_class489 , 0x4839, 0);
+ }
+ } else if (sender == _ssButton) {
+ sendMessage(_ssButton, 0x4808, 0);
+ }
+ break;
+ case 0x4826:
+ if (sender == _class489) {
+ if (sendMessage(_class489, 0x480C, _klayman->getX() > _class489->getX() ? 1 : 0) != 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B6658);
+ } else {
+ setMessageList2(0x004B65F0);
+ }
+ }
+ break;
+ case 0x482A:
+ _sprite1->setVisible(true);
+ if (_class489) {
+ sendMessage(_class489, 0x482B, 0);
+ }
+ break;
+ case 0x482B:
+ _sprite1->setVisible(false);
+ if (_class489) {
+ sendMessage(_class489, 0x482A, 0);
+ }
+ break;
+ }
+ return 0;
+}
+
+// Scene1402
+
+Class454::Class454(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority)
+ : StaticSprite(vm, fileHash, surfacePriority) {
+
+ SetFilterY(&Sprite::defFilterY);
+ SetUpdateHandler(&StaticSprite::update);
+
+}
+
+Class482::Class482(NeverhoodEngine *vm, Scene *parentScene, int which)
+ : AnimatedSprite(vm, 1100), _parentScene(parentScene), _soundResource1(vm),
+ _soundResource2(vm) {
+
+ // TODO createSurface3(900, dword_4B6768);
+ createSurface(900, 640, 480); //TODO: Remeove once the line above is done
+
+ SetFilterY(&Sprite::defFilterY);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class482::handleMessage);
+ _x = 279;
+ _y = 270;
+ if (which == 2) {
+ setFileHash(0x20060259, 0, -1);
+ _soundResource1.play(0x419014AC);
+ _soundResource2.load(0x61901C29);
+ } else if (which == 1) {
+ setFileHash(0x210A0213, 0, -1);
+ _soundResource1.play(0x41809C6C);
+ } else {
+ setFileHash(0x20060259, 0, -1);
+ _soundResource2.load(0x61901C29);
+ _newHashListIndex = -2;
+ }
+}
+
+uint32 Class482::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2002:
+ _soundResource2.play();
+ setFileHash(0x20060259, -1, -1);
+ _playBackwards = true;
+ NextState(&Class482::sub428530);
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void Class482::sub428500() {
+ sendMessage(_parentScene, 0x2000, 0);
+ stopAnimation();
+ setVisible(false);
+}
+
+void Class482::sub428530() {
+ sendMessage(_parentScene, 0x2001, 0);
+ stopAnimation();
+ setVisible(false);
+}
+
+void Class482::sub428560() {
+ sendMessage(_parentScene, 0x2003, 0);
+ stopAnimation();
+}
+
+Scene1402::Scene1402(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _flag(false), _class482(NULL), _class489(NULL) {
+
+ SetMessageHandler(&Scene1402::handleMessage);
+
+ setBackground(0x231482F0);
+ setBackgroundY(-10);
+ // TODO g_screen->field_26 = 0;
+ setPalette(0x231482F0);
+ _palette->addPalette(0x91D3A391, 0, 64, 0);
+ insertMouse433(0x482F4239);
+
+ _class454_1 = insertSprite<Class454>(0x15402D64, 1100);
+ _class454_2 = insertSprite<Class454>(0x10A02120, 1100);
+ _class454_3 = insertSprite<Class454>(0x60882BE0, 1100);
+
+ if (getGlobalVar(0x70A1189C))
+ setRectList(0x004B0C48);
+ else
+ setRectList(0x004B0C98);
+
+ if (which < 0) {
+ insertKlayman<KmScene1402>(377, 391);
+ setMessageList(0x004B0B48);
+ if (!getGlobalVar(0x70A1189C)) {
+ _class482 = insertSprite<Class482>(this, 0);
+ }
+ } else if (which == 1) {
+ insertKlayman<KmScene1402>(42, 391);
+ setMessageList(0x004B0B50);
+ } else if (which == 2) {
+ insertKlayman<KmScene1402>(377, 391);
+ setMessageList(0x004B0B60);
+ _klayman->setDoDeltaX(1);
+ if (getGlobalVar(0x70A1189C)) {
+ _class482 = insertSprite<Class482>(this, 1);
+ clearRectList();
+ showMouse(false);
+ sub428220();
+ } else {
+ _class482 = insertSprite<Class482>(this, 0);
+ }
+ } else {
+ insertKlayman<KmScene1402>(513, 391);
+ setMessageList(0x004B0B58);
+ if (!getGlobalVar(0x70A1189C)) {
+ _class482 = insertSprite<Class482>(this, 2);
+ sub428220();
+ }
+ }
+
+ if (_class482) {
+ _class482->setClipRect(0, 0, 640, _class454_3->getDrawRect().y2());
+ }
+
+ if (getGlobalVar(0x4A105B3) == 1) {
+ _class489 = insertSprite<Class489>(this, _klayman, (Sprite*)NULL);
+ _vm->_collisionMan->addSprite(_class489);
+ if (getGlobalVar(0x4A10F33) == 4) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ _klayman->setX(_class489->getX() + 100);
+ _klayman->processDelta();
+ setMessageList(0x004B0BD0);
+ } else if (getGlobalVar(0x4A10F33) == 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ _klayman->setX(_class489->getX() - 100);
+ _klayman->processDelta();
+ setMessageList(0x004B0BD0);
+ }
+ _class489->setClipRect(_class454_1->getDrawRect().x, 0, _class454_2->getDrawRect().x, _class454_3->getDrawRect().y2());
+ }
+
+ _klayman->setClipRect(_class454_1->getDrawRect().x, 0, _class454_2->getDrawRect().x2(), _class454_3->getDrawRect().y2());
+
+}
+
+void Scene1402::update() {
+ if (_flag) {
+ setBackgroundY(_vm->_rnd->getRandomNumber(10 - 1) - 10);
+ // TODO g_screen->field_26 = -10 - _background->getDrawRect().y;
+ } else {
+ setBackgroundY(-10);
+ // TODO g_screen->field_26 = 0;
+ SetUpdateHandler(&Scene::update);
+ }
+ Scene::update();
+ if (_class482) {
+ _class482->setClipRect(0, 0, 640, _class454_3->getDrawRect().y2());
+ }
+ _klayman->setClipRect(_class454_1->getDrawRect().x, 0, _class454_2->getDrawRect().x2(), _class454_3->getDrawRect().y2());
+}
+
+uint32 Scene1402::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x00F43389) {
+ if (getGlobalVar(0x70A1189C)) {
+ leaveScene(0);
+ } else {
+ clearRectList();
+ _klayman->setVisible(false);
+ showMouse(false);
+ sendMessage(_class482, 0x2002, 0);
+ sub428220();
+ }
+ }
+ break;
+ case 0x1019:
+ if (param.asInteger()) {
+ leaveScene(0);
+ } else {
+ leaveScene(1);
+ }
+ break;
+ case 0x2000:
+ sub428230();
+ showMouse(true);
+ setRectList(0x004B0C48);
+ break;
+ case 0x2001:
+ sub428230();
+ leaveScene(0);
+ break;
+ case 0x2003:
+ sub428230();
+ break;
+ case 0x4826:
+ if (sender == _class489) {
+ if (sendMessage(_class489, 0x408C, _klayman->getX() > _class489->getX() ? 1 : 0) != 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B0BB8);
+ } else {
+ setMessageList2(0x004B0B68);
+ }
+ }
+ }
+ return 0;
+}
+
+void Scene1402::sub428220() {
+ _flag = true;
+ SetUpdateHandler(&Scene1402::update);
+}
+
+void Scene1402::sub428230() {
+ _flag = false;
+}
+
+// Scene1407
+
+static const int16 kScene1407MouseFloorY[] = {
+ 106, 150, 191, 230, 267, 308, 350, 395
+};
+
+static const struct {
+ int16 x;
+ int16 floorIndex;
+ int16 sectionIndex;
+ int16 nextHoleIndex;
+} kScene1407MouseHoles[] = {
+ {125, 0, 0, 7},
+ {452, 7, 21, 0},
+ {337, 4, 11, 4},
+ {286, 6, 17, 6},
+ {348, 6, 17, 39},
+ {536, 6, 18, 42},
+ {111, 1, 3, 18},
+ {203, 1, 3, 38},
+ {270, 1, 3, 9},
+ {197, 5, 14, 3},
+ {252, 5, 14, 35},
+ {297, 5, 14, 7},
+ {359, 5, 14, 8},
+ {422, 4, 12, 26},
+ {467, 4, 12, 2},
+ {539, 4, 12, 40},
+ {111, 5, 13, 17},
+ {211, 0, 1, 20},
+ {258, 0, 1, 11},
+ {322, 0, 1, 16},
+ { 99, 6, 16, 31},
+ {142, 6, 16, 27},
+ {194, 6, 16, 12},
+ {205, 2, 6, 45},
+ {264, 2, 6, 10},
+ { 98, 4, 10, 2},
+ {152, 4, 10, 37},
+ {199, 4, 10, 13},
+ {258, 4, 10, 16},
+ {100, 7, 19, 43},
+ {168, 7, 19, 23},
+ {123, 3, 8, 14},
+ {181, 3, 8, 39},
+ {230, 3, 8, 28},
+ {292, 3, 8, 22},
+ {358, 3, 8, 36},
+ {505, 3, 9, 44},
+ {400, 2, 7, 34},
+ {454, 2, 7, 32},
+ {532, 2, 7, 46},
+ {484, 5, 15, 25},
+ {529, 5, 15, 30},
+ {251, 7, 20, 48},
+ {303, 7, 20, 21},
+ {360, 7, 20, 33},
+ {503, 0, 2, 5},
+ {459, 1, 4, 19},
+ {530, 1, 4, 42},
+ {111, 2, 5, 47},
+ {442, 6, 18, 1}
+};
+
+static const struct {
+ int16 x1, x2;
+ int16 goodHoleIndex;
+} kScene1407MouseSections[] = {
+ {100, 149, 0},
+ {182, 351, 17},
+ {430, 524, 45},
+ { 89, 293, 7},
+ {407, 555, 47},
+ { 89, 132, 48},
+ {178, 303, 23},
+ {367, 551, 38},
+ {105, 398, 31},
+ {480, 537, 36},
+ { 84, 275, 27},
+ {318, 359, 2},
+ {402, 560, 15},
+ { 91, 132, 16},
+ {179, 400, 10},
+ {461, 552, 41},
+ { 86, 218, 21},
+ {267, 376, 4},
+ {420, 560, 49},
+ { 77, 188, 30},
+ {237, 394, 44},
+ {438, 515, 5}
+};
+
+AsScene1407Mouse::AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 1100), _parentScene(parentScene), _currSectionIndex(0) {
+
+ // TODO createSurface3(100, dword_4B05B0);
+ createSurface(100, 640, 480); //TODO: Remeove once the line above is done
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ _x = 108;
+ _y = 106;
+ stIdleLookAtGoodHole();
+}
+
+void AsScene1407Mouse::suWalkTo() {
+ int16 xdelta = _walkDestX - _x;
+ if (xdelta > _deltaX)
+ xdelta = _deltaX;
+ else if (xdelta < -_deltaX)
+ xdelta = -_deltaX;
+ _deltaX = 0;
+ if (_walkDestX == _x) {
+ sendMessage(this, 0x1019, 0);
+ } else {
+ _x += xdelta;
+ processDelta();
+ }
+}
+
+void AsScene1407Mouse::upGoThroughHole() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ SetUpdateHandler(&AnimatedSprite::update);
+ removeCallbacks();
+ }
+ AnimatedSprite::update();
+}
+
+uint32 AsScene1407Mouse::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ {
+ int16 mouseX = param.asPoint().x;
+ int16 mouseY = param.asPoint().y;
+ int holeIndex;
+ for (holeIndex = 0; holeIndex < 50; holeIndex++) {
+ int16 holeX = kScene1407MouseHoles[holeIndex].x;
+ int16 holeY = kScene1407MouseFloorY[kScene1407MouseHoles[holeIndex].floorIndex];
+ if (mouseX >= holeX - 14 && mouseX <= holeX + 14 && mouseY >= holeY - 36 && mouseY <= holeY)
+ break;
+ }
+ if (holeIndex < 50 && kScene1407MouseHoles[holeIndex].sectionIndex == _currSectionIndex) {
+ _nextHoleIndex = kScene1407MouseHoles[holeIndex].nextHoleIndex;
+ _walkDestX = kScene1407MouseHoles[holeIndex].x;
+ stWalkToHole();
+ } else {
+ if (mouseX < kScene1407MouseSections[_currSectionIndex].x1) {
+ _walkDestX = kScene1407MouseSections[_currSectionIndex].x1;
+ } else if (mouseX > kScene1407MouseSections[_currSectionIndex].x2) {
+ _walkDestX = kScene1407MouseSections[_currSectionIndex].x2;
+ } else {
+ _walkDestX = mouseX;
+ }
+ stWalkToDest();
+ }
+ }
+ break;
+ case 0x1019:
+ removeCallbacks();
+ break;
+ case 0x2001:
+ {
+ // Reset the position
+ // Find the nearest hole and go through it, and exit at the first hole
+ int16 distance = 640;
+ int matchIndex = 50;
+ for (int index = 0; index < 50; index++) {
+ if (kScene1407MouseHoles[index].sectionIndex == _currSectionIndex) {
+ if (ABS(kScene1407MouseHoles[index].x - _x) < distance) {
+ matchIndex = index;
+ distance = ABS(kScene1407MouseHoles[index].x - _x);
+ }
+ }
+ }
+ if (matchIndex < 50) {
+ _nextHoleIndex = 0;
+ _walkDestX = kScene1407MouseHoles[matchIndex].x;
+ stWalkToHole();
+ }
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1407Mouse::stIdleLookAtGoodHole() {
+ setDoDeltaX(kScene1407MouseHoles[kScene1407MouseSections[_currSectionIndex].goodHoleIndex].x < _x ? 1 : 0);
+ setFileHash(0x72215194, 0, -1);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(&AsScene1407Mouse::handleMessage);
+}
+
+void AsScene1407Mouse::stWalkToDest() {
+ if (_walkDestX != _x) {
+ setDoDeltaX(_walkDestX < _x ? 1 : 0);
+ setFileHash(0x22291510, 0, -1);
+ SetSpriteCallback(&AsScene1407Mouse::suWalkTo);
+ SetMessageHandler(&AsScene1407Mouse::handleMessage);
+ NextState(&AsScene1407Mouse::stIdleLookAtGoodHole);
+ }
+}
+
+void AsScene1407Mouse::stWalkToHole() {
+ setDoDeltaX(_walkDestX < _x ? 1 : 0);
+ setFileHash(0x22291510, 0, -1);
+ SetSpriteCallback(&AsScene1407Mouse::suWalkTo);
+ SetMessageHandler(&AsScene1407Mouse::handleMessage);
+ NextState(&AsScene1407Mouse::stGoThroughHole);
+}
+
+void AsScene1407Mouse::stGoThroughHole() {
+ setFileHash(0x72215194, 0, -1);
+ SetSpriteCallback(NULL);
+ SetMessageHandler(NULL);
+ SetUpdateHandler(&AsScene1407Mouse::upGoThroughHole);
+ NextState(&AsScene1407Mouse::stArriveAtHole);
+ setVisible(false);
+ _countdown = 12;
+}
+
+void AsScene1407Mouse::stArriveAtHole() {
+ _currSectionIndex = kScene1407MouseHoles[_nextHoleIndex].sectionIndex;
+ _x = kScene1407MouseHoles[_nextHoleIndex].x;
+ _y = kScene1407MouseFloorY[kScene1407MouseHoles[_nextHoleIndex].floorIndex];
+ if (_nextHoleIndex == 1) {
+ sendMessage(_parentScene, 0x2000, 0);
+ _walkDestX = 512;
+ stWalkToDest();
+ setVisible(true);
+ } else {
+ _walkDestX = _x + 14;
+ stWalkToDest();
+ setVisible(true);
+ }
+}
+
+Scene1407::Scene1407(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm), _puzzleSolvedCountdown(0),
+ _resetButtonCountdown(0) {
+
+ _surfaceFlag = true;
+
+ SetMessageHandler(&Scene1407::handleMessage);
+ SetUpdateHandler(&Scene1407::update);
+
+ setBackground(0x00442225);
+ setPalette(0x00442225);
+ insertMouse435(0x4222100C, 20, 620);
+
+ _asMouse = insertSprite<AsScene1407Mouse>(this);
+ _ssResetButton = insertStaticSprite(0x12006600, 100);
+ _ssResetButton->setVisible(false);
+
+}
+
+void Scene1407::update() {
+ Scene::update();
+ if (_puzzleSolvedCountdown != 0 && (--_puzzleSolvedCountdown == 0)) {
+ leaveScene(1);
+ } else if (_resetButtonCountdown != 0 && (--_resetButtonCountdown == 0)) {
+ _ssResetButton->setVisible(false);
+ }
+}
+
+uint32 Scene1407::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (_puzzleSolvedCountdown == 0) {
+ // TODO: Debug/Cheat stuff
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ // Exit scene
+ leaveScene(0);
+ } else if (param.asPoint().x >= 75 && param.asPoint().x <= 104 &&
+ param.asPoint().y >= 62 && param.asPoint().y <= 90) {
+ // The reset button was clicked
+ sendMessage(_asMouse, 0x2001, 0);
+ _ssResetButton->setVisible(true);
+ _soundResource.play(0x44045000);
+ _resetButtonCountdown = 12;
+ } else {
+ // Handle the mouse
+ sendMessage(_asMouse, messageNum, param);
+ }
+ }
+ break;
+ case 0x000D:
+ // TODO: Debug/Cheat stuff
+ break;
+ case 0x2000:
+ // The mouse got the cheese (nomnom)
+ setGlobalVar(0x70A1189C, 1);
+ _soundResource.play(0x68E25540);
+ showMouse(false);
+ _puzzleSolvedCountdown = 72;
+ break;
+ }
+ return 0;
+}
+
+// Scene1403
+
+Scene1403::Scene1403(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _class489(NULL), _flag(false) {
+
+ SetMessageHandler(&Scene1403::handleMessage);
+
+ setRectList(0x004B1FF8);
+ _surfaceFlag = true;
+
+ setBackground(0x2110A234);
+ setPalette(0x2110A234);
+ insertMouse433(0x0A230219);
+
+ _class401_1 = insertStaticSprite(0x01102A33, 100);
+ _class401_1->setVisible(false);
+
+ _class401_2 = insertStaticSprite(0x04442520, 995);
+
+ _class401_3 = insertStaticSprite(0x08742271, 995);
+
+ _asTape1 = insertSprite<AsScene1201Tape>(this, 12, 1100, 201, 468, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape1);
+ _asTape1->setRepl(64, 0);
+
+ _asTape2 = insertSprite<AsScene1201Tape>(this, 16, 1100, 498, 468, 0x9048A093);
+ _vm->_collisionMan->addSprite(_asTape2);
+ _asTape2->setRepl(64, 0);
+
+ if (which < 0) {
+ insertKlayman<KmScene1402>(380, 463);
+ setMessageList(0x004B1F18);
+ } else {
+ insertKlayman<KmScene1402>(640, 463);
+ setMessageList(0x004B1F20);
+ }
+ _klayman->setRepl(64, 0);
+
+ if (getGlobalVar(0x04A105B3) == 4) {
+ _class489 = insertSprite<Class489>(this, _klayman, (Sprite*)NULL);
+ _vm->_collisionMan->addSprite(_class489);
+ if (getGlobalVar(0x04A10F33) == 4) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ _klayman->setX(_class489->getX() + 100);
+ _klayman->processDelta();
+ setMessageList(0x004B1F70);
+ }
+ _class489->setClipRect(0, 0, 640, _class401_2->getDrawRect().y2());
+ _class489->setRepl(64, 0);
+ }
+
+}
+
+uint32 Scene1403::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x88C11390) {
+ setRectList(0x004B2008);
+ _flag = true;
+ } else if (param.asInteger() == 0x08821382) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setRectList(0x004B1FF8);
+ _flag = false;
+ }
+ break;
+ case 0x1019:
+ leaveScene(0);
+ break;
+ case 0x1022:
+ if (sender == _class489) {
+ if (param.asInteger() >= 1000) {
+ setSurfacePriority(_class401_3->getSurface(), 1100);
+ } else {
+ setSurfacePriority(_class401_3->getSurface(), 995);
+ }
+ }
+ break;
+ case 0x4807:
+ _class401_1->setVisible(false);
+ break;
+ case 0x480F:
+ _class401_1->setVisible(true);
+ break;
+ case 0x4826:
+ if (sender == _class489) {
+ if (_flag) {
+ setMessageList2(0x004B1FA8);
+ } else if (param.asInteger() == 1) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B1F88);
+ } else if (sendMessage(_class489, 0x480C, _klayman->getX() > _class489->getX() ? 1 : 0) != 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B1F58);
+ } else {
+ setMessageList2(0x004B1F28);
+ }
+ } else if (sender == _asTape1 || sender == _asTape2) {
+ if (_flag) {
+ setMessageList2(0x004B1FA8);
+ } else if (_messageListStatus != 2) {
+ sendEntityMessage(_klayman, 0x1014, sender);
+ setMessageList2(0x004B1FB8);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+// Scene1404
+
+Scene1404::Scene1404(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _class489(NULL), _class545(NULL) {
+
+ if (getGlobalVar(0xC0780812) && !getGlobalVar(0x13382860)) {
+ setGlobalVar(0x13382860, 5);
+ }
+
+ SetMessageHandler(&Scene1404::handleMessage);
+ _surfaceFlag = true;
+
+ setRectList(0x004B8D80);
+
+ setBackground(0xAC0B006F);
+ setPalette(0xAC0B006F);
+ _palette->addPalette(0x00801510, 0, 65, 0);
+ insertMouse433(0xB006BAC8);
+
+ if (getGlobalVar(0x13382860) == 5) {
+ _class545 = insertSprite<Class545>(this, 2, 1100, 267, 411);
+ _vm->_collisionMan->addSprite(_class545);
+ }
+
+ _sprite1 = insertStaticSprite(0x1900A1F8, 1100);
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 14, 1100, 281, 411, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ if (which < 0) {
+ insertKlayman<KmScene1404>(376, 406);
+ setMessageList(0x004B8C28);
+ } else if (which == 1) {
+ insertKlayman<KmScene1404>(376, 406);
+ setMessageList(0x004B8C30);
+ } else if (which == 2) {
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene1404>(347, 406);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene1404>(187, 406);
+ }
+ setMessageList(0x004B8D28);
+ } else {
+ insertKlayman<KmScene1404>(30, 406);
+ setMessageList(0x004B8C38);
+ }
+
+ if (getGlobalVar(0x04A105B3) == 3) {
+ _class489 = insertSprite<Class489>(this, _klayman, (Sprite*)NULL);
+ _vm->_collisionMan->addSprite(_class489);
+ if (getGlobalVar(0x04A10F33) == 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ _klayman->setX(_class489->getX() - 100);
+ _klayman->processDelta();
+ setMessageList(0x004B8CB8);
+ }
+ _class489->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+ }
+
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+
+}
+
+Scene1404::~Scene1404() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+uint32 Scene1404::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x410650C2) {
+ if (_class489 && _class489->getX() == 220) {
+ setMessageList(0x004B8C40);
+ } else {
+ setMessageList(0x004B8CE8);
+ }
+ }
+ break;
+ case 0x1019:
+ leaveScene(0);
+ break;
+ case 0x4826:
+ if (sender == _class489) {
+ if (sendMessage(_class489, 0x480C, _klayman->getX() > _class489->getX() ? 1 : 0) != 0) {
+ sendEntityMessage(_klayman, 0x1014, _class489);
+ setMessageList2(0x004B8CA0);
+ } else {
+ setMessageList2(0x004B8C40);
+ }
+ } else if (sender == _asTape && _messageListStatus != 2) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList(0x004B8CD0);
+ } else if (sender == _class545 && _messageListStatus != 2) {
+ sendEntityMessage(_klayman, 0x1014, _class545);
+ setMessageList(0x004B8D18);
+ }
+ break;
+ }
+ return 0;
+}
+
+// Scene1405
+
+static const NPoint kAsScene1405TileItemPositions[] = {
+ {100, 80},
+ {162, 78},
+ {222, 76},
+ {292, 76},
+ {356, 82},
+ {422, 84},
+ {488, 86},
+ {550, 90},
+ {102, 134},
+ {164, 132},
+ {224, 136},
+ {294, 136},
+ {360, 136},
+ {422, 138},
+ {484, 144},
+ {548, 146},
+ { 98, 196},
+ {160, 200},
+ {228, 200},
+ {294, 202},
+ {360, 198},
+ {424, 200},
+ {482, 202},
+ {548, 206},
+ { 98, 260},
+ {160, 264},
+ {226, 260},
+ {296, 262},
+ {358, 260},
+ {424, 262},
+ {486, 264},
+ {550, 266},
+ { 94, 322},
+ {160, 316},
+ {226, 316},
+ {296, 320},
+ {358, 322},
+ {422, 324},
+ {488, 322},
+ {550, 322},
+ { 98, 380},
+ {160, 376},
+ {226, 376},
+ {294, 378},
+ {356, 380},
+ {420, 380},
+ {490, 378},
+ {552, 376}
+};
+
+AsScene1405Tile::AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 index)
+ : AnimatedSprite(vm, 1100), _parentScene(parentScene), _soundResource(vm),
+ _index(index), _countdown(0), _flag(false) {
+
+ _soundResource.load(0x05308101);
+ // TODO _soundResource.setPan
+ _x = kAsScene1405TileItemPositions[_index].x;
+ _y = kAsScene1405TileItemPositions[_index].y;
+ createSurface1(0x844B805C, 1100);
+ setVisible(false);
+ if (getSubVar(0xCCE0280F, _index))
+ _countdown = _vm->_rnd->getRandomNumber(36 - 1) + 1;
+ SetUpdateHandler(&AsScene1405Tile::update);
+ SetMessageHandler(&AsScene1405Tile::handleMessage);
+
+ debug("getSubVar(0x0C65F80B, _index) = %d", getSubVar(0x0C65F80B, _index));
+
+ setFileHash(0x844B805C, getSubVar(0x0C65F80B, _index), -1);
+ _newHashListIndex = (int16)getSubVar(0x0C65F80B, _index);
+}
+
+void AsScene1405Tile::update() {
+ updateAnim();
+ updatePosition();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ show();
+ }
+}
+
+uint32 AsScene1405Tile::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (getSubVar(0xCCE0280F, _index) == 0 && _parentScene->getCountdown() == 0) {
+ show();
+ sendMessage(_parentScene, 0x2000, _index);
+ }
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1405Tile::show() {
+ if (!_flag) {
+ _flag = true;
+ _soundResource.play();
+ setVisible(true);
+ }
+}
+
+void AsScene1405Tile::hide() {
+ if (_flag) {
+ _flag = false;
+ _soundResource.play();
+ setVisible(false);
+ }
+}
+
+Scene1405::Scene1405(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm), _selectFirstTile(true),
+ _tilesLeft(48), _countdown(0) {
+
+ _vm->gameModule()->initScene1405Vars();
+ _surfaceFlag = true;
+
+ setBackground(0x0C0C007D);
+ setPalette(0x0C0C007D);
+ insertMouse435(0xC00790C8, 20, 620);
+
+ // TODO: Some debug code: Leave two matching tiles open
+ for (int i = 0; i < 48; i++)
+ setSubVar(0xCCE0280F, i, 1);
+ int debugIndex = 0;
+ setSubVar(0xCCE0280F, debugIndex, 0);
+ for (int i = 0; i < 48; i++) {
+ if (i != debugIndex && getSubVar(0x0C65F80B, i) == getSubVar(0x0C65F80B, debugIndex)) {
+ setSubVar(0xCCE0280F, i, 0);
+ break;
+ }
+ }
+
+ for (uint32 index = 0; index < 48; index++) {
+ _tiles[index] = insertSprite<AsScene1405Tile>(this, index);
+ _vm->_collisionMan->addSprite(_tiles[index]);
+ if (getSubVar(0xCCE0280F, index))
+ _tilesLeft--;
+ }
+
+ _soundResource.load(0x68E25540);
+
+ SetMessageHandler(&Scene1405::handleMessage);
+ SetUpdateHandler(&Scene1405::update);
+
+}
+
+void Scene1405::update() {
+ Scene::update();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ _tilesLeft = 48;
+ _tiles[_firstTileIndex]->hide();
+ _tiles[_secondTileIndex]->hide();
+ for (uint32 i = 0; i < 48; i++) {
+ if (getSubVar(0xCCE0280F, i)) {
+ _tiles[i]->hide();
+ setSubVar(0xCCE0280F, i, 0);
+ }
+ }
+ }
+}
+
+uint32 Scene1405::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO: Debug/Cheat stuff
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ leaveScene(0);
+ }
+ break;
+ case 0x000D:
+ // TODO: Debug/Cheat stuff
+ break;
+ case 0x2000:
+ if (_selectFirstTile) {
+ _firstTileIndex = param.asInteger();
+ _selectFirstTile = false;
+ } else {
+ _secondTileIndex = param.asInteger();
+ if (_firstTileIndex != _secondTileIndex) {
+ _selectFirstTile = true;
+ if (getSubVar(0x0C65F80B, _secondTileIndex) == getSubVar(0x0C65F80B, _firstTileIndex)) {
+ setSubVar(0xCCE0280F, _firstTileIndex, 1);
+ setSubVar(0xCCE0280F, _secondTileIndex, 1);
+ _tilesLeft -= 2;
+ if (_tilesLeft == 0) {
+ _soundResource.play();
+ }
+ } else {
+ _countdown = 10;
+ }
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1400.h b/engines/neverhood/module1400.h
new file mode 100644
index 0000000000..d256b82134
--- /dev/null
+++ b/engines/neverhood/module1400.h
@@ -0,0 +1,296 @@
+/* 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_MODULE1400_H
+#define NEVERHOOD_MODULE1400_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module1200.h"
+
+namespace Neverhood {
+
+class Module1400 : public Module {
+public:
+ Module1400(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1400();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene1401
+
+class Class525 : public AnimatedSprite {
+public:
+ Class525(NeverhoodEngine *vm);
+ virtual ~Class525();
+protected:
+ int _countdown1;
+ int _countdown2;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ void update4662A0();
+ void update466300();
+ uint32 handleMessage466320(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage4663C0(int messageNum, const MessageParam &param, Entity *sender);
+ void sub466420();
+ void sub466460();
+ void sub4664B0();
+};
+
+class Class526 : public AnimatedSprite {
+public:
+ Class526(NeverhoodEngine *vm, Sprite *class525);
+protected:
+ Sprite *_class525;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate466720();
+ void sub466770();
+};
+
+class Class527 : public AnimatedSprite {
+public:
+ Class527(NeverhoodEngine *vm, Sprite *class526);
+protected:
+ Sprite *_class526;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate466920();
+ void sub466970();
+};
+
+class Class528 : public AnimatedSprite {
+public:
+ Class528(NeverhoodEngine *vm, Sprite *klayman, bool flag);
+protected:
+ Sprite *_klayman;
+ SoundResource _soundResource;
+ int _countdown;
+ bool _flag;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub466BF0();
+ void sub466C50();
+ void sub466CB0();
+};
+
+struct Class489Item {
+ NPoint point;
+ int8 varIndex1;
+ int8 varIndex2;
+ int8 index1;
+ int8 flag2;
+ int8 flag4;
+ int8 flag;
+};
+
+class Class489 : public AnimatedSprite {
+public:
+ Class489(NeverhoodEngine *vm, Scene *parentScene, Sprite *klayman, Sprite *class525);
+ virtual ~Class489();
+protected:
+ Scene *_parentScene;
+ Sprite *_klayman;
+ Sprite *_class525;
+ const Class489Item *_class489Item;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ int16 _remX;
+ bool _flag;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage4348E0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage434B20(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate434B60();
+ void sub434C80();
+ void sub434D80();
+ void sub434DD0();
+ void sub434DF0();
+ void sub434E60();
+ void sub434E90();
+ void sub434EC0();
+ void sub434F40();
+ void sub434F80();
+ void sub434FF0();
+ void sub435040();
+};
+
+class Scene1401 : public Scene {
+public:
+ Scene1401(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ bool _flag;
+ Sprite *_class427;
+ Class489 *_class489;
+ Sprite *_class525;
+ Sprite *_class526;
+ Sprite *_class527;
+ Sprite *_class528;
+ Sprite *_sprite1;
+ Sprite *_sprite2;
+ Sprite *_sprite3;
+ Sprite *_ssButton;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1402
+
+class Class454 : public StaticSprite {
+public:
+ Class454(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority);
+};
+
+class Class482 : public AnimatedSprite {
+public:
+ Class482(NeverhoodEngine *vm, Scene *parentScene, int which);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub428500();
+ void sub428530();
+ void sub428560();
+};
+
+class Scene1402 : public Scene {
+public:
+ Scene1402(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_class454_1;
+ Sprite *_class454_2;
+ Sprite *_class454_3;
+ Sprite *_class482;
+ Class489 *_class489;
+ bool _flag;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub428220();
+ void sub428230();
+};
+
+// Scene1407
+
+class AsScene1407Mouse : public AnimatedSprite {
+public:
+ AsScene1407Mouse(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ int16 _walkDestX;
+ int16 _currSectionIndex;
+ int16 _nextHoleIndex;
+ int _countdown;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suWalkTo();
+ void upGoThroughHole();
+ void stIdleLookAtGoodHole();
+ void stWalkToDest();
+ void stWalkToHole();
+ void stGoThroughHole();
+ void stArriveAtHole();
+};
+
+class Scene1407 : public Scene {
+public:
+ Scene1407(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource;
+ Sprite *_asMouse;
+ Sprite *_ssResetButton;
+ int _puzzleSolvedCountdown;
+ int _resetButtonCountdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1403
+
+class Scene1403 : public Scene {
+public:
+ Scene1403(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_class401_1;
+ Sprite *_class401_2;
+ Sprite *_class401_3;
+ AsScene1201Tape *_asTape1;
+ AsScene1201Tape *_asTape2;
+ Class489 *_class489;
+ bool _flag;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1404
+
+class Scene1404 : public Scene {
+public:
+ Scene1404(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Scene1404();
+protected:
+ Sprite *_sprite1;
+ Sprite *_asTape;
+ Class489 *_class489;
+ Sprite *_class545;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene1405
+
+class Scene1405;
+
+class AsScene1405Tile : public AnimatedSprite {
+public:
+ AsScene1405Tile(NeverhoodEngine *vm, Scene1405 *parentScene, uint32 index);
+ void show();
+ void hide();
+protected:
+ Scene1405 *_parentScene;
+ SoundResource _soundResource;
+ bool _flag;
+ uint32 _index;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1405 : public Scene {
+public:
+ Scene1405(NeverhoodEngine *vm, Module *parentModule, int which);
+ int getCountdown() const { return _countdown; }
+protected:
+ SoundResource _soundResource;
+ bool _selectFirstTile;
+ int _firstTileIndex;
+ int _secondTileIndex;
+ int _tilesLeft;
+ int _countdown;
+ AsScene1405Tile *_tiles[48];
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1400_H */
diff --git a/engines/neverhood/module1500.cpp b/engines/neverhood/module1500.cpp
new file mode 100644
index 0000000000..76afb956ff
--- /dev/null
+++ b/engines/neverhood/module1500.cpp
@@ -0,0 +1,147 @@
+/* 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/module1500.h"
+
+namespace Neverhood {
+
+Module1500::Module1500(NeverhoodEngine *vm, Module *parentModule, int which, bool flag)
+ : Module(vm, parentModule), _flag(flag) {
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else {
+ createScene(3, -1);
+ }
+
+}
+
+void Module1500::createScene(int sceneNum, int which) {
+ debug("Module1500::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _childObject = new Scene1501(_vm, this, 0x8420221D, 0xA61024C4, 150, 48);
+ break;
+ case 1:
+ _childObject = new Scene1501(_vm, this, 0x30050A0A, 0x58B45E58, 110, 48);
+ break;
+ case 2:
+ sendMessage(_parentModule, 0x0800, 0);
+ createSmackerScene(0x001A0005, true, true, true);
+ break;
+ case 3:
+ _childObject = new Scene1501(_vm, this, 0x0CA04202, 0, 110, 48);
+ break;
+ }
+ SetUpdateHandler(&Module1500::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1500::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ createScene(1, -1);
+ break;
+ case 1:
+ if (_flag) {
+ createScene(2, -1);
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 3:
+ createScene(0, -1);
+ break;
+ default:
+ leaveModule(0);
+ break;
+ }
+ }
+}
+
+// Scene1501
+
+Scene1501::Scene1501(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 soundFileHash, int countdown2, int countdown3)
+ : Scene(vm, parentModule, true), _soundResource(vm),
+ _countdown3(countdown3), _countdown2(countdown2), _countdown1(0), _flag(false) {
+
+ SetUpdateHandler(&Scene1501::update);
+ SetMessageHandler(&Scene1501::handleMessage);
+
+ _surfaceFlag = true;
+
+ setBackground(backgroundFileHash);
+
+ setPalette();
+ addEntity(_palette);
+ _palette->addBasePalette(backgroundFileHash, 0, 256, 0);
+ _palette->startFadeToPalette(12);
+
+ /*
+ if (soundFileHash != 0) {
+ _soundResource.set(soundFileHash);
+ _soundResource.load();
+ _soundResource.play();
+ }
+ */
+
+}
+
+void Scene1501::update() {
+
+ Scene::update();
+
+ // TODO: Since these countdowns are used a lot, maybe these can be wrapped in a class/struct
+ // so the code gets a little cleaner.
+
+ if (_countdown1 != 0) {
+ _countdown1--;
+ if (_countdown1 == 0) {
+ _vm->_screen->clear();
+ leaveScene(0);
+ }
+ } else if ((_countdown2 != 0 && (--_countdown2 == 0)) /*|| !_soundResource.isPlaying()*/) {
+ _countdown1 = 12;
+ _palette->startFadeToBlack(11);
+ }
+
+ if (_countdown3 != 0)
+ _countdown3--;
+
+ if (_countdown3 == 0 && _flag && _countdown1 == 0) {
+ _countdown1 = 12;
+ _palette->startFadeToBlack(11);
+ }
+
+}
+
+uint32 Scene1501::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ if (messageNum == 0x0009) {
+ _flag = true;
+ }
+ return messageResult;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1500.h b/engines/neverhood/module1500.h
new file mode 100644
index 0000000000..eeabec0618
--- /dev/null
+++ b/engines/neverhood/module1500.h
@@ -0,0 +1,59 @@
+/* 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.
+ *
+ */
+
+// TODO: I couldn't come up with a better name than 'Module' so far
+
+#ifndef NEVERHOOD_MODULE1500_H
+#define NEVERHOOD_MODULE1500_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/smackerscene.h"
+
+namespace Neverhood {
+
+class Module1500 : public Module {
+public:
+ Module1500(NeverhoodEngine *vm, Module *parentModule, int which, bool flag);
+protected:
+ bool _flag;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+class Scene1501 : public Scene {
+public:
+ Scene1501(NeverhoodEngine *vm, Module *parentModule, uint32 backgroundFileHash, uint32 soundFileHash, int countdown2, int countdown3);
+protected:
+ SoundResource _soundResource;
+ int _countdown1;
+ int _countdown2;
+ int _countdown3;
+ bool _flag;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1500_H */
diff --git a/engines/neverhood/module1600.cpp b/engines/neverhood/module1600.cpp
new file mode 100644
index 0000000000..c510601642
--- /dev/null
+++ b/engines/neverhood/module1600.cpp
@@ -0,0 +1,1486 @@
+/* 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/module1600.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/module1200.h"
+#include "neverhood/module2200.h"
+
+namespace Neverhood {
+
+Module1600::Module1600(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 1) {
+ createScene(4, 1);
+ } else if (which == 2) {
+ createScene(5, 0);
+ } else if (which == 3) {
+ createScene(6, 1);
+ } else if (which == 4) {
+ createScene(1, 0);
+ } else {
+ createScene(0, 0);
+ }
+
+ // TODO Sound1ChList_addSoundResources(0x1A008D8, dword_4B3BB0, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B3BB0, true, 50, 600, 5, 150);
+ // TODO Sound1ChList_sub_407C70(0x1A008D8, 0x41861371, 0x43A2507F, 0);
+
+}
+
+Module1600::~Module1600() {
+ // TODO Sound1ChList_sub_407A50(0x1A008D8);
+}
+
+void Module1600::createScene(int sceneNum, int which) {
+ debug("Module1600::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ createNavigationScene(0x004B39D0, which);
+ break;
+ case 1:
+ createNavigationScene(0x004B3A30, which);
+ break;
+ case 2:
+ createNavigationScene(0x004B3A60, which);
+ break;
+ case 3:
+ createNavigationScene(0x004B3A90, which);
+ break;
+ case 4:
+ createNavigationScene(0x004B3B20, which);
+ break;
+ case 5:
+ createNavigationScene(0x004B3B50, which);
+ break;
+ case 6:
+ createNavigationScene(0x004B3B80, which);
+ break;
+ case 7:
+ _childObject = new Scene1608(_vm, this, which);
+ break;
+ case 8:
+ _childObject = new Scene1609(_vm, this, which);
+ break;
+ case 1001:
+ if (getGlobalVar(0xA0808898) == 1) {
+ createSmackerScene(0x80050200, true, true, false);
+ } else if (getGlobalVar(0xA0808898) == 2) {
+ createSmackerScene(0x80090200, true, true, false);
+ } else {
+ createSmackerScene(0x80000200, true, true, false);
+ }
+ if (getGlobalVar(0xA0808898) >= 2)
+ setGlobalVar(0xA0808898, 0);
+ else
+ incGlobalVar(0xA0808898, +1);
+ break;
+ }
+ SetUpdateHandler(&Module1600::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1600::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 0)
+ createScene(2, 0);
+ else if (_moduleResult == 1)
+ createScene(1, 0);
+ else if (_moduleResult == 2)
+ leaveModule(4);
+ break;
+ case 1:
+ if (_moduleResult == 0)
+ createScene(1001, -1);
+ else if (_moduleResult == 1)
+ createScene(0, 3);
+ break;
+ case 2:
+ if (_moduleResult == 0)
+ createScene(3, 0);
+ else if (_moduleResult == 1)
+ createScene(0, 2);
+ break;
+ case 3:
+ if (_moduleResult == 0)
+ createScene(5, 0);
+ else if (_moduleResult == 2)
+ createScene(6, 0);
+ else if (_moduleResult == 3)
+ createScene(2, 1);
+ else if (_moduleResult == 4)
+ createScene(4, 0);
+ break;
+ case 4:
+ if (_moduleResult == 0)
+ leaveModule(1);
+ else if (_moduleResult == 1)
+ createScene(3, 1);
+ break;
+ case 5:
+ if (_moduleResult == 0)
+ leaveModule(2);
+ else if (_moduleResult == 1)
+ createScene(3, 3);
+ break;
+ case 6:
+ if (_moduleResult == 0)
+ createScene(8, -1);
+ else if (_moduleResult == 1)
+ createScene(3, 5);
+ break;
+ case 7:
+ createScene(6, 1);
+ break;
+ case 8:
+ if (_moduleResult == 0)
+ createScene(6, 0);
+ else
+ createScene(7, 0);
+ break;
+ case 1001:
+ createScene(1, 0);
+ break;
+ }
+ }
+}
+
+Class521::Class521(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
+ : AnimatedSprite(vm, 1000), _parentScene(parentScene) {
+
+ SetUpdateHandler(&Class521::update);
+ SetMessageHandler(&Class521::handleMessage);
+ SetSpriteCallback(NULL);
+
+ // TODO createSurface2(200, dword_4AF4C0);
+ createSurface(200, 640, 480); //TODO: Remove once the line above is done
+ _x = x;
+ _y = y;
+
+ _field100 = 0;
+ _exitDirection = 0;
+ _currPointIndex = 0;
+ _againDestPtFlag = 0;
+ _stepError = 0;
+ _againDestPointFlag = 0;
+ _steps = 0;
+ _flag10E = 0;
+ _moreY = 0;
+ _flag10F = 0;
+ _flag113 = 0;
+ _flag114 = 1;
+ _flag11A = 0;
+ _newDeltaXType = -1;
+ _field11E = 0;
+ _pathPoints = NULL;
+ _rectList = NULL;
+
+ setFileHash(0xD4220027, 0, -1);
+ setDoDeltaX(getGlobalVar(0x21E60190));
+
+}
+
+Class521::~Class521() {
+ if (_finalizeStateCb == AnimationCallback(&Class521::sub45D620)) {
+ setGlobalVar(0x21E60190, !getGlobalVar(0x21E60190));
+ }
+}
+
+void Class521::setPathPoints(NPointArray *pathPoints) {
+ _pathPoints = pathPoints;
+}
+
+void Class521::update() {
+ if (_newDeltaXType >= 0) {
+ setDoDeltaX(_newDeltaXType);
+ _newDeltaXType = -1;
+ }
+ AnimatedSprite::update();
+ if (_againDestPtFlag && _moreY == 0 && !_flag10F) {
+ _againDestPtFlag = 0;
+ _againDestPointFlag = 0;
+ sendPointMessage(this, 0x2004, _againDestPt);
+ } else if (_againDestPointFlag && _moreY == 0 && !_flag10F) {
+ _againDestPointFlag = 0;
+ sendMessage(this, 0x2003, _againDestPointIndex);
+ }
+ sub45CE10();
+ sub45E0A0();
+}
+
+void Class521::update45C790() {
+ Class521::update();
+ if (++_idleCounter >= _idleCounterMax)
+ sub45D050();
+ sub45E0A0();
+}
+
+uint32 Class521::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1019:
+ SetSpriteCallback(NULL);
+ break;
+ /* NOTE: Implemented in setPathPoints
+ case 0x2000:
+ case 0x2001:
+ */
+ case 0x2002:
+ // Set the current position without moving
+ _currPointIndex = param.asInteger();
+ _stepError = 0;
+ _x = pathPoint(_currPointIndex).x;
+ _y = pathPoint(_currPointIndex).y;
+ break;
+ case 0x2003:
+ // Move to a point by its index
+ {
+ int newPointIndex = param.asInteger();
+ if (_moreY <= 0 && !_flag10F) {
+ _someX = pathPoint(newPointIndex).x;
+ _someY = pathPoint(newPointIndex).y;
+ if (_currPointIndex < newPointIndex) {
+ moveToNextPoint();
+ } else if (_currPointIndex == newPointIndex && _stepError == 0) {
+ if (_currPointIndex == 0) {
+ _moreY = 0;
+ sendMessage(_parentScene, 0x2005, 0);
+ } else if (_currPointIndex == (int)_pathPoints->size()) {
+ _moreY = 0;
+ sendMessage(_parentScene, 0x2006, 0);
+ }
+ } else {
+ moveToPrevPoint();
+ }
+ } else {
+ _againDestPointFlag = 1;
+ _againDestPointIndex = newPointIndex;
+ }
+ }
+ break;
+ case 0x2004:
+ // Move to the point closest to the parameter point
+ {
+ int minMatchIndex = -1;
+ int minMatchDistance, distance;
+ NPoint pt = param.asPoint();
+ if (_moreY <= 0 && !_flag10F) {
+ // Check if we're already exiting (or something)
+ if ((pt.x <= 20 && _exitDirection == 1) ||
+ (pt.x >= 620 && _exitDirection == 3) ||
+ (pt.y <= 20 && _exitDirection == 2) ||
+ (pt.y >= 460 && _exitDirection == 4))
+ break;
+ _someX = pt.x;
+ _someY = pt.y;
+ minMatchDistance = calcDistance(_someX, _someY, _x, _y) + 1;
+ for (int i = _currPointIndex + 1; i < (int)_pathPoints->size(); i++) {
+ distance = calcDistance(_someX, _someY, pathPoint(i).x, pathPoint(i).y);
+ if (distance >= minMatchDistance)
+ break;
+ minMatchDistance = distance;
+ minMatchIndex = i;
+ }
+ for (int i = _currPointIndex; i >= 0; i--) {
+ distance = calcDistance(_someX, _someY, pathPoint(i).x, pathPoint(i).y);
+ if (distance >= minMatchDistance)
+ break;
+ minMatchDistance = distance;
+ minMatchIndex = i;
+ }
+ if (minMatchIndex == -1) {
+ if (_currPointIndex == 0) {
+ moveToPrevPoint();
+ } else {
+ SetSpriteCallback(NULL);
+ }
+ } else {
+ if (minMatchIndex > _currPointIndex) {
+ moveToNextPoint();
+ } else {
+ moveToPrevPoint();
+ }
+ }
+ } else {
+ _againDestPtFlag = 1;
+ _againDestPt = pt;
+ }
+ }
+ break;
+ case 0x2007:
+ _moreY = param.asInteger();
+ _steps = 0;
+ _flag10E = 0;
+ SetSpriteCallback(&Class521::suMoveToPrevPoint);
+ _lastDistance = 640;
+ break;
+ case 0x2008:
+ _moreY = param.asInteger();
+ _steps = 0;
+ _flag10E = 0;
+ SetSpriteCallback(&Class521::suMoveToNextPoint);
+ _lastDistance = 640;
+ break;
+ case 0x2009:
+ sub45CF80();
+ break;
+ case 0x200A:
+ sub45CFB0();
+ break;
+ /* NOTE: Implemented in setRectList
+ case 0x200B:
+ case 0x200C:
+ */
+ case 0x200E:
+ sub45D180();
+ break;
+ case 0x200F:
+ sub45CD00();
+ _newDeltaXType = param.asInteger();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Class521::handleMessage45CC30(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Class521::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (_flag10F && param.asInteger() == 0x025424A2) {
+ removeCallbacks();
+ }
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Class521::handleMessage45CCA0(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x2009:
+ sub45CF80();
+ break;
+ case 0x3002:
+ sendMessage(_parentScene, 0x200A, 0);
+ SetMessageHandler(&Class521::handleMessage);
+ break;
+ }
+ return 0;
+}
+
+void Class521::sub45CD00() {
+ bool doDeltaX = _doDeltaX;
+ SetSpriteCallback(NULL);
+ _againDestPtFlag = 0;
+ _againDestPointFlag = 0;
+ _flag10E = 0;
+ _flag10F = 0;
+ _flag113 = 0;
+ _flag114 = 0;
+ _flag11A = 0;
+ _rectList = NULL;
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ NextState(&Class521::sub45CFE0);
+ setFileHash(0x35698F78, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update45C790);
+ FinalizeState(&Class521::sub45D040);
+ setDoDeltaX(doDeltaX ? 1 : 0);
+ _currMoveDirection = 0;
+ _newMoveDirection = 0;
+ _steps = 0;
+ _idleCounter = 0;
+ _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
+}
+
+void Class521::sub45CDC0() {
+ if (_value112 == 1) {
+ _lastDistance = 640;
+ _flag113 = 0;
+ _flag10E = 0;
+ SetSpriteCallback(&Class521::suMoveToNextPoint);
+ } else if (_value112 == 2) {
+ _lastDistance = 640;
+ _flag113 = 0;
+ _flag10E = 0;
+ SetSpriteCallback(&Class521::suMoveToPrevPoint);
+ }
+}
+
+void Class521::sub45CE10() {
+ if (_flag10E && !_flag113 && !_flag10F) {
+ removeCallbacks();
+ _flag114 = 0;
+ _flag113 = 1;
+ setFileHash(0x192ADD30, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45CFE0);
+ } else if (!_flag10E && _steps && _flag113) {
+ removeCallbacks();
+ _flag113 = 0;
+ setFileHash(0x9966B138, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45D100);
+ } else {
+ bool flag = false;
+ uint index = 0;
+ if (_rectList && _rectList->size() > 0) {
+ while (index < _rectList->size()) {
+ NRect r = (*_rectList)[index];
+ if (_x >= r.x1 && _x <= r.x2 && _y >= r.y1 && _y <= r.y2)
+ break;
+ }
+ if (index < _rectList->size() && !_flag11A)
+ flag = true;
+ _flag11A = index < _rectList->size();
+ }
+ if (flag) {
+ removeCallbacks();
+ sub45D0A0();
+ } else if (_newMoveDirection != _currMoveDirection && _flag114 && !_flag10F) {
+ removeCallbacks();
+ _currMoveDirection = _newMoveDirection;
+ sub45D100();
+ }
+ }
+}
+
+void Class521::sub45CF80() {
+ setFileHash(0xA86A9538, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45CFE0);
+}
+
+void Class521::sub45CFB0() {
+ setFileHash(0xA86A9538, -1, -1);
+ _playBackwards = true;
+ SetMessageHandler(&Class521::handleMessage45CCA0);
+ SetUpdateHandler(&Class521::update);
+}
+
+void Class521::sub45CFE0() {
+ setFileHash(0x35698F78, 0, -1);
+ SetMessageHandler(&Class521::handleMessage);
+ SetUpdateHandler(&Class521::update45C790);
+ FinalizeState(&Class521::sub45D040);
+ _idleCounter = 0;
+ _currMoveDirection = 0;
+ _newMoveDirection = 0;
+ _steps = 0;
+ _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
+}
+
+void Class521::sub45D040() {
+ SetUpdateHandler(&Class521::update);
+}
+
+void Class521::sub45D050() {
+ setFileHash(0xB579A77C, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45CFE0);
+ _idleCounter = 0;
+ _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
+}
+
+void Class521::sub45D0A0() {
+ _flag10F = 1;
+ removeCallbacks();
+ setFileHash(0x9C220DA4, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ FinalizeState(&Class521::sub45D0E0);
+}
+
+void Class521::sub45D0E0() {
+ _flag10F = 0;
+ _newMoveDirection = 0;
+ sub45D100();
+}
+
+void Class521::sub45D100() {
+ _flag114 = 1;
+ if (_currMoveDirection == 1) {
+ setFileHash(0xD4AA03A4, 0, -1);
+ } else if (_currMoveDirection == 3) {
+ setFileHash(0xD00A1364, 0, -1);
+ } else if ((_currMoveDirection == 2 && _doDeltaX) || (_currMoveDirection == 4 && !_doDeltaX)) {
+ sub45D180();
+ } else {
+ setFileHash(0xD4220027, 0, -1);
+ }
+ setGlobalVar(0x21E60190, _doDeltaX ? 1 : 0);
+}
+
+void Class521::sub45D180() {
+ _flag10F = 1;
+ removeCallbacks();
+ setFileHash(0xF46A0324, 0, -1);
+ _value112 = 0;
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ FinalizeState(&Class521::sub45D620);
+ sub45CDC0();
+}
+
+void Class521::moveToNextPoint() {
+ if (_currPointIndex >= (int)_pathPoints->size() - 1) {
+ _moreY = 0;
+ sendMessage(this, 0x1019, 0);
+ sendMessage(_parentScene, 0x2006, 0);
+ } else {
+ NPoint nextPt = pathPoint(_currPointIndex + 1);
+ NPoint currPt = pathPoint(_currPointIndex);
+ if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) && nextPt.x >= currPt.x &&
+ (_currMoveDirection == 4 || _currMoveDirection == 2)) {
+ if (_currMoveDirection == 4)
+ _currMoveDirection = 2;
+ else if (_currMoveDirection == 2)
+ _currMoveDirection = 4;
+ if (_flag113)
+ sub45D390();
+ else
+ sub45D350();
+ } else {
+ if (_steps == 0) {
+ removeCallbacks();
+ _flag113 = 0;
+ setFileHash(0x9966B138, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45D100);
+ }
+ _flag10E = 0;
+ SetSpriteCallback(&Class521::suMoveToNextPoint);
+ _lastDistance = 640;
+ }
+ }
+}
+
+void Class521::sub45D350() {
+ removeCallbacks();
+ _flag10F = 1;
+ _flag10E = 1;
+ setFileHash(0x192ADD30, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45D390);
+}
+
+void Class521::sub45D390() {
+ removeCallbacks();
+ _flag10F = 1;
+ setFileHash(0xF46A0324, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ FinalizeState(&Class521::sub45D620);
+ _value112 = 1;
+ sub45CDC0();
+}
+
+void Class521::moveToPrevPoint() {
+ if (_currPointIndex == 0 && _stepError == 0) {
+ _moreY = 0;
+ sendMessage(this, 0x1019, 0);
+ sendMessage(_parentScene, 0x2005, 0);
+ } else {
+ NPoint prevPt;
+ NPoint currPt;
+ if (_stepError == 0) {
+ prevPt = pathPoint(_currPointIndex - 1);
+ currPt = pathPoint(_currPointIndex);
+ } else {
+ prevPt = pathPoint(_currPointIndex);
+ currPt = pathPoint(_currPointIndex + 1);
+ }
+ if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) && currPt.x >= prevPt.x &&
+ (_currMoveDirection == 2 || _currMoveDirection == 4)) {
+ if (_currMoveDirection == 2)
+ _currMoveDirection = 4;
+ else if (_currMoveDirection == 4)
+ _currMoveDirection = 2;
+ if (_flag113)
+ sub45D5D0();
+ else
+ sub45D580();
+ } else {
+ if (_steps == 0) {
+ removeCallbacks();
+ _flag113 = 0;
+ setFileHash(0x9966B138, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45D100);
+ }
+ _flag10E = 0;
+ SetSpriteCallback(&Class521::suMoveToPrevPoint);
+ _lastDistance = 640;
+ }
+ }
+}
+
+void Class521::sub45D580() {
+ _flag10F = 1;
+ _flag10E = 1;
+ FinalizeState(NULL);
+ setFileHash(0x192ADD30, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ NextState(&Class521::sub45D5D0);
+}
+
+void Class521::sub45D5D0() {
+ _flag10F = 1;
+ FinalizeState(NULL);
+ setFileHash(0xF46A0324, 0, -1);
+ SetMessageHandler(&Class521::handleMessage45CC30);
+ SetUpdateHandler(&Class521::update);
+ FinalizeState(&Class521::sub45D620);
+ _value112 = 2;
+ sub45CDC0();
+}
+
+void Class521::sub45D620() {
+ _flag10F = 0;
+ _newMoveDirection = 0;
+ setDoDeltaX(2);
+ sub45D100();
+}
+
+void Class521::suMoveToNextPoint() {
+ int16 newX = _x, newY = _y;
+
+ if (_currPointIndex >= (int)_pathPoints->size()) {
+ _moreY = 0;
+ sendMessage(this, 0x1019, 0);
+ sendMessage(_parentScene, 0x2006, 0);
+ return;
+ }
+
+ if (_flag10E) {
+ if (_steps <= 0) {
+ sendMessage(this, 0x1019, 0);
+ return;
+ } else {
+ _steps--;
+ }
+ } else if (_steps < 11) {
+ _steps++;
+ }
+
+ bool firstTime = true;
+ _anotherY = _steps;
+ int stepsCtr = _steps;
+
+ while (stepsCtr > 0) {
+ NPoint pt1;
+ NPoint pt2 = pathPoint(_currPointIndex);
+ if (_currPointIndex + 1 >= (int)_pathPoints->size())
+ pt1 = pathPoint(0);
+ else
+ pt1 = pathPoint(_currPointIndex + 1);
+ int16 deltaX = ABS(pt1.x - pt2.x);
+ int16 deltaY = ABS(pt1.y - pt2.y);
+ if (deltaX >= deltaY) {
+ _newMoveDirection = 2;
+ if (pt1.x < pt2.x)
+ _newMoveDirection = 4;
+ if (stepsCtr + _stepError >= deltaX) {
+ stepsCtr -= deltaX;
+ stepsCtr += _stepError;
+ _stepError = 0;
+ _currPointIndex++;
+ if (_currPointIndex == (int)_pathPoints->size() - 1)
+ stepsCtr = 0;
+ newX = pathPoint(_currPointIndex).x;
+ newY = pathPoint(_currPointIndex).y;
+ } else {
+ _stepError += stepsCtr;
+ if (pt1.x >= pt2.x)
+ newX += stepsCtr;
+ else
+ newX -= stepsCtr;
+ if (pt1.y >= pt2.y)
+ newY = pt2.y + (deltaY * _stepError) / deltaX;
+ else
+ newY = pt2.y - (deltaY * _stepError) / deltaX;
+ stepsCtr = 0;
+ }
+ } else {
+ _newMoveDirection = 3;
+ if (pt1.y < pt2.y)
+ _newMoveDirection = 1;
+ if (firstTime) {
+ if (pt1.y >= pt2.y) {
+ stepsCtr += 7;
+ } else {
+ stepsCtr -= 4;
+ if (stepsCtr < 0)
+ stepsCtr = 0;
+ }
+ _anotherY = stepsCtr;
+ }
+ if (stepsCtr + _stepError >= deltaY) {
+ stepsCtr -= deltaY;
+ stepsCtr += _stepError;
+ _stepError = 0;
+ _currPointIndex++;
+ if (_currPointIndex == (int)_pathPoints->size() - 1)
+ stepsCtr = 0;
+ newX = pathPoint(_currPointIndex).x;
+ newY = pathPoint(_currPointIndex).y;
+ } else {
+ _stepError += stepsCtr;
+ if (pt1.x >= pt2.x)
+ newX = pt2.x + (deltaX * _stepError) / deltaY;
+ else
+ newX = pt2.x - (deltaX * _stepError) / deltaY;
+ if (pt1.y >= pt2.y)
+ newY += stepsCtr;
+ else
+ newY -= stepsCtr;
+ stepsCtr = 0;
+ }
+ }
+ firstTime = false;
+ }
+
+ if (_moreY != 0) {
+ _x = newX;
+ _y = newY;
+ _moreY -= _anotherY;
+ if (_moreY <= 0) {
+ _flag10E = 1;
+ _moreY = 0;
+ }
+ } else {
+ int distance = calcDistance(_someX, _someY, _x, _y);
+ _x = newX;
+ _y = newY;
+ if (newX > 20 && newX < 620 && newY > 20 && newY < 460) {
+ _exitDirection = 0;
+ _field100 = 1;
+ } else if (_field100) {
+ _someX = pathPoint(_pathPoints->size() - 1).x;
+ _someY = pathPoint(_pathPoints->size() - 1).y;
+ _field100 = 0;
+ if (_x <= 20)
+ _exitDirection = 1;
+ else if (_x >= 620)
+ _exitDirection = 3;
+ else if (_y <= 20)
+ _exitDirection = 2;
+ else if (_y >= 460)
+ _exitDirection = 4;
+ if (_exitDirection != 0 && _flag10E) {
+ _flag10E = 0;
+ _steps = 11;
+ }
+ }
+ if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) ||
+ (_exitDirection == 0 && _lastDistance + 20 < distance))
+ _flag10E = 1;
+ if (distance < _lastDistance)
+ _lastDistance = distance;
+ if (_currPointIndex == (int)_pathPoints->size() - 1) {
+ _flag10E = 1;
+ _moreY = 0;
+ sendMessage(this, 0x1019, 0);
+ sendMessage(_parentScene, 0x2006, 0);
+ }
+ }
+
+}
+
+void Class521::suMoveToPrevPoint() {
+ int16 newX = _x, newY = _y;
+
+ if (_currPointIndex == 0 && _stepError == 0) {
+ _moreY = 0;
+ sendMessage(this, 0x1019, 0);
+ sendMessage(_parentScene, 0x2005, 0);
+ return;
+ }
+
+ if (_flag10E) {
+ if (_steps <= 0) {
+ sendMessage(this, 0x1019, 0);
+ return;
+ } else {
+ _steps--;
+ }
+ } else if (_steps < 11) {
+ _steps++;
+ }
+
+ bool firstTime = true;
+ _anotherY = _steps;
+ int stepsCtr = _steps;
+
+ while (stepsCtr > 0) {
+ if (_stepError == 0)
+ _currPointIndex--;
+ NPoint pt1;
+ NPoint pt2 = pathPoint(_currPointIndex);
+ if (_currPointIndex + 1 >= (int)_pathPoints->size())
+ pt1 = pathPoint(0);
+ else
+ pt1 = pathPoint(_currPointIndex + 1);
+ int16 deltaX = ABS(pt1.x - pt2.x);
+ int16 deltaY = ABS(pt1.y - pt2.y);
+ if (deltaX >= deltaY) {
+ _newMoveDirection = 4;
+ if (pt1.x < pt2.x)
+ _newMoveDirection = 2;
+ if (_stepError == 0)
+ _stepError = deltaX;
+ if (stepsCtr > _stepError) {
+ stepsCtr -= _stepError;
+ _stepError = 0;
+ if (_currPointIndex == 0)
+ stepsCtr = 0;
+ newX = pathPoint(_currPointIndex).x;
+ newY = pathPoint(_currPointIndex).y;
+ } else {
+ _stepError -= stepsCtr;
+ if (pt1.x >= pt2.x)
+ newX -= stepsCtr;
+ else
+ newX += stepsCtr;
+ if (pt1.y >= pt2.y)
+ newY = pt2.y + (deltaY * _stepError) / deltaX;
+ else
+ newY = pt2.y - (deltaY * _stepError) / deltaX;
+ stepsCtr = 0;
+ }
+ } else {
+ _newMoveDirection = 1;
+ if (pt1.y < pt2.y)
+ _newMoveDirection = 3;
+ if (firstTime) {
+ if (pt1.y >= pt2.y) {
+ stepsCtr -= 4;
+ if (stepsCtr < 0)
+ stepsCtr = 0;
+ } else {
+ stepsCtr += 7;
+ }
+ _anotherY = stepsCtr;
+ }
+ if (_stepError == 0)
+ _stepError = deltaY;
+ if (stepsCtr > _stepError) {
+ stepsCtr -= _stepError;
+ _stepError = 0;
+ if (_currPointIndex == 0)
+ stepsCtr = 0;
+ newX = pathPoint(_currPointIndex).x;
+ newY = pathPoint(_currPointIndex).y;
+ } else {
+ _stepError -= stepsCtr;
+ if (pt1.x >= pt2.x)
+ newX = pt2.x + (deltaX * _stepError) / deltaY;
+ else
+ newX = pt2.x - (deltaX * _stepError) / deltaY;
+ if (pt1.y >= pt2.y)
+ newY -= stepsCtr;
+ else
+ newY += stepsCtr;
+ stepsCtr = 0;
+ }
+ }
+ firstTime = false;
+ }
+
+ if (_moreY != 0) {
+ _x = newX;
+ _y = newY;
+ _moreY -= _anotherY;
+ if (_moreY <= 0) {
+ _flag10E = 1;
+ _moreY = 0;
+ }
+ } else {
+ int distance = calcDistance(_someX, _someY, _x, _y);
+ _x = newX;
+ _y = newY;
+ if (newX > 20 && newX < 620 && newY > 20 && newY < 460) {
+ _exitDirection = 0;
+ _field100 = 1;
+ } else if (_field100) {
+ _someX = pathPoint(0).x;
+ _someY = pathPoint(0).y;
+ _field100 = 0;
+ if (_x <= 20)
+ _exitDirection = 1;
+ else if (_x >= 620)
+ _exitDirection = 3;
+ else if (_y <= 20)
+ _exitDirection = 2;
+ else if (_y >= 460)
+ _exitDirection = 4;
+ if (_exitDirection != 0 && _flag10E) {
+ _flag10E = 0;
+ _steps = 11;
+ }
+ }
+ if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) ||
+ (_exitDirection == 0 && _lastDistance + 20 < distance))
+ _flag10E = 1;
+ if (distance < _lastDistance)
+ _lastDistance = distance;
+ if (_currPointIndex == 0 && _stepError == 0) {
+ _flag10E = 1;
+ _moreY = 0;
+ sendMessage(this, 0x1019, 0);
+ sendMessage(_parentScene, 0x2005, 0);
+ }
+ }
+
+}
+
+void Class521::sub45E0A0() {
+ // TODO
+}
+
+Class546::Class546(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 0x08C80144, 900, 320, 240), _soundResource(vm),
+ _parentScene(parentScene) {
+
+ setVisible(false);
+ SetMessageHandler(&Class546::handleMessage);
+ stopAnimation();
+}
+
+uint32 Class546::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ sub44D710();
+ break;
+ case 0x4809:
+ sub44D790();
+ break;
+ }
+ return messageResult;
+}
+
+void Class546::sub44D710() {
+ setFileHash(0x08C80144, 0, -1);
+ setVisible(true);
+ NextState(&Class546::sub44D760);
+ _soundResource.play(calcHash("fxDoorOpen23"));
+}
+
+void Class546::sub44D760() {
+ sendMessage(_parentScene, 0x2033, 0);
+ stopAnimation();
+ setVisible(false);
+}
+
+void Class546::sub44D790() {
+ setFileHash(0x08C80144, -1, -1);
+ setVisible(true);
+ NextState(&Class546::sub44D7F0);
+ _soundResource.play(calcHash("fxDoorClose23"));
+}
+
+void Class546::sub44D7F0() {
+ sendMessage(_parentScene, 0x2034, 0);
+ stopAnimation();
+}
+
+Class547::Class547(NeverhoodEngine *vm, int16 x, int16 y)
+ : AnimatedSprite(vm, 0x1209E09F, 1100, x, y) {
+
+ setDoDeltaX(1);
+ setFileHash(0x1209E09F, 1, -1);
+ _newHashListIndex = 1;
+}
+
+Class548::Class548(NeverhoodEngine *vm, int16 x, int16 y)
+ : AnimatedSprite(vm, 0x1209E09F, 100, x, y) {
+
+ setDoDeltaX(1);
+ _newHashListIndex = 0;
+}
+
+Class518::Class518(NeverhoodEngine *vm, Class521 *class521)
+ : AnimatedSprite(vm, 1100), _class521(class521) {
+
+ SetUpdateHandler(&Class518::update);
+ createSurface1(0x60281C10, 150);
+ setFileHash(0x60281C10, -1, -1);
+ _newHashListIndex = -2;
+}
+
+void Class518::update() {
+ _x = _class521->getX();
+ _y = _class521->getY();
+ AnimatedSprite::update();
+}
+
+Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _class521(NULL), _countdown1(0) {
+
+ setGlobalVar(0x21E60190, 1);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1608::handleMessage44D2A0);
+
+ _class545 = insertSprite<Class545>(this, 1, 1100, 198, 220);
+ _vm->_collisionMan->addSprite(_class545);
+
+ if (which < 0) {
+ if (_vm->gameState().which == 1)
+ which = 1;
+ else {
+ setRectList(0x004B47D0);
+ insertKlayman<KmScene1608>(380, 438);
+ _klayman2 = _klayman;
+ _flag4 = false;
+ _class546 = insertSprite<Class546>(this);
+ _sprite1 = insertStaticSprite(0x7D0404E8, 1100);
+ setMessageList(0x004B46A8);
+ setBackground(0x10080E01);
+ setPalette(0x10080E01);
+ _asTape = insertSprite<AsScene1201Tape>(this, 13, 1100, 412, 443, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+ SetUpdateHandler(&Scene1608::update44CE90);
+ insertMouse433(0x80E05108);
+ insertStaticSprite(0x4B18F868, 1200);
+ }
+ } else if (which == 0) {
+ _vm->gameState().which = 0;
+ setRectList(0x004B47D0);
+ insertKlayman<KmScene1608>(0, 438);
+ _klayman2 = _klayman;
+ _flag4 = false;
+ setMessageList(0x004B46B0);
+ setBackground(0x10080E01);
+ setPalette(0x10080E01);
+ _asTape = insertSprite<AsScene1201Tape>(this, 13, 1100, 412, 443, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+ insertMouse433(0x80E05108);
+ _sprite1 = insertStaticSprite(0x7D0404E8, 1100);
+ _class546 = insertSprite<Class546>(this);
+ _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480);
+ SetUpdateHandler(&Scene1608::update44CE90);
+ sendMessage(_class546, 0x4808, 0);
+ insertStaticSprite(0x4B18F868, 1200);
+ } else if (which == 2) {
+ _vm->gameState().which = 1;
+ _dataResource.load(0x003C0492);
+ _roomPathPoints = _dataResource.getPointArray(calcHash("meArchroArchRoomPath"));
+ setBackground(0x98001604);
+ setPalette(0x98001604);
+ _palette->addPalette("paPodRed", 65, 31, 65);
+ insertMouse433(0x01600988);
+ _sprite2 = insertStaticSprite(0x491F38A8, 1100);
+ _class521 = createSprite<Class521>(this, 375, 227); // Create but don't add to the sprite list yet
+ _class547 = insertSprite<Class547>(375, 227);
+ _class548 = insertSprite<Class548>(375, 227);
+ _class521->setVisible(false);
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene1608>(373, 220);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene1608>(283, 220);
+ }
+ _klayman2 = _klayman;
+ setMessageList(0x004B47A8);
+ SetMessageHandler(&Scene1608::handleMessage44D3C0);
+ SetUpdateHandler(&Scene1608::update44CED0);
+ // NOTE: Setting the point array was handled by messages 0x2000 (array) and 0x2001 (count) in the original
+ _class521->setPathPoints(_roomPathPoints);
+ sendMessage(_class521, 0x2002, _roomPathPoints->size() - 1);
+ _sprite3 = insertStaticSprite(0xB47026B0, 1100);
+ _rect1.set(_sprite3->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2());
+ _rect3.set(_sprite2->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2());
+ _rect2 = _rect1;
+ _rect2.y2 = 215;
+ _klayman->setClipRect(_rect1);
+ _class521->setClipRect(_rect1);
+ _class547->setClipRect(_rect1);
+ _class548->setClipRect(_rect1);
+ _asTape = insertSprite<AsScene1201Tape>(this, 13, 1100, 412, 443, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+ insertSprite<Class518>(_class521)->setClipRect(_rect1);
+ _flag4 = false;
+ _flag2 = false;
+ _flag1 = 0;
+ setRectList(0x004B4810);
+ }
+
+ // NOTE: Not in the else because 'which' is set to 1 in the true branch
+ if (which == 1) {
+ _vm->gameState().which = 1;
+ _dataResource.load(0x003C0492);
+ _roomPathPoints = _dataResource.getPointArray(calcHash("meArchroArchRoomPath"));
+ setBackground(0x98001604);
+ setPalette(0x98001604);
+ _palette->addPalette("paPodRed", 65, 31, 65);
+ insertMouse433(0x01600988);
+ _class521 = insertSprite<Class521>(this, 375, 227);
+ _class547 = insertSprite<Class547>(375, 227);
+ _class548 = insertSprite<Class548>(375, 227);
+ _sprite2 = insertStaticSprite(0x491F38A8, 1100);
+ _klayman2 = createSprite<KmScene1608>(this, 439, 220); // Special Klayman handling...
+ sendMessage(_klayman2, 0x2032, 1);
+ _klayman2->setDoDeltaX(1);
+ SetMessageHandler(&Scene1608::handleMessage44D470);
+ SetUpdateHandler(&Scene1608::update44D1E0);
+ _class547->setVisible(false);
+ _class548->setVisible(false);
+ // NOTE: Setting the point array was handled by messages 0x2000 (array) and 0x2001 (count) in the original
+ _class521->setPathPoints(_roomPathPoints);
+ sendMessage(_class521, 0x2002, 0);
+ sendMessage(_class521, 0x2008, 90);
+ _sprite3 = insertStaticSprite(0xB47026B0, 1100);
+ _rect1.set(_sprite3->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2());
+ _rect3.set(_sprite2->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2());
+ _rect2 = _rect1;
+ _rect2.y2 = 215;
+ _klayman2->setClipRect(_rect1);
+ _class521->setClipRect(_rect1);
+ _class547->setClipRect(_rect1);
+ _class548->setClipRect(_rect1);
+ _asTape = insertSprite<AsScene1201Tape>(this, 13, 1100, 412, 443, 0x9148A011);
+ // ... _vm->_collisionMan->addSprite(_asTape);
+ insertSprite<Class518>(_class521)->setClipRect(_rect1);
+ _flag4 = true;
+ _flag2 = true;
+ _flag1 = 0;
+ }
+
+ _palette->addPalette("paKlayRed", 0, 64, 0);
+
+}
+
+Scene1608::~Scene1608() {
+ setGlobalVar(0xC0418A02, _klayman2->isDoDeltaX() ? 1 : 0);
+ // Weird
+ if (_flag4) {
+ delete _klayman2;
+ } else {
+ delete _class521;
+ }
+}
+
+void Scene1608::update44CE90() {
+ Scene::update();
+ if (_countdown1 != 0 && (--_countdown1 == 0)) {
+ leaveScene(0);
+ }
+}
+
+void Scene1608::update44CED0() {
+ Scene::update();
+ if (_flag1 == 1) {
+ removeSurface(_klayman->getSurface());
+ removeEntity(_klayman);
+ addSprite(_class521);
+ _flag4 = true;
+ clearRectList();
+ SetUpdateHandler(&Scene1608::update44CFE0);
+ SetMessageHandler(&Scene1608::handleMessage44D510);
+ _class547->setVisible(false);
+ _class548->setVisible(false);
+ _class521->setVisible(true);
+ sendMessage(_class521, 0x2009, 0);
+ _class521->handleUpdate();
+ _klayman = NULL;
+ _flag1 = 0;
+ }
+ if (_klayman2->getX() <= 375) {
+ _klayman2->setClipRect(_rect1);
+ } else {
+ _klayman2->setClipRect(_rect2);
+ }
+}
+
+void Scene1608::update44CFE0() {
+ Scene::update();
+ if (_mouseClicked) {
+ if (_mouseClickPos.x <= 329 && _class521->getX() == 375 && _class521->getY() == 227) {
+ sendMessage(_class521, 0x200A, 0);
+ SetUpdateHandler(&Scene1608::update44D0C0);
+ } else {
+ sendPointMessage(_class521, 0x2004, _mouseClickPos);
+ SetMessageHandler(&Scene1608::handleMessage44D470);
+ SetUpdateHandler(&Scene1608::update44D1E0);
+ }
+ _mouseClicked = false;
+ }
+ if (_klayman2->getX() <= 375) {
+ _klayman2->setClipRect(_rect1);
+ } else {
+ _klayman2->setClipRect(_rect2);
+ }
+}
+
+void Scene1608::update44D0C0() {
+ Scene::update();
+ if (_flag1 == 2) {
+ _klayman = _klayman2;
+ removeSurface(_class521->getSurface());
+ removeEntity(_class521);
+ addSprite(_klayman);
+ _flag4 = false;
+ SetMessageHandler(&Scene1608::handleMessage44D3C0);
+ SetUpdateHandler(&Scene1608::update44CED0);
+ setRectList(0x004B4810);
+ _class547->setVisible(true);
+ _class548->setVisible(true);
+ _class521->setVisible(false);
+ setMessageList(0x004B4748);
+ runMessageList();
+ _klayman->handleUpdate();
+ _flag1 = 0;
+ }
+ if (_klayman2->getX() <= 375) {
+ _klayman2->setClipRect(_rect1);
+ } else {
+ _klayman2->setClipRect(_rect2);
+ }
+}
+
+void Scene1608::update44D1E0() {
+ Scene::update();
+ if (_mouseClicked) {
+ sendPointMessage(_class521, 0x2004, _mouseClickPos);
+ _mouseClicked = false;
+ }
+ if (_class521->getX() < 300) {
+ if (_flag2) {
+ _flag2 = false;
+ _class521->setClipRect(_rect1);
+ if (!_class521->isDoDeltaX())
+ sendMessage(_class521, 0x200E, 0);
+ }
+ } else if (!_flag2) {
+ _flag2 = true;
+ _class521->setClipRect(_rect3);
+ }
+}
+
+uint32 Scene1608::handleMessage44D2A0(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x20250B1A) {
+ clearRectList();
+ _klayman->setVisible(false);
+ showMouse(false);
+ _sprite1->setVisible(false);
+ sendMessage(_class546, 0x4809, 0);
+ _countdown1 = 28;
+ }
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ case 0x4826:
+ if (sender == _asTape) {
+ sendEntityMessage(_klayman2, 0x1014, _asTape);
+ setMessageList(0x004B4770);
+ } else if (sender == _class545) {
+ setMessageList(0x004B46C8);
+ }
+ break;
+ }
+ return 0;
+}
+
+uint32 Scene1608::handleMessage44D3C0(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x60842040) {
+ _flag1 = true;
+ }
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ case 0x4826:
+ if (sender == _class545) {
+ sendEntityMessage(_klayman2, 0x1014, _class545);
+ setMessageList(0x004B4760);
+ }
+ break;
+ }
+ return 0;
+}
+
+uint32 Scene1608::handleMessage44D470(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2005:
+ leaveScene(1);
+ break;
+ case 0x2006:
+ SetMessageHandler(&Scene1608::handleMessage44D510);
+ SetUpdateHandler(&Scene1608::update44CFE0);
+ sendMessage(_class521, 0x200F, 1);
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+uint32 Scene1608::handleMessage44D510(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x200A:
+ _flag1 = 2;
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+Scene1609::Scene1609(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm), _countdown1(1),
+ _index1(0), _index3(0), _flag5(true), _flag6(false) {
+
+ // TODO _vm->gameModule()->initScene3011Vars();
+ _index2 = getGlobalVar(0x2414C2F2);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene1609::handleMessage);
+ SetUpdateHandler(&Scene1609::update);
+
+ setBackground(0x92124A14);
+ setPalette(0x92124A14);
+
+ for (int i = 0; i < 12; i++)
+ _asSymbols[i] = insertSprite<AsScene3011Symbol>(i, false);
+
+ _ssButton = insertSprite<SsScene3011Button>(this, true);
+ _vm->_collisionMan->addSprite(_ssButton);
+
+ insertMouse435(0x24A10929, 20, 620);
+
+ _soundResource.load(0x68E25540);
+
+}
+
+void Scene1609::update() {
+ if (!_flag6 && _countdown1 != 0 && (--_countdown1 == 0)) {
+ if (_flag5) {
+ _index1++;
+ if (_index1 >= 12)
+ _index1 = 0;
+ _asSymbols[_index3]->change(_index1 + 12, _index1 == (int)getSubVar(0x04909A50, _index2));
+ _flag5 = false;
+ _countdown1 = 36;
+ } else {
+ _asSymbols[_index3]->hide();
+ _flag5 = true;
+ _countdown1 = 12;
+ }
+ }
+ if (_flag6 && !_soundResource.isPlaying()) {
+ leaveScene(1);
+ }
+ Scene::update();
+}
+
+uint32 Scene1609::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO: Debug stuff
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620)
+ leaveScene(0);
+ break;
+ // TODO: Debug stuff
+ case 0x2000:
+ if (!_flag6) {
+ if (_flag5)
+ _asSymbols[_index3]->change(_index1 + 12, false);
+ _asSymbols[_index3]->stopSound();
+ _index3++;
+ if (_index3 >= 12) {
+ if (testVars()) {
+ _soundResource.play();
+ setGlobalVar(0x2C531AF8, 1);
+ _flag6 = true;
+ } else {
+ _index3 = 0;
+ for (int i = 0; i < 12; i++)
+ _asSymbols[i]->hide();
+ }
+ }
+ _flag5 = true;
+ _countdown1 = 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+bool Scene1609::testVars() {
+ int index1 = 0;
+ do {
+ int cmpIndex = _asSymbols[0]->getIndex();
+ if (!_asSymbols[0]->getFlag1())
+ cmpIndex -= 12;
+ if ((int)getSubVar(0x04909A50, index1) == cmpIndex)
+ break;
+ index1++;
+ } while(1);
+ for (int index2 = 0; index2 < 12; index2++) {
+ int cmpIndex = _asSymbols[index2]->getIndex();
+ if (!_asSymbols[index2]->getFlag1())
+ cmpIndex -= 12;
+ if ((int)getSubVar(0x04909A50, index1) != cmpIndex)
+ return false;
+ _index1++;
+ if (_index1 >= 12)
+ _index1 = 0;
+ _index2++;
+ }
+ return true;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1600.h b/engines/neverhood/module1600.h
new file mode 100644
index 0000000000..efb2b943ab
--- /dev/null
+++ b/engines/neverhood/module1600.h
@@ -0,0 +1,194 @@
+/* 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_MODULE1600_H
+#define NEVERHOOD_MODULE1600_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module3000.h"
+
+namespace Neverhood {
+
+// Module1600
+
+class Module1600 : public Module {
+public:
+ Module1600(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1600();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+class Class521 : public AnimatedSprite {
+public:
+ Class521(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y);
+ ~Class521();
+ void setPathPoints(NPointArray *pathPoints);
+protected:
+ Scene *_parentScene;
+ NPointArray *_pathPoints;
+ NRectArray *_rectList;
+ int _newMoveDirection;
+ int _currMoveDirection;
+ int _exitDirection;
+ int _currPointIndex;
+ NPoint _againDestPt;
+ int _againDestPtFlag;
+ int _steps;
+ int _stepError;
+ int _idleCounter;
+ int _idleCounterMax;
+ int _lastDistance;
+ int _field100;
+ int _againDestPointFlag;
+ int _flag10E;
+ int _moreY;
+ int _flag10F;
+ int _flag113;
+ int _flag114;
+ int _flag11A;
+ int _newDeltaXType;
+ int _field11E;
+ int _againDestPointIndex;
+ int _value112;
+ int _anotherY;
+ int16 _someX, _someY;
+ NPoint pathPoint(uint index) { return (*_pathPoints)[index]; }
+ void update();
+ void update45C790();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage45CC30(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage45CCA0(int messageNum, const MessageParam &param, Entity *sender);
+ void sub45CD00();
+ void sub45CDC0();
+ void sub45CE10();
+ void sub45CF80();
+ void sub45CFB0();
+ void sub45CFE0();
+ void sub45D040();
+ void sub45D050();
+ void sub45D0A0();
+ void sub45D0E0();
+ void sub45D100();
+ void sub45D180();
+ void moveToNextPoint();
+ void sub45D350();
+ void sub45D390();
+ void moveToPrevPoint();
+ void sub45D580();
+ void sub45D5D0();
+ void sub45D620();
+ void suMoveToNextPoint();
+ void suMoveToPrevPoint();
+ void sub45E0A0();
+};
+
+class Class546 : public AnimatedSprite {
+public:
+ Class546(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub44D710();
+ void sub44D760();
+ void sub44D790();
+ void sub44D7F0();
+};
+
+class Class547 : public AnimatedSprite {
+public:
+ Class547(NeverhoodEngine *vm, int16 x, int16 y);
+};
+
+class Class548 : public AnimatedSprite {
+public:
+ Class548(NeverhoodEngine *vm, int16 x, int16 y);
+};
+
+class Class518 : public AnimatedSprite {
+public:
+ Class518(NeverhoodEngine *vm, Class521 *class521);
+protected:
+ Class521 *_class521;
+ void update();
+};
+
+class Scene1608 : public Scene {
+public:
+ Scene1608(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene1608();
+protected:
+ Class521 *_class521;
+ Sprite *_class545;
+ Sprite *_class546;
+ Sprite *_class547;
+ Sprite *_class548;
+ Sprite *_sprite1;
+ Sprite *_sprite2;
+ Sprite *_sprite3;
+ Sprite *_asTape;
+ Klayman *_klayman2;
+ NRect _rect1;
+ NRect _rect2;
+ NRect _rect3;
+ int _flag1;
+ bool _flag2;
+ bool _flag3;
+ bool _flag4;
+ int _countdown1;
+ NPointArray *_roomPathPoints;
+ void update44CE90();
+ void update44CED0();
+ void update44CFE0();
+ void update44D0C0();
+ void update44D1E0();
+ uint32 handleMessage44D2A0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage44D3C0(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage44D470(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage44D510(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1609 : public Scene {
+public:
+ Scene1609(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource;
+ Sprite *_ssButton;
+ AsScene3011Symbol *_asSymbols[12];
+ int _index1;
+ int _index2;
+ int _index3;
+ int _countdown1;
+ bool _flag5;
+ bool _flag6;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ bool testVars();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1600_H */
diff --git a/engines/neverhood/module1700.cpp b/engines/neverhood/module1700.cpp
new file mode 100644
index 0000000000..ae7a7fdc7a
--- /dev/null
+++ b/engines/neverhood/module1700.cpp
@@ -0,0 +1,278 @@
+/* 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/module1700.h"
+
+namespace Neverhood {
+
+Module1700::Module1700(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule), _soundResource(vm) {
+
+ // TODO Music18hList_add(0x04212331);
+ // TODO Sound1ChList_addSoundResources(0x04212331, dword_4AE930, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AE930, 1, 50, 600, 5, 150);
+ // TODO Sound1ChList_sub_407C70(0x04212331, 0x41861371, 0x43A2507F, 0);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 0) {
+ createScene(0, -1);
+ } else if (which == 1) {
+ createScene(4, 1);
+ } else {
+ createScene(4, 3);
+ }
+
+}
+
+Module1700::~Module1700() {
+ // TODO Sound1ChList_sub_407A50(0x04212331);
+}
+
+void Module1700::createScene(int sceneNum, int which) {
+ debug("Module1700::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AE930, 0, 0, 0, 0, 0);
+ createSmackerScene(0x3028A005, true, true, false);
+ break;
+ case 1:
+ createNavigationScene(0x004AE8B8, which);
+ break;
+ case 2:
+ createNavigationScene(0x004AE8E8, which);
+ break;
+ case 3:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AE930, 0, 0, 0, 0, 0);
+ createSmackerScene(0x01190041, true, true, false);
+ break;
+ case 4:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AE930, 0, 0, 0, 0, 0);
+ // TODO Music18hList_play(0x31114225, 0, 2, 1);
+ _childObject = new Scene1705(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module1700::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1700::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AE930, 1, 0, 0, 0);
+ createScene(1, 0);
+ break;
+ case 1:
+ if (_moduleResult == 0) {
+ createScene(2, 0);
+ } else if (_moduleResult == 1) {
+ createScene(1, 1);
+ }
+ break;
+ case 2:
+ if (_moduleResult == 0) {
+ createScene(3, -1);
+ } else if (_moduleResult == 1) {
+ createScene(1, 1);
+ } else if (_moduleResult == 2) {
+ if (!_soundResource.isPlaying()) {
+ // TODO _soundResource.setVolume(60);
+ _soundResource.play(0x58B45E58);
+ }
+ createScene(2, 2);
+ }
+ break;
+ case 3:
+ createScene(4, 0);
+ break;
+ case 4:
+ leaveModule(1);
+ break;
+ }
+ }
+}
+
+// Scene1705
+
+static const uint32 kScene1705FileHashes[] = {
+ 0x910EA801,
+ 0x920EA801,
+ 0x940EA801,
+ 0x980EA801,
+ 0x800EA801,
+ 0xB00EA801,
+ 0xD00EA801,
+ 0x100EA801,
+ 0x900EA800,
+ 0xD10EA801,
+ 0x110EA801,
+ 0x910EA800
+};
+
+Class602::Class602(NeverhoodEngine *vm, uint32 fileHash, int index)
+ : StaticSprite(vm, fileHash, 100) {
+
+ _x = _spriteResource.getPosition().x + index * 30;
+ _y = _spriteResource.getPosition().y + 160;
+ StaticSprite::update();
+}
+
+Class606::Class606(NeverhoodEngine *vm, Scene *parentScene, int index, int surfacePriority, int16 x, int16 y, uint32 fileHash)
+ : StaticSprite(vm, fileHash, surfacePriority, x - 24, y - 4), _parentScene(parentScene), _index(index) {
+
+ if (!getSubVar(0x02038314, _index) && !getSubVar(0x02720344, _index)) {
+ SetMessageHandler(&Class606::handleMessage);
+ } else {
+ setVisible(false);
+ SetMessageHandler(NULL);
+ }
+ _deltaRect = _drawRect;
+ _deltaRect.x -= 4;
+ _deltaRect.y -= 8;
+ _deltaRect.width += 8;
+ _deltaRect.height += 16;
+ Sprite::processDelta();
+}
+
+uint32 Class606::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x4806:
+ setSubVar(0x02038314, _index, 1);
+ setVisible(false);
+ SetMessageHandler(NULL);
+ break;
+ }
+ return messageResult;
+}
+
+Scene1705::Scene1705(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _paletteArea(1) {
+
+ Sprite *tempSprite;
+
+ setGlobalVar(0xE7498218, 1);
+ // TODO _vm->initVarsScene1705();
+
+ SetMessageHandler(&Scene1705::handleMessage);
+ SetUpdateHandler(&Scene1705::update);
+
+ setHitRects(0x004B69D8);
+
+ _surfaceFlag = true;
+
+ setBackground(0x03118226);
+
+ setPalette(0x03118226);
+ _palette->addBasePalette(0x91D3A391, 0, 64, 0);
+ _palette->copyBasePalette(0, 256, 0);
+ addEntity(_palette);
+
+ insertMouse433(0x18222039);
+
+ insertSprite<Class602>(kScene1705FileHashes[getSubVar(0x0A4C0A9A, 0)], 0);
+ insertSprite<Class602>(kScene1705FileHashes[getSubVar(0x0A4C0A9A, 1)], 1);
+ insertSprite<Class602>(kScene1705FileHashes[getSubVar(0x0A4C0A9A, 2)], 2);
+
+ _sprite = insertStaticSprite(0x31313A22, 1100);
+
+ _class606 = insertSprite<Class606>(this, 15, 1100, 238, 439, 0x02363852);
+ _vm->_collisionMan->addSprite(_class606);
+
+ which = 4;
+
+ if (which < 0) {
+ insertKlayman<KmScene1705>(231, 434);
+ setMessageList(0x004B69E8);
+ sendMessage(this, 0x2000, 0);
+ _klayman->setClipRect(0, 0, _sprite->getDrawRect().x2(), 480);
+ } else if (which == 1) {
+ insertKlayman<KmScene1705>(431, 434);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B6A08, false);
+ sendMessage(this, 0x2000, 1);
+ _klayman->setClipRect(0, 0, _sprite->getDrawRect().x2(), 480);
+ } else if (which == 2) {
+ insertKlayman<KmScene1705>(431, 434);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B6AA0, false);
+ sendMessage(this, 0x2000, 1);
+ _klayman->setClipRect(0, 0, _sprite->getDrawRect().x2(), 480);
+ } else if (which == 3) {
+ insertKlayman<KmScene1705>(431, 434);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B6A18, false);
+ sendMessage(this, 0x2000, 1);
+ _klayman->setClipRect(0, 0, _sprite->getDrawRect().x2(), 480);
+ } else {
+ insertKlayman<KmScene1705>(231, 74);
+ sendMessage(_klayman, 0x2000, 0);
+ setMessageList(0x004B69F0);
+ sendMessage(this, 0x2000, 0);
+ tempSprite = insertStaticSprite(0x30303822, 1100);
+ _klayman->setClipRect(0, tempSprite->getDrawRect().y, _sprite->getDrawRect().x2(), 480);
+ }
+
+}
+
+void Scene1705::update() {
+ Scene::update();
+ if (_klayman->getX() < 224 && _paletteArea != 0) {
+ _palette->addBasePalette(0xF2210C15, 0, 64, 0);
+ _palette->startFadeToPalette(12);
+ _paletteArea = 0;
+ } else if (_klayman->getX() >= 224 && _paletteArea == 0) {
+ _palette->addBasePalette(0x91D3A391, 0, 64, 0);
+ _palette->startFadeToPalette(12);
+ _paletteArea = 1;
+ }
+}
+
+uint32 Scene1705::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ if (param.asInteger()) {
+ setRectList(0x004B6B40);
+ _klayman->setKlaymanTable3();
+ } else {
+ setRectList(0x004B6B30);
+ _klayman->setKlaymanTable1();
+ }
+ break;
+ case 0x4826:
+ if (sender == _class606 && _klayman->getX() <= 318) {
+ sendEntityMessage(_klayman, 0x1014, sender);
+ setMessageList(0x004B6AC0);
+ }
+ break;
+ }
+ return 0;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1700.h b/engines/neverhood/module1700.h
new file mode 100644
index 0000000000..f7388484b2
--- /dev/null
+++ b/engines/neverhood/module1700.h
@@ -0,0 +1,72 @@
+/* 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_MODULE1700_H
+#define NEVERHOOD_MODULE1700_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/smackerscene.h"
+
+namespace Neverhood {
+
+class Module1700 : public Module {
+public:
+ Module1700(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1700();
+protected:
+ SoundResource _soundResource;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene1705
+
+class Class602 : public StaticSprite {
+public:
+ Class602(NeverhoodEngine *vm, uint32 fileHash, int index);
+};
+
+class Class606 : public StaticSprite {
+public:
+ Class606(NeverhoodEngine *vm, Scene *parentScene, int index, int surfacePriority, int16 x, int16 y, uint32 fileHash);
+protected:
+ Scene *_parentScene;
+ int _index;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1705 : public Scene {
+public:
+ Scene1705(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_sprite;
+ Sprite *_class606;
+ int _paletteArea;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1700_H */
diff --git a/engines/neverhood/module1800.cpp b/engines/neverhood/module1800.cpp
new file mode 100644
index 0000000000..cce72b0a11
--- /dev/null
+++ b/engines/neverhood/module1800.cpp
@@ -0,0 +1,170 @@
+/* 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/module1800.h"
+#include "neverhood/navigationscene.h"
+
+namespace Neverhood {
+
+Module1800::Module1800(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ // TODO Sound1ChList_addSoundResources(0x04A14718, dword_4AFE70);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AFE70, 1, 50, 600, 10, 150);
+ // TODO Sound1ChList_sub_407C70(0x04A14718, 0x8A382B55, 0x0C242F1D, 0);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 2) {
+ createScene(5, 0);
+ } else if (which == 3) {
+ createScene(0, 0);
+ } else {
+ createScene(3, 1);
+ }
+
+}
+
+Module1800::~Module1800() {
+ // TODO Sound1ChList_sub_407A50(0x04A14718);
+}
+
+void Module1800::createScene(int sceneNum, int which) {
+ static const byte kNavigationTypes00[] = {1, 0, 2, 0};
+ static const byte kNavigationTypes01[] = {5};
+ debug("Module1800::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ createNavigationScene(0x004AFD38, which, kNavigationTypes00);
+ break;
+ case 1:
+ createNavigationScene(0x004AFD98, which, kNavigationTypes01);
+ break;
+ case 2:
+ createSmackerScene(0x006C0085, true, true, false);
+ break;
+ case 3:
+ createNavigationScene(0x004AFDB0, which);
+ break;
+ case 4:
+ createNavigationScene(0x004AFDE0, which);
+ break;
+ case 5:
+ createNavigationScene(0x004AFE40, which);
+ break;
+ case 6:
+ // TODO Sound1ChList_sub_407A50(0x04A14718);
+ createSmackerScene(0x08D84010, true, true, false);
+ break;
+ case 7:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4AFE70, 0, 0, 0, 0, 0);
+ createSmackerScene(0x0168B121, true, true, false);
+ break;
+ case 8:
+ // TODO _childObject = new CreditsScene(_vm, this, 0);
+ break;
+ case 9:
+ // NOTE: Newly introduced sceneNum 9 (was duplicate 3 with own update handler)
+ createSmackerScene(0x0A840C01, true, true, false);
+ break;
+ }
+ SetUpdateHandler(&Module1800::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1800::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(4, 0);
+ } else if (_moduleResult == 2) {
+ createScene(1, -1);
+ } else if (_moduleResult == 3) {
+ createScene(3, 0);
+ }
+ break;
+ case 1:
+ if (_navigationAreaType == 3) {
+ createScene(7, -1);
+ } else {
+ createScene(2, -1);
+ }
+ break;
+ case 2:
+ createScene(0, 2);
+ break;
+ case 3:
+ if (_moduleResult == 0) {
+ createScene(9, -1);
+ } else if (_moduleResult == 1) {
+ createScene(0, 1);
+ }
+ break;
+ case 4:
+ if (_moduleResult == 0) {
+ createScene(6, -1);
+ } else if (_moduleResult == 1) {
+ createScene(5, 0);
+ } else if (_moduleResult == 2) {
+ createScene(0, 3);
+ } else if (_moduleResult == 3) {
+ createScene(4, 3);
+ }
+ break;
+ case 5:
+ if (_moduleResult == 0) {
+ leaveModule(2);
+ } else if (_moduleResult == 1) {
+ createScene(4, 3);
+ }
+ break;
+ case 6:
+ createScene(8, -1);
+ break;
+ case 7:
+ leaveModule(3);
+ break;
+ case 8:
+ leaveModule(1);
+ // TODO GameState stuff
+ break;
+ case 9:
+ leaveModule(0);
+ break;
+ }
+ } else {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+#if 0 // TODO
+ NavigationScene *navigationScene = (NavigationScene*)_childObject;
+ if (navigationScene->soundFlag1 && navigationScene->index == 2) {
+ // TODO Sound1ChList_sub_4080B0(false);
+ }
+#endif
+ break;
+ }
+ }
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1800.h b/engines/neverhood/module1800.h
new file mode 100644
index 0000000000..8ec8dfecea
--- /dev/null
+++ b/engines/neverhood/module1800.h
@@ -0,0 +1,45 @@
+/* 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_MODULE1800_H
+#define NEVERHOOD_MODULE1800_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module1800
+
+class Module1800 : public Module {
+public:
+ Module1800(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1800();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1800_H */
diff --git a/engines/neverhood/module1900.cpp b/engines/neverhood/module1900.cpp
new file mode 100644
index 0000000000..7bac3ffc96
--- /dev/null
+++ b/engines/neverhood/module1900.cpp
@@ -0,0 +1,691 @@
+/* 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/module1900.h"
+#include "neverhood/gamemodule.h"
+
+namespace Neverhood {
+
+Module1900::Module1900(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ // NOTE: The original has a Scene1908 here as well but it's not used here but in another module...
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else {
+ createScene(0, 0);
+ }
+
+ // TODO Sound1ChList_addSoundResources(0x04E1C09C, dword_4B8800, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B8800, true, 50, 600, 5, 150);
+
+}
+
+Module1900::~Module1900() {
+ // TODO Sound1ChList_sub_407A50(0x04E1C09C);
+}
+
+void Module1900::createScene(int sceneNum, int which) {
+ debug("Module1900::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _childObject = new Scene1901(_vm, this, which);
+ break;
+ case 6:
+ _childObject = new Scene1907(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module1900::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module1900::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(6, 0);
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 6:
+ createScene(0, 1);
+ break;
+ }
+ }
+}
+
+// Scene1901
+
+Scene1901::Scene1901(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ Sprite *tempSprite;
+
+ _surfaceFlag = true;
+
+ setRectList(0x004B34C8);
+
+ setBackground(0x01303227);
+ setPalette(0x01303227);
+ insertMouse433(0x0322301B);
+
+ insertStaticSprite(0x42213133, 1100);
+
+ if (!getGlobalVar(0xA9035F60)) {
+ insertStaticSprite(0x40A40168, 100);
+ } else if (getGlobalVar(0x09221A62)) {
+ insertStaticSprite(0x124404C4, 100);
+ setGlobalVar(0x2050861A, 1);
+ } else {
+ insertStaticSprite(0x02840064, 100);
+ }
+
+ if (which < 0) {
+ insertKlayman<KmScene1901>(120, 380);
+ setMessageList(0x004B3408);
+ } else if (which == 1) {
+ insertKlayman<KmScene1901>(372, 380);
+ setMessageList(0x004B3410);
+ } else {
+ insertKlayman<KmScene1901>(0, 380);
+ setMessageList(0x004B3400);
+ }
+
+ tempSprite = insertStaticSprite(0x4830A402, 1100);
+ _klayman->setClipRect(tempSprite->getDrawRect().x, 0, 640, 480);
+
+}
+
+static const NPoint kAsScene1907SymbolGroundPositions[] = {
+ {160, 310},
+ { 90, 340},
+ {210, 335},
+ {210, 380},
+ {310, 340},
+ {290, 400},
+ {400, 375},
+ {370, 435},
+ {475, 415}
+};
+
+static const NPoint kAsScene1907SymbolPluggedInPositions[] = {
+ {275, 125},
+ {244, 125},
+ {238, 131},
+ {221, 135},
+ {199, 136},
+ {168, 149},
+ {145, 152},
+ {123, 154},
+ {103, 157}
+};
+
+static const NPoint kAsScene1907SymbolGroundHitPositions[] = {
+ {275, 299},
+ {244, 299},
+ {238, 305},
+ {221, 309},
+ {199, 310},
+ {168, 323},
+ {145, 326},
+ {123, 328},
+ {103, 331}
+};
+
+static const NPoint kAsScene1907SymbolPluggedInDownPositions[] = {
+ {275, 136},
+ {244, 156},
+ {238, 183},
+ {221, 207},
+ {199, 228},
+ {168, 262},
+ {145, 285},
+ {123, 307},
+ {103, 331}
+};
+
+static const uint32 kAsScene1907SymbolFileHashes[] = {
+ 0x006A1034,
+ 0x006A1010,
+ 0x006A1814,
+ 0x006A1016,
+ 0x006A0014,
+ 0x002A1014,
+ 0x00EA1014,
+ 0x206A1014,
+ 0x046A1414
+};
+
+int AsScene1907Symbol::_symbolFlag1 = 0;
+int AsScene1907Symbol::_symbolFlag2 = 0;
+
+AsScene1907Symbol::AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene, int elementIndex, int positionIndex)
+ : AnimatedSprite(vm, 1000 - positionIndex), _soundResource1(vm), _soundResource2(vm), _soundResource3(vm),
+ _parentScene(parentScene), _elementIndex(elementIndex), _isMoving(false) {
+
+ _symbolFlag1 = 0;
+ _symbolFlag2 = 0;
+
+ if (getGlobalVar(0xA9035F60)) {
+ _isPluggedIn = true;
+ _currPositionIndex = elementIndex;
+ if (!getGlobalVar(0x09221A62)) {
+ _x = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].x;
+ _y = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].y;
+ } else {
+ _x = kAsScene1907SymbolPluggedInDownPositions[_currPositionIndex].x;
+ _y = kAsScene1907SymbolPluggedInDownPositions[_currPositionIndex].y;
+ }
+ createSurface1(kAsScene1907SymbolFileHashes[_elementIndex], 1000 + _currPositionIndex);
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1);
+ _newHashListIndex = -2;
+ } else {
+ _isPluggedIn = false;
+ _currPositionIndex = positionIndex;
+ _soundResource1.load(0x74231924);
+ _soundResource2.load(0x36691914);
+ _soundResource3.load(0x5421D806);
+ _parentScene->setPositionFree(_currPositionIndex, false);
+ _x = kAsScene1907SymbolGroundPositions[_currPositionIndex].x;
+ _y = kAsScene1907SymbolGroundPositions[_currPositionIndex].y;
+ createSurface1(kAsScene1907SymbolFileHashes[_elementIndex], 1000 + _currPositionIndex);
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1);
+ _newHashListIndex = 0;
+ }
+ _deltaRect.set(0, 0, 80, 80);
+ Sprite::processDelta();
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1907Symbol::handleMessage);
+
+}
+
+void AsScene1907Symbol::update() {
+ AnimatedSprite::updateAnim();
+ handleSpriteUpdate();
+ AnimatedSprite::updatePosition();
+ if (_symbolFlag1 && !_symbolFlag2)
+ _symbolFlag1 = 0;
+}
+
+uint32 AsScene1907Symbol::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (!_isPluggedIn && !_symbolFlag1) {
+ tryToPlugIn();
+ messageResult = 1;
+ } else {
+ messageResult = 0;
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 AsScene1907Symbol::hmTryToPlugIn(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1907Symbol::suTryToPlugIn() {
+ _currStep++;
+ _x -= _deltaX;
+ _y -= _deltaY;
+ if (_currStep == 16) {
+ _x -= _smallDeltaX;
+ _y -= _smallDeltaY;
+ SetSpriteCallback(NULL);
+ }
+}
+
+void AsScene1907Symbol::suFallOff() {
+ if (_fallOffDelay != 0) {
+ _fallOffDelay--;
+ } else {
+ _y += _yAccel;
+ _yAccel += 8;
+ if (_y >= kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y) {
+ _y = kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y;
+ stFallOffHitGround();
+ }
+ }
+}
+
+void AsScene1907Symbol::suFallOffHitGround() {
+
+ if (_x == _someX - _xBreak)
+ _x -= _smallDeltaX;
+ else
+ _x -= _deltaX;
+
+ if (_y == kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y) {
+ _y -= _someY;
+ }
+
+ if (_currStep < 8) {
+ _y -= _yAccel;
+ _yAccel -= 4;
+ if (_yAccel < 0)
+ _yAccel = 0;
+ } else if (_currStep < 15) {
+ _y += _yAccel;
+ _yAccel += 4;
+ } else {
+ _y = kAsScene1907SymbolGroundPositions[_newPositionIndex].y;
+ cbFallOffHitGroundEvent();
+ }
+
+ _currStep++;
+}
+
+void AsScene1907Symbol::suMoveDown() {
+ _y += _yIncr;
+ if (_yIncr < 11)
+ _yIncr++;
+ if (_y >= kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y) {
+ _y = kAsScene1907SymbolPluggedInDownPositions[_elementIndex].y;
+ _isMoving = false;
+ SetSpriteCallback(NULL);
+ }
+}
+
+void AsScene1907Symbol::suMoveUp() {
+ _y -= _yIncr;
+ if (getGlobalVar(0x10938830)) {
+ if (_y - (9 + (_elementIndex > 5 ? 31 : 0)) < kAsScene1907SymbolPluggedInPositions[_elementIndex].y) {
+ _yIncr--;
+ } else {
+ _yIncr++;
+ }
+ } else {
+ _yIncr = 2;
+ }
+ if (_yIncr > 9)
+ _yIncr = 9;
+ else if (_yIncr < 1)
+ _yIncr = 1;
+ if (_y < kAsScene1907SymbolPluggedInPositions[_elementIndex].y) {
+ _y = kAsScene1907SymbolPluggedInPositions[_elementIndex].y;
+ _isMoving = false;
+ SetSpriteCallback(NULL);
+ }
+}
+
+void AsScene1907Symbol::tryToPlugIn() {
+ _isPluggedIn = true;
+ _symbolFlag2++;
+ _newPositionIndex = _parentScene->getNextPosition();
+ _parentScene->setPositionFree(_currPositionIndex, true);
+ sendMessage(_parentScene, 0x1022, 1100 + _newPositionIndex);
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1);
+ SetUpdateHandler(&AsScene1907Symbol::update);
+ SetMessageHandler(&AsScene1907Symbol::hmTryToPlugIn);
+ SetSpriteCallback(&AsScene1907Symbol::suTryToPlugIn);
+ _currStep = 0;
+ _deltaX = (_x - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].x) / 16;
+ _smallDeltaX = _x - _deltaX * 16 - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].x;
+ _deltaY = (_y - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].y) / 16;
+ _smallDeltaY = _y - _deltaY * 16 - kAsScene1907SymbolPluggedInPositions[_newPositionIndex].y;
+ if (_elementIndex == _newPositionIndex) {
+ NextState(&AsScene1907Symbol::stPlugIn);
+ } else {
+ _symbolFlag1 = 1;
+ NextState(&AsScene1907Symbol::stPlugInFail);
+ }
+}
+
+void AsScene1907Symbol::fallOff(int newPositionIndex, int fallOffDelay) {
+ _isPluggedIn = false;
+ _newPositionIndex = newPositionIndex;
+ _fallOffDelay = fallOffDelay;
+ _parentScene->setPositionFree(_newPositionIndex, false);
+ _x = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].x;
+ _y = kAsScene1907SymbolPluggedInPositions[_currPositionIndex].y;
+ _someX = _x;
+ _someY = _y;
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], -1, 0);
+ _playBackwards = true;
+ _newHashListIndex = -2;
+ _currStep = 0;
+ _yAccel = 1;
+ SetUpdateHandler(&AsScene1907Symbol::update);
+ SetMessageHandler(&AsScene1907Symbol::handleMessage);
+ SetSpriteCallback(&AsScene1907Symbol::suFallOff);
+}
+
+void AsScene1907Symbol::stFallOffHitGround() {
+ _soundResource2.play();
+ sendMessage(_parentScene, 0x1022, 1000 + _newPositionIndex);
+ // TODO: Meh...
+ Entity::_priority = 1000 - _newPositionIndex;
+ _vm->_collisionMan->removeSprite(this);
+ _vm->_collisionMan->addSprite(this);
+ SetSpriteCallback(&AsScene1907Symbol::suFallOffHitGround);
+ NextState(&AsScene1907Symbol::cbFallOffHitGroundEvent);
+ _newHashListIndex = 0;
+ _currStep = 0;
+ _yAccel = 30;
+ _deltaX = (_x - kAsScene1907SymbolGroundPositions[_newPositionIndex].x) / 15;
+ _xBreak = _deltaX * 15;
+ _smallDeltaX = _x - kAsScene1907SymbolGroundPositions[_newPositionIndex].x - _xBreak;
+ _someY = 0;
+ if (kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y > kAsScene1907SymbolGroundPositions[_newPositionIndex].y)
+ _someY = kAsScene1907SymbolGroundHitPositions[_currPositionIndex].y - kAsScene1907SymbolGroundPositions[_newPositionIndex].y;
+}
+
+void AsScene1907Symbol::cbFallOffHitGroundEvent() {
+ _currPositionIndex = _newPositionIndex;
+ if (_symbolFlag2)
+ _symbolFlag2--;
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], 0, -1);
+ _newHashListIndex = 0;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene1907Symbol::handleMessage);
+ SetSpriteCallback(NULL);
+ processDelta();
+ _soundResource3.play();
+}
+
+void AsScene1907Symbol::stPlugIn() {
+ _soundResource1.play();
+ _currPositionIndex = _newPositionIndex;
+ stopAnimation();
+ SetMessageHandler(&AsScene1907Symbol::handleMessage);
+ SetSpriteCallback(NULL);
+ if (_elementIndex == 8)
+ sendMessage(_parentScene, 0x2001, 0);
+}
+
+void AsScene1907Symbol::stPlugInFail() {
+ _currPositionIndex = _newPositionIndex;
+ stopAnimation();
+ _parentScene->plugInFailed();
+}
+
+void AsScene1907Symbol::moveUp() {
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1);//????
+ stopAnimation();
+ SetMessageHandler(&AsScene1907Symbol::handleMessage);
+ SetSpriteCallback(&AsScene1907Symbol::suMoveUp);
+ _yIncr = 1;
+ _isMoving = true;
+}
+
+void AsScene1907Symbol::moveDown() {
+ setFileHash(kAsScene1907SymbolFileHashes[_elementIndex], -1, -1);//????
+ stopAnimation();
+ SetMessageHandler(&AsScene1907Symbol::handleMessage);
+ SetSpriteCallback(&AsScene1907Symbol::suMoveDown);
+ _yIncr = 4;
+ _isMoving = true;
+}
+
+SsScene1907UpDownButton::SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *AsScene1907Symbol)
+ : StaticSprite(vm, 1400), _soundResource(vm), _parentScene(parentScene), _AsScene1907Symbol(AsScene1907Symbol),
+ _countdown1(0) {
+
+ _spriteResource.load2(0x64516424);
+ createSurface(1400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ setVisible(false);
+ _drawRect.set(0, 0, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _deltaRect = _drawRect;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ processDelta();
+ _needRefresh = true;
+ _soundResource.load(0x44061000);
+ SetUpdateHandler(&SsScene1907UpDownButton::update);
+ SetMessageHandler(&SsScene1907UpDownButton::handleMessage);
+ if (getGlobalVar(0xA9035F60)) {
+ if (getGlobalVar(0x09221A62))
+ setToDownPosition();
+ else
+ setToUpPosition();
+ }
+}
+
+void SsScene1907UpDownButton::update() {
+ StaticSprite::update();
+ if (_countdown1 != 0 && (--_countdown1 == 0)) {
+ setVisible(false);
+ sendMessage(_parentScene, 0x2000, 0);
+ }
+}
+
+uint32 SsScene1907UpDownButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_countdown1 == 0 && !_AsScene1907Symbol->isMoving() && getGlobalVar(0xA9035F60)) {
+ setVisible(true);
+ _countdown1 = 4;
+ StaticSprite::update();
+ _soundResource.play();
+ }
+ messageResult = 1;
+ }
+ return messageResult;
+}
+
+void SsScene1907UpDownButton::setToUpPosition() {
+ _y = _spriteResource.getPosition().y;
+ Sprite::processDelta();
+ StaticSprite::update();
+}
+
+void SsScene1907UpDownButton::setToDownPosition() {
+ _y = _spriteResource.getPosition().y + 174;
+ Sprite::processDelta();
+ StaticSprite::update();
+}
+
+AsScene1907WaterHint::AsScene1907WaterHint(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1400) {
+
+ createSurface1(0x110A1061, 1500);
+ _x = 320;
+ _y = 240;
+ setFileHash(0x110A1061, 0, -1);
+ _newHashListIndex = 0;
+ setVisible(false);
+ _needRefresh = true;
+ AnimatedSprite::updatePosition();
+ SetUpdateHandler(&AsScene1907WaterHint::update);
+ SetMessageHandler(&Sprite::handleMessage);
+}
+
+void AsScene1907WaterHint::update() {
+ AnimatedSprite::updateAnim();
+ AnimatedSprite::updatePosition();
+}
+
+uint32 AsScene1907WaterHint::handleMessage46BA20(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene1907WaterHint::show() {
+ setVisible(true);
+ setFileHash(0x110A1061, 0, -1);
+ SetMessageHandler(&AsScene1907WaterHint::handleMessage46BA20);
+ NextState(&AsScene1907WaterHint::hide);
+}
+
+void AsScene1907WaterHint::hide() {
+ stopAnimation();
+ setVisible(false);
+ SetMessageHandler(&Sprite::handleMessage);
+}
+
+Scene1907::Scene1907(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource1(vm), _soundResource2(vm),
+ _soundResource3(vm), _soundResource4(vm), _currMovingSymbolIndex(0), _pluggedInCount(0),
+ _moveDownCountdown(0), _moveUpCountdown(0), _countdown3(0), _hasPlugInFailed(false) {
+
+ _surfaceFlag = true;
+
+ //setGlobalVar(0x10938830, 1);
+
+ setBackground(0x20628E05);
+ setPalette(0x20628E05);
+
+ for (int i = 0; i < 9; i++)
+ _positionFree[i] = true;
+
+ for (int i = 0; i < 9; i++) {
+ _asSymbols[i] = insertSprite<AsScene1907Symbol>(this, i, getRandomPositionIndex());
+ _vm->_collisionMan->addSprite(_asSymbols[i]);
+ }
+
+ _ssUpDownButton = insertSprite<SsScene1907UpDownButton>(this, _asSymbols[8]);
+ _vm->_collisionMan->addSprite(_ssUpDownButton);
+
+ _asWaterHint = insertSprite<AsScene1907WaterHint>();
+
+ insertMouse435(0x28E0120E, 20, 620);
+
+ SetMessageHandler(&Scene1907::handleMessage);
+ SetUpdateHandler(&Scene1907::update);
+
+ if (getGlobalVar(0xA9035F60))
+ _pluggedInCount = 9;
+
+ _soundResource1.load(0x72004A10);
+ _soundResource2.load(0x22082A12);
+ _soundResource3.load(0x21100A10);
+ _soundResource4.load(0x68E25540);
+
+}
+
+void Scene1907::update() {
+ Scene::update();
+
+ if (_hasPlugInFailed) {
+ int fallOffDelay = 0;
+ _hasPlugInFailed = false;
+ for (int i = 0; i < 9; i++) {
+ AsScene1907Symbol *asSymbol = _asSymbols[8 - i];
+ if (asSymbol->isPluggedIn()) {
+ asSymbol->fallOff(getRandomPositionIndex(), fallOffDelay);
+ fallOffDelay += _vm->_rnd->getRandomNumber(10 - 1) + 4;
+ }
+ }
+ }
+
+ if (_moveDownCountdown != 0 && (--_moveDownCountdown == 0)) {
+ _asSymbols[_currMovingSymbolIndex]->moveDown();
+ if (_currMovingSymbolIndex > 0) {
+ _moveDownCountdown = 2;
+ _currMovingSymbolIndex--;
+ }
+ }
+
+ if (_moveUpCountdown != 0 && (--_moveUpCountdown == 0)) {
+ _moveDownCountdown = 0;
+ for (int i = 0; i < 9; i++)
+ _asSymbols[i]->moveUp();
+ }
+
+ if (_countdown3 != 0 && (--_countdown3 == 0)) {
+ _asWaterHint->show();
+ _moveUpCountdown = 4;
+ }
+
+}
+
+uint32 Scene1907::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO DEBUG stuff
+ if ((param.asPoint().x <= 20 || param.asPoint().x >= 620) &&
+ !_hasPlugInFailed && _moveDownCountdown == 0 && _moveUpCountdown == 0 && _countdown3 == 0) {
+ leaveScene(0);
+ }
+ break;
+ // TODO Debug stuff
+ case 0x2000:
+ if (getGlobalVar(0x09221A62)) {
+ _soundResource1.play();
+ for (int i = 0; i < 9; i++)
+ _asSymbols[i]->moveUp();
+ _ssUpDownButton->setToUpPosition();
+ setGlobalVar(0x09221A62, 0);
+ } else {
+ if (!getGlobalVar(0x10938830)) {
+ _soundResource3.play();
+ _countdown3 = 5;
+ } else {
+ _soundResource2.play();
+ _ssUpDownButton->setToDownPosition();
+ setGlobalVar(0x09221A62, 1);
+ }
+ _moveDownCountdown = 1;
+ _currMovingSymbolIndex = 8;
+ }
+ break;
+ case 0x2001:
+ _soundResource4.play();
+ setGlobalVar(0xA9035F60, 1);
+ break;
+ }
+ return 0;
+}
+
+void Scene1907::plugInFailed() {
+ _pluggedInCount = 0;
+ _hasPlugInFailed = true;
+}
+
+int Scene1907::getRandomPositionIndex() {
+ bool flag = false;
+ int index = 0;
+ for (int i = 0; i < 9; i++) {
+ if (_positionFree[i])
+ flag = true;
+ }
+ if (flag) {
+ flag = false;
+ while (!flag) {
+ index = _vm->_rnd->getRandomNumber(9 - 1);
+ if (_positionFree[index])
+ flag = true;
+ }
+ }
+ return index;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module1900.h b/engines/neverhood/module1900.h
new file mode 100644
index 0000000000..7b41c5780b
--- /dev/null
+++ b/engines/neverhood/module1900.h
@@ -0,0 +1,150 @@
+/* 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_MODULE1900_H
+#define NEVERHOOD_MODULE1900_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module1200.h"
+
+namespace Neverhood {
+
+class Module1900 : public Module {
+public:
+ Module1900(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module1900();
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene1901
+
+class Scene1901 : public Scene {
+public:
+ Scene1901(NeverhoodEngine *vm, Module *parentModule, int which);
+};
+
+// Scene1907
+
+class Scene1907;
+
+class AsScene1907Symbol : public AnimatedSprite {
+public:
+ AsScene1907Symbol(NeverhoodEngine *vm, Scene1907 *parentScene, int elementIndex, int positionIndex);
+ void moveUp();
+ void moveDown();
+ void fallOff(int newPositionIndex, int fallOffDelay);
+ bool isPluggedIn() { return _isPluggedIn; }
+ bool isMoving() { return _isMoving; }
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ Scene1907 *_parentScene;
+ int _elementIndex;
+ int _currPositionIndex;
+ int _newPositionIndex;
+ bool _isPluggedIn;
+ bool _isMoving;
+ int _someX, _someY;
+ int _xBreak;
+ int _currStep;
+ int _yAccel;
+ int _yIncr;
+ int _fallOffDelay;
+ int _deltaX, _smallDeltaX;
+ int _deltaY, _smallDeltaY;
+ // Dumb, change if possible
+ static int _symbolFlag1;
+ static int _symbolFlag2;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 hmTryToPlugIn(int messageNum, const MessageParam &param, Entity *sender);
+ void suTryToPlugIn();
+ void suFallOff();
+ void suFallOffHitGround();
+ void suMoveDown();
+ void suMoveUp();
+ void tryToPlugIn();
+ void stFallOffHitGround();
+ void cbFallOffHitGroundEvent();
+ void stPlugIn();
+ void stPlugInFail();
+};
+
+class AsScene1907WaterHint : public AnimatedSprite {
+public:
+ AsScene1907WaterHint(NeverhoodEngine *vm);
+ void show();
+protected:
+ void update();
+ uint32 handleMessage46BA20(int messageNum, const MessageParam &param, Entity *sender);
+ void hide();
+};
+
+class SsScene1907UpDownButton : public StaticSprite {
+public:
+ SsScene1907UpDownButton(NeverhoodEngine *vm, Scene1907 *parentScene, AsScene1907Symbol *AsScene1907Symbol);
+ void setToUpPosition();
+ void setToDownPosition();
+protected:
+ SoundResource _soundResource;
+ Scene1907 *_parentScene;
+ AsScene1907Symbol *_AsScene1907Symbol;
+ int _countdown1;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene1907 : public Scene {
+public:
+ Scene1907(NeverhoodEngine *vm, Module *parentModule, int which);
+ void plugInFailed();
+ void setPositionFree(int index, bool value) { _positionFree[index] = value; }
+ int getNextPosition() { return _pluggedInCount++; }
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ SoundResource _soundResource4;
+ AsScene1907Symbol *_asSymbols[9];
+ SsScene1907UpDownButton *_ssUpDownButton;
+ AsScene1907WaterHint *_asWaterHint;
+ int _currMovingSymbolIndex;
+ int _pluggedInCount;
+ int _moveDownCountdown;
+ int _moveUpCountdown;
+ int _countdown3;
+ bool _hasPlugInFailed;
+ bool _positionFree[9];
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ int getRandomPositionIndex();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE1900_H */
diff --git a/engines/neverhood/module2000.cpp b/engines/neverhood/module2000.cpp
new file mode 100644
index 0000000000..9c0843c3e1
--- /dev/null
+++ b/engines/neverhood/module2000.cpp
@@ -0,0 +1,155 @@
+/* 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/module2000.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/navigationscene.h"
+
+namespace Neverhood {
+
+Module2000::Module2000(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 0) {
+ createScene(0, 3);
+ } else if (which == 1) {
+ createScene(0, 1);
+ }
+
+}
+
+Module2000::~Module2000() {
+ // TODO Sound1ChList_sub_407A50(0x81293110);
+}
+
+void Module2000::createScene(int sceneNum, int which) {
+ debug("Module2000::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _childObject = new Scene2001(_vm, this, which);
+ break;
+ case 1:
+ createNavigationScene(getGlobalVar(0x98109F12) ? 0x004B7B48 : 0x004B7B00, which);
+ break;
+ case 2:
+ setGlobalVar(0x98109F12, 1);
+ setSubVar(0x2C145A98, 1, 1);
+ createSmackerScene(0x204B2031, true, true, false);
+ break;
+ }
+ SetUpdateHandler(&Module2000::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module2000::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ leaveModule(0);
+ } else {
+ createScene(1, 0);
+ }
+ break;
+ case 1:
+ if (_moduleResult == 0) {
+ if (getGlobalVar(0x98109F12)) {
+ createScene(1, 0);
+ } else {
+ createScene(2, -1);
+ }
+ } else if (_moduleResult == 1) {
+ createScene(1, 1);
+ } else if (_moduleResult == 2) {
+ createScene(0, 0);
+ }
+ break;
+ case 2:
+ createScene(1, 0);
+ break;
+ }
+ }
+}
+
+// Scene2001
+
+Scene2001::Scene2001(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2001::handleMessage);
+
+ setBackground(0xA6417244);
+ setPalette(0xA6417244);
+ insertMouse433(0x17240A6C);
+
+ _class401 = insertStaticSprite(0x0D641724, 1100);
+
+ if (which < 0) {
+ insertKlayman<KmScene2001>(300, 345);
+ setMessageList(0x004B3538);
+ sendMessage(this, 0x2000, 0);
+ } else if (which == 1) {
+ insertKlayman<KmScene2001>(116, 345);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B3540, false);
+ sendMessage(this, 0x2000, 1);
+ } else if (which == 2) {
+ insertKlayman<KmScene2001>(116, 345);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B35F0, false);
+ sendMessage(this, 0x2000, 1);
+ } else if (which == 3) {
+ insertKlayman<KmScene2001>(116, 345);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B3550, false);
+ sendMessage(this, 0x2000, 1);
+ } else {
+ insertKlayman<KmScene2001>(390, 345);
+ setMessageList(0x004B3530);
+ sendMessage(this, 0x2000, 0);
+ _klayman->setDoDeltaX(1);
+ }
+
+ _klayman->setClipRect(_class401->getDrawRect().x, 0, 640, 480);
+
+}
+
+uint32 Scene2001::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ if (param.asInteger()) {
+ setRectList(0x004B3680);
+ _klayman->setKlaymanTable3();
+ } else {
+ setRectList(0x004B3670);
+ _klayman->setKlaymanTable1();
+ }
+ }
+ return 0;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2000.h b/engines/neverhood/module2000.h
new file mode 100644
index 0000000000..8e741b357e
--- /dev/null
+++ b/engines/neverhood/module2000.h
@@ -0,0 +1,55 @@
+/* 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_MODULE2000_H
+#define NEVERHOOD_MODULE2000_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module1200.h"
+
+namespace Neverhood {
+
+class Module2000 : public Module {
+public:
+ Module2000(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2000();
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene2001
+
+class Scene2001 : public Scene {
+public:
+ Scene2001(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_class401;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2000_H */
diff --git a/engines/neverhood/module2100.cpp b/engines/neverhood/module2100.cpp
new file mode 100644
index 0000000000..66f8631b8a
--- /dev/null
+++ b/engines/neverhood/module2100.cpp
@@ -0,0 +1,341 @@
+/* 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/module2100.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/module1200.h"
+
+namespace Neverhood {
+
+Module2100::Module2100(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ // TODO Music18hList_add(0x10A10C14, 0x11482B95);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 1) {
+ createScene(0, 0);
+ } else if (which == 2) {
+ createScene(0, 3);
+ } else {
+ createScene(0, 1);
+ }
+
+}
+
+Module2100::~Module2100() {
+ // TODO Music18hList_deleteGroup(0x10A10C14);
+}
+
+void Module2100::createScene(int sceneNum, int which) {
+ debug("Module2100::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ // TODO Music18hList_play(0x11482B95, 0, 1, 1);
+ _childObject = new Scene2101(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module2100::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module2100::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ setGlobalVar(0x2090590C, 1);
+ leaveModule(0);
+ } else {
+ leaveModule(1);
+ }
+ break;
+ }
+ }
+}
+
+// Scene2101
+
+Class538::Class538(NeverhoodEngine *vm, bool flag)
+ : AnimatedSprite(vm, 1100), _soundResource(vm) {
+
+ // TODO createSurface3(100, dword_4B9018);
+ createSurface(100, 640, 480); //TODO: Remove once the line above is done
+ _x = 320;
+ _y = 240;
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class538::handleMessage);
+ if (flag) {
+ setFileHash(0x0C202B9C, -1, -1);
+ _newHashListIndex = -2;
+ } else {
+ setVisible(false);
+ }
+}
+
+uint32 Class538::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ openDoor();
+ break;
+ case 0x4809:
+ closeDoor();
+ break;
+ }
+ return messageResult;
+}
+
+void Class538::openDoor() {
+ setFileHash(0x0C202B9C, 0, -1);
+ _newHashListIndex = -2;
+ setVisible(true);
+ _soundResource.play(calcHash("fxDoorOpen32"));
+}
+
+void Class538::closeDoor() {
+ setFileHash(0xC222A8D4, 0, -1);
+ _newHashListIndex = -2;
+ setVisible(true);
+ NextState(&Class538::hide);
+ _soundResource.play(calcHash("fxDoorClose32"));
+}
+
+void Class538::hide() {
+ stopAnimation();
+ setVisible(false);
+}
+
+Class539::Class539(NeverhoodEngine *vm, Sprite *klayman)
+ : AnimatedSprite(vm, 1400), _klayman(klayman) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&Class539::handleMessage);
+ createSurface(1200, 88, 165);
+ setVisible(false);
+}
+
+uint32 Class539::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2001:
+ _x = _klayman->getX();
+ _y = _klayman->getY() - 132;
+ setFileHash(0x0422255A, 0, -1);
+ setVisible(true);
+ break;
+ case 0x3002:
+ stopAnimation();
+ setVisible(false);
+ break;
+ }
+ return messageResult;
+}
+
+Class427::Class427(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash)
+ : StaticSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene), _countdown(0),
+ _fileHash1(fileHash1), _fileHash2(fileHash2), _soundFileHash(soundFileHash) {
+
+ SetUpdateHandler(&Class427::update);
+ SetMessageHandler(&Class427::handleMessage);
+ if (_soundFileHash == 0)
+ _soundFileHash = 0x44141000;
+ createSurface(1010, 61, 30);
+ if (_fileHash1) {
+ load(_fileHash1, true, true);
+ StaticSprite::update();
+ } else
+ setVisible(false);
+}
+
+void Class427::update() {
+ if (_countdown != 0 && (--_countdown == 0)) {
+ sendMessage(_parentScene, 0x1022, 1010);
+ if (_fileHash1) {
+ load(_fileHash1, true, true);
+ StaticSprite::update();
+ } else
+ setVisible(false);
+ }
+}
+
+uint32 Class427::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x480B:
+ sendMessage(_parentScene, 0x480B, 0);
+ setVisible(true);
+ sendMessage(_parentScene, 0x1022, 990);
+ load(_fileHash2, true, true);
+ StaticSprite::update();
+ _countdown = 16;
+ _soundResource.play(_soundFileHash);
+ break;
+ }
+ return messageResult;
+}
+
+Scene2101::Scene2101(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2101::handleMessage);
+ SetUpdateHandler(&Scene2101::update);
+
+ setBackground(0x44242305);
+ setPalette(0x44242305);
+ insertMouse433(0x4230144A);
+
+ insertStaticSprite(0x00502330, 1100);
+ _sprite1 = insertStaticSprite(0x78492010, 1100);
+ _class427 = insertSprite<Class427>(this, 0x72427010, 0x32423010, 200, 0);
+ _asTape1 = insertSprite<AsScene1201Tape>(this, 18, 1100, 412, 443, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape1);
+ _asTape2 = insertSprite<AsScene1201Tape>(this, 11, 1100, 441, 443, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape2);
+
+ if (which < 0) {
+ insertKlayman<KmScene2101>(380, 438);
+ setMessageList(0x004B8E48);
+ sendMessage(this, 0x2000, 0);
+ _class538 = insertSprite<Class538>(false);
+ _value1 = 1;
+ _countdown1 = 0;
+ } else if (which == 1) {
+ insertKlayman<KmScene2101>(640, 438);
+ setMessageList(0x004B8E50);
+ sendMessage(this, 0x2000, 0);
+ _class538 = insertSprite<Class538>(true);
+ _value1 = 2;
+ _countdown1 = 48;
+ } else if (which == 2) {
+ insertKlayman<KmScene2101>(115, 438);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B8F58);
+ sendMessage(this, 0x2000, 1);
+ _class538 = insertSprite<Class538>(false);
+ _value1 = 1;
+ _countdown1 = 0;
+ } else if (which == 3) {
+ insertKlayman<KmScene2101>(115, 438);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B8EB0);
+ sendMessage(this, 0x2000, 1);
+ _class538 = insertSprite<Class538>(false);
+ _value1 = 1;
+ _countdown1 = 0;
+ } else {
+ insertKlayman<KmScene2101>(115, 438);
+ sendMessage(_klayman, 0x2000, 1);
+ setMessageList(0x004B8EA0);
+ sendMessage(this, 0x2000, 1);
+ _class538 = insertSprite<Class538>(false);
+ _value1 = 1;
+ _countdown1 = 0;
+ }
+
+ _class539 = insertSprite<Class539>(_klayman);
+ _klayman->setClipRect(0, 0, _sprite1->getDrawRect().x2(), 480);
+
+}
+
+void Scene2101::update() {
+ if (_countdown1 != 0) {
+ if (_value1 == 2) {
+ if (--_countdown1 == 0) {
+ sendMessage(_class538, 0x4809, 0);
+ _value1 = 1;
+ }
+ } else {
+ if (_klayman->getX() > 575)
+ _messageListFlag = false;
+ if (--_countdown1 == 0) {
+ if (_klayman->getX() < 480) {
+ sendMessage(_class538, 0x4809, 0);
+ _value1 = 1;
+ } else if (_klayman->getX() >= 480 && _klayman->getX() <= 575) {
+ _klayman->setDoDeltaX(0);
+ setMessageList2(0x004B8F48);
+ sendMessage(_class538, 0x4809, 0);
+ sendMessage(_class539, 0x2001, 0);
+ _value1 = 1;
+ }
+ }
+ }
+ } else if (_value1 == 1 && _messageValue >= 0 && _klayman->getX() > 470 /* TODO ! && _messageList2 != 0x004B8F48*/) {
+ setMessageList2(0x004B8F50);
+ }
+ Scene::update();
+}
+
+uint32 Scene2101::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x02144CB1) {
+ sendEntityMessage(_klayman, 0x1014, _class427);
+ } else if (param.asInteger() == 0x21E64A00) {
+ if (_value1 == 0) {
+ setMessageList(0x004B8E80);
+ } else {
+ setMessageList(0x004B8EC8);
+ }
+ } else if (param.asInteger() == 0x41442820) {
+ messageList402220();
+ }
+ break;
+ case 0x2000:
+ if (param.asInteger() != 0) {
+ setRectList(0x004B9008);
+ _klayman->setKlaymanTable3();
+ } else {
+ setRectList(0x004B8FF8);
+ _klayman->setKlaymanTable1();
+ }
+ break;
+ case 0x480B:
+ if (sender == _class427 && _value1 == 1) {
+ sendMessage(_class538, 0x4808, 0);
+ _value1 = 0;
+ _countdown1 = 90;
+ }
+ break;
+ case 0x4826:
+ if (sender == _asTape1 || sender == _asTape2) {
+ if (_klayman->getX() >= 228 && _klayman->getX() <= 500) {
+ sendEntityMessage(_klayman, 0x1014, sender);
+ setMessageList(0x004B8F78);
+ } else if (_klayman->getX() < 228) {
+ setMessageList2(0x004B8F00);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2100.h b/engines/neverhood/module2100.h
new file mode 100644
index 0000000000..65846d7ded
--- /dev/null
+++ b/engines/neverhood/module2100.h
@@ -0,0 +1,95 @@
+/* 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_MODULE2100_H
+#define NEVERHOOD_MODULE2100_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+class Module2100 : public Module {
+public:
+ Module2100(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2100();
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene1901
+
+class Class538 : public AnimatedSprite {
+public:
+ Class538(NeverhoodEngine *vm, bool flag);
+protected:
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void openDoor();
+ void closeDoor();
+ void hide();
+};
+
+class Class539 : public AnimatedSprite {
+public:
+ Class539(NeverhoodEngine *vm, Sprite *klayman);
+protected:
+ Sprite *_klayman;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Class427 : public StaticSprite {
+public:
+ Class427(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int surfacePriority, uint32 soundFileHash);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 _soundFileHash;
+ uint32 _fileHash1, _fileHash2;
+ int16 _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+
+class Scene2101 : public Scene {
+public:
+ Scene2101(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_sprite1;
+ Sprite *_class427;
+ Sprite *_asTape1;
+ Sprite *_asTape2;
+ Sprite *_class538;
+ Sprite *_class539;
+ int _countdown1;
+ int _value1;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2100_H */
diff --git a/engines/neverhood/module2200.cpp b/engines/neverhood/module2200.cpp
new file mode 100644
index 0000000000..ab1fac8c5e
--- /dev/null
+++ b/engines/neverhood/module2200.cpp
@@ -0,0 +1,2731 @@
+/* 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/module2200.h"
+#include "neverhood/module1000.h"
+#include "neverhood/module1200.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/diskplayerscene.h"
+
+namespace Neverhood {
+
+Module2200::Module2200(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ debug("Create Module2200(%d)", which);
+
+ // TODO: Music18hList_add(0x11391412, 0x601C908C);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else {
+ createScene(0, 0);
+ }
+
+}
+
+Module2200::~Module2200() {
+ // TODO Sound1ChList_sub_407A50(0x11391412);
+}
+
+void Module2200::createScene(int sceneNum, int which) {
+ // CHECKME if this can be used regardless of the new sceneNum
+ if (sceneNum == 7 && which >= 0)
+ _vm->gameState().which = _vm->gameState().sceneNum;
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _childObject = new Scene2201(_vm, this, which);
+ break;
+ case 1:
+ // TODO Music18hList_play(0x601C908C, 0, 2, 1);
+ _childObject = new Scene2202(_vm, this, which);
+ break;
+ case 2:
+ // TODO Music18hList_play(0x601C908C, 0, 2, 1);
+ _childObject = new Scene2203(_vm, this, which);
+ break;
+ case 3:
+ // TODO Music18hList_stop(0x601C908C, 0, 2);
+ _childObject = new DiskplayerScene(_vm, this, 3);
+ break;
+ case 4:
+ // TODO Music18hList_stop(0x601C908C, 0, 2);
+ _childObject = new Scene2205(_vm, this, which);
+ break;
+ case 5:
+ // TODO Music18hList_stop(0x601C908C, 0, 2);
+ _childObject = new Scene2206(_vm, this, which);
+ break;
+ case 6:
+ _childObject = new Scene2207(_vm, this, which);
+ break;
+ case 7:
+ _childObject = new Scene2208(_vm, this, which);
+ break;
+ case 8:
+ _childObject = new Scene2208(_vm, this, which);
+ break;
+ case 9:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7180);
+ break;
+ case 10:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7198);
+ break;
+ case 11:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B71B0);
+ break;
+ case 12:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B71C8);
+ break;
+ case 13:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B71E0);
+ break;
+ case 14:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B71F8);
+ break;
+ case 15:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7210);
+ break;
+ case 16:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7228);
+ break;
+ case 17:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7240);
+ break;
+ case 18:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7258);
+ break;
+ case 19:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7270);
+ break;
+ case 20:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7288);
+ break;
+ case 21:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B72A0);
+ break;
+ case 22:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B72B8);
+ break;
+ case 23:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B72D0);
+ break;
+ case 24:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B72E8);
+ break;
+ case 25:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7300);
+ break;
+ case 26:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7318);
+ break;
+ case 27:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7330);
+ break;
+ case 28:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7348);
+ break;
+ case 29:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7360);
+ break;
+ case 30:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7378);
+ break;
+ case 31:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7390);
+ break;
+ case 32:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B73A8);
+ break;
+ case 33:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B73C0);
+ break;
+ case 34:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B73D8);
+ break;
+ case 35:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B73F0);
+ break;
+ case 36:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7408);
+ break;
+ case 37:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7420);
+ break;
+ case 38:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7438);
+ break;
+ case 39:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7450);
+ break;
+ case 40:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7468);
+ break;
+ case 41:
+ _childObject = new Scene2242(_vm, this, which);
+ break;
+ case 42:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7480);
+ break;
+ case 43:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B7498);
+ break;
+ case 44:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B74B0);
+ break;
+ case 45:
+ _childObject = new HallOfRecordsScene(_vm, this, which, 0x004B74C8);
+ break;
+ case 46:
+ _childObject = new Scene2247(_vm, this, which);
+ break;
+ case 47:
+ if (!getGlobalVar(0x98109F12)) {
+ if (getGlobalVar(0x4D080E54))
+ _childObject = new Class152(_vm, this, 0x83110287, 0x10283839);
+ else
+ _childObject = new Class152(_vm, this, 0x83412B9D, 0x12B9983C);
+ } else {
+ if (getGlobalVar(0x4D080E54))
+ _childObject = new Class152(_vm, this, 0x48632087, 0x3208348E);
+ else
+ _childObject = new Class152(_vm, this, 0x08C74886, 0x74882084);
+ }
+ break;
+ }
+ SetUpdateHandler(&Module2200::updateScene);
+ _childObject->handleUpdate();
+}
+
+#define HallOfRecordsSceneLink(nextSceneNum, prevSceneNum) \
+ if (_moduleResult == 1) createScene(nextSceneNum, 0); else if (_moduleResult == 2) createScene(7, 0); else createScene(prevSceneNum, 1)
+
+void Module2200::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(2, 0);
+ } else if (_moduleResult == 2) {
+ createScene(1, 0);
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 1:
+ createScene(0, 2);
+ break;
+ case 2:
+ if (_moduleResult == 1) {
+ createScene(4, 0);
+ } else if (_moduleResult == 2) {
+ createScene(3, 0);
+ } else {
+ createScene(0, 1);
+ }
+ break;
+ case 3:
+ createScene(2, 2);
+ break;
+ case 4:
+ if (_moduleResult == 1) {
+ createScene(5, 0);
+ } else if (_moduleResult == 2) {
+ createScene(4, 2);
+ } else {
+ createScene(2, 1);
+ }
+ break;
+ case 5:
+ if (_moduleResult == 1) {
+ createScene(46, 0);
+ } else if (_moduleResult == 2) {
+ createScene(6, 0);
+ } else if (_moduleResult == 3) {
+ createScene(8, 0);
+ } else {
+ createScene(4, 1);
+ }
+ break;
+ case 6:
+ createScene(5, 2);
+ break;
+ case 7:
+ createScene(_vm->gameState().which, 2);
+ break;
+ case 8:
+ createScene(5, 3);
+ break;
+ case 9:
+ HallOfRecordsSceneLink(10, 46);
+ break;
+ case 10:
+ HallOfRecordsSceneLink(11, 9);
+ break;
+ case 11:
+ HallOfRecordsSceneLink(12, 10);
+ break;
+ case 12:
+ HallOfRecordsSceneLink(13, 11);
+ break;
+ case 13:
+ HallOfRecordsSceneLink(14, 12);
+ break;
+ case 14:
+ HallOfRecordsSceneLink(15, 13);
+ break;
+ case 15:
+ HallOfRecordsSceneLink(16, 14);
+ break;
+ case 16:
+ HallOfRecordsSceneLink(17, 15);
+ break;
+ case 17:
+ HallOfRecordsSceneLink(18, 16);
+ break;
+ case 18:
+ HallOfRecordsSceneLink(19, 17);
+ break;
+ case 19:
+ HallOfRecordsSceneLink(20, 18);
+ break;
+ case 20:
+ HallOfRecordsSceneLink(21, 19);
+ break;
+ case 21:
+ HallOfRecordsSceneLink(22, 20);
+ break;
+ case 22:
+ HallOfRecordsSceneLink(23, 21);
+ break;
+ case 23:
+ HallOfRecordsSceneLink(24, 22);
+ break;
+ case 24:
+ HallOfRecordsSceneLink(25, 23);
+ break;
+ case 25:
+ HallOfRecordsSceneLink(26, 24);
+ break;
+ case 26:
+ HallOfRecordsSceneLink(27, 25);
+ break;
+ case 27:
+ HallOfRecordsSceneLink(28, 26);
+ break;
+ case 28:
+ HallOfRecordsSceneLink(29, 27);
+ break;
+ case 29:
+ HallOfRecordsSceneLink(30, 28);
+ break;
+ case 30:
+ HallOfRecordsSceneLink(31, 29);
+ break;
+ case 31:
+ HallOfRecordsSceneLink(32, 30);
+ break;
+ case 32:
+ HallOfRecordsSceneLink(33, 31);
+ break;
+ case 33:
+ HallOfRecordsSceneLink(34, 32);
+ break;
+ case 34:
+ HallOfRecordsSceneLink(42, 33);
+ break;
+ case 35:
+ HallOfRecordsSceneLink(36, 45);
+ break;
+ case 36:
+ HallOfRecordsSceneLink(37, 35);
+ break;
+ case 37:
+ HallOfRecordsSceneLink(38, 36);
+ break;
+ case 38:
+ HallOfRecordsSceneLink(39, 37);
+ break;
+ case 39:
+ HallOfRecordsSceneLink(40, 38);
+ break;
+ case 40:
+ HallOfRecordsSceneLink(41, 39);
+ break;
+ case 41:
+ HallOfRecordsSceneLink(47, 40);
+ break;
+ case 42:
+ HallOfRecordsSceneLink(43, 34);
+ break;
+ case 43:
+ HallOfRecordsSceneLink(44, 42);
+ break;
+ case 44:
+ HallOfRecordsSceneLink(45, 43);
+ break;
+ case 45:
+ HallOfRecordsSceneLink(35, 44);
+ break;
+ case 46:
+ HallOfRecordsSceneLink(9, 5);
+ break;
+ case 47:
+ createScene(41, 1);
+ break;
+ }
+ }
+}
+
+#undef HallOfRecordsSceneLink
+
+// Scene2201
+
+AsScene2201CeilingFan::AsScene2201CeilingFan(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1100) {
+
+ _x = 403;
+ _y = 259;
+ createSurface(100, 233, 96);
+ setFileHash(0x8600866, 0, -1);
+ SetUpdateHandler(&AnimatedSprite::update);
+}
+
+AsScene2201Door::AsScene2201Door(NeverhoodEngine *vm, Klayman *klayman, Sprite *doorLightSprite, bool flag1)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _klayman(klayman), _doorLightSprite(doorLightSprite),
+ _countdown(0), _doorOpen(flag1) {
+
+ _x = 408;
+ _y = 290;
+ createSurface(900, 63, 266);
+ SetUpdateHandler(&AsScene2201Door::update);
+ SetMessageHandler(&AsScene2201Door::handleMessage);
+ if (_doorOpen) {
+ setFileHash(0xE2CB0412, -1, -1);
+ _countdown = 48;
+ _newHashListIndex = -2;
+ } else {
+ setFileHash(0xE2CB0412, 0, -1);
+ _newHashListIndex = 0;
+ _doorLightSprite->setVisible(false);
+ }
+}
+
+void AsScene2201Door::update() {
+ if (_countdown != 0 && _doorOpen && (--_countdown == 0)) {
+ stCloseDoor();
+ }
+ AnimatedSprite::update();
+}
+
+uint32 AsScene2201Door::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x11001090) {
+ if (_doorOpen)
+ _doorLightSprite->setVisible(true);
+ } else if (param.asInteger() == 0x11283090) {
+ if (!_doorOpen)
+ _doorLightSprite->setVisible(false);
+ }
+ break;
+ case 0x2000:
+ if (_doorOpen)
+ _countdown = 144;
+ messageResult = _doorOpen ? 1 : 0;
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ case 0x4808:
+ _countdown = 144;
+ if (!_doorOpen)
+ stOpenDoor();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene2201Door::stOpenDoor() {
+ _doorOpen = true;
+ setFileHash(0xE2CB0412, 0, -1);
+ _newHashListIndex = -2;
+ _soundResource.play(calcHash("fxDoorOpen33"));
+}
+
+void AsScene2201Door::stCloseDoor() {
+ _doorOpen = false;
+ setFileHash(0xE2CB0412, -1, -1);
+ _playBackwards = true;
+ _newHashListIndex = 0;
+ _soundResource.play(calcHash("fxDoorClose33"));
+}
+
+Class444::Class444(NeverhoodEngine *vm, int pointIndex, int spriteIndex)
+ : StaticSprite(vm, 900) {
+
+ _spriteResource.load2(kClass444FileHashes[spriteIndex]);
+ createSurface(100, 16, 16);
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -(_spriteResource.getDimensions().height / 2);
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _x = kClass444Points[pointIndex].x;
+ _y = kClass444Points[pointIndex].y;
+ _needRefresh = true;
+}
+
+Scene2201::Scene2201(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundFlag(false) {
+
+ Sprite *tempSprite;
+
+ if (!getSubVar(0x40050052, 0x60400854)) {
+ // TODO _vm->gameModule()->initScene2201Vars();
+ }
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2201::handleMessage);
+ SetUpdateHandler(&Scene2201::update);
+
+ loadDataResource(0x04104242);
+ loadHitRectList();
+
+ setBackground(0x40008208);
+ setPalette(0x40008208);
+ insertMouse433(0x0820C408);
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 7, 1100, 459, 432, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ _ssDoorButton = insertSprite<Class426>(this, 0xE4A43E29, 0xE4A43E29, 100, 0);
+
+ for (uint32 i = 0; i < 9; i++) {
+ if ((int16)getSubVar(0x484498D0, i) >= 0) {
+ insertSprite<Class444>(i, (int16)getSubVar(0x484498D0, i));
+ }
+ }
+
+ _rect1.y1 = 0;
+ _rect1.x2 = 640;
+ _rect2.x2 = 640;
+ _rect2.y2 = 480;
+
+ if (!getGlobalVar(0x404290D5)) {
+ insertStaticSprite(0x00026027, 900);
+ }
+
+ tempSprite = insertStaticSprite(0x030326A0, 1100);
+ _rect1.x1 = tempSprite->getDrawRect().x;
+
+ insertStaticSprite(0x811DA061, 1100);
+
+ tempSprite = insertStaticSprite(0x11180022, 1100);
+ _rect2.x1 = tempSprite->getDrawRect().x;
+
+ tempSprite = insertStaticSprite(0x0D411130, 1100);
+ _rect1.y2 = tempSprite->getDrawRect().y2();
+ _rect2.y1 = tempSprite->getDrawRect().y2();
+
+ _doorLightSprite = insertStaticSprite(0xA4062212, 900);
+
+ if (which < 0) {
+ insertKlayman<KmScene2201>(300, 427, &_rect1, 2);
+ setMessageList(0x004B8118);
+ _asDoor = insertSprite<AsScene2201Door>(_klayman, _doorLightSprite, false);
+ } else if (which == 1) {
+ insertKlayman<KmScene2201>(412, 393, &_rect1, 2);
+ setMessageList(0x004B8130);
+ _asDoor = insertSprite<AsScene2201Door>(_klayman, _doorLightSprite, false);
+ } else if (which == 2) {
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene2201>(379, 427, &_rect1, 2);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene2201>(261, 427, &_rect1, 2);
+ }
+ setMessageList(0x004B8178);
+ _asDoor = insertSprite<AsScene2201Door>(_klayman, _doorLightSprite, false);
+ } else {
+ NPoint pt = _dataResource.getPoint(0x0304D8DC);
+ insertKlayman<KmScene2201>(pt.x, pt.y, &_rect1, 2);
+ setMessageList(0x004B8120);
+ _asDoor = insertSprite<AsScene2201Door>(_klayman, _doorLightSprite, true);
+ }
+
+ insertSprite<AsScene2201CeilingFan>();
+
+ // TODO Sound1ChList_addSoundResource(0x04106220, 0x81212040, true);
+
+}
+
+Scene2201::~Scene2201() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+ // TODO Sound1ChList_sub_407AF0(0x04106220);
+}
+
+void Scene2201::update() {
+ Scene::update();
+ if (!_soundFlag) {
+ // TODO Sound1ChList_playLooping(0x81212040);
+ _soundFlag = true;
+ }
+}
+
+uint32 Scene2201::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x402064D8) {
+ sendEntityMessage(_klayman, 0x1014, _ssDoorButton);
+ } else if (param.asInteger() == 0x35803198) {
+ if (sendMessage(_asDoor, 0x2000, 0)) {
+ setMessageList(0x004B81A0);
+ } else {
+ setMessageList(0x004B81B8);
+ }
+ } else if (param.asInteger() == 0x51445010) {
+ if (getGlobalVar(0x404290D5)) {
+ setMessageList(0x004B8108);
+ } else {
+ setMessageList(0x004B8150);
+ }
+ } else if (param.asInteger() == 0x1D203082) {
+ setMessageList(0x004B8180);
+ } else if (param.asInteger() == 0x00049091) {
+ if (getGlobalVar(0x404290D5)) {
+ setMessageList(0x004B8138);
+ } else {
+ setMessageList(0x004B8108);
+ }
+ }
+ break;
+ case 0x480B:
+ if (sender == _ssDoorButton) {
+ sendMessage(_asDoor, 0x4808, 0);
+ }
+ break;
+ case 0x4826:
+ if (sender == _asTape) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList(0x004B81C8);
+ }
+ break;
+ }
+ return 0;
+}
+
+static const NPoint kSsScene2202PuzzleTilePoints[] = {
+ {196, 105},
+ {323, 102},
+ {445, 106},
+ {192, 216},
+ {319, 220},
+ {446, 216},
+ {188, 320},
+ {319, 319},
+ {443, 322}
+};
+
+static const uint32 kSsScene2202PuzzleTileFileHashes1[] = {
+ 0xA500800C,
+ 0x2182910C,
+ 0x2323980C,
+ 0x23049084,
+ 0x21008080,
+ 0x2303900C,
+ 0x6120980C,
+ 0x2504D808
+};
+
+static const uint32 kSsScene2202PuzzleTileFileHashes2[] = {
+ 0x0AAD8080,
+ 0x0A290291,
+ 0x0A2BA398,
+ 0x822B8490,
+ 0x86298080,
+ 0x0A2B8390,
+ 0x0A69A098,
+ 0x0E2D84D8
+};
+
+SsScene2202PuzzleTile::SsScene2202PuzzleTile(NeverhoodEngine *vm, Scene *parentScene, int16 tileIndex, int16 value)
+ : StaticSprite(vm, 900), _soundResource1(vm), _soundResource2(vm), _parentScene(parentScene),
+ _value(value), _tileIndex(tileIndex), _isMoving(false) {
+
+ SetUpdateHandler(&SsScene2202PuzzleTile::update);
+ SetMessageHandler(&SsScene2202PuzzleTile::handleMessage);
+ _spriteResource.load2(kSsScene2202PuzzleTileFileHashes2[_value]);
+ if (_tileIndex >= 0 && _tileIndex <= 2) {
+ createSurface(100, 128, 128);
+ } else if (_tileIndex >= 3 && _tileIndex <= 5) {
+ createSurface(300, 128, 128);
+ } else {
+ createSurface(500, 128, 128);
+ }
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -(_spriteResource.getDimensions().height / 2);
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _deltaRect = _drawRect;
+ _x = kSsScene2202PuzzleTilePoints[_tileIndex].x;
+ _y = kSsScene2202PuzzleTilePoints[_tileIndex].y;
+ processDelta();
+ _needRefresh = true;
+ StaticSprite::update();
+ _soundResource1.load(0x40958621);
+ _soundResource2.load(0x51108241);
+}
+
+void SsScene2202PuzzleTile::update() {
+ handleSpriteUpdate();
+ StaticSprite::update();
+}
+
+uint32 SsScene2202PuzzleTile::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (!_isMoving && !getGlobalVar(0x404290D5)) {
+ sendMessage(_parentScene, 0x2000, _tileIndex);
+ }
+ messageResult = 1;
+ break;
+ case 0x2001:
+ _isMoving = true;
+ moveTile(param.asInteger());
+ break;
+ }
+ return messageResult;
+}
+
+void SsScene2202PuzzleTile::suMoveTileX() {
+
+ bool done = false;
+
+ if (_counterDirection) {
+ if (_counter > 2)
+ _counter -= 2;
+ } else {
+ if (_counter < 20)
+ _counter += 2;
+ }
+
+ for (int16 i = 0; i < _counter; i++) {
+ _x += _xIncr;
+ _errValue += _yDelta;
+ if (_errValue >= _xDelta) {
+ _errValue -= _xDelta;
+ _y += _yIncr;
+ }
+ if (_x == _newX && _y == _newY) {
+ done = true;
+ break;
+ }
+ if (_x == _xFlagPos)
+ _counterDirection = true;
+ }
+
+ if (done) {
+ stopMoving();
+ }
+
+ processDelta();
+
+}
+
+void SsScene2202PuzzleTile::suMoveTileY() {
+
+ bool done = false;
+
+ if (_counterDirection) {
+ if (_counter > 2)
+ _counter -= 2;
+ } else {
+ if (_counter < 20)
+ _counter += 2;
+ }
+
+ for (int16 i = 0; i < _counter; i++) {
+ _y += _yIncr;
+ _errValue += _xDelta;
+ if (_errValue >= _yDelta) {
+ _errValue -= _yDelta;
+ _x += _xIncr;
+ }
+ if (_x == _newX && _y == _newY) {
+ done = true;
+ break;
+ }
+ if (_x == _xFlagPos)
+ _counterDirection = true;
+ }
+
+ if (done) {
+ stopMoving();
+ }
+
+ processDelta();
+
+}
+
+void SsScene2202PuzzleTile::moveTile(int16 newTileIndex) {
+
+ _spriteResource.load2(kSsScene2202PuzzleTileFileHashes1[_value]);
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -(_spriteResource.getDimensions().height / 2);
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _needRefresh = true;
+
+ setSubVar(0x484498D0, _tileIndex, (uint32)-1);
+ setSubVar(0x484498D0, newTileIndex, (uint32)_value);
+
+ _tileIndex = newTileIndex;
+
+ _errValue = 0;
+ _counterDirection = false;
+ _counter = 0;
+
+ _newX = kSsScene2202PuzzleTilePoints[newTileIndex].x;
+ _newY = kSsScene2202PuzzleTilePoints[newTileIndex].y;
+
+ if (_x == _newX && _y == _newY)
+ return;
+
+ if (_x <= _newX) {
+ if (_y <= _newY) {
+ _xDelta = _newX - _x;
+ _yDelta = _newY - _y;
+ _xIncr = 1;
+ _yIncr = 1;
+ } else {
+ _xDelta = _newX - _x;
+ _yDelta = _y - _newY;
+ _xIncr = 1;
+ _yIncr = -1;
+ }
+ } else {
+ if (_y <= _newY) {
+ _xDelta = _x - _newX;
+ _yDelta = _newY - _y;
+ _xIncr = -1;
+ _yIncr = 1;
+ } else {
+ _xDelta = _x - _newX;
+ _yDelta = _y - _newY;
+ _xIncr = -1;
+ _yIncr = -1;
+ }
+ }
+
+ if (_xDelta > _yDelta) {
+ SetSpriteCallback(&SsScene2202PuzzleTile::suMoveTileX);
+ if (_xIncr > 0) {
+ if (_newX - _x >= 180)
+ _xFlagPos = _newX - 90;
+ else
+ _xFlagPos = _x + _newX / 2;
+ } else {
+ if (_x - _newX >= 180)
+ _xFlagPos = _x + 90;
+ else
+ _xFlagPos = _x / 2 + _newX;
+ }
+ _soundResource1.play();
+ } else {
+ SetSpriteCallback(&SsScene2202PuzzleTile::suMoveTileY);
+ if (_yIncr > 0) {
+ if (_newY - _y >= 180)
+ _xFlagPos = _newY - 90;
+ else
+ _xFlagPos = _y + _newY / 2;
+ } else {
+ if (_y - _newY >= 180)
+ _xFlagPos = _y + 90;
+ else
+ _xFlagPos = _y / 2 + _newY;
+ }
+ _soundResource2.play();
+ }
+
+}
+
+void SsScene2202PuzzleTile::stopMoving() {
+ _spriteResource.load2(kSsScene2202PuzzleTileFileHashes2[_value]);
+ _drawRect.x = -(_spriteResource.getDimensions().width / 2);
+ _drawRect.y = -(_spriteResource.getDimensions().height / 2);
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _needRefresh = true;
+ SetSpriteCallback(NULL);
+ _isMoving = false;
+ sendMessage(_parentScene, 0x2002, _tileIndex);
+}
+
+Scene2202::Scene2202(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource1(vm), _soundResource2(vm),
+ _isSolved(false), _leaveScene(false), _isTileMoving(false), _movingTileSprite(NULL), _doneMovingTileSprite(NULL) {
+
+ // TODO initScene2201Vars();
+ SetMessageHandler(&Scene2202::handleMessage);
+ SetUpdateHandler(&Scene2202::update);
+
+ _surfaceFlag = true;
+
+ setBackground(0x08100A0C);
+ setPalette(0x08100A0C);
+ addEntity(_palette);
+ insertMouse435(0x00A08089, 20, 620);
+
+ //DEBUG!
+ for (uint32 index = 0; index < 9; index++)
+ setSubVar(0x484498D0, index, 7 - index);
+
+ for (uint32 index = 0; index < 9; index++) {
+ int16 value = (int16)getSubVar(0x484498D0, index);
+ if (value >= 0) {
+ Sprite *puzzleTileSprite = insertSprite<SsScene2202PuzzleTile>(this, index, value);
+ _vm->_collisionMan->addSprite(puzzleTileSprite);
+ }
+ }
+
+ insertStaticSprite(0x55C043B8, 200);
+ insertStaticSprite(0x85500158, 400);
+ insertStaticSprite(0x25547028, 600);
+
+ _soundResource1.load(0x68E25540);
+ _soundResource2.load(0x40400457);
+
+ // TODO Sound1ChList_addSoundResource(0x60400854, 0x8101A241, true);
+ // TODO Sound1ChList_playLooping(0x8101A241);
+
+}
+
+Scene2202::~Scene2202() {
+ // TODO Sound1ChList_sub_407AF0(0x60400854);
+}
+
+void Scene2202::update() {
+ Scene::update();
+
+ if (_leaveScene && !_soundResource2.isPlaying()) {
+ leaveScene(0);
+ }
+
+ if (_isSolved && !_soundResource1.isPlaying()) {
+ _soundResource2.play();
+ _isSolved = false;
+ _leaveScene = true;
+ }
+
+ if (_movingTileSprite && !_isTileMoving) {
+ int16 value = getFreeTileIndex(_movingTileIndex);
+ if (value != -1) {
+ setSurfacePriority(_movingTileSprite->getSurface(), 700);
+ sendMessage(_movingTileSprite, 0x2001, value);
+ _movingTileSprite = NULL;
+ _isTileMoving = true;
+ }
+ }
+
+ if (_doneMovingTileSprite) {
+ setSurfacePriority(_doneMovingTileSprite->getSurface(), _surfacePriority);
+ _doneMovingTileSprite = NULL;
+ if (testIsSolved()) {
+ _soundResource1.play();
+ setGlobalVar(0x404290D5, 1);
+ _isSolved = true;
+ }
+ }
+
+}
+
+uint32 Scene2202::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO Debug stuff
+ if (param.asPoint().x <= 20 || param.asPoint().x >= 620) {
+ leaveScene(0);
+ }
+ break;
+ case 0x000D:
+ // TODO Debug stuff
+ break;
+ case 0x2000:
+ _movingTileIndex = (int16)param.asInteger();
+ _movingTileSprite = (Sprite*)sender;
+ break;
+ case 0x2002:
+ _isTileMoving = false;
+ _doneMovingTileSprite = (Sprite*)sender;
+ if (param.asInteger() <= 2) {
+ _surfacePriority = 100;
+ } else if (param.asInteger() >= 3 && param.asInteger() <= 5) {
+ _surfacePriority = 300;
+ } else {
+ _surfacePriority = 500;
+ }
+ break;
+ }
+ return 0;
+}
+
+int16 Scene2202::getFreeTileIndex(int16 index) {
+ if (index >= 3 && (int16)getSubVar(0x484498D0, index - 3) == -1) {
+ return index - 3;
+ } else if (index <= 5 && (int16)getSubVar(0x484498D0, index + 3) == -1) {
+ return index + 3;
+ } else if (index != 0 && index != 3 && index != 6 && (int16)getSubVar(0x484498D0, index - 1) == -1) {
+ return index - 1;
+ } else if (index != 2 && index != 5 && index != 8 && (int16)getSubVar(0x484498D0, index + 1) == -1) {
+ return index + 1;
+ } else
+ return -1;
+}
+
+bool Scene2202::testIsSolved() {
+ return
+ getSubVar(0x484498D0, 0) == 0 &&
+ getSubVar(0x484498D0, 2) == 2 &&
+ getSubVar(0x484498D0, 3) == 3 &&
+ getSubVar(0x484498D0, 4) == 4 &&
+ getSubVar(0x484498D0, 5) == 5 &&
+ getSubVar(0x484498D0, 6) == 6 &&
+ getSubVar(0x484498D0, 8) == 7;
+}
+
+static const uint32 kClass545FileHashes[] = {
+ 0x2450D850,
+ 0x0C9CE8D0,
+ 0x2C58A152
+};
+
+Class545::Class545(NeverhoodEngine *vm, Scene *parentScene, int index, int surfacePriority, int16 x, int16 y)
+ : AnimatedSprite(vm, kClass545FileHashes[index], surfacePriority, x, y), _parentScene(parentScene), _index(index) {
+
+ if (!getSubVar(0x0090EA95, _index) && !getSubVar(0x08D0AB11, _index)) {
+ SetMessageHandler(&Class545::handleMessage);
+ } else {
+ setVisible(false);
+ SetMessageHandler(NULL);
+ }
+}
+
+uint32 Class545::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x4806:
+ setSubVar(0x0090EA95, _index, 1);
+ setVisible(false);
+ SetMessageHandler(NULL);
+ }
+ return messageResult;
+}
+
+static const uint32 kAsScene2203DoorFileHashes[] = {
+ 0x7868AE10,
+ 0x1A488110
+};
+
+AsScene2203Door::AsScene2203Door(NeverhoodEngine *vm, Scene *parentScene, uint index)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene),
+ _index(index) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2203Door::handleMessage);
+ _x = 320;
+ _y = 240;
+ createSurface1(kAsScene2203DoorFileHashes[_index], 900);
+ if (getGlobalVar(0x9A500914) == _index) {
+ setFileHash(kAsScene2203DoorFileHashes[_index], -1, -1);
+ _newHashListIndex = -2;
+ } else {
+ setFileHash(kAsScene2203DoorFileHashes[_index], 0, -1);
+ _newHashListIndex = 0;
+ }
+}
+
+uint32 AsScene2203Door::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_index == getGlobalVar(0x9A500914))
+ sendMessage(_parentScene, 0x2002, 0);
+ else
+ sendMessage(_parentScene, 0x2001, 0);
+ messageResult = 1;
+ break;
+ case 0x2000:
+ _otherDoor = (Sprite*)param.asEntity();
+ break;
+ case 0x3002:
+ if (_index == getGlobalVar(0x9A500914))
+ sendMessage(_parentScene, 0x4808, 0);
+ stopAnimation();
+ break;
+ case 0x4808:
+ setGlobalVar(0x9A500914, _index);
+ sendMessage(_otherDoor, 0x4809, 0);
+ openDoor();
+ break;
+ case 0x4809:
+ closeDoor();
+ sendMessage(_parentScene, 0x2003, 0);
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene2203Door::openDoor() {
+ _soundResource.play(0x341014C4);
+ setFileHash(kAsScene2203DoorFileHashes[_index], 1, -1);
+}
+
+void AsScene2203Door::closeDoor() {
+ setFileHash(kAsScene2203DoorFileHashes[_index], -1, -1);
+ _playBackwards = true;
+ _newHashListIndex = 0;
+}
+
+Scene2203::Scene2203(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ if (getGlobalVar(0xC0780812) && !getGlobalVar(0x13382860))
+ setGlobalVar(0x13382860, 1);
+
+ SetMessageHandler(&Scene2203::handleMessage);
+ _surfaceFlag = true;
+
+ setBackground(0x82C80334);
+ setPalette(0x82C80334);
+ insertMouse433(0x80330824);
+
+ setHitRects(0x004B8320);
+
+ if (getGlobalVar(0x13382860) == 1) {
+ _class545 = insertSprite<Class545>(this, 2, 1100, 282, 432);
+ _vm->_collisionMan->addSprite(_class545);
+ }
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 1, 1100, 435, 432, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ _asLeftDoor = insertSprite<AsScene2203Door>(this, 0);
+ _asRightDoor = insertSprite<AsScene2203Door>(this, 1);
+
+ _ssSmallLeftDoor = insertStaticSprite(0x542CC072, 1100);
+ _ssSmallRightDoor = insertStaticSprite(0x0A2C0432, 1100);
+
+ _leftDoorClipRect.set(_ssSmallLeftDoor->getDrawRect().x, 0, 640, 480);
+ _rightDoorClipRect.set(0, 0, _ssSmallRightDoor->getDrawRect().x2(), 480);
+
+ sendEntityMessage(_asLeftDoor, 0x2000, _asRightDoor);
+ sendEntityMessage(_asRightDoor, 0x2000, _asLeftDoor);
+
+ _vm->_collisionMan->addSprite(_asLeftDoor);
+ _vm->_collisionMan->addSprite(_asRightDoor);
+
+ if (which < 0) {
+ insertKlayman<KmScene2203>(200, 427);
+ setMessageList(0x004B8340);
+ } else if (which == 1) {
+ insertKlayman<KmScene2203>(640, 427);
+ setMessageList(0x004B8350);
+ } else if (which == 2) {
+ if (getGlobalVar(0xC0418A02)) {
+ insertKlayman<KmScene2203>(362, 427);
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene2203>(202, 427);
+ }
+ setMessageList(0x004B8358);
+ } else {
+ insertKlayman<KmScene2203>(0, 427);
+ setMessageList(0x004B8348);
+ }
+
+ if (getGlobalVar(0x9A500914)) {
+ _ssSmallLeftDoor->setVisible(false);
+ _klayman->setClipRect(_rightDoorClipRect);
+ } else {
+ _ssSmallRightDoor->setVisible(false);
+ _klayman->setClipRect(_leftDoorClipRect);
+ }
+
+ setRectList(0x004B8420);
+
+}
+
+Scene2203::~Scene2203() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+uint32 Scene2203::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2001:
+ sendEntityMessage(_klayman, 0x1014, sender);
+ if (sender == _asLeftDoor) {
+ setMessageList2(0x004B83B0);
+ } else {
+ setMessageList2(0x004B83C8);
+ }
+ break;
+ case 0x2002:
+ if (sender == _asLeftDoor) {
+ setMessageList2(0x004B8370);
+ } else {
+ setMessageList2(0x004B8360);
+ }
+ break;
+ case 0x2003:
+ if (sender == _asLeftDoor) {
+ _ssSmallLeftDoor->setVisible(false);
+ } else {
+ _ssSmallRightDoor->setVisible(false);
+ }
+ break;
+ case 0x4808:
+ if (sender == _asLeftDoor) {
+ _ssSmallLeftDoor->setVisible(true);
+ _klayman->setClipRect(_leftDoorClipRect);
+ } else {
+ _ssSmallRightDoor->setVisible(true);
+ _klayman->setClipRect(_rightDoorClipRect);
+ }
+ break;
+ case 0x4826:
+ if (sender == _asTape) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList(0x004B83E0);
+ } else if (sender == _class545) {
+ sendEntityMessage(_klayman, 0x1014, _class545);
+ setMessageList(0x004B83F0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+SsScene2205DoorFrame::SsScene2205DoorFrame(NeverhoodEngine *vm)
+ : StaticSprite(vm, 900) {
+
+ SetMessageHandler(&SsScene2205DoorFrame::handleMessage);
+ _spriteResource.load2(getGlobalVar(0x4D080E54) ? 0x24306227 : 0xD90032A0);
+ createSurface(1100, 45, 206);
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _needRefresh = true;
+ StaticSprite::update();
+}
+
+uint32 SsScene2205DoorFrame::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ _spriteResource.load2(getGlobalVar(0x4D080E54) ? 0x24306227 : 0xD90032A0);
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _needRefresh = true;
+ StaticSprite::update();
+ }
+ return messageResult;
+}
+
+Scene2205::Scene2205(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ SetMessageHandler(&Scene2205::handleMessage);
+ SetUpdateHandler(&Scene2205::update);
+
+ setHitRects(0x004B0620);
+ _surfaceFlag = true;
+
+ if (getGlobalVar(0x4D080E54)) {
+ _isLightOn = true;
+ setBackground(0x0008028D);
+ setPalette(0x0008028D);
+ addEntity(_palette);
+ insertMouse433(0x80289008);
+ _ssLightSwitch = insertSprite<Class426>(this, 0x2D339030, 0x2D309030, 100, 0);
+ } else {
+ _isLightOn = false;
+ setBackground(0xD00A028D);
+ setPalette(0xD00A028D);
+ addEntity(_palette);
+ insertMouse433(0xA0289D08);
+ _ssLightSwitch = insertSprite<Class426>(this, 0x2D339030, 0xDAC86E84, 100, 0);
+ }
+
+ _palette->addBasePalette(0xD00A028D, 0, 256, 0);
+
+ _ssDoorFrame = insertSprite<SsScene2205DoorFrame>();
+
+ if (which < 0) {
+ insertKlayman<KmScene2205>(320, 417);
+ setMessageList(0x004B0658);
+ if (!getGlobalVar(0x4D080E54)) {
+ _palette->addPalette(0x68033B1C, 0, 65, 0);
+ }
+ _isKlaymanInLight = false;
+ } else if (which == 1) {
+ insertKlayman<KmScene2205>(640, 417);
+ setMessageList(0x004B0648);
+ if (!getGlobalVar(0x4D080E54)) {
+ _palette->addPalette(0x68033B1C, 0, 65, 0);
+ }
+ _isKlaymanInLight = false;
+ } else {
+ insertKlayman<KmScene2205>(0, 417);
+ setMessageList(0x004B0640);
+ _isKlaymanInLight = true;
+ }
+
+ _klayman->setClipRect(_ssDoorFrame->getDrawRect().x, 0, 640, 480);
+
+ loadDataResource(0x00144822);
+ _klayman->setSoundFlag(true);
+
+}
+
+void Scene2205::update() {
+ Scene::update();
+
+ if (!_isLightOn && getGlobalVar(0x4D080E54)) {
+ _palette->addPalette(0x0008028D, 0, 256, 0);
+ changeBackground(0x0008028D);
+ _ssLightSwitch->setFileHashes(0x2D339030, 0x2D309030);
+ sendMessage(_ssDoorFrame, 0x2000, 0);
+ changeMouseCursor(0x80289008);
+ _isLightOn = true;
+ } else if (_isLightOn && !getGlobalVar(0x4D080E54)) {
+ _palette->addPalette(0xD00A028D, 0, 256, 0);
+ changeBackground(0xD00A028D);
+ _ssLightSwitch->setFileHashes(0x2D339030, 0xDAC86E84);
+ sendMessage(_ssDoorFrame, 0x2000, 0);
+ changeMouseCursor(0xA0289D08);
+ _isKlaymanInLight = true;
+ if (_klayman->getX() > 85) {
+ _palette->addPalette(0x68033B1C, 0, 65, 0);
+ _isKlaymanInLight = false;
+ }
+ _isLightOn = false;
+ }
+
+ if (!getGlobalVar(0x4D080E54)) {
+ if (_isKlaymanInLight && _klayman->getX() > 85) {
+ _palette->addBasePalette(0x68033B1C, 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ _isKlaymanInLight = false;
+ } else if (!_isKlaymanInLight && _klayman->getX() <= 85) {
+ _palette->addBasePalette(0xD00A028D, 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ _isKlaymanInLight = true;
+ }
+ }
+
+}
+
+uint32 Scene2205::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x6449569A) {
+ setMessageList(0x004B0690);
+ } else if (param.asInteger() == 0x2841369C) {
+ setMessageList(0x004B0630);
+ } else if (param.asInteger() == 0x402064D8) {
+ sendEntityMessage(_klayman, 0x1014, _ssLightSwitch);
+ }
+ break;
+ case 0x480B:
+ setGlobalVar(0x4D080E54, getGlobalVar(0x4D080E54) ? 0 : 1);
+ break;
+ }
+ return 0;
+}
+
+static const int16 kScene2206XPositions[] = {
+ 384,
+ 480,
+ 572
+};
+
+static const uint32 kScene2206MessageIds1[] = {
+ 0x004B8998,
+ 0x004B89B8,
+ 0x004B89D8
+};
+
+static const uint32 kScene2206MessageIds2[] = {
+ 0x004B89F8,
+ 0x004B8A20,
+ 0x004B8A48
+};
+
+static const int16 kClass603XDeltas1[] = {
+ -24, -28, -18, 6, 9, -8
+};
+
+static const int16 kClass603XDeltas2[] = {
+ -8, 7, 11, 26, 13, 14
+};
+
+Class603::Class603(NeverhoodEngine *vm, uint32 fileHash)
+ : StaticSprite(vm, fileHash, 200), _soundResource(vm) {
+
+ if (getGlobalVar(0x18890C91))
+ _x -= 63;
+ SetUpdateHandler(&Class603::update);
+ SetMessageHandler(&Class603::handleMessage);
+ SetSpriteCallback(NULL);
+}
+
+void Class603::update() {
+ handleSpriteUpdate();
+ StaticSprite::update();
+}
+
+uint32 Class603::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4808:
+ _index = 0;
+ SetMessageHandler(NULL);
+ SetSpriteCallback(&Class603::spriteUpdate481E60);
+ _soundResource.play(0x032746E0);
+ break;
+ case 0x4809:
+ _index = 0;
+ SetMessageHandler(NULL);
+ SetSpriteCallback(&Class603::spriteUpdate481E90);
+ _soundResource.play(0x002642C0);
+ break;
+ }
+ return messageResult;
+}
+
+void Class603::spriteUpdate481E60() {
+ if (_index < 6) {
+ _x += kClass603XDeltas1[_index];
+ _index++;
+ } else {
+ SetMessageHandler(&Class603::handleMessage);
+ SetSpriteCallback(NULL);
+ }
+}
+
+void Class603::spriteUpdate481E90() {
+ if (_index < 6) {
+ _x += kClass603XDeltas2[_index];
+ _index++;
+ } else {
+ SetMessageHandler(&Class603::handleMessage);
+ SetSpriteCallback(NULL);
+ }
+}
+
+Class604::Class604(NeverhoodEngine *vm, uint32 fileHash)
+ : StaticSprite(vm, fileHash, 50) {
+
+ SetUpdateHandler(&Class604::update);
+ SetMessageHandler(&Class604::handleMessage);
+ SetSpriteCallback(NULL);
+}
+
+void Class604::update() {
+ handleSpriteUpdate();
+ StaticSprite::update();
+}
+
+uint32 Class604::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x4803:
+ SetMessageHandler(NULL);
+ SetSpriteCallback(&Class604::spriteUpdate482020);
+ _yDelta = 0;
+ break;
+ }
+ return messageResult;
+}
+
+void Class604::spriteUpdate482020() {
+ _yDelta++;
+ _y += _yDelta;
+}
+
+Class607::Class607(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, uint32 fileHash)
+ : StaticSprite(vm, fileHash, surfacePriority), _parentScene(parentScene) {
+
+ if (getGlobalVar(0x45080C38)) {
+ setVisible(false);
+ SetMessageHandler(NULL);
+ } else {
+ SetMessageHandler(&Class607::handleMessage);
+ }
+ _deltaRect = _drawRect;
+ processDelta();
+}
+
+uint32 Class607::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x4806:
+ setGlobalVar(0x45080C38, 1);
+ setVisible(false);
+ SetMessageHandler(NULL);
+ break;
+ }
+ return messageResult;
+}
+
+Scene2206::Scene2206(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm) {
+
+ uint32 fileHash;
+
+ SetUpdateHandler(&Scene::update);
+ SetMessageHandler(&Scene2206::handleMessage);
+ _surfaceFlag = true;
+
+ if (getGlobalVar(0x4D080E54)) {
+ fileHash = 0x41983216;
+ _sprite1 = insertStaticSprite(0x2201266A, 100);
+ _sprite2 = insertStaticSprite(0x3406A333, 300);
+ _sprite3 = insertStaticSprite(0x24A223A2, 100);
+ _sprite4 = insertSprite<Class603>(0x26133023);
+ _sprite4->setClipRect(_sprite2->getDrawRect().x, 0, 640, 480);
+ setRectList(0x004B8AF8);
+ _sprite5 = insertSprite<SsCommonButtonSprite>(this, 0x0E038022, 100, 0);
+ insertMouse433(0x83212411);
+ _class607 = insertSprite<Class607>(this, 1100, /*464, 433, */0x5E00E262);
+ _class604 = insertSprite<Class604>(0x085E25E0);
+ } else {
+ fileHash = 0xE0102A45;
+ _sprite1 = insertStaticSprite(0x1C1106B8, 100);
+ _sprite2 = insertStaticSprite(0x020462E0, 300);
+ _sprite3 = insertStaticSprite(0x900626A2, 100);
+ _sprite4 = insertSprite<Class603>(0x544822A8);
+ _sprite4->setClipRect(_sprite2->getDrawRect().x, 0, 640, 480);
+ setRectList(0x004B8B58);
+ _sprite5 = insertSprite<SsCommonButtonSprite>(this, 0x16882608, 100, 0);
+ insertMouse433(0x02A41E09);
+ _class607 = insertSprite<Class607>(this, 1100, /*464, 433, */0x52032563);
+ _class604 = insertSprite<Class604>(0x317831A0);
+ }
+
+ _class604->setClipRect(_sprite2->getDrawRect().x, 0, _sprite3->getDrawRect().x2(), _sprite1->getDrawRect().y2());
+
+ setBackground(fileHash);
+
+ setPalette(fileHash);
+ addEntity(_palette);
+
+ _palette->addBasePalette(fileHash, 0, 256, 0);
+
+ if (!getGlobalVar(0x4D080E54)) {
+ _palette->addPalette(0x0263D144, 0, 65, 0);
+ }
+
+ _vm->_collisionMan->addSprite(_class607);
+
+ if (which < 0) {
+ insertKlayman<KmScene2206>(200, 430);
+ setMessageList(0x004B88A8);
+ } else if (which == 1) {
+ insertKlayman<KmScene2206>(640, 430);
+ setMessageList(0x004B88B8);
+ } else if (which == 2) {
+ insertKlayman<KmScene2206>(205, 396);
+ setMessageList(0x004B88C8);
+ _palette->addPalette(getGlobalVar(0x4D080E54) ? 0xB103B604 : 0x0263D144, 0, 65, 0);
+ sub4819D0();
+ _soundResource.play(0x53B8284A);
+ } else if (which == 3) {
+ insertKlayman<KmScene2206>(kScene2206XPositions[getGlobalVar(0x48A68852)], 430);
+ if (getGlobalVar(0xC0418A02))
+ _klayman->setDoDeltaX(1);
+ setMessageList(0x004B8A70);
+ } else {
+ insertKlayman<KmScene2206>(0, 430);
+ setMessageList(0x004B88B0);
+ }
+
+ _klayman->setSoundFlag(true);
+ _klayman->setKlaymanTable2();
+
+}
+
+Scene2206::~Scene2206() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+uint32 Scene2206::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x800C6694) {
+ sub481B00();
+ } else if (param.asInteger() == 0x402064D8) {
+ sendEntityMessage(_klayman, 0x1014, _sprite5);
+ } else if (param.asInteger() == 0x11C40840) {
+ if (getGlobalVar(0x18890C91))
+ setMessageList(0x004B8948);
+ else
+ setMessageList(0x004B8970);
+ }
+ break;
+ case 0x4803:
+ sendMessage(_class604, 0x4803, 0);
+ break;
+ case 0x480B:
+ if (sender == _sprite5) {
+ setGlobalVar(0x18890C91, getGlobalVar(0x18890C91) ? 0 : 1);
+ if (getGlobalVar(0x18890C91))
+ sendMessage(_sprite4, 0x4808, 0);
+ else
+ sendMessage(_sprite4, 0x4809, 0);
+ }
+ break;
+ case 0x4826:
+ sendEntityMessage(_klayman, 0x1014, _class607);
+ setMessageList(0x004B8988);
+ break;
+ case 0x482A:
+ sub4819D0();
+ break;
+ case 0x482B:
+ sub481950();
+ break;
+ }
+ return messageResult;
+}
+
+void Scene2206::sub481950() {
+ if (getGlobalVar(0x4D080E54)) {
+ _palette->addBasePalette(0x41983216, 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ }
+ setSurfacePriority(_sprite1->getSurface(), 100);
+ setSurfacePriority(_sprite2->getSurface(), 300);
+ setSurfacePriority(_sprite3->getSurface(), 100);
+ setSurfacePriority(_sprite4->getSurface(), 200);
+ _klayman->setClipRect(0, 0, 640, 480);
+}
+
+void Scene2206::sub4819D0() {
+ if (!getGlobalVar(0x4D080E54)) {
+ _palette->addBasePalette(0xB103B604, 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ }
+ setSurfacePriority(_sprite1->getSurface(), 1100);
+ setSurfacePriority(_sprite2->getSurface(), 1300);
+ setSurfacePriority(_sprite3->getSurface(), 1100);
+ setSurfacePriority(_sprite4->getSurface(), 1200);
+ _klayman->setClipRect(_sprite2->getDrawRect().x, 0, _sprite3->getDrawRect().x2(), _sprite1->getDrawRect().y2());
+}
+
+void Scene2206::sub481B00() {
+ setGlobalVar(0x48A68852, (_mouseClickPos.x - 354) / 96);
+ if (getGlobalVar(0x48A68852) > 2)
+ setGlobalVar(0x48A68852, 2);
+ setGlobalVar(0x49C40058, (_mouseClickPos.y - 183) / 7);
+ setGlobalVar(0xC8C28808, calcHash("stLineagex"));
+ setGlobalVar(0x4CE79018, 0);
+ if (ABS(kScene2206XPositions[getGlobalVar(0x48A68852)] - _klayman->getX()) >= 144) {
+ setMessageList2(kScene2206MessageIds1[getGlobalVar(0x48A68852)]);
+ } else {
+ setMessageList2(kScene2206MessageIds2[getGlobalVar(0x48A68852)]);
+ }
+}
+
+static const uint32 kScene2207FileHashes[] = {
+ 0x33B1E12E,
+ 0x33D1E12E,
+ 0x3311E12E,
+ 0x3291E12E,
+ 0x3191E12E,
+ 0x3791E12E,
+ 0x3B91E12E,
+ 0x2391E12E,
+ 0x1391E12E,
+ 0x3BB1E12E,
+ 0x23B1E12E,
+ 0x13B1E12E
+};
+
+AsScene2207Elevator::AsScene2207Elevator(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 900), _parentScene(parentScene), _soundResource(vm),
+ _pointIndex(0), _destPointIndex(0), _destPointIndexDelta(0) {
+
+ NPoint pt;
+
+ _dataResource.load(0x00524846);
+ _pointArray = _dataResource.getPointArray(0x005B02B7);
+ pt = _dataResource.getPoint(0x403A82B1);
+ _x = pt.x;
+ _y = pt.y;
+ createSurface(1100, 129, 103);
+ setFileHash(getGlobalVar(0x4D080E54) ? 0xC858CC19 : 0x294B3377, 0, 0);
+ SetUpdateHandler(&AsScene2207Elevator::update);
+ SetSpriteCallback(&AsScene2207Elevator::suSetPosition);
+ SetMessageHandler(&AsScene2207Elevator::handleMessage);
+ _newHashListIndex = 0;
+}
+
+AsScene2207Elevator::~AsScene2207Elevator() {
+ // TODO Sound1ChList_sub_407AF0(0x02700413);
+}
+
+void AsScene2207Elevator::update() {
+
+ if (_destPointIndex + _destPointIndexDelta > _pointIndex) {
+ _pointIndex++;
+ setFileHash(getGlobalVar(0x4D080E54) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex);
+ _newHashListIndex = _pointIndex;
+ if (_destPointIndex + _destPointIndexDelta == _pointIndex) {
+ if (_destPointIndexDelta != 0) {
+ _destPointIndexDelta = 0;
+ } else {
+ // TODO Sound1ChList_deleteSoundByHash(0xD3B02847);
+ _soundResource.play(0x53B8284A);
+ }
+ }
+ }
+
+ if (_destPointIndex + _destPointIndexDelta < _pointIndex) {
+ _pointIndex--;
+ if (_pointIndex == 0)
+ sendMessage(_parentScene, 0x2003, 0);
+ setFileHash(getGlobalVar(0x4D080E54) ? 0xC858CC19 : 0x294B3377, _pointIndex, _pointIndex);
+ _newHashListIndex = _pointIndex;
+ if (_destPointIndex + _destPointIndexDelta == _pointIndex) {
+ if (_destPointIndexDelta != 0) {
+ _destPointIndexDelta = 0;
+ } else {
+ // TODO Sound1ChList_deleteSoundByHash(0xD3B02847);
+ _soundResource.play(0x53B8284A);
+ }
+ }
+ }
+
+ if (_pointIndex > 20 && _surface->getPriority() != 900) {
+ sendMessage(_parentScene, 0x2002, 900);
+ } else if (_pointIndex < 20 && _surface->getPriority() != 1100) {
+ sendMessage(_parentScene, 0x2002, 1100);
+ }
+
+ AnimatedSprite::update();
+
+ if (_destPointIndex + _destPointIndexDelta == _pointIndex && _isMoving) {
+ sendMessage(_parentScene, 0x2004, 0);
+ _isMoving = false;
+ }
+
+}
+
+void AsScene2207Elevator::suSetPosition() {
+ _x = (*_pointArray)[_pointIndex].x;
+ _y = (*_pointArray)[_pointIndex].y - 60;
+ processDelta();
+}
+
+uint32 AsScene2207Elevator::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2000:
+ moveToY(param.asInteger());
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene2207Elevator::moveToY(int16 y) {
+ int16 minDistance = 480;
+
+ if (!_pointArray || _pointArray->size() == 0)
+ return;
+
+ for (uint i = 0; i < _pointArray->size(); i++) {
+ int16 distance = ABS(y - (*_pointArray)[i].y);
+ if (distance < minDistance) {
+ minDistance = distance;
+ _destPointIndex = i;
+ }
+ }
+
+ if (_destPointIndex != _pointIndex) {
+ if (_destPointIndex == 0 || _destPointIndex == (int)_pointArray->size() - 1) {
+ _destPointIndexDelta = 0;
+ } else if (_destPointIndex < _pointIndex) {
+ _destPointIndexDelta = -2;
+ } else {
+ _destPointIndexDelta = 2;
+ }
+ // TODO Sound1ChList_addSoundResource(0x02700413, 0xD3B02847, true);
+ // TODO Sound1ChList_playLooping(0xD3B02847);
+ }
+
+ _isMoving = true;
+
+}
+
+AsScene2207Lever::AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX)
+ : AnimatedSprite(vm, 1100), _soundResource(vm), _parentScene(parentScene) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2207Lever::handleMessage);
+ createSurface(1010, 71, 73);
+ setDoDeltaX(doDeltaX);
+ setFileHash(0x80880090, 0, -1);
+ _newHashListIndex = 0;
+ _x = x;
+ _y = y;
+}
+
+uint32 AsScene2207Lever::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ sendMessage(_parentScene, 0x4826, 0);
+ messageResult = 1;
+ break;
+ case 0x3002:
+ removeCallbacks();
+ stopAnimation();
+ break;
+ case 0x4807:
+ stLeverUp();
+ break;
+ case 0x480F:
+ stLeverDown();
+ break;
+ case 0x482A:
+ sendMessage(_parentScene, 0x1022, 990);
+ break;
+ case 0x482B:
+ sendMessage(_parentScene, 0x1022, 1010);
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene2207Lever::stLeverDown() {
+ setFileHash(0x80880090, 1, -1);
+ FinalizeState(&AsScene2207Lever::stLeverDownEvent);
+ _soundResource.play(0x40581882);
+}
+
+void AsScene2207Lever::stLeverDownEvent() {
+ sendMessage(_parentScene, 0x480F, 0);
+}
+
+void AsScene2207Lever::stLeverUp() {
+ setFileHash(0x80880090, 6, -1);
+ FinalizeState(&AsScene2207Lever::stLeverUpEvent);
+ _playBackwards = true;
+ _soundResource.play(0x40581882);
+}
+
+void AsScene2207Lever::stLeverUpEvent() {
+ sendMessage(_parentScene, 0x4807, 0);
+}
+
+AsScene2207WallRobotAnimation::AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene)
+ : AnimatedSprite(vm, 1200), _soundResource1(vm), _soundResource2(vm),
+ _soundResource3(vm), _soundResource4(vm), _idle(true) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2207WallRobotAnimation::handleMessage);
+ createSurface1(0xCCFD6090, 100);
+ _x = 309;
+ _y = 320;
+ setFileHash(0xCCFD6090, 0, -1);
+ _newHashListIndex = 0;
+ _soundResource2.load(0x40330872);
+ _soundResource3.load(0x72A2914A);
+ _soundResource4.load(0xD4226080);
+}
+
+AsScene2207WallRobotAnimation::~AsScene2207WallRobotAnimation() {
+ // TODO Sound1ChList_sub_407AF0(0x80D00820);
+}
+
+uint32 AsScene2207WallRobotAnimation::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (!_idle) {
+ if (param.asInteger() == 0x3423093) {
+ // TODO Sound1ChList_addSoundResource(0x80D00820, 0x12121943, true);
+ // TODO Sound1ChList_playLooping(0x12121943);
+ } else if (param.asInteger() == 0x834AB011) {
+ _soundResource1.stop();
+ _soundResource2.stop();
+ _soundResource3.stop();
+ _soundResource4.stop();
+ // TODO Sound1ChList_deleteSoundByHash(0x12121943);
+ } else if (param.asInteger() == 0x3A980501) {
+ _soundResource2.play();
+ } else if (param.asInteger() == 0x2A2AD498) {
+ _soundResource3.play();
+ } else if (param.asInteger() == 0xC4980008) {
+ _soundResource4.play();
+ } else if (param.asInteger() == 0x06B84228) {
+ _soundResource1.play(0xE0702146);
+ }
+ }
+ break;
+ case 0x2006:
+ stStartAnimation();
+ break;
+ case 0x2007:
+ stStopAnimation();
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene2207WallRobotAnimation::stStartAnimation() {
+ if (!_idle) {
+ NextState(NULL);
+ } else {
+ setFileHash(0xCCFD6090, 0, -1);
+ _idle = false;
+ setVisible(true);
+ }
+}
+
+void AsScene2207WallRobotAnimation::stStopAnimation() {
+ NextState(&AsScene2207WallRobotAnimation::cbStopAnimation);
+}
+
+void AsScene2207WallRobotAnimation::cbStopAnimation() {
+ stopAnimation();
+ _soundResource1.stop();
+ _soundResource2.stop();
+ _soundResource3.stop();
+ _soundResource4.stop();
+ // TODO Sound1ChList_deleteSoundByHash(0x12121943);
+ _idle = true;
+ setVisible(false);
+}
+
+AsScene2207WallCannonAnimation::AsScene2207WallCannonAnimation(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1200), _idle(true) {
+
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2207WallCannonAnimation::handleMessage);
+ createSurface1(0x8CAA0099, 100);
+ _x = 309;
+ _y = 320;
+ setFileHash(0x8CAA0099, 0, -1);
+ _newHashListIndex = 0;
+}
+
+uint32 AsScene2207WallCannonAnimation::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2006:
+ stStartAnimation();
+ break;
+ case 0x2007:
+ stStopAnimation();
+ break;
+ case 0x3002:
+ removeCallbacks();
+ break;
+ }
+ return messageResult;
+}
+
+void AsScene2207WallCannonAnimation::stStartAnimation() {
+ if (!_idle) {
+ NextState(NULL);
+ } else {
+ setVisible(true);
+ setFileHash(0x8CAA0099, 0, -1);
+ _idle = false;
+ }
+}
+
+void AsScene2207WallCannonAnimation::stStopAnimation() {
+ NextState(&AsScene2207WallCannonAnimation::cbStopAnimation);
+}
+
+void AsScene2207WallCannonAnimation::cbStopAnimation() {
+ stopAnimation();
+ setVisible(false);
+ _idle = true;
+}
+
+SsScene2207Symbol::SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int index)
+ : StaticSprite(vm, fileHash, 100) {
+
+ _x = 330;
+ _y = 246 + index * 50;
+ StaticSprite::update();
+}
+
+Scene2207::Scene2207(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource1(vm), _soundResource2(vm),
+ _klaymanAtElevator(true), _elevatorSurfacePriority(0) {
+
+ //DEBUG
+ setGlobalVar(0x4D080E54, 1);
+
+ _vm->gameModule()->initScene3009Vars();
+
+ if (!getSubVar(0x40050052, 0x88460852))
+ setSubVar(0x40050052, 0x88460852, 1);
+
+ SetMessageHandler(&Scene2207::handleMessage);
+ SetUpdateHandler(&Scene2207::update);
+ _surfaceFlag = true;
+
+ insertKlayman<KmScene2207>(0, 0);
+ _klayman->setRepl(64, 0);
+
+ setMessageList(0x004B38E8);
+
+ _asElevator = insertSprite<AsScene2207Elevator>(this);
+
+ if (getGlobalVar(0x4D080E54)) {
+
+ setBackground(0x88C00241);
+ setPalette(0x88C00241);
+ insertMouse433(0x00245884);
+
+ _ssMaskPart1 = insertStaticSprite(0xE20A28A0, 1200);
+ _ssMaskPart2 = insertStaticSprite(0x688F62A5, 1100);
+ _ssMaskPart3 = insertStaticSprite(0x0043B038, 1100);
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 4, 1100, 277, 428, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ _asLever = insertSprite<AsScene2207Lever>(this, 527, 333, 0);
+ _vm->_collisionMan->addSprite(_asLever);
+
+ _asWallRobotAnimation = insertSprite<AsScene2207WallRobotAnimation>(this);
+ _asWallCannonAnimation = insertSprite<AsScene2207WallCannonAnimation>();
+
+ _asWallRobotAnimation->setVisible(false);
+ _asWallCannonAnimation->setVisible(false);
+
+ _ssButton = insertSprite<SsCommonButtonSprite>(this, 0x2C4061C4, 100, 0);
+
+ _asLever->setClipRect(0, 0, _ssMaskPart3->getDrawRect().x2(), 480);
+ _klayman->setClipRect(0, _ssMaskPart1->getDrawRect().y, 640, _ssMaskPart2->getDrawRect().y2());
+ _asElevator->setClipRect(0, _ssMaskPart1->getDrawRect().y, 640, _ssMaskPart2->getDrawRect().y2());
+
+ } else {
+
+ setGlobalVar(0x81890D14, 1);
+
+ setBackground(0x05C02A55);
+ setPalette(0x05C02A55);
+ insertMouse433(0x02A51054);
+
+ _ssMaskPart1 = insertStaticSprite(0x980E46A4, 1200);
+
+ insertSprite<SsScene2207Symbol>(kScene2207FileHashes[getSubVar(0x00504B86, 0)], 0);
+ insertSprite<SsScene2207Symbol>(kScene2207FileHashes[getSubVar(0x00504B86, 1)], 1);
+ insertSprite<SsScene2207Symbol>(kScene2207FileHashes[getSubVar(0x00504B86, 2)], 2);
+
+ _asTape = NULL;
+ _asLever = NULL;
+ _asWallRobotAnimation = NULL;
+ _asWallCannonAnimation = NULL;
+ _ssButton = NULL;
+
+ _klayman->setClipRect(0, _ssMaskPart1->getDrawRect().y, 640, 480);
+ _asElevator->setClipRect(0, _ssMaskPart1->getDrawRect().y, 640, 480);
+
+ }
+
+ _dataResource.load(0x00524846);
+
+ setRectList(0x004B38B8);
+
+ sendEntityMessage(_klayman, 0x1014, _asElevator);
+ sendMessage(_klayman, 0x2001, 0);
+ sendMessage(_asElevator, 0x2000, 480);
+
+ _soundResource2.load(calcHash("fxFogHornSoft"));
+
+}
+
+void Scene2207::update() {
+ Scene::update();
+ if (_elevatorSurfacePriority != 0) {
+ setSurfacePriority(_asElevator->getSurface(), _elevatorSurfacePriority);
+ _elevatorSurfacePriority = 0;
+ }
+ if (_klayman->getY() == 423) {
+ _klaymanAtElevator = _klayman->getX() > 459 && _klayman->getX() < 525;
+ }
+}
+
+uint32 Scene2207::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x0014F275) {
+ if (_klaymanAtElevator) {
+ sendMessage(_asElevator, 0x2000, _mouseClickPos.y);
+ sendEntityMessage(_klayman, 0x1014, _asElevator);
+ sendMessage(_klayman, 0x2001, 0);
+ } else {
+ messageList402220();
+ }
+ } else if (param.asInteger() == 0x34569073) {
+ if (_klaymanAtElevator) {
+ _messageListFlag1 = true;
+ sendMessage(_asElevator, 0x2000, 0);
+ sendEntityMessage(_klayman, 0x1014, _asElevator);
+ sendMessage(_klayman, 0x2001, 0);
+ } else {
+ messageList402220();
+ }
+ } else if (param.asInteger() == 0x4054C877) {
+ if (_klaymanAtElevator) {
+ sendMessage(_asElevator, 0x2000, 480);
+ sendEntityMessage(_klayman, 0x1014, _asElevator);
+ sendMessage(_klayman, 0x2001, 0);
+ } else {
+ messageList402220();
+ }
+ } else if (param.asInteger() == 0x0CBC6211) {
+ sendEntityMessage(_klayman, 0x1014, _asElevator);
+ sendMessage(_klayman, 0x2001, 0);
+ setRectList(0x004B38B8);
+ } else if (param.asInteger() == 0x402064D8) {
+ sendEntityMessage(_klayman, 0x1014, _ssButton);
+ } else if (param.asInteger() == 0x231DA241) {
+ if (_ssButton) {
+ setMessageList(0x004B38F0);
+ } else {
+ setMessageList(0x004B37D8);
+ }
+ }
+ break;
+ case 0x2002:
+ _elevatorSurfacePriority = param.asInteger();
+ break;
+ case 0x2003:
+ _messageListFlag1 = false;
+ break;
+ case 0x4807:
+ sendMessage(_asWallRobotAnimation, 0x2007, 0);
+ sendMessage(_asWallCannonAnimation, 0x2007, 0);
+ break;
+ case 0x480B:
+ if (sender == _ssButton) {
+ if (getSubVar(0x14800353, 0x40119852)) {
+ setSubVar(0x14800353, 0x40119852, 0);
+ _soundResource1.play(calcHash("fx3LocksDisable"));
+ } else {
+ setSubVar(0x14800353, 0x40119852, 1);
+ _soundResource2.play();
+ }
+ }
+ break;
+ case 0x480F:
+ sendMessage(_asWallRobotAnimation, 0x2006, 0);
+ sendMessage(_asWallCannonAnimation, 0x2006, 0);
+ _asWallRobotAnimation->setVisible(true);
+ _asWallCannonAnimation->setVisible(true);
+ break;
+ case 0x4826:
+ if (sender == _asTape) {
+ if (_klayman->getY() == 423) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList(0x004B3958);
+ }
+ } else if (_klaymanAtElevator) {
+ SetMessageHandler(&Scene2207::handleMessage2);
+ sendMessage(_asElevator, 0x2000, 347);
+ sendEntityMessage(_klayman, 0x1014, _asElevator);
+ sendMessage(_klayman, 0x2001, 0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+uint32 Scene2207::handleMessage2(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2002:
+ _elevatorSurfacePriority = param.asInteger();
+ break;
+ case 0x2004:
+ SetMessageHandler(&Scene2207::handleMessage);
+ sendMessage(_klayman, 0x2005, 0);
+ sendEntityMessage(_klayman, 0x1014, _asLever);
+ setMessageList(0x004B3920);
+ setRectList(0x004B3948);
+ break;
+ }
+ return messageResult;
+}
+
+static const uint32 kScene2208FileHashes1[] = {
+ 0x041023CB,
+ 0x041020CB,
+ 0x041026CB,
+ 0x04102ACB,
+ 0x041032CB,
+ 0x041002CB
+};
+
+static const uint32 kScene2208FileHashes2[] = {
+ 0x091206C9,
+ 0x091406C9,
+ 0x091806C9,
+ 0x090006C9,
+ 0x093006C9,
+ 0x095006C9
+};
+
+Scene2208::Scene2208(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _textResource(vm) {
+
+ SpriteResource spriteResource(_vm);
+ const char *textStart, *textEnd;
+
+ if (!getGlobalVar(0xC8C28808))
+ setGlobalVar(0xC8C28808, calcHash("stLineagex"));
+
+ _textResource.load(getGlobalVar(0xC8C28808));
+
+ textStart = _textResource.getString(getGlobalVar(0x48A68852), textEnd);
+ while (textStart < textEnd) {
+ _strings.push_back(textStart);
+ textStart += strlen(textStart) + 1;
+ }
+
+ _maxRowIndex = 8 + 10 * (3 - (getGlobalVar(0xC8C28808) == calcHash("stLineagex") ? 1 : 0));
+
+ _background = new Background(_vm, 0);
+ _background->createSurface(0, 640, 528);
+ _background->getSpriteResource().getPosition().y = 480;
+ addBackground(_background);
+
+ setPalette(0x08100289);
+ addEntity(_palette); // Why?
+
+ insertMouse435(0x0028D089, 40, 600);
+
+ createFontSurface();
+
+ _backgroundSurface = new BaseSurface(_vm, 0, 640, 480);
+ spriteResource.load2(0x08100289);
+ _backgroundSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0);
+
+ _topBackgroundSurface = new BaseSurface(_vm, 0, 640, 192);
+ spriteResource.load2(!getGlobalVar(0x4CE79018) ? kScene2208FileHashes1[getGlobalVar(0x48A68852) % 6] : getGlobalVar(0x4CE79018));
+ _topBackgroundSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0);
+
+ _bottomBackgroundSurface = new BaseSurface(_vm, 0, 640, 192);
+ spriteResource.load2(kScene2208FileHashes2[getGlobalVar(0x48A68852) % 6]);
+ _bottomBackgroundSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0);
+
+ SetUpdateHandler(&Scene2208::update);
+ SetMessageHandler(&Scene2208::handleMessage);
+
+ _visibleRowsCount = 10;
+
+ _newRowIndex = (int16)getGlobalVar(0x49C40058);
+ if (_newRowIndex + _visibleRowsCount > _maxRowIndex)
+ _newRowIndex = _maxRowIndex - _visibleRowsCount;
+ if (_newRowIndex < 6)
+ _newRowIndex = 0;
+
+ _rowScrollY = 0;
+
+ _backgroundScrollY = 48 * _newRowIndex;
+
+ _currRowIndex = _newRowIndex;
+
+ for (int16 rowIndex = 0; rowIndex < _visibleRowsCount; rowIndex++)
+ drawRow(_newRowIndex + rowIndex);
+
+ _background->getSurface()->getSysRect().y = _backgroundScrollY;
+
+ // TODO Screen.yOffset = _backgroundScrollY;
+ // TODO Scene2208_sub409080 (creates background Sprites via the text, doesn't seem to be used?)
+
+}
+
+Scene2208::~Scene2208() {
+ delete _fontSurface;
+ delete _backgroundSurface;
+ delete _topBackgroundSurface;
+ delete _bottomBackgroundSurface;
+}
+
+void Scene2208::update() {
+
+ int16 mouseY = _vm->getMouseY();
+
+ if (mouseY < 48) {
+ if (_currRowIndex > 0)
+ _newRowIndex = _currRowIndex - 1;
+ } else if (mouseY > 432) {
+ if (_currRowIndex < _maxRowIndex - _visibleRowsCount)
+ _newRowIndex = _currRowIndex + 1;
+ } else {
+ if (_currRowIndex > _newRowIndex)
+ _newRowIndex = _currRowIndex;
+ }
+
+ if (_currRowIndex < _newRowIndex) {
+ if (_rowScrollY == 0) {
+ drawRow(_currRowIndex + _visibleRowsCount);
+ }
+ _backgroundScrollY += 4;
+ _rowScrollY += 4;
+ if (_rowScrollY == 48) {
+ _rowScrollY = 0;
+ _currRowIndex++;
+ }
+ _background->getSurface()->getSysRect().y = _backgroundScrollY;
+ } else if (_currRowIndex > _newRowIndex || _rowScrollY > 0) {
+ if (_rowScrollY == 0) {
+ drawRow(_currRowIndex - 1);
+ _currRowIndex--;
+ }
+ _backgroundScrollY -= 4;
+ if (_rowScrollY == 0)
+ _rowScrollY = 48;
+ _rowScrollY -= 4;
+ _background->getSurface()->getSysRect().y = _backgroundScrollY;
+ }
+
+ // TODO Screen.yOffset = _backgroundScrollY;
+ Scene::update();
+
+}
+
+uint32 Scene2208::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x <= 40 || param.asPoint().x >= 600) {
+ leaveScene(0);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Scene2208::createFontSurface() {
+ DataResource fontData(_vm);
+ SpriteResource spriteResource(_vm);
+ fontData.load(calcHash("asRecFont"));
+ uint16 numRows = fontData.getPoint(calcHash("meNumRows")).x;
+ uint16 firstChar = fontData.getPoint(calcHash("meFirstChar")).x;
+ uint16 charWidth = fontData.getPoint(calcHash("meCharWidth")).x;
+ uint16 charHeight = fontData.getPoint(calcHash("meCharHeight")).x;
+ NPointArray *tracking = fontData.getPointArray(calcHash("meTracking"));
+ spriteResource.load2(0x0800090C);
+ _fontSurface = new FontSurface(_vm, tracking, numRows, firstChar, charWidth, charHeight);
+ _fontSurface->drawSpriteResourceEx(spriteResource, false, false, 0, 0);
+}
+
+void Scene2208::drawRow(int16 rowIndex) {
+ NDrawRect sourceRect;
+ int16 y = (rowIndex * 48) % 528;
+ if (rowIndex < 4) {
+ sourceRect.x = 0;
+ sourceRect.y = y;
+ sourceRect.width = 640;
+ sourceRect.height = 48;
+ _background->getSurface()->copyFrom(_topBackgroundSurface->getSurface(), 0, y, sourceRect, true);
+ } else if (rowIndex > _maxRowIndex - 5) {
+ sourceRect.x = 0;
+ sourceRect.y = (rowIndex - _maxRowIndex + 4) * 48;
+ sourceRect.width = 640;
+ sourceRect.height = 48;
+ _background->getSurface()->copyFrom(_bottomBackgroundSurface->getSurface(), 0, y, sourceRect, true);
+ } else {
+ rowIndex -= 4;
+ sourceRect.x = 0;
+ sourceRect.y = (rowIndex * 48) % 480;
+ sourceRect.width = 640;
+ sourceRect.height = 48;
+ _background->getSurface()->copyFrom(_backgroundSurface->getSurface(), 0, y, sourceRect, true);
+ if (rowIndex < (int)_strings.size()) {
+ const char *text = _strings[rowIndex];
+ // TODO/CHECKME: Use temporary string up to '{' character (see above)
+ _fontSurface->drawString(_background->getSurface(), 95, y, (const byte*)text);
+ }
+ }
+}
+
+static const int16 kScene2242XPositions[] = {
+ 68,
+ 158
+};
+
+static const uint32 kScene2242MessageListIds2[] = {
+ 0x004B3CB8,
+ 0x004B3CD8
+};
+
+static const uint32 kScene2242MessageListIds1[] = {
+ 0x004B3CF8,
+ 0x004B3D20
+};
+
+Scene2242::Scene2242(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _isKlaymanInLight(false) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2242::handleMessage);
+ SetUpdateHandler(&Scene2242::update);
+
+ if (getGlobalVar(0x4D080E54)) {
+ setBackground(0x11840E24);
+ setPalette(0x11840E24);
+ insertMouse433(0x40E20110);
+ setRectList(0x004B3DC8);
+ } else {
+ setBackground(0x25848E24);
+ setPalette(0x25848E24);
+ addEntity(_palette);
+ _palette->copyBasePalette(0, 256, 0);
+ _palette->addPalette(0x68033B1C, 0, 65, 0);
+ insertMouse433(0x48E20250);
+ setRectList(0x004B3E18);
+ }
+
+ _asTape = insertSprite<AsScene1201Tape>(this, 10, 1100, 464, 435, 0x9148A011);
+ _vm->_collisionMan->addSprite(_asTape);
+
+ if (which < 0) {
+ insertKlayman<KmScene2242>(200, 430);
+ setMessageList(0x004B3C18);
+ } else if (which == 1) {
+ insertKlayman<KmScene2242>(530, 430);
+ setMessageList(0x004B3D60);
+ } else if (which == 2) {
+ insertKlayman<KmScene2242>(kScene2242XPositions[!getGlobalVar(0x48A68852) ? 0 : 1], 430);
+ setMessageList(0x004B3D48);
+ if (getGlobalVar(0xC0418A02))
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmScene2242>(0, 430);
+ setMessageList(0x004B3C20);
+ }
+
+ _klayman->setSoundFlag(true);
+
+}
+
+Scene2242::~Scene2242() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+void Scene2242::update() {
+ if (!getGlobalVar(0x4D080E54)) {
+ if (_isKlaymanInLight && _klayman->getX() < 440) {
+ _palette->addBasePalette(0x68033B1C, 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ _isKlaymanInLight = false;
+ } else if (!_isKlaymanInLight && _klayman->getX() >= 440) {
+ _palette->addBasePalette(0x25848E24, 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ _isKlaymanInLight = true;
+ }
+ }
+ Scene::update();
+}
+
+uint32 Scene2242::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x800C6694) {
+ readClickedColumn();
+ }
+ break;
+ case 0x4826:
+ if (sender == _asTape) {
+ sendEntityMessage(_klayman, 0x1014, _asTape);
+ setMessageList(0x004B3D50);
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Scene2242::readClickedColumn() {
+ int index;
+ if (_mouseClickPos.x < 108) {
+ setGlobalVar(0xC8C28808, 0x04290188);
+ setGlobalVar(0x48A68852, 42);
+ setGlobalVar(0x4CE79018, calcHash("bgRecPanelStart1"));
+ index = 0;
+ } else {
+ setGlobalVar(0xC8C28808, 0x04290188);
+ setGlobalVar(0x48A68852, 43);
+ setGlobalVar(0x4CE79018, calcHash("bgRecPanelStart2"));
+ index = 1;
+ }
+ setGlobalVar(0x49C40058, (_mouseClickPos.y - 100) / 7);
+ if (ABS(_klayman->getX() - kScene2242XPositions[index]) < 133) {
+ setMessageList2(kScene2242MessageListIds1[index]);
+ } else {
+ setMessageList2(kScene2242MessageListIds2[index]);
+ }
+}
+
+static const int16 kHallOfRecordsKlaymanXPos[] = {
+ 68,
+ 157,
+ 246,
+ 335,
+ 424,
+ 513,
+ 602
+};
+
+static const uint32 kHallOfRecordsSceneMessageListIds2[] = {
+ 0x004B2978,
+ 0x004B2998,
+ 0x004B29B8,
+ 0x004B29D8,
+ 0x004B29F8,
+ 0x004B2A18,
+ 0x004B2A38
+};
+
+static const uint32 kHallOfRecordsSceneMessageListIds1[] = {
+ 0x004B2A58,
+ 0x004B2A80,
+ 0x004B2AA8,
+ 0x004B2AD0,
+ 0x004B2AF8,
+ 0x004B2B20,
+ 0x004B2B48
+};
+
+HallOfRecordsScene::HallOfRecordsScene(NeverhoodEngine *vm, Module *parentModule, int which, uint32 sceneInfo140Id)
+ : Scene(vm, parentModule, true) {
+
+ _sceneInfo140 = _vm->_staticData->getSceneInfo140Item(sceneInfo140Id);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&HallOfRecordsScene::handleMessage);
+ SetUpdateHandler(&Scene::update);
+
+ if (!getGlobalVar(0x4D080E54) && _sceneInfo140->bgFilename2) {
+ setRectList(0x004B2BF8);
+ setBackground(_sceneInfo140->bgFilename2);
+ setPalette(_sceneInfo140->bgFilename2);
+ insertMouse433(0x14320138);
+ } else {
+ setRectList(0x004B2BB8);
+ setBackground(_sceneInfo140->bgFilename1);
+ setPalette(_sceneInfo140->bgFilename1);
+ insertMouse433(0x63A40028);
+ }
+
+ if (which < 0) {
+ insertKlayman<KmHallOfRecords>(200, 430);
+ setMessageList(0x004B2900);
+ } else if (which == 1) {
+ insertKlayman<KmHallOfRecords>(640, 430);
+ setMessageList(0x004B2910);
+ } else if (which == 2) {
+ insertKlayman<KmHallOfRecords>(kHallOfRecordsKlaymanXPos[getGlobalVar(0x48A68852) - _sceneInfo140->xPosIndex], 430);
+ setMessageList(0x004B2B70);
+ if (getGlobalVar(0xC0418A02))
+ _klayman->setDoDeltaX(1);
+ } else {
+ insertKlayman<KmHallOfRecords>(0, 430);
+ setMessageList(0x004B2908);
+ }
+
+ _klayman->setSoundFlag(true);
+ _klayman->setKlaymanTable2();
+
+}
+
+HallOfRecordsScene::~HallOfRecordsScene() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+uint32 HallOfRecordsScene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x100D:
+ if (param.asInteger() == 0x800C6694) {
+ readClickedColumn();
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void HallOfRecordsScene::readClickedColumn() {
+ int16 index = (_mouseClickPos.x - 23) / 89;
+ if (index >= _sceneInfo140->count) {
+ setMessageList2(0x004B2920);
+ } else {
+ setGlobalVar(0x48A68852, _sceneInfo140->xPosIndex + index);
+ setGlobalVar(0x49C40058, (_mouseClickPos.y - 100) / 7);
+ setGlobalVar(0xC8C28808, _sceneInfo140->txFilename);
+ if (index == 0 && _sceneInfo140->bgFilename3) {
+ setGlobalVar(0x4CE79018, _sceneInfo140->bgFilename3);
+ } else {
+ setGlobalVar(0x4CE79018, 0);
+ }
+ if (ABS(_klayman->getX() - kHallOfRecordsKlaymanXPos[index]) < 133) {
+ setMessageList2(kHallOfRecordsSceneMessageListIds1[index]);
+ } else {
+ setMessageList2(kHallOfRecordsSceneMessageListIds2[index]);
+ }
+ }
+}
+
+static const int16 kScene2247XPositions[] = {
+ 513,
+ 602
+};
+
+static const uint32 kScene2247MessageListIds2[] = {
+ 0x004B54A0,
+ 0x004B54C0
+};
+
+static const uint32 kScene2247MessageListIds1[] = {
+ 0x004B54E0,
+ 0x004B5508
+};
+
+Scene2247::Scene2247(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ //DEBUG
+ setGlobalVar(0x4D080E54, 1);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2247::handleMessage);
+ SetUpdateHandler(&Scene::update);
+
+ if (getGlobalVar(0x4D080E54)) {
+ setRectList(0x004B5588);
+ setBackground(0x40339414);
+ setPalette(0x40339414);
+ insertMouse433(0x3941040B);
+ } else {
+ setRectList(0x004B55C8);
+ setBackground(0x071963E5);
+ setPalette(0x071963E5);
+ insertMouse433(0x14320138);
+ }
+
+ if (which < 0) {
+ insertKlayman<KmScene2247>(200, 430);
+ setMessageList(0x004B5428);
+ } else if (which == 1) {
+ insertKlayman<KmScene2247>(640, 430);
+ setMessageList(0x004B5438);
+ } else if (which == 2) {
+ insertKlayman<KmScene2247>(kScene2247XPositions[getGlobalVar(0xC8C28808) == 0x0008E486 ? 0 : 1], 430);
+ if (getGlobalVar(0xC0418A02))
+ _klayman->setDoDeltaX(1);
+ setMessageList(0x004B5530);
+ } else {
+ insertKlayman<KmScene2247>(0, 430);
+ setMessageList(0x004B5430);
+ }
+
+ _klayman->setSoundFlag(true);
+
+}
+
+Scene2247::~Scene2247() {
+ setGlobalVar(0xC0418A02, _klayman->isDoDeltaX() ? 1 : 0);
+}
+
+uint32 Scene2247::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ // TODO: Debug stuff
+ case 0x100D:
+ if (param.asInteger() == 0x800C6694) {
+ readClickedColumn();
+ }
+ break;
+ }
+ return messageResult;
+}
+
+void Scene2247::readClickedColumn() {
+ int index;
+ if (_mouseClickPos.x < 553) {
+ setGlobalVar(0xC8C28808, 0x0008E486);
+ setGlobalVar(0x4CE79018, calcHash("bgFatherHeader"));
+ index = 0;
+ } else {
+ setGlobalVar(0xC8C28808, 0x03086004);
+ setGlobalVar(0x4CE79018, calcHash("bgQuaterHeader"));
+ index = 1;
+ }
+ setGlobalVar(0x48A68852, 0);
+ setGlobalVar(0x49C40058, (_mouseClickPos.y - 100) / 7);
+ if (ABS(_klayman->getX() - kScene2247XPositions[index]) < 133) {
+ setMessageList2(kScene2247MessageListIds1[index]);
+ } else {
+ setMessageList2(kScene2247MessageListIds2[index]);
+ }
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2200.h b/engines/neverhood/module2200.h
new file mode 100644
index 0000000000..76a59509f2
--- /dev/null
+++ b/engines/neverhood/module2200.h
@@ -0,0 +1,403 @@
+/* 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_MODULE2200_H
+#define NEVERHOOD_MODULE2200_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module1000.h"
+#include "neverhood/graphics.h"
+
+namespace Neverhood {
+
+// Module2200
+
+class Module2200 : public Module {
+public:
+ Module2200(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2200();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene2201
+
+static const NPoint kClass444Points[] = {
+ {305, 305},
+ {321, 305},
+ {336, 305},
+ {305, 319},
+ {321, 319},
+ {336, 319},
+ {305, 332},
+ {321, 332},
+ {336, 333}
+};
+
+static const uint32 kClass444FileHashes[] = {
+ 0x88134A44,
+ 0xAA124340,
+ 0xB8124602,
+ 0xA902464C,
+ 0x890A4244,
+ 0xA8124642,
+ 0xB812C204,
+ 0x381A4A4C
+};
+
+class AsScene2201CeilingFan : public AnimatedSprite {
+public:
+ AsScene2201CeilingFan(NeverhoodEngine *vm);
+};
+
+class AsScene2201Door : public AnimatedSprite {
+public:
+ AsScene2201Door(NeverhoodEngine *vm, Klayman *klayman, Sprite *doorLightSprite, bool flag1);
+protected:
+ SoundResource _soundResource;
+ Klayman *_klayman;
+ Sprite *_doorLightSprite;
+ bool _doorOpen;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stOpenDoor();
+ void stCloseDoor();
+};
+
+class Class444 : public StaticSprite {
+public:
+ Class444(NeverhoodEngine *vm, int pointIndex, int spriteIndex);
+};
+
+class Scene2201 : public Scene {
+public:
+ Scene2201(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2201();
+protected:
+ NRect _rect1;
+ NRect _rect2;
+ Sprite *_doorLightSprite;
+ Sprite *_asDoor;
+ Sprite *_ssDoorButton;
+ Sprite *_asTape;
+ bool _soundFlag;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene2202PuzzleTile : public StaticSprite {
+public:
+ SsScene2202PuzzleTile(NeverhoodEngine *vm, Scene *parentScene, int16 tileIndex, int16 value);
+protected:
+ Scene *_parentScene;
+ int16 _value;
+ int16 _tileIndex;
+ int16 _newX, _newY;
+ int16 _xDelta, _yDelta;
+ int16 _xIncr;
+ int16 _yIncr;
+ int16 _errValue;
+ int16 _counter;
+ int16 _xFlagPos;
+ bool _counterDirection;
+ bool _isMoving;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suMoveTileX();
+ void suMoveTileY();
+ void moveTile(int16 newTileIndex);
+ void stopMoving();
+};
+
+class Scene2202 : public Scene {
+public:
+ Scene2202(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2202();
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ Sprite *_movingTileSprite;
+ Sprite *_doneMovingTileSprite;
+ bool _isTileMoving;
+ int16 _movingTileIndex;
+ int _surfacePriority;
+ bool _leaveScene;
+ bool _isSolved;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ int16 getFreeTileIndex(int16 index);
+ bool testIsSolved();
+};
+
+class Class545 : public AnimatedSprite {
+public:
+ Class545(NeverhoodEngine *vm, Scene *parentScene, int index, int surfacePriority, int16 x, int16 y);
+protected:
+ Scene *_parentScene;
+ int _index;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene2203Door : public AnimatedSprite {
+public:
+ AsScene2203Door(NeverhoodEngine *vm, Scene *parentScene, uint index);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ Sprite *_otherDoor;
+ uint _index;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void openDoor();
+ void closeDoor();
+};
+
+class Scene2203 : public Scene {
+public:
+ Scene2203(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2203();
+protected:
+ Sprite *_asLeftDoor;
+ Sprite *_asRightDoor;
+ Sprite *_ssSmallLeftDoor;
+ Sprite *_ssSmallRightDoor;
+ Sprite *_asTape;
+ Sprite *_class545;
+ NRect _leftDoorClipRect;
+ NRect _rightDoorClipRect;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene2205DoorFrame : public StaticSprite {
+public:
+ SsScene2205DoorFrame(NeverhoodEngine *vm);
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene2205 : public Scene {
+public:
+ Scene2205(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Class426 *_ssLightSwitch;
+ Sprite *_ssDoorFrame;
+ bool _isKlaymanInLight;
+ bool _isLightOn;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Class603 : public StaticSprite {
+public:
+ Class603(NeverhoodEngine *vm, uint32 fileHash);
+protected:
+ int _index;
+ SoundResource _soundResource;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate481E60();
+ void spriteUpdate481E90();
+};
+
+class Class604 : public StaticSprite {
+public:
+ Class604(NeverhoodEngine *vm, uint32 fileHash);
+protected:
+ int16 _yDelta;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void spriteUpdate482020();
+};
+
+class Class607 : public StaticSprite {
+public:
+ Class607(NeverhoodEngine *vm, Scene *parentScene, int surfacePriority, uint32 fileHash);
+protected:
+ Scene *_parentScene;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene2206 : public Scene {
+public:
+ Scene2206(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2206();
+protected:
+ Sprite *_sprite1;
+ Sprite *_sprite2;
+ Sprite *_sprite3;
+ Sprite *_sprite4;
+ Sprite *_sprite5;
+ Sprite *_class604;
+ Sprite *_class607;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void sub481950();
+ void sub4819D0();
+ void sub481B00();
+};
+
+class AsScene2207Elevator : public AnimatedSprite {
+public:
+ AsScene2207Elevator(NeverhoodEngine *vm, Scene *parentScene);
+ ~AsScene2207Elevator();
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ NPointArray *_pointArray;
+ int16 _pointIndex;
+ int16 _destPointIndex, _destPointIndexDelta;
+ bool _isMoving;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suSetPosition();
+ void moveToY(int16 y);
+};
+
+class AsScene2207Lever : public AnimatedSprite {
+public:
+ AsScene2207Lever(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y, int doDeltaX);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stLeverDown();
+ void stLeverDownEvent();
+ void stLeverUp();
+ void stLeverUpEvent();
+};
+
+class AsScene2207WallRobotAnimation : public AnimatedSprite {
+public:
+ AsScene2207WallRobotAnimation(NeverhoodEngine *vm, Scene *parentScene);
+ ~AsScene2207WallRobotAnimation();
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ SoundResource _soundResource4;
+ bool _idle;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stStartAnimation();
+ void stStopAnimation();
+ void cbStopAnimation();
+};
+
+class AsScene2207WallCannonAnimation : public AnimatedSprite {
+public:
+ AsScene2207WallCannonAnimation(NeverhoodEngine *vm);
+protected:
+ bool _idle;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void stStartAnimation();
+ void stStopAnimation();
+ void cbStopAnimation();
+};
+
+class SsScene2207Symbol : public StaticSprite {
+public:
+ SsScene2207Symbol(NeverhoodEngine *vm, uint32 fileHash, int index);
+};
+
+class Scene2207 : public Scene {
+public:
+ Scene2207(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ Sprite *_asElevator;
+ Sprite *_ssMaskPart1;
+ Sprite *_ssMaskPart2;
+ Sprite *_ssMaskPart3;
+ Sprite *_asTape;
+ Sprite *_asLever;
+ Sprite *_asWallRobotAnimation;
+ Sprite *_asWallCannonAnimation;
+ Sprite *_ssButton;
+ int _elevatorSurfacePriority;
+ bool _klaymanAtElevator;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage2(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene2208 : public Scene {
+public:
+ Scene2208(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2208();
+protected:
+ FontSurface *_fontSurface;
+ BaseSurface *_backgroundSurface;
+ BaseSurface *_topBackgroundSurface;
+ BaseSurface *_bottomBackgroundSurface;
+ TextResource _textResource;
+ int16 _backgroundScrollY;
+ int16 _newRowIndex;
+ int16 _currRowIndex;
+ int16 _rowScrollY;
+ int16 _maxRowIndex;
+ int16 _visibleRowsCount;
+ Common::Array<const char*> _strings; // TODO: Move to TextResource
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createFontSurface();
+ void drawRow(int16 rowIndex);
+};
+
+class Scene2242 : public Scene {
+public:
+ Scene2242(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2242();
+protected:
+ Sprite *_asTape;
+ bool _isKlaymanInLight;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void readClickedColumn();
+};
+
+class HallOfRecordsScene : public Scene {
+public:
+ HallOfRecordsScene(NeverhoodEngine *vm, Module *parentModule, int which, uint32 sceneInfo140Id);
+ ~HallOfRecordsScene();
+protected:
+ SceneInfo140 *_sceneInfo140;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void readClickedColumn();
+};
+
+class Scene2247 : public Scene {
+public:
+ Scene2247(NeverhoodEngine *vm, Module *parentModule, int which);
+ ~Scene2247();
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void readClickedColumn();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2200_H */
diff --git a/engines/neverhood/module2300.cpp b/engines/neverhood/module2300.cpp
new file mode 100644
index 0000000000..1513f7ba40
--- /dev/null
+++ b/engines/neverhood/module2300.cpp
@@ -0,0 +1,181 @@
+/* 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/module2300.h"
+
+namespace Neverhood {
+
+Module2300::Module2300(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule), _volume(0) {
+
+ // TODO Sound1ChList_addSoundResources(0x1A214010, dword_4B6938, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B6938, true, 50, 600, 10, 10, 150);
+
+ _flag = getGlobalVar(0x10938830) == 0;
+
+ if (_flag) {
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, 0);
+ // TODO Sound1ChList_playLooping(0x90F0D1C3);
+ } else {
+ // TODO Sound1ChList_setSoundValues(0x90F0D1C3, false, 0, 0, 0, 0);
+ }
+
+ // TODO Sound1ChList_sub_407C70(0x1A214010, 0x48498E46, 0x50399F64, 0);
+ // TODO Sound1ChList_sub_407C70(0x1A214010, 0x41861371, 0x43A2507F, 0);
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 1) {
+ createScene(2, 0);
+ } else if (which == 2) {
+ createScene(3, 0);
+ } else if (which == 3) {
+ createScene(4, -1);
+ } else if (which == 4) {
+ createScene(1, 3);
+ } else {
+ createScene(0, 1);
+ }
+
+}
+
+Module2300::~Module2300() {
+ // TODO Sound1ChList_sub_407A50(0x1A214010);
+}
+
+void Module2300::createScene(int sceneNum, int which) {
+ debug("Module2300::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ createNavigationScene(0x004B67B8, which);
+ break;
+ case 1:
+ createNavigationScene(0x004B67E8, which);
+ if (_flag) {
+ _volume = 15;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, 15);
+ }
+ break;
+ case 2:
+ createNavigationScene(0x004B6878, which);
+ break;
+ case 3:
+ if (getGlobalVar(0x10938830)) {
+ createNavigationScene(0x004B68F0, which);
+ } else {
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, _volume);
+ createNavigationScene(0x004B68A8, which);
+ if (_flag) {
+ _volume = 87;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, 87);
+ }
+ }
+ break;
+ case 4:
+ // TODO Sound1ChList_sub_4080B0(true);
+ createSmackerScene(0x20080A0B, true, true, false);
+ break;
+ }
+ SetUpdateHandler(&Module2300::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module2300::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(1, 4);
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 1:
+ if (_moduleResult == 1) {
+ createScene(0, 0);
+ } else if (_moduleResult == 2) {
+ createScene(2, 1);
+ } else if (_moduleResult == 3) {
+ createScene(1, 3);
+ } else if (_moduleResult == 4) {
+ createScene(3, 1);
+ } else if (_moduleResult == 5) {
+ leaveModule(3);
+ } else {
+ leaveModule(4);
+ }
+ break;
+ case 2:
+ if (_moduleResult == 1) {
+ leaveModule(3);
+ } else {
+ createScene(1, 5);
+ }
+ break;
+ case 3:
+ if (_moduleResult == 1) {
+ leaveModule(2);
+ } else {
+ createScene(1, 1);
+ }
+ break;
+ case 4:
+ // TODO Sound1ChList_sub_4080B0(false);
+ createScene(1, 2);
+ break;
+ }
+ } else {
+ switch (_vm->gameState().sceneNum) {
+ case 1:
+#if 0 // TODO
+ NavigationScene *navigationScene = (NavigationScene*)_childObject;
+ if (_flag && navigationScene->getSoundFlag1() && navigationScene->getNavigationIndex() == 4 &&
+ navigationScene->getSmackerPlayer() && navigationScene->getSmackerPlayer()->getFrameNumber() % 2) {
+ _volume++;
+ Sound1ChList_setVolume(0x90F0D1C3, _volume);
+ }
+#endif
+#if 0 // TODO
+ if (navigationScene->getSoundFlag1() && navigationScene->getNavigationIndex() == 0 &&
+ navigationScene->getSmackerPlayer() && navigationScene->getSmackerPlayer()->getFrameNumber() == 50) {
+ Sound1ChList_sub_407C70(0x1A214010, 0x48498E46, 0x50399F64);
+ Sound1ChList_setVolume(0x48498E46, 70);
+ Sound1ChList_setVolume(0x50399F64, 70);
+ }
+#endif
+ break;
+ case 3:
+#if 0 // TODO
+ NavigationScene *navigationScene = (NavigationScene*)_childObject;
+ if (_flag && navigationScene->getSoundFlag1() && navigationScene->getSmackerPlayer() &&
+ navigationScene->getSmackerPlayer()->getFrameNumber() % 2) {
+ _volume--;
+ Sound1ChList_setVolume(0x90F0D1C3, _volume);
+ }
+#endif
+ break;
+ }
+ }
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2300.h b/engines/neverhood/module2300.h
new file mode 100644
index 0000000000..722255978c
--- /dev/null
+++ b/engines/neverhood/module2300.h
@@ -0,0 +1,47 @@
+/* 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_MODULE2300_H
+#define NEVERHOOD_MODULE2300_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module2300
+
+class Module2300 : public Module {
+public:
+ Module2300(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2300();
+protected:
+ bool _flag;
+ int _volume;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2300_H */
diff --git a/engines/neverhood/module2600.cpp b/engines/neverhood/module2600.cpp
new file mode 100644
index 0000000000..5823e4dcb2
--- /dev/null
+++ b/engines/neverhood/module2600.cpp
@@ -0,0 +1,333 @@
+/* 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/module2600.h"
+
+namespace Neverhood {
+
+Module2600::Module2600(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule) {
+
+ if (which < 0) {
+ createScene(_vm->gameState().sceneNum, -1);
+ } else if (which == 1) {
+ createScene(4, 1);
+ } else {
+ createScene(0, 1);
+ }
+
+ // TODO Sound1ChList_addSoundResources(0x40271018, dword_4B87E8, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B87E8, true, 50, 600, 5, 150);
+ // TODO Sound1ChList_sub_407C70(0x40271018, 0x41861371, 0x43A2507F);
+
+}
+
+Module2600::~Module2600() {
+ // TODO Sound1ChList_sub_407A50(0x40271018);
+}
+
+void Module2600::createScene(int sceneNum, int which) {
+ debug("Module2600::createScene(%d, %d)", sceneNum, which);
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ createNavigationScene(0x004B8608, which);
+ break;
+ case 1:
+ createNavigationScene(0x004B8638, which);
+ break;
+ case 2:
+ createNavigationScene(0x004B86C8, which);
+ break;
+ case 3:
+ if (getGlobalVar(0x0A310817)) {
+ createNavigationScene(0x004B8758, which);
+ } else {
+ createNavigationScene(0x004B86F8, which);
+ }
+ break;
+ case 4:
+ createNavigationScene(0x004B87B8, which);
+ break;
+ case 6:
+ createNavigationScene(0x004B8698, which);
+ break;
+ case 7:
+ // TODO Sound1ChList_sub_407A50(0x40271018);
+ createSmackerScene(0x30090001, true, true, false);
+ break;
+ case 8:
+ _childObject = new Scene2609(_vm, this, which);
+ break;
+ case 1002:
+ if (getGlobalVar(0x40040831) == 1) {
+ createSmackerScene(0x018C0404, true, true, false);
+ } else if (getGlobalVar(0x40040831) == 2) {
+ createSmackerScene(0x018C0407, true, true, false);
+ } else {
+ createSmackerScene(0x818C0405, true, true, false);
+ }
+ if (getGlobalVar(0x40040831) >= 2) {
+ setGlobalVar(0x40040831, 0);
+ } else {
+ incGlobalVar(0x40040831, +1);
+ }
+ break;
+ case 1003:
+ createSmackerScene(0x001C0007, true, true, false);
+ break;
+ case 1006:
+ if (getGlobalVar(0x4E0BE910)) {
+ createSmackerScene(0x049A1181, true, true, false);
+ } else {
+ createSmackerScene(0x04981181, true, true, false);
+ }
+ break;
+ case 1008:
+ if (getGlobalVar(0x4E0BE910)) {
+ createSmackerScene(0x42B80941, true, true, false);
+ } else {
+ createSmackerScene(0x42980941, true, true, false);
+ }
+ break;
+ }
+ SetUpdateHandler(&Module2600::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module2600::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ if (_moduleResult == 1) {
+ createScene(1, 3);
+ } else {
+ leaveModule(0);
+ }
+ break;
+ case 1:
+ if (_moduleResult == 0) {
+ createScene(6, 0);
+ } else if (_moduleResult == 1) {
+ createScene(0, 0);
+ } else if (_moduleResult == 2) {
+ createScene(2, 1);
+ } else if (_moduleResult == 3) {
+ createScene(3, 0);
+ }
+ break;
+ case 2:
+ if (_moduleResult == 0) {
+ createScene(1, 0);
+ } else if (_moduleResult == 1) {
+ createScene(1002, -1);
+ }
+ break;
+ case 3:
+ if (_moduleResult == 0) {
+ if (getGlobalVar(0x0A310817)) {
+ createScene(4, 0);
+ } else {
+ createScene(1003, -1);
+ }
+ } else if (_moduleResult == 2) {
+ createScene(1, 1);
+ } else if (_moduleResult == 3) {
+ if (getGlobalVar(0x0A310817)) {
+ createScene(4, 0);
+ } else {
+ setGlobalVar(0x0A310817, 1);
+ createScene(7, -1);
+ }
+ }
+ break;
+ case 4:
+ if (_moduleResult == 0) {
+ leaveModule(1);
+ } else {
+ createScene(3, 1);
+ }
+ break;
+ case 6:
+ if (_moduleResult == 0) {
+ createScene(1006, -1);
+ } else if (_moduleResult == 1) {
+ createScene(1, 2);
+ }
+ break;
+ case 7:
+ leaveModule(0);
+ break;
+ case 8:
+ createScene(1008, -1);
+ break;
+ case 1002:
+ createScene(2, 1);
+ break;
+ case 1003:
+ createScene(3, 0);
+ break;
+ case 1006:
+ createScene(8, -1);
+ break;
+ case 1008:
+ createScene(6, 0);
+ break;
+ }
+ }
+}
+
+SsScene2609Button::SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene)
+ : StaticSprite(vm, 1400), _soundResource1(vm), _soundResource2(vm),
+ _soundResource3(vm), _soundResource4(vm), _parentScene(parentScene),
+ _countdown(0) {
+
+ _spriteResource.load2(0x825A6923);
+ createSurface(400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ if (!getGlobalVar(0x4E0BE910))
+ setVisible(false);
+
+ _drawRect.set(0, 0, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _deltaRect = _drawRect;
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ processDelta();
+ _needRefresh = true;
+
+ _soundResource1.load(0x10267160);
+ _soundResource2.load(0x7027FD64);
+ _soundResource3.load(0x44043000);
+ _soundResource4.load(0x44045000);
+
+ SetUpdateHandler(&SsScene2609Button::update);
+ SetMessageHandler(&SsScene2609Button::handleMessage);
+
+}
+
+void SsScene2609Button::update() {
+ StaticSprite::update();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ if (getGlobalVar(0x4E0BE910)) {
+ setGlobalVar(0x4E0BE910, 0);
+ sendMessage(_parentScene, 0x2001, 0);
+ } else {
+ setGlobalVar(0x4E0BE910, 1);
+ sendMessage(_parentScene, 0x2002, 0);
+ }
+ }
+}
+
+uint32 SsScene2609Button::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_countdown == 0) {
+ sendMessage(_parentScene, 0x2000, 0);
+ if (getGlobalVar(0x4E0BE910)) {
+ setVisible(false);
+ _soundResource4.play();
+ _soundResource2.play();
+ _countdown = 12;
+ } else {
+ setVisible(true);
+ _soundResource3.play();
+ _soundResource1.play();
+ _countdown = 96;
+ }
+ }
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+AsScene2609Water::AsScene2609Water(NeverhoodEngine *vm)
+ : AnimatedSprite(vm, 1000) {
+
+ _x = 240;
+ _y = 420;
+ setDoDeltaX(1);
+ createSurface1(0x9C210C90, 1200);
+ setClipRect(260, 260, 400, 368);
+ // TODO Sound1ChList_addSoundResource(0xDC2769B0, true);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene2609Water::handleMessage);
+ if (getGlobalVar(0x4E0BE910))
+ sendMessage(this, 0x2002, 0);
+}
+
+uint32 AsScene2609Water::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2001:
+ stopAnimation();
+ setVisible(false);
+ // TODO Sound1ChList_stop(0xDC2769B0);
+ break;
+ case 0x2002:
+ setFileHash(0x9C210C90, 0, -1);
+ setVisible(true);
+ // TODO Sound1ChList_playLooping(0xDC2769B0);
+ break;
+ }
+ return messageResult;
+}
+
+Scene2609::Scene2609(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _isBusy(false) {
+
+ _surfaceFlag = true;
+ setBackground(0x51409A16);
+ setPalette(0x51409A16);
+ _asWater = insertSprite<AsScene2609Water>();
+ _ssButton = insertSprite<SsScene2609Button>(this);
+ _vm->_collisionMan->addSprite(_ssButton);
+ insertMouse435(0x09A1251C, 20, 620);
+ insertStaticSprite(0x02138002, 1200);
+ insertStaticSprite(0x825E2827, 1200);
+ SetMessageHandler(&Scene2609::handleMessage);
+ SetUpdateHandler(&Scene::update);
+}
+
+uint32 Scene2609::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if ((param.asPoint().x <= 20 || param.asPoint().x >= 620) && !_isBusy)
+ leaveScene(0);
+ break;
+ case 0x2000:
+ _isBusy = true;
+ break;
+ case 0x2001:
+ _isBusy = false;
+ sendMessage(_asWater, 0x2001, 0);
+ break;
+ case 0x2002:
+ _isBusy = false;
+ sendMessage(_asWater, 0x2002, 0);
+ break;
+ }
+ return 0;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2600.h b/engines/neverhood/module2600.h
new file mode 100644
index 0000000000..d6580a6c7a
--- /dev/null
+++ b/engines/neverhood/module2600.h
@@ -0,0 +1,76 @@
+/* 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_MODULE2600_H
+#define NEVERHOOD_MODULE2600_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module2600
+
+class Module2600 : public Module {
+public:
+ Module2600(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2600();
+protected:
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+class SsScene2609Button : public StaticSprite {
+public:
+ SsScene2609Button(NeverhoodEngine *vm, Scene *parentScene);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ SoundResource _soundResource4;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene2609Water : public AnimatedSprite {
+public:
+ AsScene2609Water(NeverhoodEngine *vm);
+protected:
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene2609 : public Scene {
+public:
+ Scene2609(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ bool _isBusy;
+ Sprite *_asWater;
+ Sprite *_ssButton;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2600_H */
diff --git a/engines/neverhood/module2700.cpp b/engines/neverhood/module2700.cpp
new file mode 100644
index 0000000000..096e33546e
--- /dev/null
+++ b/engines/neverhood/module2700.cpp
@@ -0,0 +1,1038 @@
+/* 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/module2700.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/module1000.h"
+
+namespace Neverhood {
+
+static const NRect kScene2710ClipRect = NRect(0, 0, 626, 480);
+
+static const uint32 kScene2710StaticSprites[] = {
+ 0x0D2016C0,
+ 0
+};
+
+static const NRect kScene2711ClipRect = NRect(0, 0, 521, 480);
+
+static const uint32 kScene2711FileHashes1[] = {
+ 0,
+ 0x100801A1,
+ 0x201081A0,
+ 0x006800A4,
+ 0x40390120,
+ 0x000001B1,
+ 0x001000A1,
+ 0
+};
+
+static const uint32 kScene2711FileHashes2[] = {
+ 0,
+ 0x40403308,
+ 0x71403168,
+ 0x80423928,
+ 0x224131A8,
+ 0x50401328,
+ 0x70423328,
+ 0
+};
+
+static const uint32 kScene2711FileHashes3[] = {
+ 0,
+ 0x1088A021,
+ 0x108120E5,
+ 0x18A02321,
+ 0x148221A9,
+ 0x10082061,
+ 0x188820E1,
+ 0
+};
+
+static const NRect kScene2724ClipRect = NRect(0, 141, 640, 480);
+
+static const uint32 kScene2724StaticSprites[] = {
+ 0xC20D00A5,
+ 0
+};
+
+static const NRect kScene2725ClipRect = NRect(0, 0, 640, 413);
+
+static const uint32 kScene2725StaticSprites[] = {
+ 0xC20E00A5,
+ 0
+};
+
+Module2700::Module2700(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule), _soundResource1(vm), _soundResource2(vm),
+ _soundResource3(vm), _soundResource4(vm), _soundIndex(0), _flag1(false) {
+
+ // TODO Music18hList_add(0x42212411, 0x04020210);
+ // TODO Music18hList_play(0x04020210, 24, 2, 1);
+ SetMessageHandler(&Module2700::handleMessage);
+
+
+ if (which < 0) {
+ which = _vm->gameState().which;
+ if (_vm->gameState().sceneNum == 0 || _vm->gameState().sceneNum == 30 || _vm->gameState().sceneNum == 31)
+ which = -1;
+ createScene(_vm->gameState().sceneNum, which);
+ } else {
+ createScene(0, 0);
+ }
+
+ _soundResource1.load(0x00880CCC);
+ _soundResource2.load(0x00880CC0);
+ _soundResource3.load(0x00880CCC);
+ _soundResource4.load(0x00880CC0);
+
+}
+
+Module2700::~Module2700() {
+ // TODO Sound1ChList_sub_407A50(0x42212411);
+}
+
+void Module2700::createScene(int sceneNum, int which) {
+ debug("Module2700::createScene(%d, %d)", sceneNum, which);
+ if (sceneNum != 30 && sceneNum != 31)
+ _vm->gameState().which = which;
+ _vm->gameState().sceneNum = sceneNum;
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ _childObject = new Scene2701(_vm, this, which);
+ break;
+ case 1:
+ _childObject = new Scene2702(_vm, this, which);
+ break;
+ case 2:
+ if (which == 6 || which == 7)
+ createScene2703(which, 0x004B1710);
+ else if (which == 4 || which == 5)
+ createScene2703(which, 0x004B1738);
+ else if (which == 2 || which == 3)
+ createScene2703(which, 0x004B1760);
+ else
+ createScene2703(which, 0x004B1788);
+ break;
+ case 3:
+ createScene2704(which, 0x004B17B0, 150);
+ break;
+ case 4:
+ createScene2704(which, 0x004B17D8, 150);
+ break;
+ case 5:
+ if (which >= 4) {
+ _childObject = new Scene2706(_vm, this, which);
+ } else if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1828, 150);
+ } else {
+ createScene2704(which, 0x004B1800, 150);
+ }
+ break;
+ case 6:
+ createScene2704(which, 0x004B1850, 150);
+ break;
+ case 7:
+ if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1878, 150);
+ } else {
+ createScene2704(which, 0x004B18A0, 150);
+ }
+ break;
+ case 8:
+ if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B18C8, 150);
+ } else {
+ createScene2704(which, 0x004B18F0, 150);
+ }
+ break;
+ case 9:
+ createScene2704(which, 0x004B1918, 150, kScene2710StaticSprites, &kScene2710ClipRect);
+ break;
+ case 10:
+ // TODO _vm->gameModule()->initScene2808Vars2();
+ _scene2711StaticSprites[0] = kScene2711FileHashes1[getSubVar(0x40005834, 2)];
+ _scene2711StaticSprites[1] = kScene2711FileHashes2[getSubVar(0x40005834, 1)];
+ _scene2711StaticSprites[2] = kScene2711FileHashes3[getSubVar(0x40005834, 0)];
+ _scene2711StaticSprites[3] = 0x0261282E;
+ _scene2711StaticSprites[4] = 0x9608E5A0;
+ _scene2711StaticSprites[5] = 0;
+ createScene2704(which, 0x004B1950, 150, _scene2711StaticSprites, &kScene2711ClipRect);
+ break;
+ case 11:
+ createScene2704(which, 0x004B19E0, 150);
+ break;
+ case 12:
+ createScene2704(which, 0x004B1A08, 150);
+ break;
+ case 13:
+ createScene2704(which, 0x004B1A30, 150);
+ break;
+ case 14:
+ if (which == 4 || which == 5) {
+ createScene2704(which, 0x004B1A58, 150);
+ } else if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1A80, 150);
+ } else {
+ createScene2704(which, 0x004B1AA8, 150);
+ }
+ break;
+ case 15:
+ if (which == 4 || which == 5) {
+ createScene2704(which, 0x004B1AD0, 150);
+ } else if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1AF8, 150);
+ } else {
+ createScene2704(which, 0x004B1B20, 150);
+ }
+ break;
+ case 16:
+ if (which == 4 || which == 5) {
+ createScene2704(which, 0x004B1B48, 150);
+ } else if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1B70, 150);
+ } else {
+ createScene2704(which, 0x004B1B98, 150);
+ }
+ break;
+ case 17:
+ if (which == 4 || which == 5) {
+ createScene2704(which, 0x004B1BC0, 150);
+ } else if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1BE8, 150);
+ } else {
+ createScene2704(which, 0x004B1C10, 150);
+ }
+ break;
+ case 18:
+ if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1C38, 150);
+ } else {
+ createScene2704(which, 0x004B1C60, 150);
+ }
+ break;
+ case 19:
+ if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1CB0, 150);
+ } else {
+ createScene2704(which, 0x004B1C88, 150);
+ }
+ break;
+ case 20:
+ if (which == 2 || which == 3) {
+ createScene2704(which, 0x004B1CD8, 150);
+ } else {
+ createScene2704(which, 0x004B1D00, 150);
+ }
+ break;
+ case 21:
+ createScene2704(which, 0x004B1D28, 150);
+ break;
+ case 22:
+ createScene2704(which, 0x004B1D50, 150);
+ break;
+ case 23:
+ createScene2704(which, 0x004B1D78, 150, kScene2724StaticSprites, &kScene2724ClipRect);
+ break;
+ case 24:
+ createScene2704(which, 0x004B1DB0, 150, kScene2725StaticSprites, &kScene2725ClipRect);
+ break;
+ case 25:
+ createScene2704(which, 0x004B1DE8, 150);
+ break;
+ case 26:
+ createScene2704(which, 0x004B1E10, 150);
+ break;
+ case 27:
+ createScene2704(which, 0x004B1E38, 150);
+ break;
+ case 28:
+ createScene2704(which, 0x004B1E60, 150);
+ break;
+ case 30:
+ _childObject = new Class152(_vm, this, 0x09507248, 0x0724C09D);
+ break;
+ case 31:
+//TODO _childObject = new Scene2732(_vm, this, which);
+ break;
+ }
+ SetUpdateHandler(&Module2700::updateScene);
+ _childObject->handleUpdate();
+}
+
+#define SceneLinkIf(moduleResult, sceneNum, which) \
+ if (_moduleResult == moduleResult) { createScene(sceneNum, which); break; }
+
+void Module2700::updateScene() {
+ if (!updateChild()) {
+
+ debug("sceneNum = %d; _moduleResult = %d", _vm->gameState().sceneNum, _moduleResult);
+
+ switch (_vm->gameState().sceneNum) {
+ case 0:
+ SceneLinkIf(1, 1, 0);
+ leaveModule(0);
+ break;
+ case 1:
+ SceneLinkIf(1, 14, 1);
+ SceneLinkIf(2, 2, 2);
+ SceneLinkIf(3, 14, 3);
+ SceneLinkIf(4, 2, 6);
+ SceneLinkIf(5, 2, 4);
+ createScene(0, 1);
+ break;
+ case 2:
+ SceneLinkIf(1, 5, 0);
+ SceneLinkIf(2, 1, 2);
+ SceneLinkIf(3, 5, 2);
+ SceneLinkIf(4, 1, 5);
+ SceneLinkIf(5, 5, 4);
+ SceneLinkIf(6, 1, 4);
+ SceneLinkIf(7, 11, 0);
+ createScene(3, 0);
+ break;
+ case 3:
+ createScene(2, 0);
+ break;
+ case 4:
+ SceneLinkIf(1, 7, 2);
+ createScene(5, 5);
+ break;
+ case 5:
+ SceneLinkIf(1, 6, 0);
+ SceneLinkIf(2, 2, 3);
+ SceneLinkIf(3, 8, 2);
+ SceneLinkIf(4, 2, 5);
+ SceneLinkIf(5, 4, 0);
+ SceneLinkIf(6, 7, 0);
+ createScene(2, 1);
+ break;
+ case 6:
+ SceneLinkIf(1, 8, 0);
+ createScene(5, 1);
+ break;
+ case 7:
+ SceneLinkIf(1, 8, 3);
+ SceneLinkIf(2, 4, 1);
+ SceneLinkIf(3, 9, 0);
+ createScene(5, 6);
+ break;
+ case 8:
+ SceneLinkIf(1, 10, 0);
+ SceneLinkIf(2, 5, 3);
+ SceneLinkIf(3, 7, 1);
+ createScene(6, 1);
+ break;
+ case 9:
+ SceneLinkIf(1, 10, 1);
+ createScene(7, 3);
+ break;
+ case 10:
+ SceneLinkIf(1, 9, 1);
+ createScene(8, 1);
+ break;
+ case 11:
+ SceneLinkIf(1, 12, 0);
+ createScene(2, 7);
+ break;
+ case 12:
+ SceneLinkIf(1, 13, 0);
+ createScene(11, 1);
+ break;
+ case 13:
+ SceneLinkIf(1, 30, 0);
+ createScene(12, 1);
+ break;
+ case 14:
+ SceneLinkIf(1, 1, 1);
+ SceneLinkIf(2, 15, 3);
+ SceneLinkIf(3, 1, 3);
+ SceneLinkIf(4, 15, 5);
+ SceneLinkIf(5, 22, 0);
+ createScene(15, 1);
+ break;
+ case 15:
+ SceneLinkIf(1, 14, 0);
+ SceneLinkIf(2, 16, 3);
+ SceneLinkIf(3, 14, 2);
+ SceneLinkIf(4, 16, 5);
+ SceneLinkIf(5, 14, 4);
+ createScene(16, 1);
+ break;
+ case 16:
+ SceneLinkIf(1, 15, 0);
+ SceneLinkIf(2, 17, 3);
+ SceneLinkIf(3, 15, 2);
+ SceneLinkIf(4, 17, 5);
+ SceneLinkIf(5, 15, 4);
+ createScene(17, 1);
+ break;
+ case 17:
+ SceneLinkIf(1, 16, 0);
+ SceneLinkIf(2, 18, 3);
+ SceneLinkIf(3, 16, 2);
+ SceneLinkIf(4, 20, 1);
+ SceneLinkIf(5, 16, 4);
+ createScene(18, 1);
+ break;
+ case 18:
+ SceneLinkIf(1, 17, 0);
+ SceneLinkIf(2, 19, 2);
+ SceneLinkIf(3, 17, 2);
+ createScene(19, 0);
+ break;
+ case 19:
+ SceneLinkIf(1, 20, 2);
+ SceneLinkIf(2, 18, 2);
+ SceneLinkIf(3, 20, 0);
+ createScene(18, 0);
+ break;
+ case 20:
+ SceneLinkIf(1, 17, 4);
+ SceneLinkIf(2, 19, 1);
+ SceneLinkIf(3, 21, 0);
+ createScene(19, 3);
+ break;
+ case 21:
+ // TODO? GameState_sub_469C50(&field_52, 0);
+ // TODO MusicMan_stopAll (if field_52 above = 1)
+ // TODO Music18hList_delete(_musicFileHash);
+ // TODO Music18hList_play(0x04020210, 0, 2, 1);
+ // TODO Sound1ChList_sub_407AF0(0x42212411);
+ createScene(20, 3);
+ break;
+ case 22:
+ SceneLinkIf(1, 23, 0);
+ createScene(14, 5);
+ break;
+ case 23:
+ SceneLinkIf(1, 24, 0);
+ createScene(22, 1);
+ break;
+ case 24:
+ SceneLinkIf(1, 25, 0);
+ createScene(23, 1);
+ break;
+ case 25:
+ SceneLinkIf(1, 26, 0);
+ createScene(24, 1);
+ break;
+ case 26:
+ SceneLinkIf(1, 27, 0);
+ createScene(25, 1);
+ break;
+ case 27:
+ SceneLinkIf(1, 28, 0);
+ createScene(26, 1);
+ break;
+ case 28:
+ SceneLinkIf(1, 31, 0);
+ createScene(27, 1);
+ break;
+ case 29:
+ createScene(13, 1);
+ break;
+ case 30:
+ createScene(28, 1);
+ break;
+ }
+ } else {
+ switch (_vm->gameState().sceneNum) {
+ case 21:
+ if (!_flag1) {
+ // TODO Music18hList_stop(0x04020210, 0, 1);
+ // TODO _vm->gameModule()->initScene2801Vars();
+ _musicFileHash = getGlobalVar(0x89A82A15);
+ // TODO? GameState_sub_469C50(&field_52, 0);
+ // TODO MusicMan_create();
+ // TODO Music18hList_add2(0x42212411, _musicFileHash);
+ // TODO Music18hList_play2(_musicFileHash, 0, /*TODO */???, 1);
+ // TODO Sound1ChList_addSoundResource(0x42212411, 0x44014282, true);
+ // TODO Sound1ChList_setSoundValues(0x44014282, true, 120, 360, 72, 0);
+ _flag1 = true;
+ }
+ break;
+ }
+ }
+}
+
+void Module2700::update() {
+
+}
+
+uint32 Module2700::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Module::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x200D:
+ switch (_soundIndex) {
+ case 0:
+ _soundResource1.play();
+ break;
+ case 1:
+ _soundResource2.play();
+ break;
+ case 2:
+ _soundResource3.play();
+ break;
+ case 3:
+ _soundResource4.play();
+ break;
+ }
+ _soundIndex++;
+ if (_soundIndex >= 4)
+ _soundIndex = 0;
+ break;
+ }
+ return messageResult;
+}
+
+void Module2700::createScene2703(int which, uint32 sceneInfoId, const uint32 *staticSprites, const NRect *clipRect) {
+ // TODO
+}
+
+void Module2700::createScene2704(int which, uint32 sceneInfoId, int16 value, const uint32 *staticSprites, const NRect *clipRect) {
+ _childObject = new Scene2704(_vm, this, which, sceneInfoId, value, staticSprites, clipRect);
+}
+
+Class437::Class437(NeverhoodEngine *vm, uint32 fileHash)
+ : StaticSprite(vm, 0) {
+
+ _spriteResource.load2(fileHash);
+ createSurface(0, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.set(0, 0, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _needRefresh = true;
+ StaticSprite::update();
+}
+
+Scene2701::Scene2701(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true) {
+
+ NRect clipRect;
+ SceneInfo2700 *sceneInfo = _vm->_staticData->getSceneInfo2700(0x004B2240);
+ setGlobalVar(0x21E60190, 1);
+
+ _surfaceFlag = true;
+
+ setBackground(sceneInfo->bgFilename);
+ setPalette(sceneInfo->bgFilename);
+
+ _palette->addPalette(calcHash("paPodFloor"), 65, 31, 65);
+ _palette->addPalette(calcHash("paKlayFloor"), 0, 65, 0);
+
+ insertMouse433(0x08B08180);
+
+ _sprite1 = insertStaticSprite(0x1E086325, 1200);
+
+ clipRect.set(0, 0, 640, _sprite1->getDrawRect().x2());
+
+ if (sceneInfo->class437Filename) {
+ _class437 = insertSprite<Class437>(sceneInfo->class437Filename);
+ _class521 = insertSprite<Class521>(this, 320, 240);
+//TODO _class517 = insertSprite<Class517>(_class521, _class437->getSurface(), 4);
+//TODO _class520 = insertSprite<Class520>(_class521, _class437->getSurface(), 4);
+//TODO _class519 = insertSprite<Class519>(_class521, _class437->getSurface(), 4);
+ } else {
+ _class437 = NULL;
+ _class521 = insertSprite<Class521>(this, 320, 240);
+ }
+
+//TODO _class518 = insertSprite<Class518>(_class521);
+
+ _which1 = sceneInfo->which1;
+ _which2 = sceneInfo->which2;
+
+ _dataResource.load(sceneInfo->dataResourceFilename);
+ _trackPoints = _dataResource.getPointArray(sceneInfo->pointListName);
+ _class521->setPathPoints(_trackPoints);
+
+ if (which == _which2) {
+ NPoint testPoint = (*_trackPoints)[_trackPoints->size() - 1];
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ if (testPoint.x < 0 || testPoint.x >= 640 || testPoint.y < 0 || testPoint.y >= 480)
+ sendMessage(_class521, 0x2007, 150);
+ } else {
+ NPoint testPoint = (*_trackPoints)[0];
+ sendMessage(_class521, 0x2002, 0);
+ if (testPoint.x < 0 || testPoint.x >= 640 || testPoint.y < 0 || testPoint.y >= 480)
+ sendMessage(_class521, 0x2008, 150);
+ }
+
+ _class521->setClipRect(clipRect);
+ // TODO _class518->setClipRect(clipRect);
+
+ if (which == 1) {
+ SetMessageHandler(&Scene2701::handleMessage42F500);
+ } else {
+ sendMessage(_class521, 0x2009, 0);
+ SetMessageHandler(&Scene2701::handleMessage42F600);
+ }
+
+}
+
+uint32 Scene2701::handleMessage42F500(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ sendPointMessage(_class521, 0x2004, param.asPoint());
+ break;
+ case 0x2005:
+ if (_which1 >= 0)
+ SetMessageHandler(&Scene2701::handleMessage42F600);
+ break;
+ case 0x2006:
+ if (_which2 >= 0)
+ leaveScene(_which2);
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+uint32 Scene2701::handleMessage42F600(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ if (param.asPoint().x >= 385) {
+ leaveScene(0);
+ } else {
+ sendPointMessage(_class521, 0x2004, param.asPoint());
+ SetMessageHandler(&Scene2701::handleMessage42F500);
+ }
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+static const uint32 kScene2702Infos[2][3] = {
+ {0x004B5F68, 0x004B5F8C, 0x004B5FB0},
+ {0x004B5FD8, 0x004B5FFC, 0x004B6020}
+};
+
+
+Scene2702::Scene2702(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _flag1(true), _newTrackIndex(-1), _count(3) {
+
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 3; j++)
+ _sceneInfos[i][j] = _vm->_staticData->getSceneInfo2700(kScene2702Infos[i][j]);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2702::handleMessage);
+ SetUpdateHandler(&Scene2702::update);
+
+ setBackground(0x18808B00);
+ setPalette(0x18808B00);
+
+ _palette->addPalette(calcHash("paPodFloor"), 65, 31, 65);
+ _palette->addPalette(calcHash("paKlayFloor"), 0, 65, 0);
+ addEntity(_palette);
+
+ insertMouse433(0x08B04180);
+
+ _class437 = insertSprite<Class437>(0x12002035);
+ _class521 = insertSprite<Class521>(this, 320, 240);
+ //TODO _class517 = insertSprite<Class517>(_class521, _class437->getSurface(), 4);
+ //TODO insertSprite<Class518>(_class521);
+ //TODO _class520 = insertSprite<Class520>(_class521, _class437->getSurface(), 4);
+ //TODO _class519 = insertSprite<Class519>(_class521, _class437->getSurface(), 4);
+
+ _dataResource.load(0x04310014);
+
+ if (which == 1) {
+ _currSceneInfos = _sceneInfos[1];
+ _currTrackIndex = 1;
+ } else if (which == 2) {
+ _currSceneInfos = _sceneInfos[1];
+ _currTrackIndex = 2;
+ _palette->addPalette(calcHash("paPodShade"), 65, 31, 65);
+ _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0);
+ _flag1 = false;
+ } else if (which == 3) {
+ _currSceneInfos = _sceneInfos[0];
+ _currTrackIndex = 0;
+ } else if (which == 4) {
+ _currSceneInfos = _sceneInfos[0];
+ _currTrackIndex = 2;
+ _palette->addPalette(calcHash("paPodShade"), 65, 31, 65);
+ _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0);
+ _flag1 = false;
+ } else if (which == 5) {
+ _currSceneInfos = _sceneInfos[0];
+ _currTrackIndex = 1;
+ _palette->addPalette(calcHash("paPodShade"), 65, 31, 65);
+ _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0);
+ _flag1 = false;
+ } else {
+ _currSceneInfos = _sceneInfos[1];
+ _currTrackIndex = 0;
+ }
+
+ _trackPoints = _dataResource.getPointArray(_currSceneInfos[_currTrackIndex]->pointListName);
+ _class521->setPathPoints(_trackPoints);
+
+ if (which == _currSceneInfos[_currTrackIndex]->which2) {
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ sendMessage(_class521, 0x2007, 150);
+ } else {
+ sendMessage(_class521, 0x2002, 0);
+ sendMessage(_class521, 0x2008, 150);
+ }
+
+ _palette->copyBasePalette(0, 256, 0);
+
+}
+
+void Scene2702::update() {
+ Scene::update();
+ if (_flag1 && _class521->getX() > 422) {
+ debug("fade #1");
+ _palette->addBasePalette(calcHash("paPodShade"), 65, 31, 65);
+ _palette->addBasePalette(calcHash("paKlayShade"), 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ _flag1 = false;
+ } else if (!_flag1 && _class521->getX() <= 422) {
+ debug("fade #2");
+ _palette->addBasePalette(calcHash("paPodFloor"), 65, 31, 65);
+ _palette->addBasePalette(calcHash("paKlayFloor"), 0, 65, 0);
+ _palette->startFadeToPalette(12);
+ _flag1 = true;
+ }
+}
+
+uint32 Scene2702::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ findClosestTrack(param.asPoint());
+ break;
+ case 0x2005:
+ if (_newTrackIndex >= 0) {
+ if (_currSceneInfos[_currTrackIndex]->which1 < 0)
+ changeTrack();
+ } else if (_currSceneInfos[_currTrackIndex]->which1 >= 0)
+ leaveScene(_currSceneInfos[_currTrackIndex]->which1);
+ break;
+ case 0x2006:
+ if (_newTrackIndex >= 0) {
+ if (_currSceneInfos[_currTrackIndex]->which2 < 0)
+ changeTrack();
+ } else if (_currSceneInfos[_currTrackIndex]->which2 >= 0)
+ leaveScene(_currSceneInfos[_currTrackIndex]->which2);
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+void Scene2702::findClosestTrack(NPoint pt) {
+ int minMatchTrackIndex = -1;
+ int minMatchDistance = 640;
+ // Find the track which contains a point closest to pt
+ for (int infoIndex = 0; infoIndex < _count; infoIndex++) {
+ NPointArray *pointList = _dataResource.getPointArray(_currSceneInfos[infoIndex]->pointListName);
+ for (uint pointIndex = 0; pointIndex < pointList->size(); pointIndex++) {
+ NPoint testPt = (*pointList)[pointIndex];
+ int distance = calcDistance(testPt.x, testPt.y, pt.x, pt.y);
+ if (distance < minMatchDistance) {
+ minMatchTrackIndex = infoIndex;
+ minMatchDistance = distance;
+ }
+ }
+ }
+ if (minMatchTrackIndex >= 0 && minMatchTrackIndex != _currTrackIndex) {
+ _newTrackIndex = minMatchTrackIndex;
+ _newTrackDestX = pt.x;
+ if (_currSceneInfos == _sceneInfos[0]) {
+ if (_currTrackIndex == 0)
+ sendMessage(_class521, 0x2003, _trackPoints->size() - 1);
+ else
+ sendMessage(_class521, 0x2003, 0);
+ } else if (_currTrackIndex == 2) {
+ sendMessage(_class521, 0x2003, 0);
+ } else {
+ sendMessage(_class521, 0x2003, _trackPoints->size() - 1);
+ }
+ } else {
+ _newTrackIndex = -1;
+ sendMessage(_class521, 0x2004, pt.x);
+ }
+}
+
+void Scene2702::changeTrack() {
+ _currTrackIndex = _newTrackIndex;
+ _trackPoints = _dataResource.getPointArray(_currSceneInfos[_currTrackIndex]->pointListName);
+ _class521->setPathPoints(_trackPoints);
+ if (_currSceneInfos == _sceneInfos[0]) {
+ if (_currTrackIndex == 0)
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ else
+ sendMessage(_class521, 0x2002, 0);
+ } else if (_currTrackIndex == 2) {
+ sendMessage(_class521, 0x2002, 0);
+ } else {
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ }
+ sendMessage(_class521, 0x2004, _newTrackDestX);
+ _newTrackIndex = -1;
+}
+
+Scene2704::Scene2704(NeverhoodEngine *vm, Module *parentModule, int which, uint32 sceneInfoId, int16 value,
+ const uint32 *staticSprites, const NRect *clipRect)
+ : Scene(vm, parentModule, true) {
+
+ SceneInfo2700 *sceneInfo = _vm->_staticData->getSceneInfo2700(sceneInfoId);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2704::handleMessage);
+ SetUpdateHandler(&Scene2704::update);
+
+ setBackground(sceneInfo->bgFilename);
+ setPalette(sceneInfo->bgFilename);
+
+ if (sceneInfo->exPaletteFilename1)
+ _palette->addPalette(sceneInfo->exPaletteFilename1, 0, 65, 0);
+
+ if (sceneInfo->exPaletteFilename2)
+ _palette->addPalette(sceneInfo->exPaletteFilename2, 65, 31, 65);
+
+ while (staticSprites && *staticSprites)
+ insertStaticSprite(*staticSprites++, 1100);
+
+ insertMouse433(sceneInfo->mouseCursorFilename);
+
+ if (sceneInfo->class437Filename) {
+ _class437 = insertSprite<Class437>(sceneInfo->class437Filename);
+ _class521 = insertSprite<Class521>(this, 320, 240);
+//TODO _class517 = insertSprite<Class517>(_class521, _class437->getSurface(), 4);
+//TODO _class520 = insertSprite<Class520>(_class521, _class437->getSurface(), 4);
+//TODO _class519 = insertSprite<Class519>(_class521, _class437->getSurface(), 4);
+ } else {
+ _class437 = NULL;
+//TODO _class517 = NULL;
+ _class521 = insertSprite<Class521>(this, 320, 240);
+ }
+
+//TODO _class518 = insertSprite<Class518>(_class521);
+
+ _which1 = sceneInfo->which1;
+ _which2 = sceneInfo->which2;
+
+ _dataResource.load(sceneInfo->dataResourceFilename);
+ _trackPoints = _dataResource.getPointArray(sceneInfo->pointListName);
+ _class521->setPathPoints(_trackPoints);
+
+ if (sceneInfo->rectListName) {
+ _rectList = _dataResource.getRectArray(sceneInfo->rectListName);
+ // TODO _class521->setPathRects(_rectList);
+ }
+
+ if (which == _which2) {
+ NPoint testPoint = (*_trackPoints)[_trackPoints->size() - 1];
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ if (testPoint.x > 0 && testPoint.x < 640 && testPoint.y > 0 && testPoint.y < 480)
+ sendMessage(_class521, 0x2009, 0);
+ else
+ sendMessage(_class521, 0x2007, 0);
+ } else {
+ NPoint testPoint = (*_trackPoints)[0];
+ sendMessage(_class521, 0x2002, 0);
+ if (testPoint.x > 0 && testPoint.x < 640 && testPoint.y > 0 && testPoint.y < 480)
+ sendMessage(_class521, 0x2009, 0);
+ else
+ sendMessage(_class521, 0x2008, 0);
+ }
+
+ if (clipRect) {
+ _class521->getClipRect() = *clipRect;
+#if 0
+ if (_class517)
+ _class517->getClipRect() = *clipRect;
+ if (_class520)
+ _class520->getClipRect() = *clipRect;
+ if (_class519)
+ _class519->getClipRect() = *clipRect;
+ if (_class518)
+ _class518->getClipRect() = *clipRect;
+#endif
+ }
+
+}
+
+void Scene2704::update() {
+ Scene::update();
+ if (_mouseClicked) {
+ sendPointMessage(_class521, 0x2004, _mouseClickPos);
+ _mouseClicked = false;
+ }
+}
+
+uint32 Scene2704::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2005:
+ if (_which1 >= 0)
+ leaveScene(_which1);
+ break;
+ case 0x2006:
+ if (_which2 >= 0)
+ leaveScene(_which2);
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+static const int kSceneInfo2706Count = 3;
+static const struct { const char *pointListName; int which1, which2; } kSceneInfo2706[] = {
+ {"me06slotSlotPath2", 4, -1},
+ {"me06slotSlotPath3", -1, 6},
+ {"me06slotSlotPath4", -1, 5}
+};
+
+Scene2706::Scene2706(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _newTrackIndex(-1) {
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene2706::handleMessage);
+
+ setBackground(0x18808B88);
+ setPalette(0x18808B88);
+
+ _palette->addPalette(calcHash("paPodShade"), 65, 31, 65);
+ _palette->addPalette(calcHash("paKlayShade"), 0, 65, 0);
+
+ insertMouse433(0x08B8C180);
+
+ _class437 = insertSprite<Class437>(0x18808B88);
+ _class521 = insertSprite<Class521>(this, 320, 240);
+//TODO _class517 = insertSprite<Class517>(_class521, _class437->getSurface(), 4);
+//TODO _class518 = insertSprite<Class518>(_class521);
+//TODO _class520 = insertSprite<Class520>(_class521, _class437->getSurface(), 4);
+//TODO _class519 = insertSprite<Class519>(_class521, _class437->getSurface(), 4);
+
+ _dataResource.load(0x06000162);
+
+ if (which == 5)
+ _currTrackIndex = 2;
+ else if (which == 6)
+ _currTrackIndex = 1;
+ else
+ _currTrackIndex = 0;
+
+ _trackPoints = _dataResource.getPointArray(calcHash(kSceneInfo2706[_currTrackIndex].pointListName));
+ _class521->setPathPoints(_trackPoints);
+
+ if (which == kSceneInfo2706[_currTrackIndex].which2) {
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ if (which == 5)
+ sendMessage(_class521, 0x2007, 50);
+ else
+ sendMessage(_class521, 0x2007, 150);
+ } else {
+ sendMessage(_class521, 0x2002, 0);
+ if (which == 5)
+ sendMessage(_class521, 0x2008, 50);
+ else
+ sendMessage(_class521, 0x2008, 150);
+ }
+
+}
+
+uint32 Scene2706::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ findClosestTrack(param.asPoint());
+ break;
+ case 0x2005:
+ if (_newTrackIndex >= 0) {
+ if (kSceneInfo2706[_currTrackIndex].which1 < 0)
+ changeTrack();
+ } else if (kSceneInfo2706[_currTrackIndex].which1 >= 0)
+ leaveScene(kSceneInfo2706[_currTrackIndex].which1);
+ break;
+ case 0x2006:
+ if (_newTrackIndex >= 0) {
+ if (kSceneInfo2706[_currTrackIndex].which2 < 0)
+ changeTrack();
+ } else if (kSceneInfo2706[_currTrackIndex].which2 >= 0)
+ leaveScene(kSceneInfo2706[_currTrackIndex].which2);
+ break;
+ case 0x200D:
+ sendMessage(_parentModule, 0x200D, 0);
+ break;
+ }
+ return 0;
+}
+
+void Scene2706::findClosestTrack(NPoint pt) {
+ int minMatchTrackIndex = -1;
+ int minMatchDistance = 640;
+ // Find the track which contains a point closest to pt
+ for (int infoIndex = 0; infoIndex < kSceneInfo2706Count; infoIndex++) {
+ NPointArray *pointList = _dataResource.getPointArray(calcHash(kSceneInfo2706[infoIndex].pointListName));
+ for (uint pointIndex = 0; pointIndex < pointList->size(); pointIndex++) {
+ NPoint testPt = (*pointList)[pointIndex];
+ int distance = calcDistance(testPt.x, testPt.y, pt.x, pt.y);
+ if (distance < minMatchDistance) {
+ minMatchTrackIndex = infoIndex;
+ minMatchDistance = distance;
+ }
+ }
+ }
+ if (minMatchTrackIndex >= 0 && minMatchTrackIndex != _currTrackIndex) {
+ _newTrackIndex = minMatchTrackIndex;
+ _newTrackDestX = pt.x;
+ if (_currTrackIndex == 0)
+ sendMessage(_class521, 0x2003, _trackPoints->size() - 1);
+ else
+ sendMessage(_class521, 0x2003, 0);
+ } else {
+ _newTrackIndex = -1;
+ sendMessage(_class521, 0x2004, pt.x);
+ }
+}
+
+void Scene2706::changeTrack() {
+ _currTrackIndex = _newTrackIndex;
+ _trackPoints = _dataResource.getPointArray(calcHash(kSceneInfo2706[_currTrackIndex].pointListName));
+ _class521->setPathPoints(_trackPoints);
+ if (_currTrackIndex == 0)
+ sendMessage(_class521, 0x2002, _trackPoints->size() - 1);
+ else
+ sendMessage(_class521, 0x2002, 0);
+ sendMessage(_class521, 0x2004, _newTrackDestX);
+ _newTrackIndex = -1;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/module2700.h b/engines/neverhood/module2700.h
new file mode 100644
index 0000000000..f1ef3f5727
--- /dev/null
+++ b/engines/neverhood/module2700.h
@@ -0,0 +1,134 @@
+/* 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_MODULE2700_H
+#define NEVERHOOD_MODULE2700_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module1600.h"
+
+namespace Neverhood {
+
+// Module2700
+
+class Module2700 : public Module {
+public:
+ Module2700(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module2700();
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ SoundResource _soundResource4;
+ int _soundIndex;
+ bool _flag1;
+ uint32 _scene2711StaticSprites[6];
+ uint32 _musicFileHash;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createScene2703(int which, uint32 sceneInfoId, const uint32 *staticSprites = NULL, const NRect *clipRect = NULL);
+ void createScene2704(int which, uint32 sceneInfoId, int16 value, const uint32 *staticSprites = NULL, const NRect *clipRect = NULL);
+};
+
+class Class437 : public StaticSprite {
+public:
+ Class437(NeverhoodEngine *vm, uint32 fileHash);
+};
+
+class Scene2701 : public Scene {
+public:
+ Scene2701(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Class521 *_class521;
+ Sprite *_class437;
+ Sprite *_class517;
+ Sprite *_class520;
+ Sprite *_class519;
+ Sprite *_class518;
+ Sprite *_sprite1;
+ int _which1, _which2;
+ NPointArray *_trackPoints;
+ uint32 handleMessage42F500(int messageNum, const MessageParam &param, Entity *sender);
+ uint32 handleMessage42F600(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene2702 : public Scene {
+public:
+ Scene2702(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Class521 *_class521;
+ Sprite *_class437;
+ Sprite *_class517;
+ Sprite *_class520;
+ Sprite *_class519;
+ int16 _newTrackDestX;
+ int _currTrackIndex, _newTrackIndex;
+ int _count;
+ bool _flag1;
+ SceneInfo2700 *_sceneInfos[2][3];
+ SceneInfo2700 **_currSceneInfos;
+ NPointArray *_trackPoints;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void findClosestTrack(NPoint pt);
+ void changeTrack();
+};
+
+class Scene2704 : public Scene {
+public:
+ Scene2704(NeverhoodEngine *vm, Module *parentModule, int which, uint32 sceneInfoId, int16 value,
+ const uint32 *staticSprites = NULL, const NRect *clipRect = NULL);
+protected:
+ Class521 *_class521;
+ Sprite *_class437;
+ int _which1, _which2;
+ NPointArray *_trackPoints;
+ NRectArray *_rectList;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene2706 : public Scene {
+public:
+ Scene2706(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Class521 *_class521;
+ Sprite *_class437;
+ Sprite *_class517;
+ Sprite *_class518;
+ Sprite *_class520;
+ Sprite *_class519;
+ int16 _newTrackDestX;
+ int _currTrackIndex, _newTrackIndex;
+ NPointArray *_trackPoints;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void findClosestTrack(NPoint pt);
+ void changeTrack();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE2700_H */
diff --git a/engines/neverhood/module3000.cpp b/engines/neverhood/module3000.cpp
new file mode 100644
index 0000000000..783e6166ea
--- /dev/null
+++ b/engines/neverhood/module3000.cpp
@@ -0,0 +1,1617 @@
+/* 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/module3000.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/navigationscene.h"
+
+namespace Neverhood {
+
+Module3000::Module3000(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Module(vm, parentModule), _soundVolume(0) {
+
+ // TODO Sound1ChList_addSoundResources(0x81293110, dword_4B7FC8, true);
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B7FC8, 1, 50, 600, 5, 150);
+ // TODO Sound1ChList_setSoundValues(0x90F0D1C3, false, 20000, 30000, 20000, 30000);
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x48498E46, 0x50399F64, 0);
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x40030A51, 0xC862CA15, 0);
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x41861371, 0x43A2507F, 0);
+
+ _flag = getGlobalVar(0x10938830) != 0;
+
+ if (_flag) {
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, 0);
+ // TODO Sound1ChList_playLooping(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() {
+ // TODO Sound1ChList_sub_407A50(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(0x01BA1A52)) {
+ createNavigationScene(0x004B7C80, which);
+ } else if (getGlobalVar(0x10938830)) {
+ createNavigationScene(0x004B7CE0, which);
+ } else {
+ createNavigationScene(0x004B7CB0, which);
+ }
+ break;
+ case 2:
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x40030A51, 0xC862CA15, 0);
+ if (_flag) {
+ _soundVolume = 90;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, 90);
+ }
+ if (getGlobalVar(0x10938830)) {
+ createNavigationScene(0x004B7D58, which);
+ } else {
+ createNavigationScene(0x004B7D10, which);
+ }
+ break;
+ case 3:
+ if (getGlobalVar(0x09221A62))
+ createNavigationScene(0x004B7E60, which);
+ else if (getGlobalVar(0x10938830))
+ createNavigationScene(0x004B7DA0, which);
+ else
+ createNavigationScene(0x004B7E00, which);
+ break;
+ case 4:
+ if (getGlobalVar(0x09221A62))
+ createNavigationScene(0x004B7F20, which);
+ else
+ createNavigationScene(0x004B7EC0, which);
+ break;
+ case 5:
+ createNavigationScene(0x004B7F80, which, kNavigationTypes05);
+ break;
+ case 6:
+ createNavigationScene(0x004B7FB0, which, kNavigationTypes06);
+ break;
+ case 7:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B7FC8, 0, 0, 0, 0, 0);
+ if (!getSubVar(0x40050052, 0x089809C2)) {
+ setSubVar(0x40050052, 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:
+ // TODO Sound1ChList_setSoundValuesMulti(dword_4B7FC8, 0, 0, 0, 0, 0);
+ if (!getSubVar(0x40050052, 0x10130993)) {
+ setSubVar(0x40050052, 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(0x01BA1A52))
+ if (getGlobalVar(0x10938830))
+ createSmackerScene(0x00940021, true, true, false);
+ else
+ createSmackerScene(0x01140021, true, true, false);
+ else
+ if (getGlobalVar(0x10938830))
+ createSmackerScene(0x001011B1, true, true, false);
+ else
+ createSmackerScene(0x001021B1, true, true, false);
+ setGlobalVar(0x01BA1A52, getGlobalVar(0x01BA1A52) ? 0 : 1);
+ break;
+ case 1006:
+ createSmackerScene(0x080810C5, true, true, false);
+ break;
+ case 1008:
+ createSmackerScene(getGlobalVar(0xF0402B0A), true, true, false);
+ break;
+ }
+ SetUpdateHandler(&Module3000::updateScene);
+ _childObject->handleUpdate();
+}
+
+void Module3000::updateScene() {
+ if (!updateChild()) {
+ switch (_vm->gameState().sceneNum) {
+ case 1:
+ if (!getGlobalVar(0x01BA1A52)) {
+ 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:
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x41861371, 0x43A2507F, 0);
+ if (_flag) {
+ _soundVolume = 0;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, 0);
+ }
+ if (_moduleResult == 0) {
+ createScene(3, 0);
+ } else if (_moduleResult == 1) {
+ setGlobalVar(0x01BA1A52, 0);
+ createScene(1, 1);
+ }
+ break;
+ case 3:
+ if (_moduleResult == 1)
+ createScene(4, 0);
+ else if (_moduleResult == 3)
+ createScene(10, -1);
+ else if (getGlobalVar(0x09221A62))
+ 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:
+ _flag = getGlobalVar(0x10938830); // CHECKME
+ if (_moduleResult != 1) {
+ // TODO: Sound1ChList_setSoundValuesMulti(dword_4B7FC8, true, 0, 0, 0, 0):
+ createScene(4, 1);
+ } else if (getGlobalVar(0xF0402B0A)) {
+ createScene(1008, -1);
+ } else {
+ // TODO: Sound1ChList_setSoundValuesMulti(dword_4B7FC8, 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(0x01BA1A52))
+ 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 0 // ALL TODO
+ if (navigationScene()->getSoundFlag1()) {
+ uint32 frameNumber = navigationScene()->getFrameNumber();
+ int navigationIndex = navigationScene()->getIndex();
+ if (navigationIndex == 1) {
+ if (frameNumber == 0) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x48498E46, 0x50399F64, 0);
+ // TODO Sound1ChList_setVolume(0x48498E46, 70);
+ // TODO Sound1ChList_setVolume(0x50399F64, 70);
+ } else if (frameNumber == 100) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x41861371, 0x43A2507F, 0);
+ }
+ } else if (navigationIndex == 0) {
+ if (frameNumber == 0) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x48498E46, 0x50399F64, 0);
+ // TODO Sound1ChList_setVolume(0x48498E46, 70);
+ // TODO Sound1ChList_setVolume(0x50399F64, 70);
+ } else if (frameNumber == 10) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x40030A51, 0xC862CA15, 0);
+ }
+ if (_flag && _soundVolume < 90 && frameNumber % 2) {
+ if (frameNumber == 0)
+ _soundVolume = 40;
+ else
+ _soundVolume++;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, _soundVolume);
+ }
+ }
+ }
+#endif
+ break;
+ case 2:
+#if 0 // ALL TODO
+ if (navigationScene()->getSoundFlag1()) {
+ uint32 frameNumber = navigationScene()->getFrameNumber();
+ int navigationIndex = navigationScene()->getIndex();
+ if (_flag && _soundVolume > 1 && frameNumber % 2) {
+ _soundVolume--;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, _soundVolume);
+ }
+ if (navigationIndex == 0) {
+ if (frameNumber == 35) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x41861371, 0x43A2507F, 0);
+ }
+ } else if (navigationIndex == 1) {
+ if (frameNumber == 55) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x48498E46, 0x50399F64, 0);
+ // TODO Sound1ChList_setVolume(0x48498E46, 70);
+ // TODO Sound1ChList_setVolume(0x50399F64, 70);
+ }
+ }
+ }
+#endif
+ break;
+ case 3:
+#if 0 // ALL TODO
+ if (navigationScene()->getSoundFlag1()) {
+ uint32 frameNumber = navigationScene()->getFrameNumber();
+ int navigationIndex = navigationScene()->getIndex();
+ if (navigationIndex == 2) {
+ if (frameNumber == 40) {
+ // TODO Sound1ChList_sub_407C70(0x81293110, 0x40030A51, 0xC862CA15, 0);
+ }
+ if (_flag && _soundVolume < 90 && frameNumber % 2) {
+ if (frameNumber == 0)
+ _soundVolume = 40;
+ else
+ _soundVolume++;
+ // TODO Sound1ChList_setVolume(0x90F0D1C3, _soundVolume);
+ }
+ }
+ }
+#endif
+ break;
+ case 5:
+#if 0 // ALL TODO
+ if (navigationScene()->getSoundFlag1() && navigationScene()->getIndex() == 0) {
+ // TODO Sound1ChList_sub_4080B0(false);
+ }
+#endif
+ break;
+ }
+ }
+}
+
+// Scene3009
+
+static const uint32 kScene3009SmackerFileHashes[] = {
+ 0x1010000D,
+ 0x340A0049,
+ 0x340A0049,
+ 0x0282081D,
+ 0x0082080D,
+ 0x0882080D,
+ 0x0882080D,
+ 0x0282081D,
+ 0x004B000B,
+ 0x014B000B,
+ 0x044B000B,
+ 0x0282081D,
+ 0x0282081D,
+ 0x0282081D,
+ 0x340A0049
+};
+
+static const uint32 kScene3009CannonLocationFileHashes[] = {
+ 0x00000000,
+ 0x8004001B,
+ 0x0004001A,
+ 0x1048404B,
+ 0x50200109,
+ 0x12032109,
+ 0x10201109,
+ 0x000A2030,
+ 0x000A0028,
+ 0x000A0028,
+ 0x000A0028,
+ 0x040A1069,
+ 0x040A1069,
+ 0x040A1069,
+ 0x240A1101
+};
+
+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), _soundResource(vm), _parentScene(parentScene),
+ _flag1(false) {
+
+ _spriteResource.load2(0x120B24B0);
+ createSurface(400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _deltaRect.x = 0;
+ _deltaRect.y = 0;
+ _deltaRect.width = _spriteResource.getDimensions().width;
+ _deltaRect.height = _spriteResource.getDimensions().height;
+ setVisible(false);
+ processDelta();
+ _needRefresh = true;
+ SetUpdateHandler(&SsScene3009FireCannonButton::update);
+ SetMessageHandler(&SsScene3009FireCannonButton::handleMessage);
+ _soundResource.load(0x3901B44F);
+}
+
+void SsScene3009FireCannonButton::update() {
+ StaticSprite::update();
+ if (_flag1 && !_soundResource.isPlaying()) {
+ sendMessage(_parentScene, 0x2000, 0);
+ setVisible(false);
+ }
+}
+
+uint32 SsScene3009FireCannonButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (!_flag1 && !_parentScene->sub462E90()) {
+ _flag1 = true;
+ setVisible(true);
+ _soundResource.play();
+ }
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+SsScene3009SymbolEdges::SsScene3009SymbolEdges(NeverhoodEngine *vm, int index)
+ : StaticSprite(vm, 1400), _blinkCountdown(0) {
+
+ _spriteResource.load2(kSsScene3009SymbolEdgesFileHashes[index]);
+ createSurface(600, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _needRefresh = true;
+ if (getGlobalVar(0x0C0288F4)) {
+ hide();
+ } else {
+ startBlinking();
+ }
+ SetUpdateHandler(&SsScene3009SymbolEdges::update);
+}
+
+void SsScene3009SymbolEdges::update() {
+ if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) {
+ if (_blinkToggle) {
+ setVisible(true);
+ } else {
+ setVisible(false);
+ }
+ StaticSprite::update();
+ _blinkCountdown = 3;
+ _blinkToggle = !_blinkToggle;
+ }
+}
+
+void SsScene3009SymbolEdges::show() {
+ setVisible(true);
+ StaticSprite::update();
+ _blinkCountdown = 0;
+}
+
+void SsScene3009SymbolEdges::hide() {
+ setVisible(false);
+ StaticSprite::update();
+ _blinkCountdown = 0;
+}
+
+void SsScene3009SymbolEdges::startBlinking() {
+ setVisible(true);
+ StaticSprite::update();
+ _blinkCountdown = 3;
+ _blinkToggle = true;
+}
+
+SsScene3009TargetLine::SsScene3009TargetLine(NeverhoodEngine *vm, int index)
+ : StaticSprite(vm, 1400) {
+
+ _spriteResource.load2(kSsScene3009TargetLineFileHashes[index]);
+ createSurface(600, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ setVisible(false);
+ _needRefresh = true;
+}
+
+void SsScene3009TargetLine::show() {
+ setVisible(true);
+ StaticSprite::update();
+}
+
+SsScene3009SymbolArrow::SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index)
+ : StaticSprite(vm, 1400), _soundResource(vm), _asSymbol(asSymbol),
+ _index(index), _enabled(true), _countdown(0) {
+
+ _incrDecr = _index % 2;
+
+ _spriteResource.load2(kSsScene3009SymbolArrowFileHashes2[_index]);
+ createSurface(1200, 33, 31);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = 33;
+ _drawRect.height = 31;
+ _deltaRect = _drawRect;
+ processDelta();
+ _needRefresh = true;
+ SetUpdateHandler(&SsScene3009SymbolArrow::update);
+ SetMessageHandler(&SsScene3009SymbolArrow::handleMessage);
+ _soundResource.load(0x2C852206);
+}
+
+void SsScene3009SymbolArrow::hide() {
+ _enabled = false;
+ setVisible(false);
+}
+
+void SsScene3009SymbolArrow::update() {
+ StaticSprite::update();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ _spriteResource.load2(kSsScene3009SymbolArrowFileHashes2[_index]);
+ _needRefresh = true;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ }
+}
+
+uint32 SsScene3009SymbolArrow::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (_enabled && _countdown == 0) {
+ _countdown = 2;
+ _spriteResource.load2(kSsScene3009SymbolArrowFileHashes1[_index]);
+ _needRefresh = true;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _soundResource.play();
+ 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(0x000809C2) ? 52 : 266;
+ createSurface1(0xC2463913, 1200);
+ _needRefresh = true;
+ updatePosition();
+ setVisible(false);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage);
+}
+
+void AsScene3009VerticalIndicator::show() {
+ setFileHash(0xC2463913, 0, -1);
+ setVisible(true);
+ updatePosition();
+ _enabled = true;
+}
+
+uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const MessageParam &param, 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 varValue)
+ : AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) {
+
+ _x = getGlobalVar(0x9040018A) ? 533 : 92;
+ _y = 150;
+ createSurface1(0xC0C12954, 1200);
+ _needRefresh = true;
+ updatePosition();
+ setVisible(false);
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene3009HorizontalIndicator::handleMessage);
+ if (varValue == 8 || varValue == 9 || varValue == 10) {
+ SetSpriteCallback(&AsScene3009HorizontalIndicator::suMoveRight);
+ _x = 280;
+ }
+}
+
+uint32 AsScene3009HorizontalIndicator::handleMessage(int messageNum, const MessageParam &param, 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) {
+ SetSpriteCallback(NULL);
+ _x = 92;
+ }
+}
+
+void AsScene3009HorizontalIndicator::suMoveRight() {
+ _x += 6;
+ if (_x > 533) {
+ SetSpriteCallback(NULL);
+ _x = 533;
+ }
+}
+
+void AsScene3009HorizontalIndicator::show() {
+ setFileHash(0xC0C12954, 0, -1);
+ setVisible(true);
+ updatePosition();
+ _enabled = true;
+}
+
+void AsScene3009HorizontalIndicator::stMoveLeft() {
+ _x = 533;
+ SetSpriteCallback(&AsScene3009HorizontalIndicator::suMoveLeft);
+}
+
+void AsScene3009HorizontalIndicator::stMoveRight() {
+ _x = 330;
+ SetSpriteCallback(&AsScene3009HorizontalIndicator::suMoveRight);
+}
+
+AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int index)
+ : AnimatedSprite(vm, 1100), _parentScene(parentScene), _index(index) {
+
+ _symbolIndex = getSubVar(0x00000914, _index);
+
+ _x = kAsScene3009SymbolPoints[_index].x;
+ _y = kAsScene3009SymbolPoints[_index].y;
+ createSurface1(kAsScene3009SymbolFileHashes[_index / 3], 1200);
+ setFileHash(kAsScene3009SymbolFileHashes[_index / 3], _symbolIndex, -1);
+ _newHashListIndex = _symbolIndex;
+ _needRefresh = true;
+ updatePosition();
+ SetUpdateHandler(&AnimatedSprite::update);
+ SetMessageHandler(&AsScene3009Symbol::handleMessage);
+ _ssArrowPrev = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _index * 2 + 0);
+ _vm->_collisionMan->addSprite(_ssArrowPrev);
+ _ssArrowNext = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _index * 2 + 1);
+ _vm->_collisionMan->addSprite(_ssArrowNext);
+}
+
+uint32 AsScene3009Symbol::handleMessage(int messageNum, const MessageParam &param, 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--;
+ }
+ setFileHash(kAsScene3009SymbolFileHashes[_index / 3], _symbolIndex, -1);
+ _newHashListIndex = _symbolIndex;
+ setSubVar(0x00000914, _index, _symbolIndex);
+ if (_index / 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, true), _keepVideo(false), _flag2(false),
+ /*_flag3(false), */_flag4(false), _lockSymbolsPart1Countdown(1), _lockSymbolsPart2Countdown(1) {
+
+ _cannonLocation = getGlobalVar(0x20580A86);
+ debug("_cannonLocation = %d", _cannonLocation);
+
+ _vm->gameModule()->initScene3009Vars();
+
+ setGlobalVar(0xF0402B0A, 0);
+ _surfaceFlag = true;
+
+ _vm->_screen->clear();
+
+ setBackground(0xD000420C);
+ setPalette(0xD000420C);
+ insertMouse435(0x04208D08, 20, 620);
+
+ _ssFireCannonButton = insertSprite<SsScene3009FireCannonButton>(this);
+ _vm->_collisionMan->addSprite(_ssFireCannonButton);
+
+ _asVerticalIndicator = insertSprite<AsScene3009VerticalIndicator>(this, _cannonLocation);
+ _vm->_collisionMan->addSprite(_asVerticalIndicator);
+
+ _asHorizontalIndicator = insertSprite<AsScene3009HorizontalIndicator>(this, _cannonLocation);
+ _vm->_collisionMan->addSprite(_asHorizontalIndicator);
+
+ if (_cannonLocation != 0 && _cannonLocation != 8 && _cannonLocation != 9 && _cannonLocation != 10) {
+ _keepVideo = true;
+ } else {
+ _keepVideo = false;
+ if (_cannonLocation != 0) {
+ _asHorizontalIndicator->stMoveRight();
+ _flag4 = true;
+ }
+ }
+
+ _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, kScene3009SmackerFileHashes[_cannonLocation], 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 i = 0; i < 6; i++) {
+ _asSymbols[i] = insertSprite<AsScene3009Symbol>(this, i);
+ if (i < 3)
+ _correctSymbols[i] = getSubVar(0x00504B86, i);
+ else
+ _correctSymbols[i] = getSubVar(0x0A4C0A9A, i - 3);
+ }
+
+ SetMessageHandler(&Scene3009::handleMessage);
+ SetUpdateHandler(&Scene3009::update);
+
+ // DEBUG: Set the correct code
+ for (int i = 0; i < 6; i++)
+ setSubVar(0x00000914, i, _correctSymbols[i]);
+ sendMessage(this, 0x2003, 0);
+ //setGlobalVar(0x610210B7, 1);
+
+}
+
+void Scene3009::update() {
+ Scene::update();
+
+ if (!_keepVideo && _smackerPlayer->getFrameNumber() + 1 == _smackerPlayer->getFrameCount() && _cannonLocation <= 14) {
+ switch (_cannonLocation) {
+ case 0:
+ case 14:
+ _smackerPlayer->open(0x340A0049, true);
+ _palette->usePalette();
+ _keepVideo = true;
+ break;
+ case 8:
+ _smackerPlayer->open(0x0082080D, true);
+ _palette->usePalette();
+ _keepVideo = true;
+ _flag4 = false;
+ break;
+ case 9:
+ _smackerPlayer->open(0x0282080D, true);
+ _palette->usePalette();
+ _keepVideo = true;
+ _flag4 = false;
+ break;
+ case 10:
+ _smackerPlayer->open(0x0882080D, true);
+ _palette->usePalette();
+ _keepVideo = true;
+ _flag4 = false;
+ break;
+ case 11:
+ case 12:
+ case 13:
+ if (_flag2) {
+ if (_cannonLocation == 11)
+ _smackerPlayer->open(0x110A000F, false);
+ else if (_cannonLocation == 12)
+ _smackerPlayer->open(0x500B004F, false);
+ else if (_cannonLocation == 13)
+ _smackerPlayer->open(0x100B010E, false);
+ _palette->usePalette();
+ _flag2 = false;
+ _asHorizontalIndicator->stMoveLeft();
+ } else {
+ playExtVideo();
+ }
+ break;
+ }
+ }
+
+ if (_lockSymbolsPart1Countdown != 0 && (--_lockSymbolsPart1Countdown == 0) && isSymbolsPart1Solved()) {
+ for (int i = 0; i < 3; i++)
+ _asSymbols[i]->hide();
+ if (!getGlobalVar(0x0C0288F4) || getGlobalVar(0x000809C2) || getGlobalVar(0x9040018A)) {
+ _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(0x0C0288F4) || getGlobalVar(0x000809C2) || getGlobalVar(0x9040018A)) {
+ _ssSymbolEdges[1]->show();
+ _ssTargetLines[1]->show();
+ _asHorizontalIndicator->show();
+ }
+ }
+
+}
+
+uint32 Scene3009::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO: Debug stuff
+ if ((param.asPoint().x <= 20 || param.asPoint().x >= 620) && !getGlobalVar(0x000809C2)) {
+ setGlobalVar(0x20580A86, 0);
+ leaveScene(0);
+ }
+ break;
+ case 0x000D:
+ // TODO: Debug stuff
+ break;
+ case 0x2000:
+ if (!getGlobalVar(0x000809C2)) {
+ if (!getGlobalVar(0x10938830)) {
+ _cannonLocation = 1;
+ setGlobalVar(0x10938830, 1);
+ } else {
+ _cannonLocation = 2;
+ }
+ } else if (!getGlobalVar(0x9040018A)) {
+ _cannonLocation = 3;
+ } else if (!getGlobalVar(0x610210B7)) {
+ _cannonLocation = 4;
+ } else if (!getGlobalVar(0x0C0288F4)) {
+ setGlobalVar(0x0C0288F4, 1);
+ _cannonLocation = 5;
+ } else {
+ _cannonLocation = 6;
+ }
+ playExtVideo();
+ break;
+ case 0x2001:
+ _lockSymbolsPart1Countdown = 24;
+ break;
+ case 0x2002:
+ if (!getGlobalVar(0x9040018A) && !_flag4) {
+ if (getGlobalVar(0x000809C2)) {
+ _cannonLocation = 14;
+ setGlobalVar(0x000809C2, 0);
+ } else {
+ _cannonLocation = 7;
+ setGlobalVar(0x000809C2, 1);
+ }
+ playExtVideo();
+ }
+ break;
+ case 0x2003:
+ _lockSymbolsPart2Countdown = 24;
+ break;
+ case 0x2004:
+ if (getGlobalVar(0x000809C2)) {
+ if (!getGlobalVar(0x9040018A)) {
+ if (!getGlobalVar(0x610210B7)) {
+ _cannonLocation = 8;
+ } else if (!getGlobalVar(0x0C0288F4)) {
+ _cannonLocation = 9;
+ } else {
+ _cannonLocation = 10;
+ }
+ setGlobalVar(0x9040018A, 1);
+ _flag4 = true;
+ playExtVideo();
+ } else {
+ if (!getGlobalVar(0x610210B7)) {
+ _cannonLocation = 11;
+ _smackerPlayer->open(0x108A000F, false);
+ } else if (!getGlobalVar(0x0C0288F4)) {
+ _cannonLocation = 12;
+ _smackerPlayer->open(0x500B002F, false);
+ } else {
+ _cannonLocation = 13;
+ _smackerPlayer->open(0x100B008E, false);
+ }
+ _palette->usePalette();
+ _flag2 = true;
+ _flag4 = true;
+ _keepVideo = false;
+ setGlobalVar(0x9040018A, 0);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+void Scene3009::playExtVideo() {
+ setGlobalVar(0x20580A86, _cannonLocation);
+ setGlobalVar(0xF0402B0A, kScene3009CannonLocationFileHashes[_cannonLocation]);
+ leaveScene(1);
+}
+
+bool Scene3009::isSymbolsPart1Solved() {
+ for (int i = 0; i < 3; i++)
+ if (_correctSymbols[i] != getSubVar(0x00000914, i))
+ return false;
+ return true;
+}
+
+bool Scene3009::isSymbolsPart2Solved() {
+ for (int i = 3; i < 6; i++)
+ if (_correctSymbols[i] != getSubVar(0x00000914, i))
+ return false;
+ return true;
+}
+
+bool Scene3009::sub462E90() {
+ return _flag4;
+}
+
+// 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), _soundResource1(vm),
+ _soundResource2(vm), _soundResource3(vm), _buttonLocked(false), _countdown1(0),
+ _countdown2(0), _buttonIndex(buttonIndex) {
+
+ NDimensions dimensions1, dimensions2;
+
+ _buttonEnabled = getSubVar(0x14800353, kScene3010ButtonNameHashes[_buttonIndex]) != 0;
+ _spriteResource.load2(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
+ dimensions1 = _spriteResource.getDimensions();
+ _spriteResource.load2(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
+ dimensions2 = _spriteResource.getDimensions();
+ createSurface(400,
+ MAX(dimensions1.width, dimensions2.width),
+ MAX(dimensions1.height, dimensions2.height));
+ setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
+ if (initDisabled) {
+ disableButton();
+ } else if (_buttonEnabled) {
+ _countdown1 = initCountdown * 12 + 1;
+ }
+ _soundResource1.load(0xF4217243);
+ _soundResource2.load(0x44049000);
+ _soundResource3.load(0x6408107E);
+ SetUpdateHandler(&SsScene3010DeadBoltButton::update);
+ SetMessageHandler(&SsScene3010DeadBoltButton::handleMessage);
+}
+
+void SsScene3010DeadBoltButton::update() {
+
+ if (_countdown1 != 0 && (--_countdown1 == 0)) {
+ _soundResource1.play();
+ setVisible(false);
+ setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
+ }
+
+ if (_countdown2 != 0 && (--_countdown2 == 0)) {
+ setVisible(true);
+ setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
+ }
+
+}
+
+uint32 SsScene3010DeadBoltButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x1011:
+ if (!_buttonLocked && _countdown1 == 0) {
+ if (_buttonEnabled) {
+ _soundResource2.play();
+ _soundResource3.play();
+ setVisible(true);
+ _buttonLocked = true;
+ sendMessage(_parentScene, 0x2000, _buttonIndex);
+ } else {
+ sendMessage(_parentScene, 0x2002, _buttonIndex);
+ }
+ _needRefresh = true;
+ StaticSprite::update();
+ }
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+void SsScene3010DeadBoltButton::disableButton() {
+ _buttonLocked = true;
+ setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
+ setVisible(true);
+}
+
+void SsScene3010DeadBoltButton::setSprite(uint32 fileHash) {
+ _spriteResource.load(fileHash);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _deltaRect = _drawRect;
+ processDelta();
+ _needRefresh = true;
+ StaticSprite::update();
+}
+
+void SsScene3010DeadBoltButton::setCountdown(int count) {
+ _countdown2 = count * 18 + 1;
+}
+
+AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked)
+ : AnimatedSprite(vm, 1100), _soundResource1(vm), _soundResource2(vm), _soundResource3(vm),
+ _parentScene(parentScene), _boltIndex(boltIndex), _soundToggle(true), _unlocked(false), _locked(false),
+ _countdown(0) {
+
+ _x = kAsScene3010DeadBoltPoints[_boltIndex].x;
+ _y = kAsScene3010DeadBoltPoints[_boltIndex].y;
+
+ if (getSubVar(0x14800353, kScene3010ButtonNameHashes[_boltIndex])) {
+ createSurface1(kAsScene3010DeadBoltFileHashes1[_boltIndex], 1200);
+ setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
+ _soundResource1.load(0x46005BC4);
+ } else {
+ createSurface1(kAsScene3010DeadBoltFileHashes2[_boltIndex], 1200);
+ setFileHash(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
+ _soundResource1.load(0x420073DC);
+ _soundResource2.load(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 &param, Entity *sender) {
+ uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x3002:
+ removeCallbacks();
+ 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) {
+ setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0);
+ _newHashListIndex = -2;
+ } else {
+ setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
+ SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
+ FinalizeState(&AsScene3010DeadBolt::stIdleMessage);
+ NextState(&AsScene3010DeadBolt::stIdle);
+ _soundResource1.play();
+ }
+ _unlocked = true;
+ _soundResource3.load(0x4010C345);
+ }
+}
+
+void AsScene3010DeadBolt::stIdleMessage() {
+ stopAnimation();
+ SetMessageHandler(&Sprite::handleMessage);
+ sendMessage(_parentScene, 0x2001, _boltIndex);
+}
+
+void AsScene3010DeadBolt::lock() {
+ if (!_locked) {
+ _locked = true;
+ setVisible(true);
+ setFileHash(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
+ SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
+ FinalizeState(&AsScene3010DeadBolt::stDisabledMessage);
+ NextState(&AsScene3010DeadBolt::stIdle);
+ if (_soundToggle) {
+ _soundResource1.play();
+ } else {
+ _soundResource2.play();
+ }
+ _soundToggle = !_soundToggle;
+ }
+}
+
+void AsScene3010DeadBolt::setCountdown(int count) {
+ _countdown = count * 18 + 1;
+}
+
+void AsScene3010DeadBolt::stDisabled() {
+ setVisible(true);
+ setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
+ SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
+ FinalizeState(&AsScene3010DeadBolt::stDisabledMessage);
+ NextState(&AsScene3010DeadBolt::stIdle);
+ _playBackwards = true;
+ _soundResource3.play();
+}
+
+void AsScene3010DeadBolt::stDisabledMessage() {
+ setVisible(false);
+ sendMessage(_parentScene, 0x2003, _boltIndex);
+}
+
+Scene3010::Scene3010(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _soundResource(vm), _countdown(0),
+ _doorUnlocked(false), _checkUnlocked(false) {
+
+ int initCountdown = 0;
+
+ // DEBUG: Enable all buttons
+ setSubVar(0x14800353, kScene3010ButtonNameHashes[0], 1);
+ setSubVar(0x14800353, kScene3010ButtonNameHashes[1], 1);
+ setSubVar(0x14800353, kScene3010ButtonNameHashes[2], 1);
+
+ _surfaceFlag = true;
+
+ 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
+ _vm->_collisionMan->addSprite(_ssDeadBoltButtons[i]);
+ if (getSubVar(0x14800353, kScene3010ButtonNameHashes[i]))
+ initCountdown++;
+ _boltUnlocking[i] = false;
+ _boltUnlocked[i] = false;
+ }
+
+ if (which == 0) {
+ insertMouse435(0x02622800, 20, 620);
+ }
+
+ _soundResource.load(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 &param, Entity *sender) {
+ Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0001:
+ // TODO: Debug stuff
+ 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 0x000D:
+ // TODO: Debug stuff
+ 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(0x00040153)) {
+ setGlobalVar(0x00040153, 1);
+ _soundResource.play();
+ _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), _soundResource(vm),
+ _countdown(0) {
+
+ if (flag) {
+ _spriteResource.load2(0x11282020);
+ } else {
+ _spriteResource.load2(0x994D0433);
+ }
+ _soundResource.load(0x44061000);
+ createSurface(400, _spriteResource.getDimensions().width, _spriteResource.getDimensions().height);
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ _deltaRect = _drawRect;
+ setVisible(false);
+ processDelta();
+ _needRefresh = true;
+ SetUpdateHandler(&SsScene3011Button::update);
+ SetMessageHandler(&SsScene3011Button::handleMessage);
+}
+
+void SsScene3011Button::update() {
+ StaticSprite::update();
+ if (_countdown != 0 && (--_countdown == 0)) {
+ setVisible(false);
+ }
+}
+
+uint32 SsScene3011Button::handleMessage(int messageNum, const MessageParam &param, 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);
+ _soundResource.play();
+ }
+ messageResult = 1;
+ break;
+ }
+ return messageResult;
+}
+
+AsScene3011Symbol::AsScene3011Symbol(NeverhoodEngine *vm, int index, bool flag)
+ : AnimatedSprite(vm, 1000), _soundResource1(vm), _soundResource2(vm),
+ _index(index), _flag1(flag), _flag2(false) {
+
+ if (flag) {
+ _x = 310;
+ _y = 200;
+ createSurface1(kAsScene3011SymbolFileHashes[_index], 1200);
+ _soundResource1.load(0x6052C60F);
+ _soundResource2.load(0x6890433B);
+ } else {
+ _index = 12;
+ _x = index * 39 + 96;
+ _y = 225;
+ createSurface(1200, 41, 48);
+ _soundResource1.load(0x64428609);
+ _soundResource2.load(0x7080023B);
+ }
+ setVisible(false);
+ _needRefresh = true;
+ SetUpdateHandler(&AnimatedSprite::update);
+}
+
+void AsScene3011Symbol::show(bool flag) {
+ _flag2 = flag;
+ setFileHash(kAsScene3011SymbolFileHashes[_index], 0, -1);
+ setVisible(true);
+ if (flag) {
+ _soundResource2.play();
+ } else {
+ _soundResource1.play();
+ }
+}
+
+void AsScene3011Symbol::hide() {
+ stopAnimation();
+ setVisible(false);
+}
+
+void AsScene3011Symbol::stopSound() {
+ if (_flag2) {
+ _soundResource2.stop();
+ } else {
+ _soundResource2.stop();
+ }
+}
+
+void AsScene3011Symbol::change(int index, bool flag) {
+ _index = index;
+ _flag2 = flag;
+ setFileHash(kAsScene3011SymbolFileHashes[_index], 0, -1);
+ setVisible(true);
+ if (flag) {
+ _soundResource2.play();
+ } else {
+ _soundResource1.play();
+ }
+}
+
+Scene3011::Scene3011(NeverhoodEngine *vm, Module *parentModule, int which)
+ : Scene(vm, parentModule, true), _updateStatus(0), _buttonClicked(false), _index2(0) {
+
+ // TODO _vm->gameModule()->initScene3011Vars();
+ _index1 = getGlobalVar(0x2414C2F2);
+
+ _surfaceFlag = true;
+ SetMessageHandler(&Scene3011::handleMessage);
+ SetUpdateHandler(&Scene3011::update);
+
+ setBackground(0x92124A04);
+ setPalette(0xA4070114);
+ addEntity(_palette);
+
+ insertMouse435(0x24A00929, 20, 620);
+
+ for (int i = 0; i < 12; i++)
+ _asSymbols[i] = insertSprite<AsScene3011Symbol>(i, true);
+
+ _ssButton = insertSprite<SsScene3011Button>(this, true);
+ _vm->_collisionMan->addSprite(_ssButton);
+
+}
+
+void Scene3011::update() {
+ Scene::update();
+
+ if (_countdown != 0 && (--_countdown == 0)) {
+ switch (_updateStatus) {
+ case 0:
+ if (_buttonClicked) {
+ if (_index1 == _index2) {
+ do {
+ _index3 = _vm->_rnd->getRandomNumber(12 - 1);
+ } while (_index1 == _index3);
+ _asSymbols[getSubVar(0x04909A50, _index3)]->show(true);
+ } else {
+ _asSymbols[getSubVar(0x04909A50, _index2)]->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 (_index1 == _index2) {
+ _asSymbols[getSubVar(0x04909A50, _index3)]->hide();
+ } else {
+ _asSymbols[getSubVar(0x04909A50, _index2)]->hide();
+ }
+ _index2++;
+ if (_index2 >= 12)
+ _index2 = 0;
+ break;
+ }
+ }
+}
+
+uint32 Scene3011::handleMessage(int messageNum, const MessageParam &param, 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
diff --git a/engines/neverhood/module3000.h b/engines/neverhood/module3000.h
new file mode 100644
index 0000000000..2e25a0dec1
--- /dev/null
+++ b/engines/neverhood/module3000.h
@@ -0,0 +1,269 @@
+/* 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_MODULE3000_H
+#define NEVERHOOD_MODULE3000_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/module1200.h"
+
+namespace Neverhood {
+
+class Module3000 : public Module {
+public:
+ Module3000(NeverhoodEngine *vm, Module *parentModule, int which);
+ virtual ~Module3000();
+protected:
+ int _soundVolume;
+ bool _flag;
+ void createScene(int sceneNum, int which);
+ void updateScene();
+};
+
+// Scene3009
+
+class Scene3009;
+
+class SsScene3009FireCannonButton : public StaticSprite {
+public:
+ SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene);
+protected:
+ Scene3009 *_parentScene;
+ SoundResource _soundResource;
+ bool _flag1;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene3009SymbolEdges : public StaticSprite {
+public:
+ SsScene3009SymbolEdges(NeverhoodEngine *vm, int index);
+ void show();
+ void hide();
+ void startBlinking();
+protected:
+ int _blinkCountdown;
+ bool _blinkToggle;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene3009TargetLine : public StaticSprite {
+public:
+ SsScene3009TargetLine(NeverhoodEngine *vm, int index);
+ void show();
+};
+
+class SsScene3009SymbolArrow : public StaticSprite {
+public:
+ SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index);
+ void hide();
+protected:
+ SoundResource _soundResource;
+ Sprite *_asSymbol;
+ int _index;
+ int _incrDecr;
+ bool _enabled;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene3009VerticalIndicator : public AnimatedSprite {
+public:
+ AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index);
+ void show();
+protected:
+ Scene3009 *_parentScene;
+ bool _enabled;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene3009HorizontalIndicator : public AnimatedSprite {
+public:
+ AsScene3009HorizontalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, uint32 varValue);
+ void show();
+ void stMoveLeft();
+ void stMoveRight();
+protected:
+ Scene3009 *_parentScene;
+ bool _enabled;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void suMoveLeft();
+ void suMoveRight();
+};
+
+class AsScene3009Symbol : public AnimatedSprite {
+public:
+ AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int index);
+ void hide();
+protected:
+ Scene3009 *_parentScene;
+ int _index;
+ uint32 _symbolIndex;
+ SsScene3009SymbolArrow *_ssArrowPrev;
+ SsScene3009SymbolArrow *_ssArrowNext;
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class Scene3009 : public Scene {
+public:
+ Scene3009(NeverhoodEngine *vm, Module *parentModule, int which);
+ bool sub462E90();
+protected:
+ int _lockSymbolsPart1Countdown;
+ int _lockSymbolsPart2Countdown;
+ SmackerPlayer *_smackerPlayer;
+ Sprite *_ssFireCannonButton;
+ SsScene3009SymbolEdges *_ssSymbolEdges[2];
+ SsScene3009TargetLine *_ssTargetLines[2];
+ AsScene3009VerticalIndicator *_asVerticalIndicator;
+ AsScene3009HorizontalIndicator *_asHorizontalIndicator;
+ AsScene3009Symbol *_asSymbols[6];
+ uint32 _cannonLocation;
+ uint32 _correctSymbols[6];
+ bool _keepVideo;
+ bool _flag2;
+ // UNUSED? bool _flag3;
+ bool _flag4;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void playExtVideo();
+ bool isSymbolsPart1Solved();
+ bool isSymbolsPart2Solved();
+};
+
+// Scene3010
+
+class SsScene3010DeadBoltButton : public StaticSprite {
+public:
+ SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled);
+ void setCountdown(int count);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ int _buttonIndex;
+ bool _buttonEnabled;
+ bool _buttonLocked;
+ int _countdown1;
+ int _countdown2;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void disableButton();
+ void setSprite(uint32 fileHash);
+};
+
+class AsScene3010DeadBolt : public AnimatedSprite {
+public:
+ AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked);
+ void setCountdown(int count);
+ void lock();
+ void unlock(bool skipAnim);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ SoundResource _soundResource3;
+ int _boltIndex;
+ int _countdown;
+ bool _soundToggle;
+ bool _unlocked;
+ bool _locked;
+ void update();
+ uint32 hmAnimation(int messageNum, const MessageParam &param, Entity *sender);
+ void stIdle();
+ void stIdleMessage();
+ void stDisabled();
+ void stDisabledMessage();
+};
+
+class Scene3010 : public Scene {
+public:
+ Scene3010(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ SoundResource _soundResource;
+ int _countdown;
+ bool _doorUnlocked;
+ bool _checkUnlocked;
+ SsScene3010DeadBoltButton *_ssDeadBoltButtons[3];
+ AsScene3010DeadBolt *_asDeadBolts[3];
+ bool _boltUnlocked[3];
+ bool _boltUnlocking[3];
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene3011
+
+class SsScene3011Button : public StaticSprite {
+public:
+ SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag);
+protected:
+ Scene *_parentScene;
+ SoundResource _soundResource;
+ int _countdown;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene3011Symbol : public AnimatedSprite {
+public:
+ AsScene3011Symbol(NeverhoodEngine *vm, int index, bool flag);
+ void show(bool flag);
+ void hide();
+ void stopSound();
+ void change(int index, bool flag);
+ bool getFlag1() { return _flag1; }
+ int getIndex() { return _index; }
+protected:
+ SoundResource _soundResource1;
+ SoundResource _soundResource2;
+ bool _flag1;
+ bool _flag2;
+ int _index;
+};
+
+class Scene3011 : public Scene {
+public:
+ Scene3011(NeverhoodEngine *vm, Module *parentModule, int which);
+protected:
+ Sprite *_ssButton;
+ AsScene3011Symbol *_asSymbols[12];
+ int _updateStatus;
+ bool _buttonClicked;
+ int _countdown;
+ int _index1;
+ int _index2;
+ int _index3;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void fadeIn();
+ void fadeOut();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULE3000_H */
diff --git a/engines/neverhood/mouse.cpp b/engines/neverhood/mouse.cpp
new file mode 100644
index 0000000000..03b1478c55
--- /dev/null
+++ b/engines/neverhood/mouse.cpp
@@ -0,0 +1,249 @@
+/* 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/mouse.h"
+
+namespace Neverhood {
+
+// TODO: Use CursorMan
+
+Mouse::Mouse(NeverhoodEngine *vm, uint32 fileHash, const NRect &mouseRect)
+ : StaticSprite(vm, 2000), _mouseType(kMouseType433),
+ _mouseCursorResource(vm), _frameNum(0) {
+
+ _mouseRect = mouseRect;
+ init(fileHash);
+ if (_x >= _mouseRect.x1 && _x <= _mouseRect.x2 &&
+ _y >= _mouseRect.y1 && _y <= _mouseRect.y2) {
+ _mouseCursorResource.setCursorNum(1);
+ } else {
+ _mouseCursorResource.setCursorNum(4);
+ }
+ updateCursor();
+}
+
+Mouse::Mouse(NeverhoodEngine *vm, uint32 fileHash, int16 x1, int16 x2)
+ : StaticSprite(vm, 2000), _mouseType(kMouseType435),
+ _mouseCursorResource(vm), _frameNum(0), _x1(x1), _x2(x2) {
+
+ init(fileHash);
+ if (_x <= _x1) {
+ _mouseCursorResource.setCursorNum(6);
+ } else if (_x >= _x2) {
+ _mouseCursorResource.setCursorNum(5);
+ } else {
+ _mouseCursorResource.setCursorNum(4);
+ }
+ updateCursor();
+}
+
+Mouse::Mouse(NeverhoodEngine *vm, uint32 fileHash, int type)
+ : StaticSprite(vm, 2000), _mouseType(kMouseTypeNavigation),
+ _mouseCursorResource(vm), _type(type), _frameNum(0) {
+
+ init(fileHash);
+ _mouseCursorResource.setCursorNum(0);
+}
+
+void Mouse::init(uint32 fileHash) {
+ _mouseCursorResource.load(fileHash);
+ _x = _vm->getMouseX();
+ _y = _vm->getMouseY();
+ createSurface(2000, 32, 32);
+ SetUpdateHandler(&Mouse::update);
+ SetMessageHandler(&Mouse::handleMessage);
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = 32;
+ _drawRect.height = 32;
+ _deltaRect = _drawRect;
+ processDelta();
+ _needRefresh = true;
+}
+
+void Mouse::load(uint32 fileHash) {
+ _mouseCursorResource.load(fileHash);
+ _needRefresh = true;
+}
+
+void Mouse::update() {
+ updateCursor();
+ _frameNum++;
+ if (_frameNum >= 6)
+ _frameNum = 0;
+ _needRefresh = _frameNum % 2 == 0;
+}
+
+uint32 Mouse::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ debug(7, "Mouse::handleMessage(%04X)", messageNum);
+ uint32 messageResult = 0;
+ if (messageNum != 5) {
+ messageResult = Sprite::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x2064:
+ _x = param.asPoint().x;
+ _y = param.asPoint().y;
+ switch (_type) {
+ case 1:
+ if (_x >= 320)
+ messageResult = 1;
+ else
+ messageResult = 0;
+ break;
+ case 2:
+ default:
+ if (_x < 100)
+ messageResult = 0;
+ else if (_x > 540)
+ messageResult = 1;
+ else
+ messageResult = 2;
+ break;
+ case 3:
+ if (_x < 100)
+ messageResult = 0;
+ else if (_x > 540)
+ messageResult = 1;
+ else
+ messageResult = 4;
+ break;
+ case 4:
+ if (_x < 100)
+ messageResult = 0;
+ else if (_x > 540)
+ messageResult = 1;
+ else if (_y >= 150)
+ messageResult = 2;
+ else
+ messageResult = 3;
+ break;
+ case 5:
+ if (_y >= 240)
+ messageResult = 4;
+ else
+ messageResult = 3;
+ break;
+ }
+ break;
+ case 0x4002:
+ _x = param.asPoint().x;
+ _y = param.asPoint().y;
+ updateCursorNum();
+ processDelta();
+ break;
+ }
+ } else {
+ // TODO: Debug stuff
+ }
+ return messageResult;
+}
+
+void Mouse::updateCursor() {
+
+ if (!_surface)
+ return;
+
+ if (_doDeltaX) {
+ _surface->getDrawRect().x = filterX(_x - _drawRect.width - _drawRect.x + 1);
+ } else {
+ _surface->getDrawRect().x = filterX(_x + _drawRect.x);
+ }
+
+ if (_doDeltaY) {
+ _surface->getDrawRect().y = filterY(_y - _drawRect.height - _drawRect.y + 1);
+ } else {
+ _surface->getDrawRect().y = filterY(_y + _drawRect.y);
+ }
+
+ if (_needRefresh) {
+ _needRefresh = false;
+ _drawRect = _mouseCursorResource.getRect();
+ _surface->drawMouseCursorResource(_mouseCursorResource, _frameNum / 2);
+ }
+
+}
+
+void Mouse::updateCursorNum() {
+ switch (_mouseType) {
+ case kMouseType433:
+ if (_x >= _mouseRect.x1 && _x <= _mouseRect.x2 &&
+ _y >= _mouseRect.y1 && _y <= _mouseRect.y2) {
+ _mouseCursorResource.setCursorNum(1);
+ } else {
+ _mouseCursorResource.setCursorNum(4);
+ }
+ break;
+ case kMouseType435:
+ if (_x <= _x1) {
+ _mouseCursorResource.setCursorNum(6);
+ } else if (_x >= _x2) {
+ _mouseCursorResource.setCursorNum(5);
+ } else {
+ _mouseCursorResource.setCursorNum(4);
+ }
+ break;
+ case kMouseTypeNavigation:
+ switch (_type) {
+ case 1:
+ if (_x >= 320)
+ _mouseCursorResource.setCursorNum(5);
+ else
+ _mouseCursorResource.setCursorNum(6);
+ break;
+ case 2:
+ default:
+ if (_x < 100)
+ _mouseCursorResource.setCursorNum(6);
+ else if (_x > 540)
+ _mouseCursorResource.setCursorNum(5);
+ else
+ _mouseCursorResource.setCursorNum(0);
+ break;
+ case 3:
+ if (_x < 100)
+ _mouseCursorResource.setCursorNum(1);
+ else if (_x > 540)
+ _mouseCursorResource.setCursorNum(1);
+ break;
+ case 4:
+ if (_x < 100)
+ _mouseCursorResource.setCursorNum(6);
+ else if (_x > 540)
+ _mouseCursorResource.setCursorNum(5);
+ else if (_y >= 150)
+ _mouseCursorResource.setCursorNum(0);
+ else
+ _mouseCursorResource.setCursorNum(3);
+ break;
+ case 5:
+ if (_y >= 240)
+ _mouseCursorResource.setCursorNum(2);
+ else
+ _mouseCursorResource.setCursorNum(3);
+ break;
+ }
+ break;
+ }
+
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/mouse.h b/engines/neverhood/mouse.h
new file mode 100644
index 0000000000..0b4f6b81db
--- /dev/null
+++ b/engines/neverhood/mouse.h
@@ -0,0 +1,62 @@
+/* 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_MOUSE_H
+#define NEVERHOOD_MOUSE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/sprite.h"
+#include "neverhood/graphics.h"
+#include "neverhood/resource.h"
+
+namespace Neverhood {
+
+enum MouseType {
+ kMouseType433,
+ kMouseType435,
+ kMouseTypeNavigation
+};
+
+class Mouse : public StaticSprite {
+public:
+ Mouse(NeverhoodEngine *vm, uint32 fileHash, const NRect &mouseRect);
+ Mouse(NeverhoodEngine *vm, uint32 fileHash, int16 x1, int16 x2);
+ Mouse(NeverhoodEngine *vm, uint32 fileHash, int _type);
+ void load(uint32 fileHash);
+ void updateCursor();
+protected:
+ MouseType _mouseType;
+ MouseCursorResource _mouseCursorResource;
+ int _frameNum;
+ NRect _mouseRect;
+ int16 _x1;
+ int16 _x2;
+ int _type;
+ void init(uint32 fileHash);
+ void update();
+ void updateCursorNum();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MOUSE_H */
diff --git a/engines/neverhood/navigationscene.cpp b/engines/neverhood/navigationscene.cpp
new file mode 100644
index 0000000000..7a3161cb47
--- /dev/null
+++ b/engines/neverhood/navigationscene.cpp
@@ -0,0 +1,217 @@
+/* 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/navigationscene.h"
+#include "neverhood/mouse.h"
+
+namespace Neverhood {
+
+NavigationScene::NavigationScene(NeverhoodEngine *vm, Module *parentModule, uint32 navigationListId, int navigationIndex, const byte *itemsTypes)
+ : Scene(vm, parentModule, true), _itemsTypes(itemsTypes), _navigationIndex(navigationIndex), _smackerDone(false),
+ _soundFlag1(false), _soundFlag2(false), _smackerFileHash(0), _interactive(true), _done(false) {
+
+ _navigationList = _vm->_staticData->getNavigationList(navigationListId);
+ for (NavigationList::iterator it = _navigationList->begin(); it != _navigationList->end(); it++) {
+ debug("%08X %08X %08X %08X %d %d %08X", (*it).fileHash, (*it).leftSmackerFileHash, (*it).rightSmackerFileHash,
+ (*it).middleSmackerFileHash, (*it).interactive, (*it).middleFlag, (*it).mouseCursorFileHash);
+ }
+
+ if (_navigationIndex < 0) {
+ _navigationIndex = (int)getGlobalVar(0x4200189E);
+ if (_navigationIndex >= (int)_navigationList->size())
+ _navigationIndex = 0;
+ }
+ setGlobalVar(0x4200189E, _navigationIndex);
+
+ SetUpdateHandler(&NavigationScene::update);
+ SetMessageHandler(&NavigationScene::handleMessage);
+
+ _smackerPlayer = new SmackerPlayer(_vm, this, (*_navigationList)[_navigationIndex].fileHash, true, true);
+
+ addEntity(_smackerPlayer);
+
+ addSurface(_smackerPlayer->getSurface());
+
+ createMouseCursor();
+
+ _vm->_screen->clear();
+
+ sendMessage(_parentModule, 0x100A, _navigationIndex);
+
+}
+
+NavigationScene::~NavigationScene() {
+ // TODO Sound1ChList_sub_4080B0(0);
+ // TODO Sound1ChList_sub_408110(0);
+}
+
+int NavigationScene::getNavigationAreaType() {
+ NPoint mousePos;
+ mousePos.x = _mouseCursor->getX();
+ mousePos.y = _mouseCursor->getY();
+ return sendPointMessage(_mouseCursor, 0x2064, mousePos);
+}
+
+void NavigationScene::update() {
+ if (_smackerFileHash != 0) {
+ showMouse(false);
+ _smackerPlayer->open(_smackerFileHash, false);
+ _vm->_screen->clear();
+ _smackerDone = false;
+ _smackerFileHash = 0;
+ } else if (_smackerDone) {
+ if (_done) {
+ sendMessage(_parentModule, 0x1009, _navigationIndex);
+ } else {
+ const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex];
+ createMouseCursor();
+ showMouse(true);
+ _soundFlag2 = false;
+ _soundFlag1 = false;
+ _interactive = true;
+ // TODO Sound1ChList_sub_4080B0(0);
+ // TODO Sound1ChList_sub_408110(0);
+ _smackerDone = false;
+ _smackerPlayer->open(navigationItem.fileHash, true);
+ _vm->_screen->clear();
+ sendMessage(_parentModule, 0x100A, _navigationIndex);
+ }
+ }
+ Scene::update();
+}
+
+uint32 NavigationScene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x0000:
+ if (_interactive)
+ sendMessage(_mouseCursor, 0x4002, param);
+ break;
+ case 0x0001:
+ if (_interactive)
+ handleNavigation(param.asPoint());
+ break;
+ case 0x0009:
+ if (!_interactive)
+ _smackerDone = true;
+ break;
+ case 0x3002:
+ _smackerDone = true;
+ break;
+ }
+ return 0;
+}
+
+void NavigationScene::createMouseCursor() {
+
+ const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex];
+ uint32 mouseCursorFileHash;
+ int areaType;
+
+ if (_mouseCursor) {
+ deleteSprite((Sprite**)&_mouseCursor);
+ }
+
+ mouseCursorFileHash = navigationItem.mouseCursorFileHash;
+ // TODO: Check the resource...
+ if (mouseCursorFileHash == 0)
+ mouseCursorFileHash = 0x63A40028;
+
+ if (_itemsTypes) {
+ areaType = _itemsTypes[_navigationIndex];
+ } else if (navigationItem.middleSmackerFileHash != 0 || navigationItem.middleFlag) {
+ areaType = 0;
+ } else {
+ areaType = 1;
+ }
+
+ insertNavigationMouse(mouseCursorFileHash, areaType);
+ sendPointMessage(_mouseCursor, 0x4002, _vm->getMousePos());
+
+}
+
+void NavigationScene::handleNavigation(const NPoint &mousePos) {
+
+ const NavigationItem &navigationItem = (*_navigationList)[_navigationIndex];
+ bool oldSoundFlag1 = _soundFlag1;
+ bool oldSoundFlag2 = _soundFlag2;
+ uint32 direction = sendPointMessage(_mouseCursor, 0x2064, mousePos);
+
+ switch (direction) {
+ // TODO: Merge cases 0 and 1?
+ case 0:
+ if (navigationItem.leftSmackerFileHash != 0) {
+ _smackerFileHash = navigationItem.leftSmackerFileHash;
+ _interactive = false;
+ _soundFlag1 = false;
+ _soundFlag2 = true;
+ do {
+ _navigationIndex--;
+ if (_navigationIndex < 0)
+ _navigationIndex = _navigationList->size() - 1;
+ } while (!(*_navigationList)[_navigationIndex].interactive);
+ setGlobalVar(0x4200189E, _navigationIndex);
+ } else {
+ sendMessage(_parentModule, 0x1009, _navigationIndex);
+ }
+ break;
+ case 1:
+ if (navigationItem.rightSmackerFileHash != 0) {
+ _smackerFileHash = navigationItem.rightSmackerFileHash;
+ _interactive = false;
+ _soundFlag1 = false;
+ _soundFlag2 = true;
+ do {
+ _navigationIndex++;
+ if (_navigationIndex >= (int)_navigationList->size())
+ _navigationIndex = 0;
+ } while (!(*_navigationList)[_navigationIndex].interactive);
+ setGlobalVar(0x4200189E, _navigationIndex);
+ } else {
+ sendMessage(_parentModule, 0x1009, _navigationIndex);
+ }
+ break;
+ case 2:
+ case 3:
+ case 4:
+ if (navigationItem.middleFlag) {
+ sendMessage(_parentModule, 0x1009, _navigationIndex);
+ } else if (navigationItem.middleSmackerFileHash != 0) {
+ _smackerFileHash = navigationItem.middleSmackerFileHash;
+ _interactive = false;
+ _soundFlag1 = true;
+ _soundFlag2 = false;
+ _done = true;
+ }
+ break;
+ }
+
+ if (oldSoundFlag2 != _soundFlag2) {
+ // TODO Sound1ChList_sub_408110(_soundFlag2);
+ }
+
+ if (oldSoundFlag1 != _soundFlag1) {
+ // TODO Sound1ChList_sub_4080B0(_soundFlag1);
+ }
+
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/navigationscene.h b/engines/neverhood/navigationscene.h
new file mode 100644
index 0000000000..c37a7fc178
--- /dev/null
+++ b/engines/neverhood/navigationscene.h
@@ -0,0 +1,56 @@
+/* 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_NAVIGATIONSCENE_H
+#define NEVERHOOD_NAVIGATIONSCENE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/resourceman.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+class NavigationScene : public Scene {
+public:
+ NavigationScene(NeverhoodEngine *vm, Module *parentModule, uint32 navigationListId, int navigationIndex, const byte *itemsTypes);
+ virtual ~NavigationScene();
+ int getNavigationAreaType();
+protected:
+ SmackerPlayer *_smackerPlayer;
+ bool _smackerDone;
+ NavigationList *_navigationList;
+ int _navigationIndex;
+ uint32 _smackerFileHash;
+ bool _interactive;
+ bool _soundFlag1;
+ bool _soundFlag2;
+ bool _done;
+ const byte *_itemsTypes;
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void createMouseCursor();
+ void handleNavigation(const NPoint &mousePos);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_NAVIGATIONSCENE_H */
diff --git a/engines/neverhood/neverhood.cpp b/engines/neverhood/neverhood.cpp
new file mode 100644
index 0000000000..f1f4bab9cd
--- /dev/null
+++ b/engines/neverhood/neverhood.cpp
@@ -0,0 +1,248 @@
+/* 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 "common/file.h"
+#include "common/config-manager.h"
+#include "base/plugins.h"
+#include "base/version.h"
+#include "graphics/cursorman.h"
+#include "engines/util.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/blbarchive.h"
+#include "neverhood/collisionman.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/gamevars.h"
+#include "neverhood/graphics.h"
+#include "neverhood/resourceman.h"
+#include "neverhood/resource.h"
+#include "neverhood/screen.h"
+#include "neverhood/staticdata.h"
+
+namespace Neverhood {
+
+NeverhoodEngine::NeverhoodEngine(OSystem *syst, const NeverhoodGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
+ // Setup mixer
+ if (!_mixer->isReady()) {
+ warning("Sound initialization failed.");
+ }
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+
+ _rnd = new Common::RandomSource("neverhood");
+
+}
+
+NeverhoodEngine::~NeverhoodEngine() {
+ delete _rnd;
+}
+
+Common::Error NeverhoodEngine::run() {
+ initGraphics(640, 480, true);
+
+ _isSaveAllowed = false;
+
+ _mouseX = 0;
+ _mouseY = 0;
+
+ _gameState.sceneNum = 0;
+ _gameState.field2 = 0;
+
+ _staticData = new StaticData();
+ _staticData->load("neverhood.dat");
+
+ _gameVars = new GameVars();
+
+ _screen = new Screen(this);
+
+ _res = new ResourceMan();
+ _res->addArchive("a.blb");
+ _res->addArchive("c.blb");
+ _res->addArchive("hd.blb");
+ _res->addArchive("i.blb");
+ _res->addArchive("m.blb");
+ _res->addArchive("s.blb");
+ _res->addArchive("t.blb");
+
+ CursorMan.showMouse(true);
+ {
+ // DEBUG: Dummy cursor
+ byte buffer[2*2];
+ memset(buffer, 255, 4);
+ CursorMan.replaceCursor(buffer, 2, 2, 0, 0, 0);
+ }
+
+#if 0
+ // TODO: This should probably be implemented as debug command later
+ dumpAllResources();
+#endif
+
+#if 1
+
+ _collisionMan = new CollisionMan(this);
+ _gameModule = new GameModule(this);
+
+ _gameModule->startup();
+
+ // Preliminary main loop, needs some more work but works for testing
+ while (!shouldQuit()) {
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ _keyState = event.kbd.keycode;
+ break;
+ case Common::EVENT_KEYUP:
+ _keyState = Common::KEYCODE_INVALID;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ _gameModule->handleMouseMove(event.mouse.x, event.mouse.y);
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_RBUTTONDOWN:
+ _gameModule->handleMouseDown(event.mouse.x, event.mouse.y);
+ break;
+ case Common::EVENT_QUIT:
+ _system->quit();
+ break;
+ default:
+ break;
+ }
+ }
+
+ //debug("millis %d", _system->getMillis());
+ _gameModule->handleUpdate();
+ _gameModule->draw();
+ _screen->wait();
+ _screen->update();
+
+ debug(0, "---------------------------------------");
+
+ }
+
+ delete _gameModule;
+ delete _collisionMan;
+#endif
+
+
+ delete _res;
+ delete _screen;
+
+ delete _gameVars;
+ delete _staticData;
+
+ debug("Ok.");
+
+ return Common::kNoError;
+}
+
+NPoint NeverhoodEngine::getMousePos() {
+ NPoint pt;
+ pt.x = _mouseX;
+ pt.y = _mouseY;
+ return pt;
+}
+
+void writeTga(const char *filename, byte *pixels, byte *palette, int16 width, int16 height) {
+ byte identsize = 0;
+ byte colourmaptype = 1;
+ byte imagetype = 1;
+ uint16 colourmapstart = 0;
+ uint16 colourmaplength = 256;
+ byte colourmapbits = 24;
+ uint16 xstart = 0;
+ uint16 ystart = 0;
+ byte bits = 8;
+ byte descriptor = 0x20;
+ Common::DumpFile tga;
+ tga.open(filename);
+ tga.writeByte(identsize);
+ tga.writeByte(colourmaptype);
+ tga.writeByte(imagetype);
+ tga.writeUint16LE(colourmapstart);
+ tga.writeUint16LE(colourmaplength);
+ tga.writeByte(colourmapbits);
+ tga.writeUint16LE(xstart);
+ tga.writeUint16LE(ystart);
+ tga.writeUint16LE(width);
+ tga.writeUint16LE(height);
+ tga.writeByte(bits);
+ tga.writeByte(descriptor);
+ tga.write(palette, 768);
+ tga.write(pixels, width * height);
+ tga.close();
+}
+
+void NeverhoodEngine::dumpAllResources() {
+
+ PaletteResource paletteResource(this);
+ byte *vgaPalette = new byte[768];
+ paletteResource.load(0x4086520E);
+ byte *srcpalette = paletteResource.palette();
+ for (int i = 0; i < 256; i++) {
+ vgaPalette[i * 3 + 2] = srcpalette[i * 4 + 0];
+ vgaPalette[i * 3 + 1] = srcpalette[i * 4 + 1];
+ vgaPalette[i * 3 + 0] = srcpalette[i * 4 + 2];
+ }
+
+#if 0
+ for (int i = 0; i < 768; i++)
+ vgaPalette[i] <<= 2;
+#endif
+
+ uint entriesCount = _res->getEntryCount();
+ debug("%d entries", entriesCount);
+
+ for (uint i = 0; i < entriesCount; i++) {
+ const ResourceFileEntry &entry = _res->getEntry(i);
+ int type = _res->getResourceTypeByHash(entry.fileHash);
+ debug("hash: %08X; type: %d", entry.fileHash, type);
+ if (type == 4) {
+ AnimResource anim(this);
+ anim.load(entry.fileHash);
+ for (uint frameIndex = 0; frameIndex < anim.getFrameCount(); frameIndex++) {
+ const AnimFrameInfo &frameInfo = anim.getFrameInfo(frameIndex);
+ int16 width = (frameInfo.rect.width + 3) & 0xFFFC;
+ byte *pixels = new byte[width * frameInfo.rect.height];
+ memset(pixels, 0, width * frameInfo.rect.height);
+ anim.draw(frameIndex, pixels, width, false, false);
+ Common::String filename =
+ frameInfo.frameHash != 0
+ ? Common::String::format("%08X_%03d_%08X.tga", entry.fileHash, frameIndex, frameInfo.frameHash)
+ : Common::String::format("%08X_%03d.tga", entry.fileHash, frameIndex);
+ writeTga(filename.c_str(), pixels, vgaPalette, width, frameInfo.rect.height);
+ delete[] pixels;
+ }
+ static int n = 0;
+ //if (n++ == 25) break;
+ }
+ }
+
+ delete[] vgaPalette;
+
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/neverhood.h b/engines/neverhood/neverhood.h
new file mode 100644
index 0000000000..adc46198d6
--- /dev/null
+++ b/engines/neverhood/neverhood.h
@@ -0,0 +1,135 @@
+/* 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_H
+#define NEVERHOOD_H
+
+#include "common/scummsys.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/random.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "audio/mixer.h"
+#include "engines/engine.h"
+
+namespace Neverhood {
+
+enum NeverhoodGameFeatures {
+};
+
+struct NeverhoodGameDescription;
+
+class CollisionMan;
+class GameModule;
+class GameVars;
+class ResourceMan;
+class Screen;
+class StaticData;
+struct NPoint;
+
+struct GameState {
+ int sceneNum;
+ int which;
+ int field2;
+};
+
+class NeverhoodEngine : public ::Engine {
+protected:
+
+ Common::Error run();
+
+public:
+ NeverhoodEngine(OSystem *syst, const NeverhoodGameDescription *gameDesc);
+ virtual ~NeverhoodEngine();
+
+ // Detection related functions
+ const NeverhoodGameDescription *_gameDescription;
+ const char *getGameId() const;
+ uint32 getFeatures() const;
+ uint16 getVersion() const;
+ Common::Platform getPlatform() const;
+ bool hasFeature(EngineFeature f) const;
+
+ Common::RandomSource *_rnd;
+
+ int16 _mouseX, _mouseY;
+ Common::KeyCode _keyState;
+ uint16 _buttonState;
+
+ GameState _gameState;
+ GameVars *_gameVars;
+ Screen *_screen;
+ ResourceMan *_res;
+ GameModule *_gameModule;
+ StaticData *_staticData;
+ CollisionMan *_collisionMan;
+
+public:
+
+ /* Save/load */
+
+ enum kReadSaveHeaderError {
+ kRSHENoError = 0,
+ kRSHEInvalidType = 1,
+ kRSHEInvalidVersion = 2,
+ kRSHEIoError = 3
+ };
+
+ struct SaveHeader {
+ Common::String description;
+ uint32 version;
+ byte gameID;
+ uint32 flags;
+ Graphics::Surface *thumbnail;
+ };
+
+ bool _isSaveAllowed;
+
+ bool canLoadGameStateCurrently() { return _isSaveAllowed; }
+ bool canSaveGameStateCurrently() { return _isSaveAllowed; }
+
+#if 0 // Not used yet but let's keep it for later when it is
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameState(int slot, const Common::String &description);
+ void savegame(const char *filename, const char *description);
+ void loadgame(const char *filename);
+ const char *getSavegameFilename(int num);
+ static Common::String getSavegameFilename(const Common::String &target, int num);
+ static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
+#endif
+
+ GameState& gameState() { return _gameState; }
+ GameModule *gameModule() { return _gameModule; }
+ int16 getMouseX() const { return _mouseX; }
+ int16 getMouseY() const { return _mouseY; }
+ NPoint getMousePos();
+
+ void dumpAllResources();
+
+public:
+
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_H */
diff --git a/engines/neverhood/palette.cpp b/engines/neverhood/palette.cpp
new file mode 100644
index 0000000000..481e0e5058
--- /dev/null
+++ b/engines/neverhood/palette.cpp
@@ -0,0 +1,177 @@
+/* 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/palette.h"
+#include "neverhood/resource.h"
+#include "neverhood/screen.h"
+
+namespace Neverhood {
+
+// Palette
+
+Palette::Palette(NeverhoodEngine *vm) : Entity(vm, 0) {
+ init();
+ memset(_palette, 0, 1024);
+ SetUpdateHandler(&Palette::update);
+}
+
+Palette::Palette(NeverhoodEngine *vm, byte *palette) : Entity(vm, 0) {
+ init();
+ memcpy(_palette, palette, 1024);
+ SetUpdateHandler(&Palette::update);
+}
+
+Palette::Palette(NeverhoodEngine *vm, const char *filename) : Entity(vm, 0) {
+ PaletteResource paletteResource(_vm);
+ init();
+ paletteResource.load(calcHash(filename));
+ paletteResource.copyPalette(_palette);
+ SetUpdateHandler(&Palette::update);
+}
+
+Palette::Palette(NeverhoodEngine *vm, uint32 fileHash) : Entity(vm, 0) {
+ PaletteResource paletteResource(_vm);
+ init();
+ paletteResource.load(fileHash);
+ paletteResource.copyPalette(_palette);
+ SetUpdateHandler(&Palette::update);
+}
+
+Palette::~Palette() {
+ _vm->_screen->unsetPaletteData(_palette);
+ delete[] _palette;
+ delete[] _basePalette;
+}
+
+void Palette::init() {
+ _status = 0;
+ _palette = new byte[1024];
+ _basePalette = new byte[1024];
+}
+
+void Palette::usePalette() {
+ _vm->_screen->setPaletteData(_palette);
+}
+
+void Palette::addPalette(const char *filename, int toIndex, int count, int fromIndex) {
+ addPalette(calcHash(filename), toIndex, count, fromIndex);
+}
+
+void Palette::addPalette(uint32 fileHash, int toIndex, int count, int fromIndex) {
+ PaletteResource paletteResource(_vm);
+ if (toIndex + count > 256)
+ count = 256 - toIndex;
+ paletteResource.load(fileHash);
+ memcpy(_palette + toIndex * 4, paletteResource.palette() + fromIndex * 4, count * 4);
+ _vm->_screen->testPalette(_palette);
+}
+
+void Palette::addBasePalette(uint32 fileHash, int toIndex, int count, int fromIndex) {
+ PaletteResource paletteResource(_vm);
+ if (toIndex + count > 256)
+ count = 256 - toIndex;
+ paletteResource.load(fileHash);
+ memcpy(_basePalette + toIndex * 4, paletteResource.palette() + fromIndex * 4, count * 4);
+}
+
+void Palette::copyPalette(const byte *palette, int toIndex, int count, int fromIndex) {
+ if (toIndex + count > 256)
+ count = 256 - toIndex;
+ memcpy(_palette + toIndex * 4, palette + fromIndex * 4, count * 4);
+ _vm->_screen->testPalette(_palette);
+}
+
+void Palette::copyBasePalette(int toIndex, int count, int fromIndex) {
+ if (toIndex + count > 256)
+ count = 256 - toIndex;
+ memcpy(_basePalette + toIndex * 4, _palette + fromIndex * 4, count * 4);
+}
+
+void Palette::startFadeToBlack(int counter) {
+ debug(2, "Palette::startFadeToBlack(%d)", counter);
+ if (counter == 0)
+ counter = 1;
+ _fadeToR = 0;
+ _fadeToG = 0;
+ _fadeToB = 0;
+ _palCounter = counter;
+ _fadeStep = 255 / counter;
+ _status = 1;
+}
+
+void Palette::startFadeToWhite(int counter) {
+ debug(2, "Palette::startFadeToWhite(%d)", counter);
+ if (counter == 0)
+ counter = 1;
+ _fadeToR = 255;
+ _fadeToG = 255;
+ _fadeToB = 255;
+ _palCounter = counter;
+ _fadeStep = 255 / counter;
+ _status = 1;
+}
+
+void Palette::startFadeToPalette(int counter) {
+ debug(2, "Palette::startFadeToPalette(%d)", counter);
+ if (counter == 0)
+ counter = 1;
+ _palCounter = counter;
+ _fadeStep = 255 / counter;
+ _status = 2;
+}
+
+void Palette::update() {
+ debug(2, "Palette::update() _status = %d", _status);
+ if (_status == 1) {
+ if (_palCounter > 1) {
+ for (int i = 0; i < 256; i++) {
+ fadeColor(_palette + i * 4, _fadeToR, _fadeToG, _fadeToB);
+ }
+ _vm->_screen->testPalette(_palette);
+ _palCounter--;
+ } else {
+ memset(_palette, 0, 1024);
+ _status = 0;
+ }
+ } else if (_status == 2) {
+ if (_palCounter > 1) {
+ for (int i = 0; i < 256; i++) {
+ fadeColor(_palette + i * 4, _basePalette[i * 4 + 0], _basePalette[i * 4 + 1], _basePalette[i * 4 + 2]);
+ }
+ _vm->_screen->testPalette(_palette);
+ _palCounter--;
+ } else {
+ memcpy(_palette, _basePalette, 256 * 4);
+ _status = 0;
+ }
+ }
+}
+
+void Palette::fadeColor(byte *rgb, byte toR, byte toG, byte toB) {
+ #define FADE(color, toColor) color += _fadeStep < toColor - color ? _fadeStep : (-_fadeStep <= toColor - color ? toColor - color : -_fadeStep)
+ FADE(rgb[0], toR);
+ FADE(rgb[1], toG);
+ FADE(rgb[2], toB);
+ #undef FADE
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/palette.h b/engines/neverhood/palette.h
new file mode 100644
index 0000000000..79660130e1
--- /dev/null
+++ b/engines/neverhood/palette.h
@@ -0,0 +1,65 @@
+/* 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_PALETTE_H
+#define NEVERHOOD_PALETTE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/entity.h"
+
+namespace Neverhood {
+
+class Palette : public Entity {
+public:
+ // Default constructor with black palette
+ Palette(NeverhoodEngine *vm);
+ // Create from existing palette
+ Palette(NeverhoodEngine *vm, byte *palette);
+ // Create from resource with filename
+ Palette(NeverhoodEngine *vm, const char *filename);
+ // Create from resource with fileHash
+ Palette(NeverhoodEngine *vm, uint32 fileHash);
+ virtual ~Palette();
+ void init();
+ void usePalette();
+ void addPalette(const char *filename, int toIndex, int count, int fromIndex);
+ void addPalette(uint32 fileHash, int toIndex, int count, int fromIndex);
+ void addBasePalette(uint32 fileHash, int toIndex, int count, int fromIndex);
+ void copyPalette(const byte *palette, int toIndex, int count, int fromIndex);
+ void copyBasePalette(int toIndex, int count, int fromIndex);
+ void startFadeToBlack(int counter);
+ void startFadeToWhite(int counter);
+ void startFadeToPalette(int counter);
+protected:
+ int _status;
+ byte *_palette;
+ byte *_basePalette;
+ int _palCounter;
+ byte _fadeToR, _fadeToG, _fadeToB;
+ int _fadeStep;
+ void update();
+ void fadeColor(byte *rgb, byte toR, byte toG, byte toB);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_PALETTE_H */
diff --git a/engines/neverhood/resource.cpp b/engines/neverhood/resource.cpp
new file mode 100644
index 0000000000..9678031554
--- /dev/null
+++ b/engines/neverhood/resource.cpp
@@ -0,0 +1,679 @@
+/* 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 "common/memstream.h"
+#include "neverhood/resource.h"
+#include "neverhood/resourceman.h"
+
+namespace Neverhood {
+
+// TODO: Since the load() methods are similar in most cases some of the code therein
+// can probably be copied into another method (e.g. inside the resource manager)
+// to reduce code.
+
+// SpriteResource
+
+SpriteResource::SpriteResource(NeverhoodEngine *vm)
+ : _vm(vm), _resourceHandle(-1), _pixels(NULL) {
+}
+
+SpriteResource::~SpriteResource() {
+ unload();
+}
+
+void SpriteResource::draw(byte *dest, int destPitch, bool flipX, bool flipY) {
+ if (_pixels) {
+ if (_rle) {
+ unpackSpriteRle(_pixels, _dimensions.width, _dimensions.height, dest, destPitch, flipX, flipY);
+ } else {
+ unpackSpriteNormal(_pixels, _dimensions.width, _dimensions.height, dest, destPitch, flipX, flipY);
+ }
+ }
+}
+
+bool SpriteResource::load(uint32 fileHash) {
+ debug(2, "SpriteResource::load(%08X)", fileHash);
+ // TODO: Later merge with load2 and make the mode a parameter
+ unload();
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ debug(2, "SpriteResource::load(0x%08X) _resourceHandle = %d", fileHash, _resourceHandle);
+ if (_resourceHandle != -1) {
+ if (_vm->_res->getResourceType(_resourceHandle) == 2) {
+ byte *spriteData = _vm->_res->loadResource(_resourceHandle, true);
+ parseBitmapResource(spriteData, &_rle, &_dimensions, NULL, NULL, &_pixels);
+ } else {
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ }
+ }
+ return _pixels != NULL;
+}
+
+bool SpriteResource::load2(uint32 fileHash) {
+ unload();
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ if (_resourceHandle != -1) {
+ if (_vm->_res->getResourceType(_resourceHandle) == 2) {
+ byte *spriteData = _vm->_res->loadResource(_resourceHandle, true);
+ parseBitmapResource(spriteData, &_rle, &_dimensions, &_position, NULL, &_pixels);
+ } else {
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ }
+ }
+ return _pixels != NULL;
+}
+
+void SpriteResource::unload() {
+ if (_resourceHandle != -1) {
+ _vm->_res->unloadResource(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ } else {
+ delete[] _pixels;
+ }
+ _pixels = NULL;
+ _rle = false;
+}
+
+// PaletteResource
+
+PaletteResource::PaletteResource(NeverhoodEngine *vm)
+ : _vm(vm), _resourceHandle(-1), _palette(NULL) {
+}
+
+PaletteResource::~PaletteResource() {
+ unload();
+}
+
+bool PaletteResource::load(uint32 fileHash) {
+ debug(2, "PaletteResource::load(%08X)", fileHash);
+ unload();
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ if (_resourceHandle != -1) {
+ _palette = _vm->_res->loadResource(_resourceHandle, true);
+ switch (_vm->_res->getResourceType(_resourceHandle)) {
+ case 2:
+ // Palette is stored in a bitmap
+ parseBitmapResource(_palette, NULL, NULL, NULL, &_palette, NULL);
+ break;
+ case 3:
+ // _palette already points to the correct data
+ break;
+ default:
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ break;
+ }
+ }
+ return _palette != NULL;
+}
+
+void PaletteResource::unload() {
+ if (_resourceHandle != -1) {
+ _vm->_res->unloadResource(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ _palette = NULL;
+ }
+}
+
+void PaletteResource::copyPalette(byte *destPalette) {
+ if (_palette) {
+ memcpy(destPalette, _palette, 1024);
+ } else {
+ // TODO?: buildDefaultPalette(palette);
+ }
+}
+
+// AnimResource
+
+AnimResource::AnimResource(NeverhoodEngine *vm)
+ : _vm(vm), _width(0), _height(0), _currSpriteData(NULL) {
+
+ clear();
+ clear2();
+}
+
+AnimResource::~AnimResource() {
+ unloadInternal();
+}
+
+void AnimResource::draw(uint frameIndex, byte *dest, int destPitch, bool flipX, bool flipY) {
+ const AnimFrameInfo frameInfo = _frames[frameIndex];
+ _currSpriteData = _spriteData + frameInfo.spriteDataOffs;
+ _width = frameInfo.rect.width;
+ _height = frameInfo.rect.height;
+ if (_replEnabled && _replOldColor != _replNewColor)
+ unpackSpriteRleRepl(_currSpriteData, _width, _height, dest, destPitch, _replOldColor, _replNewColor, flipX, flipY);
+ else
+ unpackSpriteRle(_currSpriteData, _width, _height, dest, destPitch, flipX, flipY);
+}
+
+bool AnimResource::load(uint32 fileHash) {
+ debug(2, "AnimResource::load(%08X)", fileHash);
+
+ if (fileHash == _fileHash)
+ return true;
+
+ unload();
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ if (_resourceHandle == -1)
+ return false;
+
+ byte *resourceData, *animList, *frameList;
+ uint16 animInfoStartOfs, animListIndex, animListCount;
+ uint16 frameListStartOfs, frameCount;
+ uint32 spriteDataOfs, paletteDataOfs;
+
+ if (_vm->_res->getResourceType(_resourceHandle) != 4) {
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ return false;
+ }
+
+ resourceData = _vm->_res->loadResource(_resourceHandle);
+ if (!resourceData) {
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ return false;
+ }
+
+ animListCount = READ_LE_UINT16(resourceData);
+ animInfoStartOfs = READ_LE_UINT16(resourceData + 2);
+ spriteDataOfs = READ_LE_UINT32(resourceData + 4);
+ paletteDataOfs = READ_LE_UINT32(resourceData + 8);
+
+ animList = resourceData + 12;
+ for (animListIndex = 0; animListIndex < animListCount; animListIndex++) {
+ debug(8, "hash: %08X", READ_LE_UINT32(animList));
+ if (READ_LE_UINT32(animList) == fileHash)
+ break;
+ animList += 8;
+ }
+
+ if (animListIndex >= animListCount) {
+ _vm->_res->unloadResource(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ return false;
+ }
+
+ _spriteData = resourceData + spriteDataOfs;
+ if (paletteDataOfs > 0)
+ _paletteData = resourceData + paletteDataOfs;
+
+ frameCount = READ_LE_UINT16(animList + 4);
+ frameListStartOfs = READ_LE_UINT16(animList + 6);
+
+ debug(8, "frameCount = %d; frameListStartOfs = %04X; animInfoStartOfs = %04X", frameCount, frameListStartOfs, animInfoStartOfs);
+
+ frameList = resourceData + animInfoStartOfs + frameListStartOfs;
+
+ _frames.clear();
+ _frames.reserve(frameCount);
+
+ for (uint16 frameIndex = 0; frameIndex < frameCount; frameIndex++) {
+ AnimFrameInfo frameInfo;
+ frameInfo.frameHash = READ_LE_UINT32(frameList);
+ frameInfo.counter = READ_LE_UINT16(frameList + 4);
+ frameInfo.rect.x = READ_LE_UINT16(frameList + 6);
+ frameInfo.rect.y = READ_LE_UINT16(frameList + 8);
+ frameInfo.rect.width = READ_LE_UINT16(frameList + 10);
+ frameInfo.rect.height = READ_LE_UINT16(frameList + 12);
+ frameInfo.deltaX = READ_LE_UINT16(frameList + 14);
+ frameInfo.deltaY = READ_LE_UINT16(frameList + 16);
+ frameInfo.deltaRect.x = READ_LE_UINT16(frameList + 18);
+ frameInfo.deltaRect.y = READ_LE_UINT16(frameList + 20);
+ frameInfo.deltaRect.width = READ_LE_UINT16(frameList + 22);
+ frameInfo.deltaRect.height = READ_LE_UINT16(frameList + 24);
+ frameInfo.field_1A = READ_LE_UINT16(frameList + 26);
+ frameInfo.spriteDataOffs = READ_LE_UINT32(frameList + 28);
+ debug(8, "frameHash = %08X; counter = %d; rect = (%d,%d,%d,%d); deltaX = %d; deltaY = %d; deltaRect = (%d,%d,%d,%d); field_1A = %04X; spriteDataOffs = %08X",
+ frameInfo.frameHash, frameInfo.counter,
+ frameInfo.rect.x, frameInfo.rect.y, frameInfo.rect.width, frameInfo.rect.height,
+ frameInfo.deltaX, frameInfo.deltaY,
+ frameInfo.deltaRect.x, frameInfo.deltaRect.y, frameInfo.deltaRect.width, frameInfo.deltaRect.height,
+ frameInfo.field_1A, frameInfo.spriteDataOffs);
+ frameList += 32;
+ _frames.push_back(frameInfo);
+ }
+
+ _fileHash = fileHash;
+
+ return true;
+
+}
+
+void AnimResource::unload() {
+ if (_resourceHandle != -1) {
+ _vm->_res->unloadResource(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ clear();
+ }
+}
+
+void AnimResource::clear() {
+ _resourceHandle = -1;
+ _currSpriteData = NULL;
+ _fileHash = 0;
+ _paletteData = NULL;
+ _spriteData = NULL;
+}
+
+void AnimResource::clear2() {
+ clear();
+ _replEnabled = true;
+ _replOldColor = 0;
+ _replNewColor = 0;
+}
+
+bool AnimResource::loadInternal(uint32 fileHash) {
+ unloadInternal();
+ return load(fileHash);
+}
+
+void AnimResource::unloadInternal() {
+ unload();
+ clear2();
+}
+
+int16 AnimResource::getFrameIndex(uint32 frameHash) {
+ int16 frameIndex = -1;
+ for (uint i = 0; i < _frames.size(); i++)
+ if (_frames[i].frameHash == frameHash) {
+ frameIndex = (int16)i;
+ break;
+ }
+ debug(2, "AnimResource::getFrameIndex(%08X) -> %d", frameHash, frameIndex);
+ return frameIndex;
+}
+
+void AnimResource::setRepl(byte oldColor, byte newColor) {
+ _replOldColor = oldColor;
+ _replNewColor = newColor;
+}
+
+NDimensions AnimResource::loadSpriteDimensions(uint32 fileHash) {
+ NDimensions dimensions;
+ byte *resDimensions = _vm->_res->getResourceExtDataByHash(fileHash);
+ if (resDimensions) {
+ dimensions.width = READ_LE_UINT16(resDimensions + 0);
+ dimensions.height = READ_LE_UINT16(resDimensions + 2);
+ } else {
+ dimensions.width = 0;
+ dimensions.height = 0;
+ }
+ return dimensions;
+}
+
+// MouseCursorResource
+
+MouseCursorResource::MouseCursorResource(NeverhoodEngine *vm)
+ : _cursorSprite(vm), _cursorNum(4), _currFileHash(0) {
+
+ _rect.width = 32;
+ _rect.height = 32;
+}
+
+void MouseCursorResource::load(uint32 fileHash) {
+ if (_currFileHash != fileHash) {
+ if (_cursorSprite.load(fileHash) && !_cursorSprite.isRle() &&
+ _cursorSprite.getDimensions().width == 96 && _cursorSprite.getDimensions().height == 224) {
+ _currFileHash = fileHash;
+ } else {
+ unload();
+ }
+ }
+}
+
+void MouseCursorResource::unload() {
+ _cursorSprite.unload();
+ _currFileHash = 0;
+ _cursorNum = 4;
+}
+
+NDrawRect& MouseCursorResource::getRect() {
+ static const NPoint kCursorHotSpots[] = {
+ {-15, -5},
+ {-17, -25},
+ {-17, -30},
+ {-14, -1},
+ {-3, -7},
+ {-30, -18},
+ {-1, -18}
+ };
+ _rect.x = kCursorHotSpots[_cursorNum].x;
+ _rect.y = kCursorHotSpots[_cursorNum].y;
+ return _rect;
+}
+
+void MouseCursorResource::draw(int frameNum, byte *dest, int destPitch) {
+ if (_cursorSprite.getPixels()) {
+ int sourcePitch = (_cursorSprite.getDimensions().width + 3) & 0xFFFC; // 4 byte alignment
+ byte *source = _cursorSprite.getPixels() + _cursorNum * (sourcePitch * 32) + frameNum * 32;
+ for (int16 yc = 0; yc < 32; yc++) {
+ memcpy(dest, source, 32);
+ source += sourcePitch;
+ dest += destPitch;
+ }
+ }
+}
+
+// TextResource
+
+TextResource::TextResource(NeverhoodEngine *vm)
+ : _vm(vm), _resourceHandle(-1), _textData(NULL), _count(0) {
+
+}
+
+TextResource::~TextResource() {
+ unload();
+}
+
+void TextResource::load(uint32 fileHash) {
+ unload();
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ if (_resourceHandle != -1) {
+ if (_vm->_res->getResourceType(_resourceHandle) == 6) {
+ _textData = _vm->_res->loadResource(_resourceHandle, true);
+ _count = READ_LE_UINT32(_textData);
+ } else {
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ }
+ }
+}
+
+void TextResource::unload() {
+ if (_resourceHandle != -1) {
+ _vm->_res->unloadResource(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ _textData = NULL;
+ _count = 0;
+ }
+}
+
+const char *TextResource::getString(uint index, const char *&textEnd) {
+ const char *textStart = (const char*)(_textData + 4 + _count * 4 + READ_LE_UINT32(_textData + (index + 1) * 4));
+ textEnd = (const char*)(_textData + 4 + _count * 4 + READ_LE_UINT32(_textData + (index + 2) * 4));
+ return textStart;
+}
+
+// DataResource
+
+DataResource::DataResource(NeverhoodEngine *vm)
+ : _vm(vm), _resourceHandle(-1) {
+}
+
+DataResource::~DataResource() {
+ unload();
+}
+
+void DataResource::load(uint32 fileHash) {
+ debug(2, "DataResource::load(%08X)", fileHash);
+ byte *data = NULL;
+ uint32 dataSize = 0;
+ unload();
+ _resourceHandle = _vm->_res->useResource(fileHash);
+ if (_resourceHandle != -1) {
+ if (_vm->_res->getResourceType(_resourceHandle) == 5) {
+ data = _vm->_res->loadResource(_resourceHandle, true);
+ dataSize = _vm->_res->getResourceSize(_resourceHandle);
+ } else {
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ }
+ }
+ if (data && dataSize) {
+ Common::MemoryReadStream dataS(data, dataSize);
+ uint itemCount = dataS.readUint16LE();
+ uint32 itemStartOffs = 2 + itemCount * 8;
+ debug(2, "itemCount = %d", itemCount);
+ for (uint i = 0; i < itemCount; i++) {
+ dataS.seek(2 + i * 8);
+ DRDirectoryItem drDirectoryItem;
+ drDirectoryItem.nameHash = dataS.readUint32LE();
+ drDirectoryItem.offset = dataS.readUint16LE();
+ drDirectoryItem.type = dataS.readUint16LE();
+ debug(2, "%03d nameHash = %08X; offset = %04X; type = %d", i, drDirectoryItem.nameHash, drDirectoryItem.offset, drDirectoryItem.type);
+ dataS.seek(itemStartOffs + drDirectoryItem.offset);
+ switch (drDirectoryItem.type) {
+ case 1:
+ {
+ debug(3, "NPoint");
+ NPoint point;
+ point.x = dataS.readUint16LE();
+ point.y = dataS.readUint16LE();
+ debug(3, "(%d, %d)", point.x, point.y);
+ drDirectoryItem.offset = _points.size();
+ _points.push_back(point);
+ break;
+ }
+ case 2:
+ {
+ uint count = dataS.readUint16LE();
+ NPointArray *pointArray = new NPointArray();
+ debug(3, "NPointArray; count = %d", count);
+ for (uint j = 0; j < count; j++) {
+ NPoint point;
+ point.x = dataS.readUint16LE();
+ point.y = dataS.readUint16LE();
+ debug(3, "(%d, %d)", point.x, point.y);
+ pointArray->push_back(point);
+ }
+ drDirectoryItem.offset = _pointArrays.size();
+ _pointArrays.push_back(pointArray);
+ break;
+ }
+ case 3:
+ {
+ uint count = dataS.readUint16LE();
+ HitRectList *hitRectList = new HitRectList();
+ debug(3, "HitRectList; count = %d", count);
+ for (uint j = 0; j < count; j++) {
+ HitRect hitRect;
+ hitRect.rect.x1 = dataS.readUint16LE();
+ hitRect.rect.y1 = dataS.readUint16LE();
+ hitRect.rect.x2 = dataS.readUint16LE();
+ hitRect.rect.y2 = dataS.readUint16LE();
+ hitRect.type = dataS.readUint16LE() + 0x5001;
+ debug(3, "(%d, %d, %d, %d) -> %04d", hitRect.rect.x1, hitRect.rect.y1, hitRect.rect.x2, hitRect.rect.y2, hitRect.type);
+ hitRectList->push_back(hitRect);
+ }
+ drDirectoryItem.offset = _hitRectLists.size();
+ _hitRectLists.push_back(hitRectList);
+ break;
+ }
+ case 4:
+ {
+ uint count = dataS.readUint16LE();
+ MessageList *messageList = new MessageList();
+ debug(3, "MessageList; count = %d", count);
+ for (uint j = 0; j < count; j++) {
+ MessageItem messageItem;
+ messageItem.messageNum = dataS.readUint32LE();
+ messageItem.messageValue = dataS.readUint32LE();
+ debug(3, "(%08X, %08X)", messageItem.messageNum, messageItem.messageValue);
+ messageList->push_back(messageItem);
+ }
+ drDirectoryItem.offset = _messageLists.size();
+ _messageLists.push_back(messageList);
+ break;
+ }
+ case 5:
+ {
+ uint count = dataS.readUint16LE();
+ DRSubRectList *drSubRectList = new DRSubRectList();
+ debug(3, "SubRectList; count = %d", count);
+ for (uint j = 0; j < count; j++) {
+ DRSubRect drSubRect;
+ drSubRect.rect.x1 = dataS.readUint16LE();
+ drSubRect.rect.y1 = dataS.readUint16LE();
+ drSubRect.rect.x2 = dataS.readUint16LE();
+ drSubRect.rect.y2 = dataS.readUint16LE();
+ drSubRect.messageListHash = dataS.readUint32LE();
+ drSubRect.messageListItemIndex = dataS.readUint16LE();
+ debug(3, "(%d, %d, %d, %d) -> %08X (%d)", drSubRect.rect.x1, drSubRect.rect.y1, drSubRect.rect.x2, drSubRect.rect.y2, drSubRect.messageListHash, drSubRect.messageListItemIndex);
+ drSubRectList->push_back(drSubRect);
+ }
+ drDirectoryItem.offset = _drSubRectLists.size();
+ _drSubRectLists.push_back(drSubRectList);
+ break;
+ }
+ case 6:
+ {
+ DRRect drRect;
+ drRect.rect.x1 = dataS.readUint16LE();
+ drRect.rect.y1 = dataS.readUint16LE();
+ drRect.rect.x2 = dataS.readUint16LE();
+ drRect.rect.y2 = dataS.readUint16LE();
+ drRect.subRectIndex = dataS.readUint16LE();
+ debug(3, "(%d, %d, %d, %d) -> %d", drRect.rect.x1, drRect.rect.y1, drRect.rect.x2, drRect.rect.y2, drRect.subRectIndex);
+ drDirectoryItem.offset = _drRects.size();
+ _drRects.push_back(drRect);
+ break;
+ }
+ case 7:
+ {
+ uint count = dataS.readUint16LE();
+ NRectArray *rectArray = new NRectArray();
+ debug(3, "NRectArray; count = %d", count);
+ for (uint j = 0; j < count; j++) {
+ NRect rect;
+ rect.x1 = dataS.readUint16LE();
+ rect.y1 = dataS.readUint16LE();
+ rect.x2 = dataS.readUint16LE();
+ rect.y2 = dataS.readUint16LE();
+ debug(3, "(%d, %d, %d, %d)", rect.x1, rect.y1, rect.x2, rect.y2);
+ rectArray->push_back(rect);
+ }
+ drDirectoryItem.offset = _rectArrays.size();
+ _rectArrays.push_back(rectArray);
+ break;
+ }
+ }
+ _directory.push_back(drDirectoryItem);
+ }
+ }
+}
+
+void DataResource::unload() {
+ if (_resourceHandle != -1) {
+ _vm->_res->unloadResource(_resourceHandle);
+ _vm->_res->unuseResource(_resourceHandle);
+ _resourceHandle = -1;
+ // TODO: Clear arrays
+ }
+}
+
+NPoint DataResource::getPoint(uint32 nameHash) {
+ DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(nameHash, 1);
+ if (drDirectoryItem)
+ return _points[drDirectoryItem->offset];
+ return NPoint();
+}
+
+NPointArray *DataResource::getPointArray(uint32 nameHash) {
+ DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(nameHash, 2);
+ if (drDirectoryItem)
+ return _pointArrays[drDirectoryItem->offset];
+ return NULL;
+}
+
+NRectArray *DataResource::getRectArray(uint32 nameHash) {
+ DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(nameHash, 3);
+ if (drDirectoryItem)
+ return _rectArrays[drDirectoryItem->offset];
+ return NULL;
+}
+
+HitRectList *DataResource::getHitRectList() {
+ DataResource::DRDirectoryItem *drDirectoryItem = findDRDirectoryItem(calcHash("HitArray"), 3);
+ if (drDirectoryItem)
+ return _hitRectLists[drDirectoryItem->offset];
+ return NULL;
+}
+
+MessageList *DataResource::getMessageListAtPos(int16 klaymanX, int16 klaymanY, int16 mouseX, int16 mouseY) {
+ for (uint i = 0; i < _drRects.size(); i++) {
+ if (klaymanX >= _drRects[i].rect.x1 && klaymanX <= _drRects[i].rect.x2 &&
+ klaymanY >= _drRects[i].rect.y1 && klaymanY <= _drRects[i].rect.y2) {
+ DRSubRectList *drSubRectList = _drSubRectLists[_drRects[i].subRectIndex];
+ for (uint j = 0; j < drSubRectList->size(); j++) {
+ DRSubRect &subRect = (*drSubRectList)[j];
+ if (mouseX >= subRect.rect.x1 && mouseX <= subRect.rect.x2 &&
+ mouseY >= subRect.rect.y1 && mouseY <= subRect.rect.y2) {
+ return _messageLists[subRect.messageListItemIndex];
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+DataResource::DRDirectoryItem *DataResource::findDRDirectoryItem(uint32 nameHash, uint16 type) {
+ for (Common::Array<DRDirectoryItem>::iterator it = _directory.begin(); it != _directory.end(); it++) {
+ if ((*it).nameHash == nameHash && (*it).type == type)
+ return &(*it);
+ }
+ return NULL;
+}
+
+// SoundResource
+// ALL TODO
+
+SoundResource::SoundResource(NeverhoodEngine *vm)
+ : _vm(vm) {
+}
+
+bool SoundResource::isPlaying() {
+ return false;
+}
+
+void SoundResource::load(uint32 fileHash) {
+}
+
+void SoundResource::play(uint32 fileHash, bool looping) {
+}
+
+void SoundResource::play() {
+}
+
+uint32 calcHash(const char *value) {
+ uint32 hash = 0, shiftValue = 0;
+ while (*value != 0) {
+ char ch = *value++;
+ if (ch >= 'a' && ch <= 'z')
+ ch -= 32;
+ else if (ch >= '0' && ch <= '9')
+ ch += 22;
+ shiftValue += ch - 64;
+ if (shiftValue >= 32)
+ shiftValue -= 32;
+ hash ^= 1 << shiftValue;
+ }
+ return hash;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/resource.h b/engines/neverhood/resource.h
new file mode 100644
index 0000000000..6436509228
--- /dev/null
+++ b/engines/neverhood/resource.h
@@ -0,0 +1,212 @@
+/* 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_RESOURCE_H
+#define NEVERHOOD_RESOURCE_H
+
+#include "common/str.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/graphics.h"
+#include "neverhood/staticdata.h"
+
+namespace Neverhood {
+
+class SpriteResource {
+public:
+ SpriteResource(NeverhoodEngine *vm);
+ ~SpriteResource();
+ void draw(byte *dest, int destPitch, bool flipX, bool flipY);
+ bool load(uint32 fileHash);
+ bool load2(uint32 fileHash);
+ void unload();
+ const NDimensions& getDimensions() { return _dimensions; }
+ NPoint& getPosition() { return _position; }
+ bool isRle() const { return _rle; }
+ byte *getPixels() const { return _pixels; }
+protected:
+ NeverhoodEngine *_vm;
+ int _resourceHandle;
+ NDimensions _dimensions;
+ NPoint _position;
+ byte *_pixels;
+ bool _rle;
+};
+
+class PaletteResource {
+public:
+ PaletteResource(NeverhoodEngine *vm);
+ ~PaletteResource();
+ bool load(uint32 fileHash);
+ void unload();
+ void copyPalette(byte *destPalette);
+ byte *palette() { return _palette; }
+protected:
+ NeverhoodEngine *_vm;
+ int _resourceHandle;
+ byte *_palette;
+};
+
+struct AnimFrameInfo {
+ uint32 frameHash;
+ int16 counter;
+ NDrawRect rect;
+ int16 deltaX, deltaY;
+ NDrawRect deltaRect;
+ uint16 field_1A;
+ uint32 spriteDataOffs;
+};
+
+class AnimResource {
+public:
+ AnimResource(NeverhoodEngine *vm);
+ ~AnimResource();
+ void draw(uint frameIndex, byte *dest, int destPitch, bool flipX, bool flipY);
+ bool load(uint32 fileHash);
+ void unload();
+ void clear();
+ void clear2();
+ bool loadInternal(uint32 fileHash);
+ void unloadInternal();
+ uint getFrameCount() const { return _frames.size(); }
+ const AnimFrameInfo& getFrameInfo(int16 index) const { return _frames[index]; }
+ int16 getFrameIndex(uint32 frameHash);
+ void setReplEnabled(bool value) { _replEnabled = value; }
+ void setRepl(byte oldColor, byte newColor);
+ NDimensions loadSpriteDimensions(uint32 fileHash);
+protected:
+ NeverhoodEngine *_vm;
+ int _resourceHandle;
+ int16 _width, _height;
+ byte *_currSpriteData;
+ uint32 _fileHash;
+ byte *_paletteData;
+ byte *_spriteData;
+ bool _replEnabled;
+ byte _replOldColor;
+ byte _replNewColor;
+ Common::Array<AnimFrameInfo> _frames;
+};
+
+class MouseCursorResource {
+public:
+ MouseCursorResource(NeverhoodEngine *vm);
+ void load(uint32 fileHash);
+ void unload();
+ NDrawRect& getRect();
+ void draw(int frameNum, byte *dest, int destPitch);
+ int getCursorNum() const { return _cursorNum; }
+ void setCursorNum(int value) { _cursorNum = value; }
+protected:
+ int _cursorNum;
+ SpriteResource _cursorSprite;
+ NDrawRect _rect;
+ uint32 _currFileHash;
+};
+
+class TextResource {
+public:
+ TextResource(NeverhoodEngine *vm);
+ ~TextResource();
+ void load(uint32 fileHash);
+ void unload();
+ const char *getString(uint index, const char *&textEnd);
+ uint getCount() const { return _count;}
+protected:
+ NeverhoodEngine *_vm;
+ int _resourceHandle;
+ byte *_textData;
+ uint _count;
+};
+
+/* DataResource
+ 1 Single NPoint
+ 2 Array of NPoints
+ 3 Array of NRects
+ 4 MessageList
+ 5 SubRectList
+ 6 RectList
+*/
+
+class DataResource {
+public:
+ DataResource(NeverhoodEngine *vm);
+ ~DataResource();
+ void load(uint32 fileHash);
+ void unload();
+ NPoint getPoint(uint32 nameHash);
+ NPointArray *getPointArray(uint32 nameHash);
+ NRectArray *getRectArray(uint32 nameHash);
+ HitRectList *getHitRectList();
+ MessageList *getMessageListAtPos(int16 klaymanX, int16 klaymanY, int16 mouseX, int16 mouseY);
+protected:
+
+ struct DRDirectoryItem {
+ uint32 nameHash;
+ uint16 offset;
+ uint16 type;
+ };
+
+ struct DRRect {
+ NRect rect;
+ uint16 subRectIndex;
+ };
+
+ struct DRSubRect {
+ NRect rect;
+ uint32 messageListHash;
+ uint16 messageListItemIndex;
+ };
+
+ typedef Common::Array<DRSubRect> DRSubRectList;
+
+ NeverhoodEngine *_vm;
+ int _resourceHandle;
+ Common::Array<DRDirectoryItem> _directory;
+ Common::Array<NPoint> _points;
+ Common::Array<NPointArray*> _pointArrays;
+ Common::Array<NRectArray*> _rectArrays;
+ Common::Array<HitRectList*> _hitRectLists;
+ Common::Array<MessageList*> _messageLists;
+ Common::Array<DRRect> _drRects;
+ Common::Array<DRSubRectList*> _drSubRectLists;
+ DataResource::DRDirectoryItem *findDRDirectoryItem(uint32 nameHash, uint16 type);
+};
+
+// TODO: Dummy class atm
+
+class SoundResource {
+public:
+ SoundResource(NeverhoodEngine *vm);
+ bool isPlaying();
+ void load(uint32 fileHash);
+ void play(uint32 fileHash, bool looping = false);
+ void play();
+ void stop() { /*DUMMY*/ }
+protected:
+ NeverhoodEngine *_vm;
+};
+
+uint32 calcHash(const char *value);
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_RESOURCE_H */
diff --git a/engines/neverhood/resourceman.cpp b/engines/neverhood/resourceman.cpp
new file mode 100644
index 0000000000..0538f58e87
--- /dev/null
+++ b/engines/neverhood/resourceman.cpp
@@ -0,0 +1,172 @@
+/* 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/resourceman.h"
+
+namespace Neverhood {
+
+ResourceMan::ResourceMan() {
+}
+
+ResourceMan::~ResourceMan() {
+}
+
+void ResourceMan::addArchive(const Common::String &filename) {
+ BlbArchive *archive = new BlbArchive();
+ uint archiveIndex = _archives.size();
+ archive->open(filename);
+ _archives.push_back(archive);
+ debug("ResourceMan::addArchive(%s) %d files", filename.c_str(), archive->getCount());
+ _entries.reserve(_entries.size() + archive->getCount());
+ for (uint archiveEntryIndex = 0; archiveEntryIndex < archive->getCount(); archiveEntryIndex++) {
+ BlbArchiveEntry *archiveEntry = archive->getEntry(archiveEntryIndex);
+ ResourceFileEntry *entry = findEntrySimple(archiveEntry->fileHash);
+ if (entry) {
+ if (archiveEntry->timeStamp > _archives[entry->archiveIndex]->getEntry(entry->entryIndex)->timeStamp) {
+ entry->archiveIndex = archiveIndex;
+ entry->entryIndex = archiveEntryIndex;
+ }
+ } else {
+ ResourceFileEntry newEntry;
+ newEntry.fileHash = archiveEntry->fileHash;
+ newEntry.resourceHandle = -1;
+ newEntry.archiveIndex = archiveIndex;
+ newEntry.entryIndex = archiveEntryIndex;
+ _entries.push_back(newEntry);
+ }
+ }
+}
+
+ResourceFileEntry *ResourceMan::findEntrySimple(uint32 fileHash) {
+ for (uint i = 0; i < _entries.size(); i++) {
+ if (_entries[i].fileHash == fileHash)
+ return &_entries[i];
+ }
+ return NULL;
+}
+
+ResourceFileEntry *ResourceMan::findEntry(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntrySimple(fileHash);
+ for (; entry && getArchiveEntry(entry)->comprType == 0x65; fileHash = getArchiveEntry(entry)->diskSize)
+ entry = findEntrySimple(fileHash);
+ return entry;
+}
+
+BlbArchiveEntry *ResourceMan::getArchiveEntry(ResourceFileEntry *entry) const {
+ return _archives[entry->archiveIndex]->getEntry(entry->entryIndex);
+}
+
+int ResourceMan::useResource(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntry(fileHash);
+ if (entry->resourceHandle != -1) {
+ _resources[entry->resourceHandle]->useRefCount++;
+ } else {
+ Resource *resource = new Resource();
+ resource->fileHash = entry->fileHash;
+ resource->archiveIndex = entry->archiveIndex;
+ resource->entryIndex = entry->entryIndex;
+ resource->data = NULL;
+ resource->dataRefCount = 0;
+ resource->useRefCount = 1;
+ entry->resourceHandle = (int)_resources.size();
+ _resources.push_back(resource);
+ }
+ return entry->resourceHandle;
+}
+
+void ResourceMan::unuseResource(int resourceHandle) {
+ Resource *resource = _resources[resourceHandle];
+ if (resource->useRefCount > 0)
+ resource->useRefCount--;
+}
+
+void ResourceMan::unuseResourceByHash(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntry(fileHash);
+ if (entry->resourceHandle != -1)
+ unuseResource(entry->resourceHandle);
+}
+
+int ResourceMan::getResourceHandleByHash(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntry(fileHash);
+ return entry->resourceHandle;
+}
+
+bool ResourceMan::isResourceDataValid(int resourceHandle) const {
+ return _resources[resourceHandle]->data != NULL;
+}
+
+uint32 ResourceMan::getResourceSize(int resourceHandle) const {
+ Resource *resource = _resources[resourceHandle];
+ return _archives[resource->archiveIndex]->getEntry(resource->entryIndex)->size;
+}
+
+byte ResourceMan::getResourceType(int resourceHandle) {
+ Resource *resource = _resources[resourceHandle];
+ return _archives[resource->archiveIndex]->getEntry(resource->entryIndex)->type;
+}
+
+byte ResourceMan::getResourceTypeByHash(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntry(fileHash);
+ return getArchiveEntry(entry)->type;
+}
+
+byte *ResourceMan::getResourceExtData(int resourceHandle) {
+ Resource *resource = _resources[resourceHandle];
+ return _archives[resource->archiveIndex]->getEntryExtData(resource->entryIndex);
+}
+
+byte *ResourceMan::getResourceExtDataByHash(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntrySimple(fileHash);
+ return entry ? _archives[entry->archiveIndex]->getEntryExtData(entry->entryIndex) : NULL;
+}
+
+byte *ResourceMan::loadResource(int resourceHandle, bool moveToFront) {
+ Resource *resource = _resources[resourceHandle];
+ if (resource->data != NULL) {
+ resource->dataRefCount++;
+ } else {
+ BlbArchive *archive = _archives[resource->archiveIndex];
+ BlbArchiveEntry *archiveEntry = archive->getEntry(resource->entryIndex);
+ resource->data = new byte[archiveEntry->size];
+ archive->load(resource->entryIndex, resource->data, 0);
+ resource->dataRefCount = 1;
+ }
+ return resource->data;
+}
+
+void ResourceMan::unloadResource(int resourceHandle) {
+ Resource *resource = _resources[resourceHandle];
+ if (resource->dataRefCount > 0)
+ resource->dataRefCount--;
+}
+
+void ResourceMan::freeResource(Resource *resource) {
+ delete[] resource->data;
+ resource->data = NULL;
+}
+
+Common::SeekableReadStream *ResourceMan::createStream(uint32 fileHash) {
+ ResourceFileEntry *entry = findEntry(fileHash);
+ return _archives[entry->archiveIndex]->createStream(entry->entryIndex);
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/resourceman.h b/engines/neverhood/resourceman.h
new file mode 100644
index 0000000000..ed5bffaf9b
--- /dev/null
+++ b/engines/neverhood/resourceman.h
@@ -0,0 +1,81 @@
+/* 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_RESOURCEMAN_H
+#define NEVERHOOD_RESOURCEMAN_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/blbarchive.h"
+
+namespace Neverhood {
+
+struct ResourceFileEntry {
+ uint32 fileHash;
+ int resourceHandle;
+ uint archiveIndex;
+ uint entryIndex;
+};
+
+struct Resource {
+ uint32 fileHash;
+ uint archiveIndex;
+ uint entryIndex;
+ byte *data;
+ int dataRefCount;
+ int useRefCount;
+};
+
+class ResourceMan {
+public:
+ ResourceMan();
+ ~ResourceMan();
+ void addArchive(const Common::String &filename);
+ ResourceFileEntry *findEntrySimple(uint32 fileHash);
+ ResourceFileEntry *findEntry(uint32 fileHash);
+ BlbArchiveEntry *getArchiveEntry(ResourceFileEntry *entry) const;
+ int useResource(uint32 fileHash);
+ void unuseResource(int resourceHandle);
+ void unuseResourceByHash(uint32 fileHash);
+ int getResourceHandleByHash(uint32 fileHash);
+ bool isResourceDataValid(int resourceHandle) const;
+ uint32 getResourceSize(int resourceHandle) const;
+ byte getResourceType(int resourceHandle);
+ byte getResourceTypeByHash(uint32 fileHash);
+ byte *getResourceExtData(int resourceHandle);
+ byte *getResourceExtDataByHash(uint32 fileHash);
+ byte *loadResource(int resourceHandle, bool moveToFront = false);
+ void unloadResource(int resourceHandle);
+ void freeResource(Resource *resource);
+ Common::SeekableReadStream *createStream(uint32 fileHash);
+ const ResourceFileEntry& getEntry(uint index) { return _entries[index]; }
+ uint getEntryCount() { return _entries.size(); }
+private:
+ Common::Array<BlbArchive*> _archives;
+ Common::Array<ResourceFileEntry> _entries;
+ Common::Array<Resource*> _resources;
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_RESOURCEMAN_H */
diff --git a/engines/neverhood/scene.cpp b/engines/neverhood/scene.cpp
new file mode 100644
index 0000000000..9a588f283f
--- /dev/null
+++ b/engines/neverhood/scene.cpp
@@ -0,0 +1,615 @@
+/* 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/scene.h"
+#include "neverhood/collisionman.h"
+
+namespace Neverhood {
+
+Scene::Scene(NeverhoodEngine *vm, Module *parentModule, bool clearHitRects)
+ : Entity(vm, 0), _parentModule(parentModule), _dataResource(vm) {
+
+ _messageListFlag1 = false;
+ _systemCallbackFlag = false;
+ _messageList = NULL;
+ _rectType = 0;
+ _mouseClickPos.x = 0;
+ _mouseClickPos.y = 0;
+ _mouseClicked = false;
+ _rectList = NULL;
+ _klayman = NULL;
+ _mouseCursor = NULL;
+ _palette = NULL;
+ _background = NULL;
+ // TODO _field_8E = -1;
+ if (clearHitRects) {
+ _vm->_collisionMan->clearHitRects();
+ _vm->_collisionMan->clearSprites();
+ }
+ _vm->_screen->setFps(24);
+ // TODO g_screen->hSmack = NULL;
+ // TODO g_screen->field_24 = 0;
+ // TODO g_screen->field_26 = 0;
+ // TODO g_screen->resetDirtyRects();
+ _messageListFlag = true;
+ _surfaceFlag = false;
+ _messageList2 = NULL;
+ _smackerPlayer = NULL;
+ _smkFileHash = 0;
+ _messageListFlag2 = false;
+ _messageValue = -1;
+
+ SetUpdateHandler(&Scene::update);
+ SetMessageHandler(&Scene::handleMessage);
+}
+
+Scene::~Scene() {
+
+ if (_palette) {
+ removeEntity(_palette);
+ delete _palette;
+ }
+
+ // Delete all entities
+ for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++)
+ delete *iter;
+
+ // Don't delete surfaces since they always belong to an entity
+
+}
+
+void Scene::draw() {
+ if (_smackerPlayer) {
+ if (_surfaceFlag) {
+ // TODO g_screen->resetDirtyRects();
+ // TODO g_screen->copyDirtyRects();
+ // TODO g_screen->addDirtyRects();
+ }
+ if (_smackerPlayer->getSurface())
+ _smackerPlayer->getSurface()->draw();
+ } else {
+#if 0
+ if (_surfaceFlag) {
+ // TODO g_screen->copyDirtyRects();
+ for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++)
+ (*iter)->addDirtyRect();
+ // TODO g_screen->addDirtyRects();
+ }
+#endif
+ for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++) {
+ //debug(4, "priority = %d", (*iter)->getPriority());
+ (*iter)->draw();
+ }
+ }
+}
+
+void Scene::addEntity(Entity *entity) {
+ int index = 0, insertIndex = -1;
+ for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++) {
+ if ((*iter)->getPriority() > entity->getPriority()) {
+ insertIndex = index;
+ break;
+ }
+ index++;
+ }
+ if (insertIndex >= 0)
+ _entities.insert_at(insertIndex, entity);
+ else
+ _entities.push_back(entity);
+}
+
+bool Scene::removeEntity(Entity *entity) {
+ for (uint index = 0; index < _entities.size(); index++) {
+ if (_entities[index] == entity) {
+ _entities.remove_at(index);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Scene::addSurface(BaseSurface *surface) {
+ int index = 0, insertIndex = -1;
+ for (Common::Array<BaseSurface*>::iterator iter = _surfaces.begin(); iter != _surfaces.end(); iter++) {
+ if ((*iter)->getPriority() > surface->getPriority()) {
+ insertIndex = index;
+ break;
+ }
+ index++;
+ }
+ if (insertIndex >= 0)
+ _surfaces.insert_at(insertIndex, surface);
+ else
+ _surfaces.push_back(surface);
+}
+
+bool Scene::removeSurface(BaseSurface *surface) {
+ for (uint index = 0; index < _surfaces.size(); index++) {
+ if (_surfaces[index] == surface) {
+ _surfaces.remove_at(index);
+ return true;
+ }
+ }
+ return false;
+}
+
+Sprite *Scene::addSprite(Sprite *sprite) {
+ addEntity(sprite);
+ addSurface(sprite->getSurface());
+ return sprite;
+}
+
+void Scene::setSurfacePriority(BaseSurface *surface, int priority) {
+ surface->setPriority(priority);
+ if (removeSurface(surface))
+ addSurface(surface);
+}
+
+void Scene::deleteSprite(Sprite **sprite) {
+ _vm->_collisionMan->removeSprite(*sprite);
+ removeSurface((*sprite)->getSurface());
+ removeEntity(*sprite);
+ delete *sprite;
+ *sprite = NULL;
+}
+
+Background *Scene::addBackground(Background *background) {
+ addEntity(background);
+ addSurface(background->getSurface());
+ return background;
+}
+
+void Scene::setBackground(uint32 fileHash, bool dirtyBackground) {
+ _background = addBackground(new DirtyBackground(_vm, fileHash, 0, 0));
+}
+
+void Scene::changeBackground(uint32 fileHash) {
+ _background->load(fileHash);
+}
+
+void Scene::setPalette(uint32 fileHash) {
+ _palette = fileHash ? new Palette(_vm, fileHash) : new Palette(_vm);
+ _palette->usePalette();
+}
+
+void Scene::setHitRects(uint32 id) {
+ _vm->_collisionMan->setHitRects(id);
+}
+
+Sprite *Scene::insertStaticSprite(uint32 fileHash, int surfacePriority) {
+ return addSprite(new StaticSprite(_vm, fileHash, surfacePriority));
+}
+
+void Scene::insertMouse433(uint32 fileHash, NRect *mouseRect) {
+ NRect rect(-1, -1, -1, -1);
+ if (mouseRect)
+ rect = *mouseRect;
+ _mouseCursor = new Mouse(_vm, 0x0820C408, rect);
+ addSprite(_mouseCursor);
+}
+
+void Scene::insertMouse435(uint32 fileHash, int16 x1, int16 x2) {
+ _mouseCursor = new Mouse(_vm, fileHash, x1, x2);
+ addSprite(_mouseCursor);
+}
+
+void Scene::insertNavigationMouse(uint32 fileHash, int type) {
+ _mouseCursor = new Mouse(_vm, fileHash, type);
+ addSprite(_mouseCursor);
+}
+
+void Scene::showMouse(bool visible) {
+ _mouseCursor->getSurface()->setVisible(visible);
+}
+
+void Scene::changeMouseCursor(uint32 fileHash) {
+ _mouseCursor->load(fileHash);
+ _mouseCursor->updateCursor();
+}
+
+SmackerPlayer *Scene::addSmackerPlayer(SmackerPlayer *smackerPlayer) {
+ addEntity(smackerPlayer);
+ addSurface(smackerPlayer->getSurface());
+ return smackerPlayer;
+}
+
+void Scene::update() {
+
+ if (_smkFileHash != 0) {
+ // TODO
+ _smackerPlayer = new SmackerPlayer(_vm, this, _smkFileHash, true, 0);
+ _savedUpdateHandlerCb = _updateHandlerCb;
+ _savedMessageHandlerCb = _messageHandlerCb;
+ SetUpdateHandler(&Scene::smackerUpdate);
+ SetMessageHandler(&Scene::smackerHandleMessage);
+ _smackerDone = false;
+ smackerUpdate();
+ // g_screen->smackerPlayer = _smackerPlayer;
+ _smkFileHash = 0;
+ } else {
+ if (_mouseClicked) {
+ if (_klayman) {
+ // TODO: Merge later
+ if (_messageListFlag &&
+ _klayman->hasMessageHandler() &&
+ sendMessage(_klayman, 0x1008, 0) != 0 &&
+ queryPositionSprite(_mouseClickPos.x, _mouseClickPos.y)) {
+ _mouseClicked = false;
+ } else if (_messageListFlag &&
+ _klayman->hasMessageHandler() &&
+ sendMessage(_klayman, 0x1008, 0) != 0) {
+ _mouseClicked = !queryPositionRectList(_mouseClickPos.x, _mouseClickPos.y);
+ }
+ } else if (queryPositionSprite(_mouseClickPos.x, _mouseClickPos.y)) {
+ _mouseClicked = false;
+ }
+ }
+
+ runMessageList();
+
+ // Update all entities
+ for (Common::Array<Entity*>::iterator iter = _entities.begin(); iter != _entities.end(); iter++)
+ (*iter)->handleUpdate();
+
+ }
+
+}
+
+void Scene::leaveScene(uint32 result) {
+ sendMessage(_parentModule, 0x1009, result);
+}
+
+uint32 Scene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0: // mouse moved
+ if (_mouseCursor && _mouseCursor->hasMessageHandler())
+ sendMessage(_mouseCursor, 0x4002, param);
+ // TODO queryPositionSomeRects(param.asPoint().x, param.asPoint().y);
+ break;
+ case 1: // mouse clicked
+ _mouseClicked = true;
+ _mouseClickPos = param.asPoint();
+ break;
+ /* ORIGINAL DEBUG
+ case 3:
+ drawSurfaceRects();
+ break;
+ */
+ /* ORIGINAL DEBUG
+ case 4:
+ drawRectListRects();
+ break;
+ */
+ case 5:
+#if 0
+ broadcastObjectMessage5();
+#endif
+ break;
+ case 6:
+ sendMessage(_parentModule, 0x1009, param);
+ break;
+ case 0x1006:
+ if (_messageListFlag1) {
+ _messageListFlag1 = false;
+ if (_messageListIndex == _messageListCount)
+ sendMessage(_klayman, 0x4004, 0);
+ else {
+ runMessageList();
+ }
+ }
+ break;
+ case 0x1007:
+ if (_messageListFlag1) {
+ _messageListFlag1 = false;
+ _messageList = NULL;
+ sendMessage(_klayman, 0x4004, 0);
+ }
+ break;
+ case 0x101D:
+ if (_mouseCursor) {
+ _prevVisible = _mouseCursor->getSurface()->getVisible();
+ _mouseCursor->getSurface()->setVisible(false);
+ }
+ break;
+ case 0x101E:
+ if (_prevVisible && _mouseCursor) {
+ _mouseCursor->getSurface()->setVisible(false);
+ // TODO sendMessage(_mouseCursor, 0x4002, g_Screen->_mousePos);
+ }
+ break;
+ case 0x1022:
+ setSurfacePriority(((Sprite*)sender)->getSurface(), param.asInteger());
+ break;
+ }
+ return 0;
+}
+
+void Scene::smackerUpdate() {
+ //**ALL TODO
+#if 0
+ _smackerPlayer->handleUpdate();
+ if (_smackerDone) {
+ delete _smackerPlayer;
+ _smackerPlayer = NULL;
+ _updateHandlerCb = _savedUpdateHandlerCb;
+ _messageHandlerCb = _savedMessageHandlerCb;
+ if (_palette)
+ _palette->usePalette();
+ // TODO _background->restore();
+ // TODO g_screen->smackerPlayer = NULL;
+ }
+#endif
+}
+
+uint32 Scene::smackerHandleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x3002:
+ _smackerDone = true;
+ break;
+ }
+ return 0;
+}
+
+bool Scene::queryPositionSprite(int16 mouseX, int16 mouseY) {
+ debug("Scene::queryPositionSprite(%d, %d)", mouseX, mouseY);
+ for (uint i = 0; i < _vm->_collisionMan->getSpriteCount(); i++) {
+ Sprite *sprite = _vm->_collisionMan->getSprite(i);
+ if (sprite->hasMessageHandler() && sprite->isPointInside(mouseX, mouseY) &&
+ sendPointMessage(sprite, 0x1011, _mouseClickPos) != 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Scene::queryPositionRectList(int16 mouseX, int16 mouseY) {
+ int16 klaymanX = _klayman->getX();
+ int16 klaymanY = _klayman->getY();
+ if (_rectType == 1) {
+ RectList &rectList = *_rectList;
+ for (uint i = 0; i < rectList.size(); i++) {
+ debug("(%d, %d) ? (%d, %d, %d, %d)", klaymanX, klaymanY, rectList[i].rect.x1, rectList[i].rect.y1, rectList[i].rect.x2, rectList[i].rect.y2);
+ if (klaymanX >= rectList[i].rect.x1 && klaymanX <= rectList[i].rect.x2 &&
+ klaymanY >= rectList[i].rect.y1 && klaymanY <= rectList[i].rect.y2) {
+ for (uint j = 0; j < rectList[i].subRects.size(); j++) {
+ debug(" (%d, %d) ? (%d, %d, %d, %d)", mouseX, mouseY, rectList[i].subRects[j].rect.x1, rectList[i].subRects[j].rect.y1, rectList[i].subRects[j].rect.x2, rectList[i].subRects[j].rect.y2);
+ if (mouseX >= rectList[i].subRects[j].rect.x1 && mouseX <= rectList[i].subRects[j].rect.x2 &&
+ mouseY >= rectList[i].subRects[j].rect.y1 && mouseY <= rectList[i].subRects[j].rect.y2) {
+ debug("Scene::queryPositionRectList() -> %08X", rectList[i].subRects[j].messageListId);
+ return setMessageList2(rectList[i].subRects[j].messageListId);
+ }
+ }
+ }
+ }
+ } else if (_rectType == 2) {
+ MessageList *messageList = _dataResource.getMessageListAtPos(klaymanX, klaymanY, mouseX, mouseY);
+ if (messageList && messageList->size())
+ setMessageList2(messageList, true, true);
+ }
+ return true;
+}
+
+void Scene::setMessageList(uint32 id, bool messageListFlag, bool systemCallbackFlag) {
+ setMessageList(_vm->_staticData->getMessageList(id), messageListFlag, systemCallbackFlag);
+}
+
+void Scene::setMessageList(MessageList *messageList, bool messageListFlag, bool systemCallbackFlag) {
+ debug("Scene::setMessageList(%p)", (void*)messageList);
+ _messageList = messageList;
+ _messageListCount = _messageList ? _messageList->size() : 0;
+ _messageListIndex = 0;
+ _messageListFlag1 = false;
+ _messageListFlag = messageListFlag;
+ _systemCallbackFlag = systemCallbackFlag;
+ _messageListStatus = 1;
+ sendMessage(_klayman, 0x101C, 0);
+
+ // DEBUG: Show message list
+ for (uint i = 0; i < messageList->size(); i++) {
+ debug("A: %02d: %04X, %08X", i, (*messageList)[i].messageNum, (*messageList)[i].messageValue);
+ }
+ debug("A: ================================================================");
+
+}
+
+bool Scene::setMessageList2(uint32 id, bool messageListFlag, bool systemCallbackFlag) {
+ return setMessageList2(_vm->_staticData->getMessageList(id), messageListFlag, systemCallbackFlag);
+}
+
+bool Scene::setMessageList2(MessageList *messageList, bool messageListFlag, bool systemCallbackFlag) {
+ bool result = false;
+
+ debug("Scene::setMessageList2(%p)", (void*)messageList);
+
+ // DEBUG: Show message list
+ for (uint i = 0; i < messageList->size(); i++) {
+ debug("B: %02d: %04X, %08X", i, (*messageList)[i].messageNum, (*messageList)[i].messageValue);
+ }
+ debug("B: ================================================================");
+
+ if (_messageListStatus == 1) {
+ if (messageList != _messageList2) {
+ if (_messageValue >= 0) {
+ sendMessage(_parentModule, 0x1023, _messageValue);
+ _messageValue = -1;
+ }
+ _messageList2 = messageList;
+ setMessageList(messageList, messageListFlag, systemCallbackFlag);
+ result = true;
+ }
+ } else if (_messageListStatus == 2) {
+ if (messageList == _messageList2) {
+ if (_messageValue >= 0) {
+ sendMessage(_parentModule, 0x1023, _messageValue);
+ _messageValue = -1;
+ }
+ _messageList2 = messageList;
+ setMessageList(messageList, messageListFlag, systemCallbackFlag);
+ result = true;
+ }
+ } else {
+ if (_messageValue >= 0) {
+ sendMessage(_parentModule, 0x1023, _messageValue);
+ _messageValue = -1;
+ }
+ _messageList2 = messageList;
+ setMessageList(messageList, messageListFlag, systemCallbackFlag);
+ result = true;
+ }
+ return result;
+}
+
+void Scene::runMessageList() {
+ debug(7, "Scene::runMessageList() _messageListFlag2 = %d; _messageListFlag1 = %d", _messageListFlag2, _messageListFlag1);
+
+ if (_messageListFlag2 || _messageListFlag1)
+ return;
+
+ _messageListFlag2 = true;
+
+ if (!_messageList) {
+ _messageList2 = NULL;
+ _messageListStatus = 0;
+ }
+
+ if (_messageList && _klayman) {
+
+ while (_messageList && _messageListIndex < _messageListCount && !_messageListFlag1) {
+ uint32 messageNum = (*_messageList)[_messageListIndex].messageNum;
+ uint32 messageParam = (*_messageList)[_messageListIndex].messageValue;
+
+ debug("Scene::runMessageList() %04X, %08X", messageNum, messageParam);
+
+ _messageListIndex++;
+ if (_messageListIndex == _messageListCount) {
+ sendMessage(_klayman, 0x1021, 0);
+ }
+ if (_systemCallbackFlag) {
+ messageNum = convertMessageNum(messageNum);
+ }
+ if (messageNum != 0x4003) {
+ if (messageNum == 0x1009 || messageNum == 0x1024) {
+ sendMessage(_parentModule, messageNum, messageParam);
+ } else if (messageNum == 0x100A) {
+ _messageValue = messageParam;
+ sendMessage(_parentModule, messageNum, messageParam);
+ } else if (messageNum == 0x4001) {
+ _messageListFlag1 = true;
+ sendPointMessage(_klayman, 0x4001, _mouseClickPos);
+ } else if (messageNum == 0x100D) {
+ if (this->hasMessageHandler() && sendMessage(this, 0x100D, messageParam) != 0)
+ continue;
+ } else if (messageNum == 0x101A) {
+ _messageListStatus = 0;
+ } else if (messageNum == 0x101B) {
+ _messageListStatus = 2;
+ } else if (messageNum == 0x1020) {
+ _messageListFlag = false;
+ } else if (messageNum >= 0x2000 && messageNum <= 0x2FFF) {
+ if (this->hasMessageHandler() && sendMessage(this, messageNum, messageParam) != 0) {
+ _messageListFlag2 = false;
+ return;
+ }
+ } else {
+ _messageListFlag1 = true;
+ if (_klayman->hasMessageHandler() && sendMessage(_klayman, messageNum, messageParam) != 0) {
+ _messageListFlag1 = false;
+ }
+ }
+ }
+ if (_messageListIndex == _messageListCount) {
+ _messageListFlag = true;
+ _messageList = NULL;
+ }
+ }
+ }
+
+ _messageListFlag2 = false;
+
+}
+
+void Scene::messageList402220() {
+ _messageListFlag1 = false;
+ _messageList = NULL;
+ _messageListFlag = true;
+ sendMessage(_klayman, 0x4004, 0);
+}
+
+void Scene::setRectList(uint32 id) {
+ setRectList(_vm->_staticData->getRectList(id));
+}
+
+void Scene::setRectList(RectList *rectList) {
+ _rectList = rectList;
+ _rectType = 1;
+}
+
+void Scene::clearRectList() {
+ _rectList = NULL;
+ _rectType = 0;
+}
+
+void Scene::loadHitRectList() {
+ HitRectList *hitRectList = _dataResource.getHitRectList();
+ debug("Scene::loadHitRectList() hitRectList = %p", (void*)hitRectList);
+ if (hitRectList) {
+ _hitRectList = *hitRectList;
+ _vm->_collisionMan->setHitRects(&_hitRectList);
+ }
+}
+
+void Scene::loadDataResource(uint32 fileHash) {
+ _dataResource.load(fileHash);
+ _rectType = 2;
+ if (_klayman)
+ _klayman->loadDataResource(fileHash);
+}
+
+uint16 Scene::convertMessageNum(uint32 messageNum) {
+ switch (messageNum) {
+ case 0x00004004:
+ return 0x4001;
+ case 0x00000083:
+ return 0x100A;
+ case 0x044001C8:
+ return 0x481C;
+ case 0x02420480:
+ return 0x4818;
+ case 0x08004025:
+ return 0x100D;
+ case 0x04404281:
+ return 0x4824;
+ case 0x08400880:
+ return 0x4825;
+ case 0x08209081:
+ return 0x4823;
+ case 0x24000060:
+ return 0x1009;
+ case 0x42002200:
+ return 0x4004;
+ case 0x428D4894:
+ return 0x101A;
+ }
+ return 0x1000;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/scene.h b/engines/neverhood/scene.h
new file mode 100644
index 0000000000..e962266168
--- /dev/null
+++ b/engines/neverhood/scene.h
@@ -0,0 +1,214 @@
+/* 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_SCENE_H
+#define NEVERHOOD_SCENE_H
+
+#include "common/array.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/background.h"
+#include "neverhood/entity.h"
+#include "neverhood/graphics.h"
+#include "neverhood/klayman.h"
+#include "neverhood/module.h"
+#include "neverhood/palette.h"
+#include "neverhood/smackerplayer.h"
+#include "neverhood/sprite.h"
+#include "neverhood/staticdata.h"
+
+namespace Neverhood {
+
+class Scene : public Entity {
+public:
+ Scene(NeverhoodEngine *vm, Module *parentModule, bool clearHitRects);
+ virtual ~Scene();
+ virtual void draw();
+ void addEntity(Entity *entity);
+ bool removeEntity(Entity *entity);
+ void addSurface(BaseSurface *surface);
+ bool removeSurface(BaseSurface *surface);
+ Sprite *addSprite(Sprite *sprite);
+ void setSurfacePriority(BaseSurface *surface, int priority);
+ void deleteSprite(Sprite **sprite);
+ Background *addBackground(Background *background);
+ void setBackground(uint32 fileHash, bool dirtyBackground = true);
+ void changeBackground(uint32 fileHash);
+ void setBackgroundY(int16 y) { _background->getSurface()->getDrawRect().y = y; }
+ int16 getBackgroundY() { return _background->getSurface()->getDrawRect().y; }
+ void setPalette(uint32 fileHash = 0);
+ void setHitRects(uint32 id);
+ Sprite *insertStaticSprite(uint32 fileHash, int surfacePriority);
+ void insertMouse433(uint32 fileHash, NRect *mouseRect = NULL);
+ void insertMouse435(uint32 fileHash, int16 x1, int16 x2);
+ void insertNavigationMouse(uint32 fileHash, int type);
+ void showMouse(bool visible);
+ void changeMouseCursor(uint32 fileHash);
+ SmackerPlayer *addSmackerPlayer(SmackerPlayer *smackerPlayer);
+ void update();
+ void leaveScene(uint32 result);
+ // Some crazy templated functions to make the logic code smaller/simpler (imo!)
+ // insertKlayman
+ template<class T>
+ void insertKlayman() {
+ _klayman = (T*)addSprite(new T(_vm, this));
+ }
+ template<class T, class Arg1>
+ void insertKlayman(Arg1 arg1) {
+ _klayman = (T*)addSprite(new T(_vm, this, arg1));
+ }
+ template<class T, class Arg1, class Arg2>
+ void insertKlayman(Arg1 arg1, Arg2 arg2) {
+ _klayman = (T*)addSprite(new T(_vm, this, arg1, arg2));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3>
+ void insertKlayman(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
+ _klayman = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4>
+ void insertKlayman(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
+ _klayman = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3, arg4));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5>
+ void insertKlayman(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) {
+ _klayman = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3, arg4, arg5));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6>
+ void insertKlayman(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) {
+ _klayman = (T*)addSprite(new T(_vm, this, arg1, arg2, arg3, arg4, arg5, arg6));
+ }
+ // insertSprite
+ template<class T>
+ T* insertSprite() {
+ return (T*)addSprite(new T(_vm));
+ }
+ template<class T, class Arg1>
+ T* insertSprite(Arg1 arg1) {
+ return (T*)addSprite(new T(_vm, arg1));
+ }
+ template<class T, class Arg1, class Arg2>
+ T* insertSprite(Arg1 arg1, Arg2 arg2) {
+ return (T*)addSprite(new T(_vm, arg1, arg2));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3>
+ T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
+ return (T*)addSprite(new T(_vm, arg1, arg2, arg3));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4>
+ T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
+ return (T*)addSprite(new T(_vm, arg1, arg2, arg3, arg4));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5>
+ T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) {
+ return (T*)addSprite(new T(_vm, arg1, arg2, arg3, arg4, arg5));
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6>
+ T* insertSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) {
+ return (T*)addSprite(new T(_vm, arg1, arg2, arg3, arg4, arg5, arg6));
+ }
+ // createSprite
+ template<class T>
+ T* createSprite() {
+ return new T(_vm);
+ }
+ template<class T, class Arg1>
+ T* createSprite(Arg1 arg1) {
+ return new T(_vm, arg1);
+ }
+ template<class T, class Arg1, class Arg2>
+ T* createSprite(Arg1 arg1, Arg2 arg2) {
+ return new T(_vm, arg1, arg2);
+ }
+ template<class T, class Arg1, class Arg2, class Arg3>
+ T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
+ return new T(_vm, arg1, arg2, arg3);
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4>
+ T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) {
+ return new T(_vm, arg1, arg2, arg3, arg4);
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5>
+ T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) {
+ return new T(_vm, arg1, arg2, arg3, arg4, arg5);
+ }
+ template<class T, class Arg1, class Arg2, class Arg3, class Arg4, class Arg5, class Arg6>
+ T* createSprite(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6) {
+ return new T(_vm, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+protected:
+ Module *_parentModule;
+ Common::Array<Entity*> _entities;
+ Common::Array<BaseSurface*> _surfaces;
+ bool _systemCallbackFlag;
+ MessageList *_messageList;
+ uint _messageListCount;
+ uint _messageListIndex;
+ bool _messageListFlag1;
+ NPoint _mouseClickPos;
+ bool _mouseClicked;
+ DataResource _dataResource;
+ RectList *_rectList;
+ HitRectList _hitRectList;
+ int _rectType;
+ // TODO 0000008E field_8E dw ?
+ Mouse *_mouseCursor;
+ Klayman *_klayman;
+ Palette *_palette;
+ Background *_background;
+ bool _surfaceFlag;
+ bool _messageListFlag;
+ MessageList *_messageList2;
+ int _messageListStatus;
+ SmackerPlayer *_smackerPlayer;
+ void (Entity::*_savedUpdateHandlerCb)();
+ uint32 (Entity::*_savedMessageHandlerCb)(int messageNum, const MessageParam &param, Entity *sender);
+ bool _smackerDone;
+ // TODO 000000BD field_BD db ?
+ // TODO 000000BE field_BE db ?
+ // TODO 000000BF field_BF db ?
+ uint32 _smkFileHash;
+ // TODO 000000C4 hitArray dd ?
+ bool _messageListFlag2;
+ bool _prevVisible;
+ int _messageValue;
+ // TODO 000000CF field_CF db ?
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void smackerUpdate();
+ uint32 smackerHandleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ bool queryPositionSprite(int16 mouseX, int16 mouseY);
+ bool queryPositionRectList(int16 mouseX, int16 mouseY);
+ void setMessageList(uint32 id, bool messageListFlag = true, bool systemCallbackFlag = false);
+ void setMessageList(MessageList *messageList, bool messageListFlag = true, bool systemCallbackFlag = false);
+ bool setMessageList2(uint32 id, bool messageListFlag = true, bool systemCallbackFlag = false);
+ bool setMessageList2(MessageList *messageList, bool messageListFlag = true, bool systemCallbackFlag = false);
+ void runMessageList();
+ void setRectList(uint32 id);
+ void setRectList(RectList *rectList);
+ void clearRectList();
+ void loadHitRectList();
+ void messageList402220();
+ void loadDataResource(uint32 fileHash);
+ uint16 convertMessageNum(uint32 messageNum);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_SCENE_H */
diff --git a/engines/neverhood/screen.cpp b/engines/neverhood/screen.cpp
new file mode 100644
index 0000000000..351e51a3e9
--- /dev/null
+++ b/engines/neverhood/screen.cpp
@@ -0,0 +1,289 @@
+/* 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 "graphics/palette.h"
+#include "neverhood/screen.h"
+
+namespace Neverhood {
+
+Screen::Screen(NeverhoodEngine *vm)
+ : _vm(vm), _paletteData(NULL), _paletteChanged(false) {
+
+ _ticks = _vm->_system->getMillis();
+
+ _backScreen = new Graphics::Surface();
+ _backScreen->create(640, 480, Graphics::PixelFormat::createFormatCLUT8());
+
+}
+
+Screen::~Screen() {
+ delete _backScreen;
+}
+
+void Screen::update() {
+ updatePalette();
+ // TODO: Implement actual code
+ _vm->_system->copyRectToScreen((const byte*)_backScreen->pixels, _backScreen->pitch, 0, 0, 640, 480);
+ _vm->_system->updateScreen();
+}
+
+void Screen::wait() {
+ // TODO
+ _vm->_system->delayMillis(40);
+}
+
+void Screen::setFps(int fps) {
+ _frameDelay = 1000 / fps;
+}
+
+int Screen::getFps() {
+ return 1000 / _frameDelay;
+}
+
+void Screen::setPaletteData(byte *paletteData) {
+ _paletteChanged = true;
+ _paletteData = paletteData;
+}
+
+void Screen::unsetPaletteData(byte *paletteData) {
+ if (_paletteData == paletteData) {
+ _paletteChanged = false;
+ _paletteData = NULL;
+ }
+}
+
+void Screen::testPalette(byte *paletteData) {
+ if (_paletteData == paletteData)
+ _paletteChanged = true;
+}
+
+void Screen::updatePalette() {
+ if (_paletteChanged && _paletteData) {
+ byte *tempPalette = new byte[768];
+ for (int i = 0; i < 256; i++) {
+ tempPalette[i * 3 + 0] = _paletteData[i * 4 + 0];
+ tempPalette[i * 3 + 1] = _paletteData[i * 4 + 1];
+ tempPalette[i * 3 + 2] = _paletteData[i * 4 + 2];
+ }
+ _vm->_system->getPaletteManager()->setPalette(tempPalette, 0, 256);
+ delete[] tempPalette;
+ _paletteChanged = false;
+ }
+}
+
+void Screen::clear() {
+ memset(_backScreen->pixels, 0, _backScreen->pitch * _backScreen->h);
+}
+
+void Screen::drawSurface2(const Graphics::Surface *surface, NDrawRect &drawRect, NRect &clipRect, bool transparent) {
+
+ int16 destX, destY;
+ NRect ddRect;
+
+ if (drawRect.x + drawRect.width >= clipRect.x2)
+ ddRect.x2 = clipRect.x2 - drawRect.x;
+ else
+ ddRect.x2 = drawRect.width;
+
+ if (drawRect.x < clipRect.x1) {
+ destX = clipRect.x1;
+ ddRect.x1 = clipRect.x1 - drawRect.x;
+ } else {
+ destX = drawRect.x;
+ ddRect.x1 = 0;
+ }
+
+ if (drawRect.y + drawRect.height >= clipRect.y2)
+ ddRect.y2 = clipRect.y2 - drawRect.y;
+ else
+ ddRect.y2 = drawRect.height;
+
+ if (drawRect.y < clipRect.y1) {
+ destY = clipRect.y1;
+ ddRect.y1 = clipRect.y1 - drawRect.y;
+ } else {
+ destY = drawRect.y;
+ ddRect.y1 = 0;
+ }
+
+ //debug(2, "draw: x = %d; y = %d; (%d, %d, %d, %d)", destX, destY, ddRect.x1, ddRect.y1, ddRect.x2, ddRect.y2);
+
+ blit(surface, destX, destY, ddRect, transparent);
+
+ // Useful for debugging
+ //_backScreen->frameRect(Common::Rect(clipRect.x1, clipRect.y1, clipRect.x2, clipRect.y2), 250);
+ //_backScreen->frameRect(Common::Rect(destX, destY, destX + ddRect.x2, destY + ddRect.y2), 255);
+ //_backScreen->frameRect(Common::Rect(drawRect.x, drawRect.y, drawRect.x + drawRect.width, drawRect.y + drawRect.height), 255);
+
+}
+
+void Screen::drawSurface3(const Graphics::Surface *surface, int16 x, int16 y, NDrawRect &drawRect, NRect &clipRect, bool transparent) {
+
+ int16 destX, destY;
+ NRect ddRect;
+
+ if (x + drawRect.width >= clipRect.x2)
+ ddRect.x2 = clipRect.x2 - drawRect.x - x;
+ else
+ ddRect.x2 = drawRect.x + drawRect.width;
+
+ if (x < clipRect.x1) {
+ destX = clipRect.x1;
+ ddRect.x1 = clipRect.x1 + drawRect.x - x;
+ } else {
+ destX = x;
+ ddRect.x1 = drawRect.x;
+ }
+
+ if (y + drawRect.height >= clipRect.y2)
+ ddRect.y2 = clipRect.y2 + drawRect.y - y;
+ else
+ ddRect.y2 = drawRect.y + drawRect.height;
+
+ if (y < clipRect.y1) {
+ destY = clipRect.y1;
+ ddRect.y1 = clipRect.y1 + drawRect.y - y;
+ } else {
+ destY = y;
+ ddRect.y1 = drawRect.y;
+ }
+
+ blit(surface, destX, destY, ddRect, transparent);
+
+}
+
+void Screen::blit(const Graphics::Surface *surface, int16 destX, int16 destY, NRect &ddRect, bool transparent) {
+
+ const byte *source = (const byte*)surface->getBasePtr(ddRect.x1, ddRect.y1);
+ byte *dest = (byte*)_backScreen->getBasePtr(destX, destY);
+ int width = ddRect.x2 - ddRect.x1;
+ int height = ddRect.y2 - ddRect.y1;
+
+ if (width <= 0 || height <= 0)
+ return;
+
+ if (!transparent) {
+ while (height--) {
+ memcpy(dest, source, width);
+ source += surface->pitch;
+ dest += _backScreen->pitch;
+ }
+ } else {
+ while (height--) {
+ for (int xc = 0; xc < width; xc++)
+ if (source[xc] != 0)
+ dest[xc] = source[xc];
+ source += surface->pitch;
+ dest += _backScreen->pitch;
+ }
+ }
+
+}
+
+void Screen::drawDoubleSurface2(const Graphics::Surface *surface, NDrawRect &drawRect) {
+
+ const byte *source = (const byte*)surface->getBasePtr(0, 0);
+ byte *dest = (byte*)_backScreen->getBasePtr(drawRect.x, drawRect.y);
+
+ for (int16 yc = 0; yc < surface->h; yc++) {
+ byte *row = dest;
+ for (int16 xc = 0; xc < surface->w; xc++) {
+ *row++ = *source;
+ *row++ = *source++;
+ }
+ memcpy(dest + _backScreen->pitch, dest, surface->w * 2);
+ dest += _backScreen->pitch;
+ dest += _backScreen->pitch;
+ }
+
+}
+
+void Screen::drawUnk(const Graphics::Surface *surface, NDrawRect &drawRect, NDrawRect &sysRect, NRect &clipRect, bool transparent) {
+
+ int16 x, y;
+ bool xflag, yflag;
+ NDrawRect newDrawRect;
+
+ x = sysRect.x;
+ if (sysRect.width <= x || -sysRect.width >= x) {
+ x = x % sysRect.width;
+ }
+ if (x < 0)
+ x += sysRect.width;
+
+ y = sysRect.y;
+ if (y >= sysRect.height || -sysRect.height >= y) {
+ y = y % sysRect.height;
+ }
+ if (y < 0)
+ y += sysRect.height;
+
+ xflag = x <= 0;
+ yflag = y <= 0;
+
+ newDrawRect.x = x;
+ newDrawRect.width = sysRect.width - x;
+ if (drawRect.width < newDrawRect.width) {
+ xflag = true;
+ newDrawRect.width = drawRect.width;
+ }
+
+ newDrawRect.y = y;
+ newDrawRect.height = sysRect.height - y;
+ if (drawRect.height < newDrawRect.height) {
+ yflag = true;
+ newDrawRect.height = drawRect.height;
+ }
+
+ drawSurface3(surface, drawRect.x, drawRect.y, newDrawRect, clipRect, transparent);
+
+ if (!xflag) {
+ newDrawRect.x = 0;
+ newDrawRect.y = y;
+ newDrawRect.width = x + drawRect.width - sysRect.width;
+ newDrawRect.height = sysRect.height - y;
+ if (drawRect.height < newDrawRect.height)
+ newDrawRect.height = drawRect.height;
+ drawSurface3(surface, sysRect.width + drawRect.x - x, drawRect.y, newDrawRect, clipRect, transparent);
+ }
+
+ if (!yflag) {
+ newDrawRect.x = x;
+ newDrawRect.y = 0;
+ newDrawRect.width = sysRect.width - x;
+ newDrawRect.height = y + drawRect.height - sysRect.height;
+ if (drawRect.width < newDrawRect.width)
+ newDrawRect.width = drawRect.width;
+ drawSurface3(surface, drawRect.x, sysRect.height + drawRect.y - y, newDrawRect, clipRect, transparent);
+ }
+
+ if (!xflag && !yflag) {
+ newDrawRect.x = 0;
+ newDrawRect.y = 0;
+ newDrawRect.width = x + drawRect.width - sysRect.width;
+ newDrawRect.height = y + drawRect.height - sysRect.height;
+ drawSurface3(surface, sysRect.width + drawRect.x - x, sysRect.height + drawRect.y - y, newDrawRect, clipRect, transparent);
+ }
+
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/screen.h b/engines/neverhood/screen.h
new file mode 100644
index 0000000000..e813e63f20
--- /dev/null
+++ b/engines/neverhood/screen.h
@@ -0,0 +1,61 @@
+/* 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_SCREEN_H
+#define NEVERHOOD_SCREEN_H
+
+#include "graphics/surface.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/graphics.h"
+
+namespace Neverhood {
+
+class Screen {
+public:
+ Screen(NeverhoodEngine *vm);
+ ~Screen();
+ void update();
+ void wait();
+ void setFps(int fps);
+ int getFps();
+ void setPaletteData(byte *paletteData);
+ void unsetPaletteData(byte *paletteData);
+ void testPalette(byte *paletteData);
+ void updatePalette();
+ void clear();
+ void drawSurface2(const Graphics::Surface *surface, NDrawRect &drawRect, NRect &clipRect, bool transparent);
+ void drawSurface3(const Graphics::Surface *surface, int16 x, int16 y, NDrawRect &drawRect, NRect &clipRect, bool transparent);
+ void blit(const Graphics::Surface *surface, int16 destX, int16 destY, NRect &ddRect, bool transparent);
+ void drawDoubleSurface2(const Graphics::Surface *surface, NDrawRect &drawRect);
+ void drawUnk(const Graphics::Surface *surface, NDrawRect &drawRect, NDrawRect &sysRect, NRect &clipRect, bool transparent);
+protected:
+ NeverhoodEngine *_vm;
+ Graphics::Surface *_backScreen;
+ uint32 _ticks;
+ uint32 _frameDelay;
+ byte *_paletteData;
+ bool _paletteChanged;
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_SCREEN_H */
diff --git a/engines/neverhood/smackerplayer.cpp b/engines/neverhood/smackerplayer.cpp
new file mode 100644
index 0000000000..9ae7e14eed
--- /dev/null
+++ b/engines/neverhood/smackerplayer.cpp
@@ -0,0 +1,250 @@
+/* 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 "graphics/palette.h"
+#include "neverhood/smackerplayer.h"
+#include "neverhood/palette.h"
+#include "neverhood/resourceman.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// SmackerSurface
+
+SmackerSurface::SmackerSurface(NeverhoodEngine *vm)
+ : BaseSurface(vm, 0, 0, 0), _smackerFrame(NULL) {
+}
+
+void SmackerSurface::draw() {
+ if (_smackerFrame && _visible && _drawRect.width > 0 && _drawRect.height > 0) {
+ _vm->_screen->drawSurface2(_smackerFrame, _drawRect, _clipRect, false);
+ }
+}
+
+void SmackerSurface::setSmackerFrame(const Graphics::Surface *smackerFrame) {
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = smackerFrame->w;
+ _drawRect.height = smackerFrame->h;
+ // TODO: Check if _sysRect is needed at all in the reimplementation...
+ _sysRect.x = 0;
+ _sysRect.y = 0;
+ _sysRect.width = (smackerFrame->w + 3) & 0xFFFC; // align by 4 bytes
+ _sysRect.height = smackerFrame->h;
+ _smackerFrame = smackerFrame;
+}
+
+// SmackerDoubleSurface
+
+SmackerDoubleSurface::SmackerDoubleSurface(NeverhoodEngine *vm)
+ : SmackerSurface(vm) {
+}
+
+void SmackerDoubleSurface::draw() {
+ if (_smackerFrame && _visible && _drawRect.width > 0 && _drawRect.height > 0) {
+ _vm->_screen->drawDoubleSurface2(_smackerFrame, _drawRect);
+ }
+}
+
+// SmackerPlayer
+
+SmackerPlayer::SmackerPlayer(NeverhoodEngine *vm, Scene *scene, uint32 fileHash, bool doubleSurface, bool flag)
+ : Entity(vm, 0), _scene(scene), _doubleSurface(doubleSurface), _dirtyFlag(false), _flag2(false),
+ _palette(NULL), _smackerDecoder(NULL), _smackerSurface(NULL), _stream(NULL), _smackerFirst(true),
+ _drawX(-1), _drawY(-1) {
+
+ SetUpdateHandler(&SmackerPlayer::update);
+ open(fileHash, flag);
+}
+
+SmackerPlayer::~SmackerPlayer() {
+ close();
+}
+
+void SmackerPlayer::open(uint32 fileHash, bool keepLastFrame) {
+ debug("SmackerPlayer::open(%08X)", fileHash);
+
+ _fileHash = fileHash;
+ _keepLastFrame = keepLastFrame;
+
+ close();
+
+ if (_doubleSurface) {
+ _smackerSurface = new SmackerDoubleSurface(_vm);
+ } else {
+ _smackerSurface = new SmackerSurface(_vm);
+ }
+
+ _smackerFirst = true;
+
+ _stream = _vm->_res->createStream(fileHash);
+
+ // TODO: _keepLastFrame stuff
+
+ _smackerDecoder = new Video::SmackerDecoder(_vm->_mixer);
+ _smackerDecoder->loadStream(_stream);
+
+ _palette = new Palette(_vm);
+ _palette->usePalette();
+
+}
+
+void SmackerPlayer::close() {
+ delete _smackerDecoder;
+ delete _palette;
+ // NOTE: The SmackerDecoder deletes the _stream
+ delete _smackerSurface;
+ _smackerDecoder = NULL;
+ _palette = NULL;
+ _stream = NULL;
+ _smackerSurface = NULL;
+}
+
+void SmackerPlayer::gotoFrame(uint frameNumber) {
+ // TODO?
+}
+
+uint32 SmackerPlayer::getFrameCount() {
+ return _smackerDecoder ? _smackerDecoder->getFrameCount() : 0;
+}
+
+uint32 SmackerPlayer::getFrameNumber() {
+ return _smackerDecoder ? _smackerDecoder->getCurFrame() : 0;
+}
+
+uint SmackerPlayer::getStatus() {
+ return 0;
+}
+
+void SmackerPlayer::setDrawPos(int16 x, int16 y) {
+ _drawX = x;
+ _drawY = y;
+ if (_smackerSurface) {
+ _smackerSurface->getDrawRect().x = _drawX;
+ _smackerSurface->getDrawRect().y = _drawY;
+ }
+}
+
+void SmackerPlayer::rewind() {
+
+ delete _smackerDecoder;
+ _smackerDecoder = NULL;
+ _stream = NULL;
+
+ _smackerFirst = true;
+
+ _stream = _vm->_res->createStream(_fileHash);
+
+ _smackerDecoder = new Video::SmackerDecoder(_vm->_mixer);
+ _smackerDecoder->loadStream(_stream);
+
+}
+
+void SmackerPlayer::update() {
+ debug(8, "SmackerPlayer::update()");
+
+ if (!_smackerDecoder)
+ return;
+
+ if (_dirtyFlag) {
+ // TODO _vm->_screen->resetDirtyRects();
+ _dirtyFlag = false;
+ }
+
+#if 0
+ if (!_smackerDecoder->endOfVideo()) {
+ updateFrame();
+ if (_smackerDecoder->endOfVideo() && !_keepLastFrame) {
+ // Inform the scene about the end of the video playback
+ if (_scene) {
+ sendMessage(_scene, 0x3002, 0);
+ }
+ _flag2 = true;
+ } else {
+ if (_smackerDecoder->endOfVideo()) {
+ rewind();
+ updateFrame();
+ }
+ _flag2 = false;
+ }
+ }
+#endif
+
+ if (!_smackerDecoder->endOfVideo()) {
+ updateFrame();
+ } else if (!_keepLastFrame) {
+ // Inform the scene about the end of the video playback
+ if (_scene) {
+ sendMessage(_scene, 0x3002, 0);
+ }
+ _flag2 = true;
+ } else {
+ rewind();
+ updateFrame();
+ _flag2 = false;
+ }
+
+}
+
+void SmackerPlayer::updateFrame() {
+ const Graphics::Surface *smackerFrame = _smackerDecoder->decodeNextFrame();
+
+ if (_smackerFirst) {
+ _smackerSurface->setSmackerFrame(smackerFrame);
+ if (_drawX < 0 || _drawY < 0) {
+ if (_doubleSurface) {
+ _drawX = 320 - _smackerDecoder->getWidth();
+ _drawY = 240 - _smackerDecoder->getHeight();
+ } else {
+ _drawX = (640 - _smackerDecoder->getWidth()) / 2;
+ _drawY = (480 - _smackerDecoder->getHeight()) / 2;
+ }
+ }
+ _smackerSurface->getDrawRect().x = _drawX;
+ _smackerSurface->getDrawRect().y = _drawY;
+ _smackerFirst = false;
+ }
+
+ if (_doubleSurface) {
+ // TODO
+ }
+
+ // TODO _vm->_screen->_skipUpdate = true;
+ _dirtyFlag = true;
+
+ if (_smackerDecoder->hasDirtyPalette()) {
+ updatePalette();
+ }
+}
+
+void SmackerPlayer::updatePalette() {
+ byte tempPalette[1024];
+ const byte *smackerPalette = _smackerDecoder->getPalette();
+ for (int i = 0; i < 256; i++) {
+ tempPalette[i * 4 + 0] = smackerPalette[i * 3 + 0];
+ tempPalette[i * 4 + 1] = smackerPalette[i * 3 + 1];
+ tempPalette[i * 4 + 2] = smackerPalette[i * 3 + 2];
+ }
+ _palette->copyPalette(tempPalette, 0, 256, 0);
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/smackerplayer.h b/engines/neverhood/smackerplayer.h
new file mode 100644
index 0000000000..883cb52245
--- /dev/null
+++ b/engines/neverhood/smackerplayer.h
@@ -0,0 +1,83 @@
+/* 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_SMACKERPLAYER_H
+#define NEVERHOOD_SMACKERPLAYER_H
+
+#include "video/smk_decoder.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/entity.h"
+
+namespace Neverhood {
+
+class Scene;
+class Palette;
+
+class SmackerSurface : public BaseSurface {
+public:
+ SmackerSurface(NeverhoodEngine *vm);
+ virtual void draw();
+ void setSmackerFrame(const Graphics::Surface *smackerFrame);
+protected:
+ const Graphics::Surface *_smackerFrame;
+};
+
+class SmackerDoubleSurface : public SmackerSurface {
+public:
+ SmackerDoubleSurface(NeverhoodEngine *vm);
+ virtual void draw();
+};
+
+class SmackerPlayer : public Entity {
+public:
+ SmackerPlayer(NeverhoodEngine *vm, Scene *scene, uint32 fileHash, bool doubleSurface, bool flag);
+ ~SmackerPlayer();
+ BaseSurface *getSurface() { return _smackerSurface; }
+ void open(uint32 fileHash, bool keepLastFrame);
+ void close();
+ void gotoFrame(uint frameNumber);
+ uint32 getFrameCount();
+ uint32 getFrameNumber();
+ uint getStatus();
+ void setDrawPos(int16 x, int16 y);
+ void rewind();
+protected:
+ Scene *_scene;
+ Palette *_palette;
+ Video::SmackerDecoder *_smackerDecoder;
+ SmackerSurface *_smackerSurface;
+ uint32 _fileHash;
+ bool _smackerFirst;
+ bool _doubleSurface;
+ Common::SeekableReadStream *_stream;
+ bool _keepLastFrame;
+ bool _flag2;
+ bool _dirtyFlag;
+ int _drawX, _drawY;
+ void update();
+ void updateFrame();
+ void updatePalette();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_SMACKERPLAYER_H */
diff --git a/engines/neverhood/smackerscene.cpp b/engines/neverhood/smackerscene.cpp
new file mode 100644
index 0000000000..fe78e5021e
--- /dev/null
+++ b/engines/neverhood/smackerscene.cpp
@@ -0,0 +1,122 @@
+/* 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/smackerscene.h"
+
+namespace Neverhood {
+
+SmackerScene::SmackerScene(NeverhoodEngine *vm, Module *parentModule, bool doubleSurface, bool flag1, bool canAbort)
+ : Scene(vm, parentModule, true), _doubleSurface(doubleSurface), _flag1(flag1), _canAbort(canAbort), _fieldDF(false),
+ _fileHashListIndex(-1), _fileHashList(NULL), _playNextVideoFlag(false) {
+
+ debug("SmackerScene::SmackerScene(%d, %d, %d)", doubleSurface, flag1, canAbort);
+
+ // NOTE: Merged from SmackerScene::init, maybe split again if needed (incl. parameter flags)
+
+ if (getGlobalVar(0x06C02850)) {
+ _flag1 = true;
+ _canAbort = true;
+ }
+
+ if (_doubleSurface) {
+ _vm->_screen->clear();
+ }
+
+ _fileHash[0] = 0;
+ _fileHash[1] = 0;
+
+ SetUpdateHandler(&SmackerScene::update);
+ SetMessageHandler(&SmackerScene::handleMessage);
+
+}
+
+SmackerScene::~SmackerScene() {
+
+}
+
+void SmackerScene::setFileHash(uint32 fileHash) {
+ debug("SmackerScene::setFileHash(%08X)", fileHash);
+ _fileHash[0] = fileHash;
+ _fileHashList = _fileHash;
+}
+
+void SmackerScene::setFileHashList(const uint32 *fileHashList) {
+ debug("SmackerScene::setFileHashList(...)");
+ _fileHashList = fileHashList;
+}
+
+void SmackerScene::nextVideo() {
+ debug("SmackerScene::nextVideo()");
+
+ _fileHashListIndex++;
+
+ if (_fileHashList && _fileHashList[_fileHashListIndex] != 0) {
+ uint32 smackerFileHash = _fileHashList[_fileHashListIndex];
+ if (_vm->_res->getResourceTypeByHash(smackerFileHash) != 10) {
+ // Not a Smacker file
+ sendMessage(_parentModule, 0x1009, 0);
+ return;
+ }
+ _fieldDF = getSubVar(0x00800410, smackerFileHash);
+ if (!_fieldDF) {
+ setSubVar(0x00800410, smackerFileHash, 1);
+ }
+ if (_fileHashListIndex == 0) {
+ _smackerPlayer = addSmackerPlayer(new SmackerPlayer(_vm, this, smackerFileHash, _doubleSurface, false));
+ // TODO? Screen.hSmack = _smackerPlayer;
+ } else {
+ _smackerPlayer->open(smackerFileHash, false);
+ }
+ } else {
+ sendMessage(_parentModule, 0x1009, 0);
+ }
+
+}
+
+void SmackerScene::update() {
+ if (_playNextVideoFlag) {
+ nextVideo();
+ _playNextVideoFlag = false;
+ }
+ Scene::update();
+}
+
+uint32 SmackerScene::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ uint32 messageResult = Scene::handleMessage(messageNum, param, sender);
+ switch (messageNum) {
+ case 0x0009:
+ if ((_fieldDF && _flag1) || (_canAbort && _flag1))
+ _playNextVideoFlag = true;
+ break;
+ case 0x000C:
+ if (_canAbort) {
+ sendMessage(_parentModule, 0x1009, 0);
+ }
+ break;
+ case 0x3002:
+ _playNextVideoFlag = true;
+ break;
+ }
+ return messageResult;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/smackerscene.h b/engines/neverhood/smackerscene.h
new file mode 100644
index 0000000000..05237664c3
--- /dev/null
+++ b/engines/neverhood/smackerscene.h
@@ -0,0 +1,54 @@
+/* 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_SMACKERSCENE_H
+#define NEVERHOOD_SMACKERSCENE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/resourceman.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+class SmackerScene : public Scene {
+public:
+ SmackerScene(NeverhoodEngine *vm, Module *parentModule, bool doubleSurface, bool flag1, bool canAbort);
+ virtual ~SmackerScene();
+ void setFileHash(uint32 fileHash);
+ void setFileHashList(const uint32 *fileHashList);
+ void nextVideo();
+protected:
+ bool _doubleSurface;
+ bool _flag1;
+ bool _canAbort;
+ bool _fieldDF;
+ bool _playNextVideoFlag;
+ int _fileHashListIndex;
+ const uint32 *_fileHashList;
+ uint32 _fileHash[2];
+ void update();
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_SMACKERSCENE_H */
diff --git a/engines/neverhood/sprite.cpp b/engines/neverhood/sprite.cpp
new file mode 100644
index 0000000000..697bd6e262
--- /dev/null
+++ b/engines/neverhood/sprite.cpp
@@ -0,0 +1,528 @@
+/* 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/sprite.h"
+
+namespace Neverhood {
+
+// Sprite
+
+Sprite::Sprite(NeverhoodEngine *vm, int objectPriority)
+ : Entity(vm, objectPriority), _x(0), _y(0), _spriteUpdateCb(NULL), _filterXCb(NULL), _filterYCb(NULL),
+ _dataResource(vm), _doDeltaX(false), _doDeltaY(false), _needRefresh(false), _flags(0) {
+
+ _name = "Sprite";
+ SetMessageHandler(&Sprite::handleMessage);
+
+}
+
+Sprite::~Sprite() {
+ delete _surface;
+}
+
+void Sprite::processDelta() {
+ if (_doDeltaX) {
+ _rect.x1 = _x - _deltaRect.x - _deltaRect.width + 1;
+ _rect.x2 = _x - _deltaRect.x;
+ } else {
+ _rect.x1 = _x + _deltaRect.x;
+ _rect.x2 = _x + _deltaRect.x + _deltaRect.width - 1;
+ }
+ if (_doDeltaY) {
+ _rect.y1 = _y - _deltaRect.y - _deltaRect.height + 1;
+ _rect.y2 = _y - _deltaRect.y;
+ } else {
+ _rect.y1 = _y + _deltaRect.y;
+ _rect.y2 = _y + _deltaRect.y + _deltaRect.height - 1;
+ }
+}
+
+void Sprite::setDoDeltaX(int type) {
+ // Clear, set or toggle
+ _doDeltaX = type == 2 ? !_doDeltaX : type == 1;
+}
+
+void Sprite::setDoDeltaY(int type) {
+ // Clear, set or toggle
+ _doDeltaY = type == 2 ? !_doDeltaY : type == 1;
+}
+
+bool Sprite::isPointInside(int16 x, int16 y) {
+ return x >= _rect.x1 && x <= _rect.x2 && y >= _rect.y1 && y <= _rect.y2;
+}
+
+bool Sprite::checkCollision(NRect &rect) {
+ return (_rect.x1 < rect.x2) && (rect.x1 < _rect.x2) && (_rect.y1 < rect.y2) && (rect.y1 < _rect.y2);
+}
+
+uint32 Sprite::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+ switch (messageNum) {
+ case 0x0005:
+ // TODO: Draw debug marker (?)
+ // TODO g_Screen->drawLine(_x - 5, _y, _x + 6, _y);
+ // TODO g_Screen->drawLine(_x, _y - 5, _x, _y + 6);
+ break;
+ }
+ return 0;
+}
+
+void Sprite::loadDataResource(uint32 fileHash) {
+ _dataResource.load(fileHash);
+}
+
+void Sprite::createSurface(int surfacePriority, int16 width, int16 height) {
+ _surface = new BaseSurface(_vm, surfacePriority, width, height);
+}
+
+int16 Sprite::defFilterY(int16 y) {
+ // TODO return y - g_screen->field_26;
+ return y;
+}
+
+void Sprite::setClipRect(int16 x1, int16 y1, int16 x2, int16 y2) {
+ NRect &clipRect = _surface->getClipRect();
+ clipRect.x1 = x1;
+ clipRect.y1 = y1;
+ clipRect.x2 = x2;
+ clipRect.y2 = y2;
+}
+
+void Sprite::setClipRect(NRect& clipRect) {
+ _surface->getClipRect() = clipRect;
+}
+
+void Sprite::setClipRect(NDrawRect& drawRect) {
+ setClipRect(drawRect.x, drawRect.y, drawRect.x2(), drawRect.y2());
+}
+
+// StaticSprite
+
+StaticSprite::StaticSprite(NeverhoodEngine *vm, int objectPriority)
+ : Sprite(vm, objectPriority), _spriteResource(vm) {
+
+ _name = "StaticSprite";
+
+}
+
+StaticSprite::StaticSprite(NeverhoodEngine *vm, const char *filename, int surfacePriority, int16 x, int16 y, int16 width, int16 height)
+ : Sprite(vm, 0), _spriteResource(vm) {
+
+ _name = "StaticSprite";
+ init(calcHash(filename), surfacePriority, x, y, width, height);
+
+}
+
+StaticSprite::StaticSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x, int16 y, int16 width, int16 height)
+ : Sprite(vm, 0), _spriteResource(vm) {
+ _name = "StaticSprite";
+ init(fileHash, surfacePriority, x, y, width, height);
+}
+
+void StaticSprite::init(uint32 fileHash, int surfacePriority, int16 x, int16 y, int16 width, int16 height) {
+
+ _spriteResource.load2(fileHash);
+
+ if (width == 0)
+ width = _spriteResource.getDimensions().width;
+
+ if (height == 0)
+ height = _spriteResource.getDimensions().height;
+
+ createSurface(surfacePriority, width, height);
+
+ _x = x == kDefPosition ? _spriteResource.getPosition().x : x;
+ _y = y == kDefPosition ? _spriteResource.getPosition().y : y;
+
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = width;
+ _drawRect.height = height;
+
+ _needRefresh = true;
+
+ update();
+
+}
+
+void StaticSprite::update() {
+
+ if (!_surface)
+ return;
+
+ if (_doDeltaX) {
+ _surface->getDrawRect().x = filterX(_x - _drawRect.x - _drawRect.width + 1);
+ } else {
+ _surface->getDrawRect().x = filterX(_x + _drawRect.x);
+ }
+
+ if (_doDeltaY) {
+ _surface->getDrawRect().y = filterY(_y - _drawRect.y - _drawRect.height + 1);
+ } else {
+ _surface->getDrawRect().y = filterY(_y + _drawRect.y);
+ }
+
+ if (_needRefresh) {
+ _surface->drawSpriteResourceEx(_spriteResource, _doDeltaX, _doDeltaY, _drawRect.width, _drawRect.height);
+ _needRefresh = false;
+ }
+
+}
+
+void StaticSprite::load(uint32 fileHash, bool dimensions, bool position) {
+
+ _spriteResource.load2(fileHash);
+
+ if (dimensions) {
+ _drawRect.x = 0;
+ _drawRect.y = 0;
+ _drawRect.width = _spriteResource.getDimensions().width;
+ _drawRect.height = _spriteResource.getDimensions().height;
+ }
+
+ if (position) {
+ _x = _spriteResource.getPosition().x;
+ _y = _spriteResource.getPosition().y;
+ }
+
+ _needRefresh = true;
+
+}
+
+// AnimatedSprite
+
+AnimatedSprite::AnimatedSprite(NeverhoodEngine *vm, int objectPriority)
+ : Sprite(vm, objectPriority), _animResource(vm) {
+
+ init();
+}
+
+AnimatedSprite::AnimatedSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x, int16 y)
+ : Sprite(vm, 1100), _animResource(vm) {
+
+ init();
+ SetUpdateHandler(&AnimatedSprite::update);
+ createSurface1(fileHash, surfacePriority);
+ _x = x;
+ _y = y;
+ setFileHash(fileHash, 0, -1);
+}
+
+void AnimatedSprite::init() {
+ _name = "AnimatedSprite";
+ _counter = 0;
+ _fileHash1 = 0;
+ _deltaX = 0;
+ _deltaY = 0;
+ _fileHash2 = 0;
+ // TODO _callbackList = 0;
+ _frameIndex3 = 0;
+ _frameIndex = 0;
+ _hashListIndex = -1;
+ _finalizeStateCb = NULL;
+ _currStateCb = NULL;
+ _nextStateCb = NULL;
+ _newHashListIndex = -1;
+ _fileHash4 = 0;
+ _flag = false;
+ _replOldColor = 0;
+ _replNewColor = 0;
+ _animResource.setReplEnabled(false);
+ _playBackwards = false;
+}
+
+void AnimatedSprite::update() {
+ updateAnim();
+ handleSpriteUpdate();
+ updatePosition();
+}
+
+void AnimatedSprite::updateDeltaXY() {
+ if (_doDeltaX) {
+ _x -= _deltaX;
+ } else {
+ _x += _deltaX;
+ }
+ if (_doDeltaY) {
+ _y -= _deltaY;
+ } else {
+ _y += _deltaY;
+ }
+ _deltaX = 0;
+ _deltaY = 0;
+ processDelta();
+}
+
+void AnimatedSprite::setRepl(byte oldColor, byte newColor) {
+ _replOldColor = oldColor;
+ _replNewColor = newColor;
+ _animResource.setReplEnabled(true);
+}
+
+void AnimatedSprite::clearRepl() {
+ _replOldColor = 0;
+ _replNewColor = 0;
+ _animResource.setReplEnabled(false);
+}
+
+void AnimatedSprite::updateAnim() {
+
+ _flag = false;
+
+ if (_fileHash1 == 0) {
+ if (_newHashListIndex != -1) {
+ _hashListIndex = _newHashListIndex == -2 ? _animResource.getFrameCount() - 1 : _newHashListIndex;
+ _newHashListIndex = -1;
+ } else if (_fileHash4 != 0) {
+ _hashListIndex = MAX<int16>(0, _animResource.getFrameIndex(_fileHash4));
+ _fileHash4 = 0;
+ }
+ if (_fileHash1 == 0 && _frameIndex != _hashListIndex) {
+ if (_counter != 0)
+ _counter--;
+ if (_counter == 0 && _animResource.getFrameCount() != 0) {
+
+ if (_fileHash2 != 0) {
+ if (_animResource.loadInternal(_fileHash2)) {
+ _currAnimFileHash = _fileHash2;
+ } else {
+ _animResource.loadInternal(calcHash("sqDefault"));
+ _currAnimFileHash = 0;
+ }
+ if (_replOldColor != _replNewColor) {
+ _animResource.setRepl(_replOldColor, _replNewColor);
+ }
+ _fileHash2 = 0;
+ if (_animStatus != 0) {
+ _frameIndex = _fileHash6 != 0 ? MAX<int16>(0, _animResource.getFrameIndex(_fileHash6)) : 0;
+ _frameIndex2 = _fileHash5 != 0 ? MAX<int16>(0, _animResource.getFrameIndex(_fileHash5)) : _animResource.getFrameCount() - 1;
+ } else {
+ _frameIndex = _frameIndex3 != -1 ? _frameIndex3 : _animResource.getFrameCount() - 1;
+ _frameIndex2 = _frameIndex4 != -1 ? _frameIndex4 : _animResource.getFrameCount() - 1;
+ }
+ } else {
+ updateFrameIndex();
+ }
+ if (_fileHash1 == 0)
+ updateFrameInfo();
+ }
+ }
+ }
+
+ if (_fileHash1 != 0) {
+ if (_animStatus == 2) {
+ _hashListIndex = _frameIndex;
+ } else {
+ if (_animStatus == 1) {
+ if (_animResource.loadInternal(_fileHash1)) {
+ _currAnimFileHash = _fileHash1;
+ } else {
+ _animResource.loadInternal(calcHash("sqDefault"));
+ _currAnimFileHash = 0;
+ }
+ if (_replOldColor != _replNewColor) {
+ _animResource.setRepl(_replOldColor, _replNewColor);
+ }
+ _fileHash1 = 0;
+ _frameIndex = _fileHash6 != 0 ? MAX<int16>(0, _animResource.getFrameIndex(_fileHash6)) : 0;
+ _frameIndex2 = _fileHash5 != 0 ? MAX<int16>(0, _animResource.getFrameIndex(_fileHash5)) : _animResource.getFrameCount() - 1;
+ } else {
+ if (_animResource.loadInternal(_fileHash1)) {
+ _currAnimFileHash = _fileHash1;
+ } else {
+ _animResource.loadInternal(calcHash("sqDefault"));
+ _currAnimFileHash = 0;
+ }
+ if (_replOldColor != _replNewColor) {
+ _animResource.setRepl(_replOldColor, _replNewColor);
+ }
+ _fileHash1 = 0;
+ _frameIndex = _frameIndex3 != -1 ? _frameIndex3 : _animResource.getFrameCount() - 1;
+ _frameIndex2 = _frameIndex4 != -1 ? _frameIndex4 : _animResource.getFrameCount() - 1;
+ }
+ updateFrameInfo();
+ }
+
+ if (_newHashListIndex != -1) {
+ _hashListIndex = _newHashListIndex == -2 ? _animResource.getFrameCount() - 1 : _newHashListIndex;
+ _newHashListIndex = -1;
+ } else if (_fileHash4 != 0) {
+ _hashListIndex = MAX<int16>(0, _animResource.getFrameIndex(_fileHash4));
+ _fileHash4 = 0;
+ }
+
+ }
+
+}
+
+void AnimatedSprite::updatePosition() {
+
+ if (!_surface)
+ return;
+
+ if (_doDeltaX) {
+ _surface->getDrawRect().x = filterX(_x - _drawRect.x - _drawRect.width + 1);
+ } else {
+ _surface->getDrawRect().x = filterX(_x + _drawRect.x);
+ }
+
+ if (_doDeltaY) {
+ _surface->getDrawRect().y = filterY(_y - _drawRect.y - _drawRect.height + 1);
+ } else {
+ _surface->getDrawRect().y = filterY(_y + _drawRect.y);
+ }
+
+ if (_needRefresh) {
+ _surface->drawAnimResource(_animResource, _frameIndex, _doDeltaX, _doDeltaY, _drawRect.width, _drawRect.height);
+ _needRefresh = false;
+ }
+
+}
+
+void AnimatedSprite::updateFrameIndex() {
+ if (!_playBackwards) {
+ if (_frameIndex < _frameIndex2) {
+ _frameIndex++;
+ } else {
+ // Inform self about end of current animation
+ // The caller can then e.g. set a new animation fileHash
+ sendMessage(this, 0x3002, 0);
+ if (_fileHash1 == 0)
+ _frameIndex = 0;
+ }
+ } else {
+ if (_frameIndex > 0) {
+ _frameIndex--;
+ } else {
+ sendMessage(this, 0x3002, 0);
+ if (_fileHash1 == 0)
+ _frameIndex = _frameIndex2;
+ }
+ }
+}
+
+void AnimatedSprite::updateFrameInfo() {
+ debug(8, "AnimatedSprite::updateFrameInfo()");
+
+ const AnimFrameInfo &frameInfo = _animResource.getFrameInfo(_frameIndex);
+
+ _flag = true;
+ _drawRect = frameInfo.rect;
+ _deltaX = frameInfo.deltaX;
+ _deltaY = frameInfo.deltaY;
+ _deltaRect = frameInfo.deltaRect;
+ _counter = frameInfo.counter;
+
+ processDelta();
+
+ _needRefresh = true;
+
+ if (frameInfo.frameHash != 0) {
+ sendMessage(this, 0x100D, frameInfo.frameHash);
+ }
+
+}
+
+void AnimatedSprite::createSurface1(uint32 fileHash, int surfacePriority) {
+ NDimensions dimensions = _animResource.loadSpriteDimensions(fileHash);
+ _surface = new BaseSurface(_vm, surfacePriority, dimensions.width, dimensions.height);
+}
+
+void AnimatedSprite::setFileHash(uint32 fileHash, int16 frameIndex3, int16 frameIndex4) {
+ debug(2, "AnimatedSprite::setFileHash(%08X, %d, %d)", fileHash, frameIndex3, frameIndex4);
+ _fileHash1 = fileHash;
+ _frameIndex3 = frameIndex3;
+ _frameIndex4 = frameIndex4;
+ _fileHash4 = 0;
+ _animStatus = 0;
+ _playBackwards = false;
+ _newHashListIndex = -1;
+ _hashListIndex = -1;
+}
+
+void AnimatedSprite::stopAnimation() {
+ _fileHash1 = 1;
+ _animStatus = 2;
+}
+
+void AnimatedSprite::setFileHash2(uint32 fileHash, uint32 fileHash6, uint32 fileHash5) {
+ debug(2, "AnimatedSprite::setFileHash2(%08X, %08X, %08X)", fileHash, fileHash6, fileHash5);
+ _fileHash1 = fileHash;
+ _fileHash6 = fileHash6;
+ _fileHash5 = fileHash5;
+ _fileHash4 = 0;
+ _animStatus = 1;
+ _playBackwards = false;
+ _newHashListIndex = -1;
+ _hashListIndex = -1;
+}
+
+void AnimatedSprite::setFileHash3(uint32 fileHash2, uint32 fileHash6, uint32 fileHash5) {
+ _fileHash2 = fileHash2;
+ _fileHash6 = fileHash6;
+ _fileHash5 = fileHash5;
+ _fileHash4 = 0;
+ _animStatus = 1;
+ _playBackwards = false;
+ _newHashListIndex = -1;
+ _hashListIndex = -1;
+}
+
+void AnimatedSprite::setFinalizeState(AnimationCb finalizeStateCb) {
+ if (_finalizeStateCb)
+ (this->*_finalizeStateCb)();
+ _finalizeStateCb = finalizeStateCb;
+}
+
+void AnimatedSprite::gotoState(AnimationCb currStateCb) {
+ if (_finalizeStateCb) {
+ AnimationCb cb = _finalizeStateCb;
+ _finalizeStateCb = NULL;
+ (this->*cb)();
+ }
+ // TODO _callbackList = NULL;
+ _nextStateCb = NULL;
+ _currStateCb = currStateCb;
+ if (_currStateCb)
+ (this->*_currStateCb)();
+}
+
+void AnimatedSprite::removeCallbacks() {
+ if (_finalizeStateCb) {
+ AnimationCb cb = _finalizeStateCb;
+ _finalizeStateCb = NULL;
+ (this->*cb)();
+ }
+ if (_nextStateCb) {
+ _currStateCb = _nextStateCb;
+ _nextStateCb = NULL;
+ debug("Fire _nextStateCb '%s'", _nextStateCbName.c_str());
+ (this->*_currStateCb)();
+#if 0 // TODO
+ } else if (_callbackList) {
+ removeCallbackList();
+#endif
+ } else {
+ _currStateCb = NULL;
+ }
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/sprite.h b/engines/neverhood/sprite.h
new file mode 100644
index 0000000000..aa2272464e
--- /dev/null
+++ b/engines/neverhood/sprite.h
@@ -0,0 +1,178 @@
+/* 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_SPRITE_H
+#define NEVERHOOD_SPRITE_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/entity.h"
+#include "neverhood/graphics.h"
+#include "neverhood/resource.h"
+
+namespace Neverhood {
+
+#define SetSpriteCallback(callback) _spriteUpdateCb = static_cast <void (Sprite::*)(void)> (callback); debug(2, "SetSpriteCallback(" #callback ")"); _spriteUpdateCbName = #callback
+#define SetFilterX(callback) _filterXCb = static_cast <int16 (Sprite::*)(int16)> (callback); debug(2, "SetFilterX(" #callback ")")
+#define SetFilterY(callback) _filterYCb = static_cast <int16 (Sprite::*)(int16)> (callback); debug(2, "SetFilterY(" #callback ")")
+
+const int16 kDefPosition = -32768;
+
+class Sprite : public Entity {
+public:
+ Sprite(NeverhoodEngine *vm, int objectPriority);
+ ~Sprite();
+ void init() {}
+ BaseSurface *getSurface() { return _surface; }
+ void processDelta();
+ void setDoDeltaX(int type);
+ void setDoDeltaY(int type);
+ bool isPointInside(int16 x, int16 y);
+ bool checkCollision(NRect &rect);
+ int16 getX() const { return _x; }
+ int16 getY() const { return _y; }
+ void setX(int16 value) { _x = value; }
+ void setY(int16 value) { _y = value; }
+ uint16 getFlags() const { return _flags; }
+ bool isDoDeltaX() const { return _doDeltaX; }
+ bool isDoDeltaY() const { return _doDeltaY; }
+ NRect& getRect() { return _rect; }
+ uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+ void loadDataResource(uint32 fileHash);
+ int16 defFilterY(int16 y);
+ void setVisible(bool value) { _surface->setVisible(value); }
+ NDrawRect& getDrawRect() { return _surface->getDrawRect(); }
+ // Some shortcuts to set the clipRect
+ NRect& getClipRect() { return _surface->getClipRect(); }
+ void setClipRect(int16 x1, int16 y1, int16 x2, int16 y2);
+ void setClipRect(NRect& clipRect);
+ void setClipRect(NDrawRect& drawRect);
+protected:
+ void (Sprite::*_spriteUpdateCb)();
+ Common::String _spriteUpdateCbName; // For debugging purposes
+ int16 (Sprite::*_filterXCb)(int16);
+ int16 (Sprite::*_filterYCb)(int16);
+ BaseSurface *_surface;
+ int16 _x, _y;
+ bool _doDeltaX, _doDeltaY;
+ bool _needRefresh;
+ //0000002B field_2B db ?
+ //0000002C field2C dd ? // unused
+ NDrawRect _drawRect;
+ NDrawRect _deltaRect;
+ NRect _rect;
+ uint16 _flags;
+ //0000004A field4A dw ? // seems to be unused except in ctor
+ DataResource _dataResource;
+ void createSurface(int surfacePriority, int16 width, int16 height);
+ void handleSpriteUpdate() {
+ if (_spriteUpdateCb)
+ (this->*_spriteUpdateCb)();
+ }
+ int16 filterX(int16 x) {
+ return _filterXCb ? (this->*_filterXCb)(x) : x;
+ }
+ int16 filterY(int16 y) {
+ return _filterYCb ? (this->*_filterYCb)(y) : y;
+ }
+};
+
+class StaticSprite : public Sprite {
+public:
+ StaticSprite(NeverhoodEngine *vm, int objectPriority);
+ StaticSprite(NeverhoodEngine *vm, const char *filename, int surfacePriority, int16 x = kDefPosition, int16 y = kDefPosition, int16 width = 0, int16 height = 0);
+ StaticSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x = kDefPosition, int16 y = kDefPosition, int16 width = 0, int16 height = 0);
+ void load(uint32 fileHash, bool dimensions, bool position);
+ void update();
+protected:
+ SpriteResource _spriteResource;
+ void init(uint32 fileHash, int surfacePriority, int16 x = kDefPosition, int16 y = kDefPosition, int16 width = 0, int16 height = 0);
+};
+
+#define AnimationCallback(callback) static_cast <void (AnimatedSprite::*)()> (callback)
+#define GotoState(callback) gotoState(static_cast <void (AnimatedSprite::*)()> (callback))
+#define NextState(callback) _nextStateCb = static_cast <void (AnimatedSprite::*)(void)> (callback); debug(2, "NextState(" #callback ")"); _nextStateCbName = #callback
+#define FinalizeState(callback) setFinalizeState(static_cast <void (AnimatedSprite::*)()> (callback));
+
+class AnimatedSprite : public Sprite {
+public:
+ AnimatedSprite(NeverhoodEngine *vm, int objectPriority);
+ AnimatedSprite(NeverhoodEngine *vm, uint32 fileHash, int surfacePriority, int16 x, int16 y);
+ void update();
+ void updateDeltaXY();
+ void setRepl(byte oldColor, byte newColor);
+ void clearRepl();
+ uint32 getCurrAnimFileHash() const { return _currAnimFileHash; }
+ int16 getFrameIndex() const { return _frameIndex; }
+ int16 getFrameIndex(uint32 frameHash) { return _animResource.getFrameIndex(frameHash); }
+ void setNewHashListIndex(int value) { _newHashListIndex = value; }
+ void setFileHash(uint32 fileHash, int16 frameIndex3, int16 frameIndex4);
+protected:
+ typedef void (AnimatedSprite::*AnimationCb)();
+ AnimResource _animResource;
+ uint32 _currAnimFileHash;
+ uint32 _fileHash1;
+ uint32 _fileHash2;
+ int16 _frameIndex;
+ int16 _frameIndex3;
+ int16 _frameIndex2;
+ int16 _frameIndex4;
+ uint32 _fileHash6;
+ uint32 _fileHash5;
+ int16 _animStatus;
+ int16 _counter;
+ int _hashListIndex;
+ int _newHashListIndex;
+ uint32 _fileHash4;
+ int16 _deltaX, _deltaY;
+ byte _replOldColor;
+ byte _replNewColor;
+ bool _playBackwards;
+ bool _flag;
+ /* TODO
+ callbackListIndex dw ?
+ callbackListCount dw ?
+ callbackList dd ?
+ */
+ AnimationCb _finalizeStateCb;
+ AnimationCb _currStateCb;
+ AnimationCb _nextStateCb;
+ // For debugging purposes
+ Common::String _finalizeStateCbName;
+ Common::String _currStateCbName;
+ Common::String _nextStateCbName;
+ void init();
+ void updateAnim();
+ void updatePosition();
+ void updateFrameIndex();
+ void updateFrameInfo();
+ void createSurface1(uint32 fileHash, int surfacePriority);
+ void stopAnimation();
+ void setFileHash2(uint32 fileHash, uint32 fileHash6, uint32 fileHash5);
+ void setFileHash3(uint32 fileHash2, uint32 fileHash6, uint32 fileHash5);
+ void setFinalizeState(AnimationCb finalizeStateCb);
+ void gotoState(AnimationCb currStateCb);
+ void removeCallbacks();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_SPRITE_H */
diff --git a/engines/neverhood/staticdata.cpp b/engines/neverhood/staticdata.cpp
new file mode 100644
index 0000000000..147a319d2e
--- /dev/null
+++ b/engines/neverhood/staticdata.cpp
@@ -0,0 +1,200 @@
+/* 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/staticdata.h"
+
+namespace Neverhood {
+
+StaticData::StaticData() {
+}
+
+StaticData::~StaticData() {
+}
+
+void StaticData::load(const char *filename) {
+
+ Common::File fd;
+
+ if (!fd.open(filename))
+ error("StaticData::load() Could not open %s", filename);
+
+ fd.readUint32LE(); // magic
+ fd.readUint32LE(); // version
+
+ // Load message lists
+ uint32 messageListsCount = fd.readUint32LE();
+ debug("messageListsCount: %d", messageListsCount);
+ for (uint32 i = 0; i < messageListsCount; i++) {
+ MessageList *messageList = new MessageList();
+ uint32 id = fd.readUint32LE();
+ uint32 itemCount = fd.readUint32LE();
+ for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
+ MessageItem messageItem;
+ messageItem.messageNum = fd.readUint16LE();
+ messageItem.messageValue = fd.readUint32LE();
+ messageList->push_back(messageItem);
+ }
+ _messageLists[id] = messageList;
+ }
+
+ // Load rect lists
+ uint32 rectListsCount = fd.readUint32LE();
+ debug("rectListsCount: %d", rectListsCount);
+ for (uint32 i = 0; i < rectListsCount; i++) {
+ RectList *rectList = new RectList();
+ uint32 id = fd.readUint32LE();
+ uint32 itemCount = fd.readUint32LE();
+ for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
+ RectItem rectItem;
+ rectItem.rect.x1 = fd.readUint16LE();
+ rectItem.rect.y1 = fd.readUint16LE();
+ rectItem.rect.x2 = fd.readUint16LE();
+ rectItem.rect.y2 = fd.readUint16LE();
+ uint32 subItemCount = fd.readUint32LE();
+ rectItem.subRects.reserve(subItemCount);
+ for (uint32 subItemIndex = 0; subItemIndex < subItemCount; subItemIndex++) {
+ SubRectItem subRectItem;
+ subRectItem.rect.x1 = fd.readUint16LE();
+ subRectItem.rect.y1 = fd.readUint16LE();
+ subRectItem.rect.x2 = fd.readUint16LE();
+ subRectItem.rect.y2 = fd.readUint16LE();
+ subRectItem.messageListId = fd.readUint32LE();
+ rectItem.subRects.push_back(subRectItem);
+ }
+ rectList->push_back(rectItem);
+ }
+ _rectLists[id] = rectList;
+ }
+
+ // Load hit rects
+ uint32 hitRectListsCount = fd.readUint32LE();
+ debug("hitRectListsCount: %d", hitRectListsCount);
+ for (uint32 i = 0; i < hitRectListsCount; i++) {
+ HitRectList *hitRectList = new HitRectList();
+ uint32 id = fd.readUint32LE();
+ uint32 itemCount = fd.readUint32LE();
+ for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
+ HitRect hitRect;
+ hitRect.rect.x1 = fd.readUint16LE();
+ hitRect.rect.y1 = fd.readUint16LE();
+ hitRect.rect.x2 = fd.readUint16LE();
+ hitRect.rect.y2 = fd.readUint16LE();
+ hitRect.type = fd.readUint16LE();
+ hitRectList->push_back(hitRect);
+ }
+ _hitRectLists[id] = hitRectList;
+ }
+
+ // Load navigation lists
+ uint32 navigationListsCount = fd.readUint32LE();
+ debug("navigationListsCount: %d", navigationListsCount);
+ for (uint32 i = 0; i < navigationListsCount; i++) {
+ NavigationList *navigationList = new NavigationList();
+ uint32 id = fd.readUint32LE();
+ uint32 itemCount = fd.readUint32LE();
+ for (uint32 itemIndex = 0; itemIndex < itemCount; itemIndex++) {
+ NavigationItem navigationItem;
+ navigationItem.fileHash = fd.readUint32LE();
+ navigationItem.leftSmackerFileHash = fd.readUint32LE();
+ navigationItem.rightSmackerFileHash = fd.readUint32LE();
+ navigationItem.middleSmackerFileHash = fd.readUint32LE();
+ navigationItem.interactive = fd.readByte();
+ navigationItem.middleFlag = fd.readByte();
+ navigationItem.mouseCursorFileHash = fd.readUint32LE();
+ navigationList->push_back(navigationItem);
+ }
+ _navigationLists[id] = navigationList;
+ }
+
+ // Load SceneInfo140 items
+ uint32 sceneInfo140ItemsCount = fd.readUint32LE();
+ debug("sceneInfo140ItemsCount: %d", sceneInfo140ItemsCount);
+ for (uint32 i = 0; i < sceneInfo140ItemsCount; i++) {
+ SceneInfo140 *sceneInfo140 = new SceneInfo140();
+ uint32 id = fd.readUint32LE();
+ sceneInfo140->bgFilename1 = fd.readUint32LE();
+ sceneInfo140->bgFilename2 = fd.readUint32LE();
+ sceneInfo140->txFilename = fd.readUint32LE();
+ sceneInfo140->bgFilename3 = fd.readUint32LE();
+ sceneInfo140->xPosIndex = fd.readByte();
+ sceneInfo140->count = fd.readByte();
+ _sceneInfo140Items[id] = sceneInfo140;
+ }
+
+ // Load SceneInfo2700 items
+ uint32 sceneInfo2700ItemsCount = fd.readUint32LE();
+ debug("sceneInfo2700ItemsCount: %d", sceneInfo2700ItemsCount);
+ for (uint32 i = 0; i < sceneInfo2700ItemsCount; i++) {
+ SceneInfo2700 *sceneInfo2700 = new SceneInfo2700();
+ uint32 id = fd.readUint32LE();
+ sceneInfo2700->bgFilename = fd.readUint32LE();
+ sceneInfo2700->class437Filename = fd.readUint32LE();
+ sceneInfo2700->dataResourceFilename = fd.readUint32LE();
+ sceneInfo2700->pointListName = fd.readUint32LE();
+ sceneInfo2700->rectListName = fd.readUint32LE();
+ sceneInfo2700->exPaletteFilename2 = fd.readUint32LE();
+ sceneInfo2700->exPaletteFilename1 = fd.readUint32LE();
+ sceneInfo2700->mouseCursorFilename = fd.readUint32LE();
+ sceneInfo2700->which1 = fd.readUint16LE();
+ sceneInfo2700->which2 = fd.readUint16LE();
+ _sceneInfo2700Items[id] = sceneInfo2700;
+ }
+
+}
+
+HitRectList *StaticData::getHitRectList(uint32 id) {
+ if (!_hitRectLists[id])
+ error("StaticData::getHitRectList() HitRectList with id %08X not found", id);
+ return _hitRectLists[id];
+}
+
+RectList *StaticData::getRectList(uint32 id) {
+ if (!_rectLists[id])
+ error("StaticData::getRectList() RectList with id %08X not found", id);
+ return _rectLists[id];
+}
+
+MessageList *StaticData::getMessageList(uint32 id) {
+ if (!_messageLists[id])
+ error("StaticData::getMessageList() MessageList with id %08X not found", id);
+ return _messageLists[id];
+}
+
+NavigationList *StaticData::getNavigationList(uint32 id) {
+ if (!_navigationLists[id])
+ error("StaticData::getNavigationList() NavigationList with id %08X not found", id);
+ return _navigationLists[id];
+}
+
+SceneInfo140 *StaticData::getSceneInfo140Item(uint32 id) {
+ if (!_sceneInfo140Items[id])
+ error("StaticData::getSceneInfo140Item() SceneInfo140 with id %08X not found", id);
+ return _sceneInfo140Items[id];
+}
+
+SceneInfo2700 *StaticData::getSceneInfo2700(uint32 id) {
+ if (!_sceneInfo2700Items[id])
+ error("StaticData::getSceneInfo2700() SceneInfo2700 with id %08X not found", id);
+ return _sceneInfo2700Items[id];
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/staticdata.h b/engines/neverhood/staticdata.h
new file mode 100644
index 0000000000..2a2db556e0
--- /dev/null
+++ b/engines/neverhood/staticdata.h
@@ -0,0 +1,116 @@
+/* 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_STATICDATA_H
+#define NEVERHOOD_STATICDATA_H
+
+#include "common/array.h"
+#include "common/hashmap.h"
+#include "neverhood/neverhood.h"
+#include "neverhood/graphics.h"
+
+namespace Neverhood {
+
+struct HitRect {
+ NRect rect;
+ uint16 type;
+};
+
+typedef Common::Array<HitRect> HitRectList;
+
+struct SubRectItem {
+ NRect rect;
+ uint32 messageListId;
+};
+
+struct RectItem {
+ NRect rect;
+ Common::Array<SubRectItem> subRects;
+};
+
+typedef Common::Array<RectItem> RectList;
+
+struct MessageItem {
+ uint32 messageNum;
+ uint32 messageValue;
+};
+
+typedef Common::Array<MessageItem> MessageList;
+
+struct NavigationItem {
+ uint32 fileHash;
+ uint32 leftSmackerFileHash;
+ uint32 rightSmackerFileHash;
+ uint32 middleSmackerFileHash;
+ byte interactive;
+ byte middleFlag;
+ uint32 mouseCursorFileHash;
+};
+
+typedef Common::Array<NavigationItem> NavigationList;
+
+struct SceneInfo140 {
+ uint32 bgFilename1;
+ uint32 bgFilename2;
+ uint32 txFilename;
+ uint32 bgFilename3;
+ byte xPosIndex;
+ byte count;
+};
+
+struct SceneInfo2700 {
+ uint32 id;
+ uint32 bgFilename;
+ uint32 class437Filename;
+ uint32 dataResourceFilename;
+ uint32 pointListName;
+ uint32 rectListName;
+ uint32 exPaletteFilename2;
+ uint32 exPaletteFilename1;
+ uint32 mouseCursorFilename;
+ int16 which1;
+ int16 which2;
+};
+
+class StaticData {
+public:
+ StaticData();
+ ~StaticData();
+ void load(const char *filename);
+ HitRectList *getHitRectList(uint32 id);
+ RectList *getRectList(uint32 id);
+ MessageList *getMessageList(uint32 id);
+ NavigationList *getNavigationList(uint32 id);
+ SceneInfo140 *getSceneInfo140Item(uint32 id);
+ SceneInfo2700 *getSceneInfo2700(uint32 id);
+protected:
+ Common::HashMap<uint32, HitRectList*> _hitRectLists;
+ Common::HashMap<uint32, RectList*> _rectLists;
+ Common::HashMap<uint32, MessageList*> _messageLists;
+ Common::HashMap<uint32, NavigationList*> _navigationLists;
+ Common::HashMap<uint32, SceneInfo140*> _sceneInfo140Items;
+ Common::HashMap<uint32, SceneInfo2700*> _sceneInfo2700Items;
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_STATICDATA_H */