[Scummvm-cvs-logs] scummvm master -> c977561b467e7700a3c717b73a8398089f79aeba

bluegr bluegr at gmail.com
Mon Sep 30 23:57:55 CEST 2013


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
c977561b46 NEVERHOOD: Split some more sprites from their respective scenes


Commit: c977561b467e7700a3c717b73a8398089f79aeba
    https://github.com/scummvm/scummvm/commit/c977561b467e7700a3c717b73a8398089f79aeba
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2013-09-30T14:55:46-07:00

Commit Message:
NEVERHOOD: Split some more sprites from their respective scenes

This splits modules 2700, 2900 and 3000

Changed paths:
  A engines/neverhood/modules/module2700_sprites.cpp
  A engines/neverhood/modules/module2700_sprites.h
  A engines/neverhood/modules/module2900_sprites.cpp
  A engines/neverhood/modules/module2900_sprites.h
  A engines/neverhood/modules/module3000_sprites.cpp
  A engines/neverhood/modules/module3000_sprites.h
    engines/neverhood/console.cpp
    engines/neverhood/module.mk
    engines/neverhood/modules/module1600.cpp
    engines/neverhood/modules/module2500.cpp
    engines/neverhood/modules/module2700.cpp
    engines/neverhood/modules/module2700.h
    engines/neverhood/modules/module2900.cpp
    engines/neverhood/modules/module2900.h
    engines/neverhood/modules/module3000.cpp
    engines/neverhood/modules/module3000.h



diff --git a/engines/neverhood/console.cpp b/engines/neverhood/console.cpp
index 708c687..34438d8 100644
--- a/engines/neverhood/console.cpp
+++ b/engines/neverhood/console.cpp
@@ -29,6 +29,7 @@
 #include "neverhood/smackerscene.h"
 #include "neverhood/sound.h"
 #include "neverhood/modules/module1600.h"
+#include "neverhood/modules/module3000_sprites.h"
 
 namespace Neverhood {
 
diff --git a/engines/neverhood/module.mk b/engines/neverhood/module.mk
index 052c830..abedee0 100644
--- a/engines/neverhood/module.mk
+++ b/engines/neverhood/module.mk
@@ -32,10 +32,13 @@ MODULE_OBJS = \
 	modules/module2500.o \
 	modules/module2600.o \
 	modules/module2700.o \
+	modules/module2700_sprites.o \
 	modules/module2800.o \
 	modules/module2800_sprites.o \
 	modules/module2900.o \
+	modules/module2900_sprites.o \
 	modules/module3000.o \
+	modules/module3000_sprites.o \
 	mouse.o \
 	navigationscene.o \
 	neverhood.o \
diff --git a/engines/neverhood/modules/module1600.cpp b/engines/neverhood/modules/module1600.cpp
index a5a785e..e675eae 100644
--- a/engines/neverhood/modules/module1600.cpp
+++ b/engines/neverhood/modules/module1600.cpp
@@ -24,6 +24,7 @@
 #include "neverhood/gamemodule.h"
 #include "neverhood/modules/module1200.h"
 #include "neverhood/modules/module2200.h"
+#include "neverhood/modules/module3000_sprites.h"
 
 namespace Neverhood {
 
diff --git a/engines/neverhood/modules/module2500.cpp b/engines/neverhood/modules/module2500.cpp
index 46ce2ba..183793f 100644
--- a/engines/neverhood/modules/module2500.cpp
+++ b/engines/neverhood/modules/module2500.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "neverhood/modules/module2500.h"
+#include "neverhood/modules/module2700_sprites.h"
 #include "neverhood/modules/module1600.h"
 
 namespace Neverhood {
diff --git a/engines/neverhood/modules/module2700.cpp b/engines/neverhood/modules/module2700.cpp
index 7aea82f..f0bda6f 100644
--- a/engines/neverhood/modules/module2700.cpp
+++ b/engines/neverhood/modules/module2700.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "neverhood/modules/module2700.h"
+#include "neverhood/modules/module2700_sprites.h"
 #include "neverhood/gamemodule.h"
 #include "neverhood/modules/module1000.h"
 
@@ -536,83 +537,6 @@ void Module2700::createScene2704(int which, uint32 trackInfoId, int16 value, con
 	_childObject = new Scene2704(_vm, this, which, trackInfoId, value, staticSprites, clipRect);
 }
 
-static const NPoint kCarShadowOffsets[] = {
-	{-63,  3}, {-48, 40}, {-33, 58},
-	{  0, 65}, { 40, 53}, { 56, 27},
-	{ 63,  0}, {-30, 26}, {  0, 30},
-	{ 26, 25}
-};
-
-SsCommonTrackShadowBackground::SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash)
-	: StaticSprite(vm, 0) {
-
-	loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition, 0);
-}
-
-AsCommonCarShadow::AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index)
-	: AnimatedSprite(vm, 1100), _asCar(asCar), _index(index), _animFileHash(0) {
-
-	SetUpdateHandler(&AsCommonCarShadow::update);
-	createShadowSurface(shadowSurface, 211, 147, 100);
-	updateShadow();
-}
-
-void AsCommonCarShadow::update() {
-	updateShadow();
-	AnimatedSprite::update();
-}
-
-void AsCommonCarShadow::updateShadow() {
-	if (_asCar->getFrameIndex() != _currFrameIndex || _asCar->getCurrAnimFileHash() != _animFileHash) {
-		uint32 fileHash = _asCar->getCurrAnimFileHash();
-		if (fileHash == 0x35698F78 || fileHash == 0x192ADD30 || fileHash == 0x9C220DA4 ||
-			fileHash == 0x9966B138 || fileHash == 0xB579A77C || fileHash == 0xA86A9538 ||
-			fileHash == 0xD4220027 || fileHash == 0xD00A1364 || fileHash == 0xD4AA03A4 ||
-			fileHash == 0xF46A0324) {
-			startAnimation(fileHash, _asCar->getFrameIndex(), -1);
-			_newStickFrameIndex = _asCar->getFrameIndex();
-		}
-		_animFileHash = fileHash;
-	}
-	_x = _asCar->getX() + kCarShadowOffsets[_index].x;
-	_y = _asCar->getY() + kCarShadowOffsets[_index].y;
-	if (!_asCar->getVisible()) {
-		startAnimation(0x1209E09F, 0, -1);
-		_newStickFrameIndex = 0;
-	}
-	setDoDeltaX(_asCar->isDoDeltaX() ? 1 : 0);
-}
-
-AsCommonCarConnectorShadow::AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index)
-	: AnimatedSprite(vm, 1100), _asCar(asCar), _index(index) {
-
-	SetUpdateHandler(&AsCommonCarConnectorShadow::update);
-	createShadowSurface1(shadowSurface, 0x60281C10, 150);
-	startAnimation(0x60281C10, -1, -1);
-	_newStickFrameIndex = STICK_LAST_FRAME;
-}
-
-void AsCommonCarConnectorShadow::update() {
-	_x = _asCar->getX() + kCarShadowOffsets[_index].x;
-	_y = _asCar->getY() + kCarShadowOffsets[_index].y;
-	AnimatedSprite::update();
-}
-
-AsCommonCarTrackShadow::AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex)
-	: AnimatedSprite(vm, 1100), _asCar(asCar) {
-
-	SetUpdateHandler(&AsCommonCarTrackShadow::update);
-	createShadowSurface1(shadowSurface, 0x0759129C, 100);
-	startAnimation(0x0759129C, frameIndex, -1);
-	_newStickFrameIndex = frameIndex;
-}
-
-void AsCommonCarTrackShadow::update() {
-	_x = _asCar->getX();
-	_y = _asCar->getY();
-	AnimatedSprite::update();
-}
-
 Scene2701::Scene2701(NeverhoodEngine *vm, Module *parentModule, int which)
 	: Scene(vm, parentModule) {
 
diff --git a/engines/neverhood/modules/module2700.h b/engines/neverhood/modules/module2700.h
index 158bb60..20cc014 100644
--- a/engines/neverhood/modules/module2700.h
+++ b/engines/neverhood/modules/module2700.h
@@ -49,39 +49,6 @@ protected:
 	void createScene2704(int which, uint32 trackInfoId, int16 value, const uint32 *staticSprites = NULL, const NRect *clipRect = NULL);
 };
 
-class SsCommonTrackShadowBackground : public StaticSprite {
-public:
-	SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash);
-};
-
-class AsCommonCarShadow : public AnimatedSprite {
-public:
-	AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index);
-protected:
-	uint _index;
-	AnimatedSprite *_asCar;
-	uint32 _animFileHash;
-	void update();
-	void updateShadow();
-};
-
-class AsCommonCarConnectorShadow : public AnimatedSprite {
-public:
-	AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index);
-protected:
-	uint _index;
-	Sprite *_asCar;
-	void update();
-};
-
-class AsCommonCarTrackShadow : public AnimatedSprite {
-public:
-	AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex);
-protected:
-	Sprite *_asCar;
-	void update();
-};
-
 class Scene2701 : public Scene {
 public:
 	Scene2701(NeverhoodEngine *vm, Module *parentModule, int which);
diff --git a/engines/neverhood/modules/module2700_sprites.cpp b/engines/neverhood/modules/module2700_sprites.cpp
new file mode 100644
index 0000000..abafcff
--- /dev/null
+++ b/engines/neverhood/modules/module2700_sprites.cpp
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "neverhood/modules/module2700_sprites.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/modules/module1000.h"
+
+namespace Neverhood {
+
+static const NRect kScene2710ClipRect = { 0, 0, 626, 480 };
+
+static const uint32 kScene2710StaticSprites[] = {
+	0x0D2016C0,
+	0
+};
+
+static const NRect kScene2711ClipRect = { 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 = { 0, 141, 640, 480 };
+
+static const uint32 kScene2724StaticSprites[] = {
+	0xC20D00A5,
+	0
+};
+
+static const NRect kScene2725ClipRect = { 0, 0, 640, 413 };
+
+static const uint32 kScene2725StaticSprites[] = {
+	0xC20E00A5,
+	0
+};
+
+static const NPoint kCarShadowOffsets[] = {
+	{-63,  3}, {-48, 40}, {-33, 58},
+	{  0, 65}, { 40, 53}, { 56, 27},
+	{ 63,  0}, {-30, 26}, {  0, 30},
+	{ 26, 25}
+};
+
+SsCommonTrackShadowBackground::SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash)
+	: StaticSprite(vm, 0) {
+
+	loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition, 0);
+}
+
+AsCommonCarShadow::AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index)
+	: AnimatedSprite(vm, 1100), _asCar(asCar), _index(index), _animFileHash(0) {
+
+	SetUpdateHandler(&AsCommonCarShadow::update);
+	createShadowSurface(shadowSurface, 211, 147, 100);
+	updateShadow();
+}
+
+void AsCommonCarShadow::update() {
+	updateShadow();
+	AnimatedSprite::update();
+}
+
+void AsCommonCarShadow::updateShadow() {
+	if (_asCar->getFrameIndex() != _currFrameIndex || _asCar->getCurrAnimFileHash() != _animFileHash) {
+		uint32 fileHash = _asCar->getCurrAnimFileHash();
+		if (fileHash == 0x35698F78 || fileHash == 0x192ADD30 || fileHash == 0x9C220DA4 ||
+			fileHash == 0x9966B138 || fileHash == 0xB579A77C || fileHash == 0xA86A9538 ||
+			fileHash == 0xD4220027 || fileHash == 0xD00A1364 || fileHash == 0xD4AA03A4 ||
+			fileHash == 0xF46A0324) {
+			startAnimation(fileHash, _asCar->getFrameIndex(), -1);
+			_newStickFrameIndex = _asCar->getFrameIndex();
+		}
+		_animFileHash = fileHash;
+	}
+	_x = _asCar->getX() + kCarShadowOffsets[_index].x;
+	_y = _asCar->getY() + kCarShadowOffsets[_index].y;
+	if (!_asCar->getVisible()) {
+		startAnimation(0x1209E09F, 0, -1);
+		_newStickFrameIndex = 0;
+	}
+	setDoDeltaX(_asCar->isDoDeltaX() ? 1 : 0);
+}
+
+AsCommonCarConnectorShadow::AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index)
+	: AnimatedSprite(vm, 1100), _asCar(asCar), _index(index) {
+
+	SetUpdateHandler(&AsCommonCarConnectorShadow::update);
+	createShadowSurface1(shadowSurface, 0x60281C10, 150);
+	startAnimation(0x60281C10, -1, -1);
+	_newStickFrameIndex = STICK_LAST_FRAME;
+}
+
+void AsCommonCarConnectorShadow::update() {
+	_x = _asCar->getX() + kCarShadowOffsets[_index].x;
+	_y = _asCar->getY() + kCarShadowOffsets[_index].y;
+	AnimatedSprite::update();
+}
+
+AsCommonCarTrackShadow::AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex)
+	: AnimatedSprite(vm, 1100), _asCar(asCar) {
+
+	SetUpdateHandler(&AsCommonCarTrackShadow::update);
+	createShadowSurface1(shadowSurface, 0x0759129C, 100);
+	startAnimation(0x0759129C, frameIndex, -1);
+	_newStickFrameIndex = frameIndex;
+}
+
+void AsCommonCarTrackShadow::update() {
+	_x = _asCar->getX();
+	_y = _asCar->getY();
+	AnimatedSprite::update();
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/modules/module2700_sprites.h b/engines/neverhood/modules/module2700_sprites.h
new file mode 100644
index 0000000..b9575df
--- /dev/null
+++ b/engines/neverhood/modules/module2700_sprites.h
@@ -0,0 +1,68 @@
+/* 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_MODULES_MODULE2700_SPRITES_H
+#define NEVERHOOD_MODULES_MODULE2700_SPRITES_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/modules/module1600.h"
+
+namespace Neverhood {
+
+class SsCommonTrackShadowBackground : public StaticSprite {
+public:
+	SsCommonTrackShadowBackground(NeverhoodEngine *vm, uint32 fileHash);
+};
+
+class AsCommonCarShadow : public AnimatedSprite {
+public:
+	AsCommonCarShadow(NeverhoodEngine *vm, AnimatedSprite *asCar, BaseSurface *shadowSurface, uint index);
+protected:
+	uint _index;
+	AnimatedSprite *_asCar;
+	uint32 _animFileHash;
+	void update();
+	void updateShadow();
+};
+
+class AsCommonCarConnectorShadow : public AnimatedSprite {
+public:
+	AsCommonCarConnectorShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, uint index);
+protected:
+	uint _index;
+	Sprite *_asCar;
+	void update();
+};
+
+class AsCommonCarTrackShadow : public AnimatedSprite {
+public:
+	AsCommonCarTrackShadow(NeverhoodEngine *vm, Sprite *asCar, BaseSurface *shadowSurface, int16 frameIndex);
+protected:
+	Sprite *_asCar;
+	void update();
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULES_MODULE2700_SPRITES_H */
diff --git a/engines/neverhood/modules/module2900.cpp b/engines/neverhood/modules/module2900.cpp
index 9e51001..032f096 100644
--- a/engines/neverhood/modules/module2900.cpp
+++ b/engines/neverhood/modules/module2900.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "neverhood/modules/module2900.h"
+#include "neverhood/modules/module2900_sprites.h"
 #include "neverhood/gamemodule.h"
 #include "neverhood/modules/module1100.h"
 #include "neverhood/modules/module1300.h"
@@ -141,211 +142,6 @@ static const uint32 kScene2901FileHashes2[] = {
 	0x08030029
 };
 
-static const uint32 kSsScene2901LocationButtonFileHashes[] = {
-	0x2311326A,
-	0x212323AC,
-	0x10098138,
-	0x25213167,
-	0x1119A363,
-	0x94452612,
-	0x39464212,
-	0x01860450,
-	0x53002104,
-	0x58E68412,
-	0x18600300,
-	0xB650A890,
-	0x2452A7C4,
-	0xA0232748,
-	0x08862B02,
-	0x2491E648,
-	0x0010EB46,
-	0x214C8A11,
-	0x16A31921,
-	0x0AC33A00,
-	0x238028AA,
-	0x26737A21,
-	0x063039A8,
-	0x51286C60,
-	0x464006B4,
-	0x42242538,
-	0x20716010,
-	0x4A2000AE,
-	0x225124A6,
-	0x28E82E45,
-	0x58652C04,
-	0xC82210A4,
-	0x62A84060,
-	0xC0693CB4,
-	0x22212C64,
-	0x5034EA71
-};
-
-static const NPoint kSsScene2901LocationButtonPoints[] = {
-	{525, 120}, {576, 149}, {587, 205},
-	{538, 232}, {484, 205}, {479, 153}
-};
-
-static const uint32 kSsScene2901LocationButtonLightFileHashes1[] = {
-	0x03136246,
-	0x2106216E,
-	0x4025A13A,
-	0x21816927,
-	0x110B2202,
-	0xCC0522B2,
-	0x3CC24258,
-	0x59C600F0,
-	0x534A2480,
-	0x50E61019,
-	0x34400150,
-	0x225BA090,
-	0xB059AFC4,
-	0xE093A741,
-	0x0086BF09,
-	0x3281E760,
-	0xA048AB42,
-	0x20649C01,
-	0x14611904,
-	0x26E33850,
-	0x23A52A68,
-	0xA2733024,
-	0x10203880,
-	0x1B2DE860,
-	0x0644A6EC,
-	0x426E20BC,
-	0x80292014,
-	0x4360B02E,
-	0x22742664,
-	0x98682705,
-	0x0925B82C,
-	0x5C2918A4,
-	0xD2284920,
-	0x41083CA6,
-	0x6824A864,
-	0x50266B10
-};
-
-static const uint32 kSsScene2901LocationButtonLightFileHashes2[] = {
-	0x43C46D4C,
-	0x43C4AD4C,
-	0x43C52D4C,
-	0x43C62D4C,
-	0x43C02D4C,
-	0x43CC2D4C
-};
-
-static const uint32 kSsScene2901BrokenButtonFileHashes[] = {
-	0x3081BD3A,
-	0xD3443003,
-	0x0786A320,
-	0xE3A22029,
-	0x61611814,
-	0x425848E2
-};
-
-static const uint32 kSsScene2901BigButtonFileHashes[] = {
-	0x010D7748,
-	0x9D02019A,
-	0x351A2F43,
-	0x448138E5,
-	0x02788CF0,
-	0x71718024
-};
-
-SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index)
-	: StaticSprite(vm, 900), _parentScene(parentScene), _index(index), _countdown1(0) {
-
-	const NPoint &pt = kSsScene2901LocationButtonPoints[_index];
-
-	loadSprite(kSsScene2901LocationButtonFileHashes[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 800);
-	_collisionBounds.set(pt.x - 25, pt.y - 25, pt.x + 25, pt.y + 25);
-	setVisible(false);
-	loadSound(0, 0x440430C0);
-	SetUpdateHandler(&SsScene2901LocationButton::update);
-	SetMessageHandler(&SsScene2901LocationButton::handleMessage);
-}
-
-void SsScene2901LocationButton::update() {
-	updatePosition();
-	if (_countdown1 != 0 && (--_countdown1) == 0) {
-		setVisible(false);
-	}
-}
-
-uint32 SsScene2901LocationButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
-	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
-	switch (messageNum) {
-	case 0x1011:
-		if (_countdown1 == 0) {
-			playSound(0);
-			setVisible(true);
-			_countdown1 = 4;
-			sendMessage(_parentScene, 0x2001, _index);
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
-SsScene2901LocationButtonLight::SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index)
-	: StaticSprite(vm, 900), _index(index) {
-
-	loadSprite(kSsScene2901LocationButtonLightFileHashes1[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 900);
-	setVisible(false);
-	loadSound(0, kSsScene2901LocationButtonLightFileHashes2[_index]);
-}
-
-void SsScene2901LocationButtonLight::show() {
-	playSound(0);
-	setVisible(true);
-	updatePosition();
-}
-
-void SsScene2901LocationButtonLight::hide() {
-	setVisible(false);
-	updatePosition();
-}
-
-SsScene2901BrokenButton::SsScene2901BrokenButton(NeverhoodEngine *vm, int which)
-	: StaticSprite(vm, 900) {
-
-	loadSprite(kSsScene2901BrokenButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 900);
-}
-
-SsScene2901BigButton::SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which)
-	: StaticSprite(vm, 900), _parentScene(parentScene), _which(which), _countdown1(0) {
-
-	loadSprite(kSsScene2901BigButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 400);
-	_collisionBounds.set(62, 94, 322, 350);
-	setVisible(false);
-	loadSound(0, 0xF3D420C8);
-	SetUpdateHandler(&SsScene2901BigButton::update);
-	SetMessageHandler(&SsScene2901BigButton::handleMessage);
-}
-
-void SsScene2901BigButton::update() {
-	updatePosition();
-	if (_countdown1 != 0 && (--_countdown1) == 0) {
-		setVisible(false);
-		sendMessage(_parentScene, 0x2000, 0);
-	}
-}
-
-uint32 SsScene2901BigButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
-	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
-	switch (messageNum) {
-	case 0x1011:
-		if (_countdown1 == 0) {
-			playSound(0);
-			setVisible(true);
-			_countdown1 = 4;
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
 Scene2901::Scene2901(NeverhoodEngine *vm, Module *parentModule, int which)
 	: Scene(vm, parentModule), _currLocationButtonNum(which), _selectedButtonNum(which),
 	_currWhirlButtonNum(0), _prevWhirlButtonNum(0), _countdown1(1), _skipCountdown(0), _blinkOn(0) {
diff --git a/engines/neverhood/modules/module2900.h b/engines/neverhood/modules/module2900.h
index 142f39a..5f6ed29 100644
--- a/engines/neverhood/modules/module2900.h
+++ b/engines/neverhood/modules/module2900.h
@@ -42,41 +42,7 @@ protected:
 	void updateMusic(bool halfVolume);
 };
 
-class SsScene2901LocationButton : public StaticSprite {
-public:
-	SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index);
-protected:
-	Scene *_parentScene;
-	uint _index;
-	int _countdown1;
-	void update();
-	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
-};
-
-class SsScene2901LocationButtonLight : public StaticSprite {
-public:
-	SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index);
-	void show();
-	void hide();
-protected:
-	uint _index;
-};
-
-class SsScene2901BrokenButton : public StaticSprite {
-public:
-	SsScene2901BrokenButton(NeverhoodEngine *vm, int which);
-};
-
-class SsScene2901BigButton : public StaticSprite {
-public:
-	SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which);
-protected:
-	Scene *_parentScene;
-	int _which;
-	int _countdown1;
-	void update();
-	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
-};
+class SsScene2901LocationButtonLight;
 
 class Scene2901 : public Scene {
 public:
diff --git a/engines/neverhood/modules/module2900_sprites.cpp b/engines/neverhood/modules/module2900_sprites.cpp
new file mode 100644
index 0000000..33b7715
--- /dev/null
+++ b/engines/neverhood/modules/module2900_sprites.cpp
@@ -0,0 +1,233 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "neverhood/modules/module2900_sprites.h"
+#include "neverhood/gamemodule.h"
+
+namespace Neverhood {
+
+static const uint32 kSsScene2901LocationButtonFileHashes[] = {
+	0x2311326A,
+	0x212323AC,
+	0x10098138,
+	0x25213167,
+	0x1119A363,
+	0x94452612,
+	0x39464212,
+	0x01860450,
+	0x53002104,
+	0x58E68412,
+	0x18600300,
+	0xB650A890,
+	0x2452A7C4,
+	0xA0232748,
+	0x08862B02,
+	0x2491E648,
+	0x0010EB46,
+	0x214C8A11,
+	0x16A31921,
+	0x0AC33A00,
+	0x238028AA,
+	0x26737A21,
+	0x063039A8,
+	0x51286C60,
+	0x464006B4,
+	0x42242538,
+	0x20716010,
+	0x4A2000AE,
+	0x225124A6,
+	0x28E82E45,
+	0x58652C04,
+	0xC82210A4,
+	0x62A84060,
+	0xC0693CB4,
+	0x22212C64,
+	0x5034EA71
+};
+
+static const NPoint kSsScene2901LocationButtonPoints[] = {
+	{525, 120}, {576, 149}, {587, 205},
+	{538, 232}, {484, 205}, {479, 153}
+};
+
+static const uint32 kSsScene2901LocationButtonLightFileHashes1[] = {
+	0x03136246,
+	0x2106216E,
+	0x4025A13A,
+	0x21816927,
+	0x110B2202,
+	0xCC0522B2,
+	0x3CC24258,
+	0x59C600F0,
+	0x534A2480,
+	0x50E61019,
+	0x34400150,
+	0x225BA090,
+	0xB059AFC4,
+	0xE093A741,
+	0x0086BF09,
+	0x3281E760,
+	0xA048AB42,
+	0x20649C01,
+	0x14611904,
+	0x26E33850,
+	0x23A52A68,
+	0xA2733024,
+	0x10203880,
+	0x1B2DE860,
+	0x0644A6EC,
+	0x426E20BC,
+	0x80292014,
+	0x4360B02E,
+	0x22742664,
+	0x98682705,
+	0x0925B82C,
+	0x5C2918A4,
+	0xD2284920,
+	0x41083CA6,
+	0x6824A864,
+	0x50266B10
+};
+
+static const uint32 kSsScene2901LocationButtonLightFileHashes2[] = {
+	0x43C46D4C,
+	0x43C4AD4C,
+	0x43C52D4C,
+	0x43C62D4C,
+	0x43C02D4C,
+	0x43CC2D4C
+};
+
+static const uint32 kSsScene2901BrokenButtonFileHashes[] = {
+	0x3081BD3A,
+	0xD3443003,
+	0x0786A320,
+	0xE3A22029,
+	0x61611814,
+	0x425848E2
+};
+
+static const uint32 kSsScene2901BigButtonFileHashes[] = {
+	0x010D7748,
+	0x9D02019A,
+	0x351A2F43,
+	0x448138E5,
+	0x02788CF0,
+	0x71718024
+};
+
+SsScene2901LocationButton::SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index)
+	: StaticSprite(vm, 900), _parentScene(parentScene), _index(index), _countdown1(0) {
+
+	const NPoint &pt = kSsScene2901LocationButtonPoints[_index];
+
+	loadSprite(kSsScene2901LocationButtonFileHashes[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 800);
+	_collisionBounds.set(pt.x - 25, pt.y - 25, pt.x + 25, pt.y + 25);
+	setVisible(false);
+	loadSound(0, 0x440430C0);
+	SetUpdateHandler(&SsScene2901LocationButton::update);
+	SetMessageHandler(&SsScene2901LocationButton::handleMessage);
+}
+
+void SsScene2901LocationButton::update() {
+	updatePosition();
+	if (_countdown1 != 0 && (--_countdown1) == 0) {
+		setVisible(false);
+	}
+}
+
+uint32 SsScene2901LocationButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+	switch (messageNum) {
+	case 0x1011:
+		if (_countdown1 == 0) {
+			playSound(0);
+			setVisible(true);
+			_countdown1 = 4;
+			sendMessage(_parentScene, 0x2001, _index);
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+SsScene2901LocationButtonLight::SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index)
+	: StaticSprite(vm, 900), _index(index) {
+
+	loadSprite(kSsScene2901LocationButtonLightFileHashes1[which * 6 + index], kSLFDefDrawOffset | kSLFDefPosition, 900);
+	setVisible(false);
+	loadSound(0, kSsScene2901LocationButtonLightFileHashes2[_index]);
+}
+
+void SsScene2901LocationButtonLight::show() {
+	playSound(0);
+	setVisible(true);
+	updatePosition();
+}
+
+void SsScene2901LocationButtonLight::hide() {
+	setVisible(false);
+	updatePosition();
+}
+
+SsScene2901BrokenButton::SsScene2901BrokenButton(NeverhoodEngine *vm, int which)
+	: StaticSprite(vm, 900) {
+
+	loadSprite(kSsScene2901BrokenButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 900);
+}
+
+SsScene2901BigButton::SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which)
+	: StaticSprite(vm, 900), _parentScene(parentScene), _which(which), _countdown1(0) {
+
+	loadSprite(kSsScene2901BigButtonFileHashes[which], kSLFDefDrawOffset | kSLFDefPosition, 400);
+	_collisionBounds.set(62, 94, 322, 350);
+	setVisible(false);
+	loadSound(0, 0xF3D420C8);
+	SetUpdateHandler(&SsScene2901BigButton::update);
+	SetMessageHandler(&SsScene2901BigButton::handleMessage);
+}
+
+void SsScene2901BigButton::update() {
+	updatePosition();
+	if (_countdown1 != 0 && (--_countdown1) == 0) {
+		setVisible(false);
+		sendMessage(_parentScene, 0x2000, 0);
+	}
+}
+
+uint32 SsScene2901BigButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+	switch (messageNum) {
+	case 0x1011:
+		if (_countdown1 == 0) {
+			playSound(0);
+			setVisible(true);
+			_countdown1 = 4;
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/modules/module2900_sprites.h b/engines/neverhood/modules/module2900_sprites.h
new file mode 100644
index 0000000..9f7df50
--- /dev/null
+++ b/engines/neverhood/modules/module2900_sprites.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_MODULES_MODULE2900_SPRITES_H
+#define NEVERHOOD_MODULES_MODULE2900_SPRITES_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+
+namespace Neverhood {
+
+// Module2900
+
+class SsScene2901LocationButton : public StaticSprite {
+public:
+	SsScene2901LocationButton(NeverhoodEngine *vm, Scene *parentScene, int which, uint index);
+protected:
+	Scene *_parentScene;
+	uint _index;
+	int _countdown1;
+	void update();
+	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class SsScene2901LocationButtonLight : public StaticSprite {
+public:
+	SsScene2901LocationButtonLight(NeverhoodEngine *vm, int which, uint index);
+	void show();
+	void hide();
+protected:
+	uint _index;
+};
+
+class SsScene2901BrokenButton : public StaticSprite {
+public:
+	SsScene2901BrokenButton(NeverhoodEngine *vm, int which);
+};
+
+class SsScene2901BigButton : public StaticSprite {
+public:
+	SsScene2901BigButton(NeverhoodEngine *vm, Scene *parentScene, int which);
+protected:
+	Scene *_parentScene;
+	int _which;
+	int _countdown1;
+	void update();
+	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULES_MODULE2900_SPRITES_H */
diff --git a/engines/neverhood/modules/module3000.cpp b/engines/neverhood/modules/module3000.cpp
index ab3c18d..e17e9d4 100644
--- a/engines/neverhood/modules/module3000.cpp
+++ b/engines/neverhood/modules/module3000.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "neverhood/modules/module3000.h"
+#include "neverhood/modules/module3000_sprites.h"
 #include "neverhood/gamemodule.h"
 #include "neverhood/navigationscene.h"
 
@@ -415,343 +416,6 @@ static const uint32 kScene3009CannonActionVideos[] = {
 	0x240A1101	// 14 Lower the cannon
 };
 
-static const uint32 kSsScene3009SymbolEdgesFileHashes[] = {
-	0x618827A0,
-	0xB1A92322
-};
-
-static const uint32 kSsScene3009TargetLineFileHashes[] = {
-	0x4011018C,
-	0x15086623
-};
-
-static const NPoint kAsScene3009SymbolPoints[] = {
-	{289, 338},
-	{285, 375},
-	{284, 419},
-	{456, 372},
-	{498, 372},
-	{541, 372}
-};
-
-static const uint32 kAsScene3009SymbolFileHashes[] = {
-	0x24542582,
-	0x1CD61D96
-};
-
-static const uint32 kSsScene3009SymbolArrowFileHashes1[] = {
-	0x24016060,
-	0x21216221,
-	0x486160A0,
-	0x42216422,
-	0x90A16120,
-	0x84216824,
-	0x08017029,
-	0x08217029,
-	0x10014032,
-	0x10214032,
-	0x20012004,
-	0x20212004
-};
-
-static const uint32 kSsScene3009SymbolArrowFileHashes2[] = {
-	0x40092024,
-	0x01636002,
-	0x8071E028,
-	0x02A56064,
-	0x00806031,
-	0x052960A8,
-	0x0A116130,
-	0x0A316130,
-	0x14216200,
-	0x14016200,
-	0x28416460,
-	0x28616460
-};
-
-SsScene3009FireCannonButton::SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene)
-	: StaticSprite(vm, 1400), _parentScene(parentScene), _isClicked(false) {
-
-	loadSprite(0x120B24B0, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
-	setVisible(false);
-	SetUpdateHandler(&SsScene3009FireCannonButton::update);
-	SetMessageHandler(&SsScene3009FireCannonButton::handleMessage);
-	loadSound(0, 0x3901B44F);
-}
-
-void SsScene3009FireCannonButton::update() {
-	updatePosition();
-	if (_isClicked && !isSoundPlaying(0)) {
-		sendMessage(_parentScene, 0x2000, 0);
-		setVisible(false);
-	}
-}
-
-uint32 SsScene3009FireCannonButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
-	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
-	switch (messageNum) {
-	case 0x1011:
-		if (!_isClicked && !_parentScene->isTurning()) {
-			_isClicked = true;
-			setVisible(true);
-			playSound(0);
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
-SsScene3009SymbolEdges::SsScene3009SymbolEdges(NeverhoodEngine *vm, int index)
-	: StaticSprite(vm, 1400), _blinkCountdown(0) {
-
-	loadSprite(kSsScene3009SymbolEdgesFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600);
-	if (getGlobalVar(V_ROBOT_HIT))
-		hide();
-	else
-		startBlinking();
-	SetUpdateHandler(&SsScene3009SymbolEdges::update);
-}
-
-void SsScene3009SymbolEdges::update() {
-	if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) {
-		if (_blinkToggle) {
-			setVisible(true);
-		} else {
-			setVisible(false);
-		}
-		updatePosition();
-		_blinkCountdown = 3;
-		_blinkToggle = !_blinkToggle;
-	}
-}
-
-void SsScene3009SymbolEdges::show() {
-	setVisible(true);
-	updatePosition();
-	_blinkCountdown = 0;
-}
-
-void SsScene3009SymbolEdges::hide() {
-	setVisible(false);
-	updatePosition();
-	_blinkCountdown = 0;
-}
-
-void SsScene3009SymbolEdges::startBlinking() {
-	setVisible(true);
-	updatePosition();
-	_blinkCountdown = 3;
-	_blinkToggle = true;
-}
-
-SsScene3009TargetLine::SsScene3009TargetLine(NeverhoodEngine *vm, int index)
-	: StaticSprite(vm, 1400) {
-
-	loadSprite(kSsScene3009TargetLineFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600);
-	setVisible(false);
-}
-
-void SsScene3009TargetLine::show() {
-	setVisible(true);
-	updatePosition();
-}
-
-SsScene3009SymbolArrow::SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index)
-	: StaticSprite(vm, 1400), _asSymbol(asSymbol), _index(index), _enabled(true), _countdown(0) {
-
-	_incrDecr = _index % 2;
-
-	createSurface(1200, 33, 31);
-	loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefPosition);
-	_drawOffset.set(0, 0, 33, 31);
-	_collisionBoundsOffset = _drawOffset;
-	updateBounds();
-	_needRefresh = true;
-
-	SetUpdateHandler(&SsScene3009SymbolArrow::update);
-	SetMessageHandler(&SsScene3009SymbolArrow::handleMessage);
-	loadSound(0, 0x2C852206);
-}
-
-void SsScene3009SymbolArrow::hide() {
-	_enabled = false;
-	setVisible(false);
-}
-
-void SsScene3009SymbolArrow::update() {
-	updatePosition();
-	if (_countdown != 0 && (--_countdown == 0)) {
-		loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefDrawOffset);
-	}
-}
-
-uint32 SsScene3009SymbolArrow::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
-	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
-	switch (messageNum) {
-	case 0x1011:
-		if (_enabled && _countdown == 0) {
-			_countdown = 2;
-			loadSprite(kSsScene3009SymbolArrowFileHashes1[_index], kSLFDefDrawOffset);
-			playSound(0);
-			sendMessage(_asSymbol, 0x2005, _incrDecr);
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
-AsScene3009VerticalIndicator::AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index)
-	: AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) {
-
-	_x = 300;
-	_y = getGlobalVar(V_CANNON_RAISED) ? 52 : 266;
-	createSurface1(0xC2463913, 1200);
-	_needRefresh = true;
-	updatePosition();
-	setVisible(false);
-	SetUpdateHandler(&AnimatedSprite::update);
-	SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage);
-}
-
-void AsScene3009VerticalIndicator::show() {
-	startAnimation(0xC2463913, 0, -1);
-	setVisible(true);
-	updatePosition();
-	_enabled = true;
-}
-
-uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const MessageParam &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 cannonTargetStatus)
-	: AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) {
-
-	_x = getGlobalVar(V_CANNON_TURNED) ? 533 : 92;
-	_y = 150;
-	createSurface1(0xC0C12954, 1200);
-	_needRefresh = true;
-	updatePosition();
-	setVisible(false);
-	SetUpdateHandler(&AnimatedSprite::update);
-	SetMessageHandler(&AsScene3009HorizontalIndicator::handleMessage);
-	if (cannonTargetStatus == kCTSRightRobotNoTarget || cannonTargetStatus == kCTSRightRobotIsTarget || cannonTargetStatus == kCTSRightNoRobot) {
-		SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight);
-		_x = 280;
-	}
-}
-
-uint32 AsScene3009HorizontalIndicator::handleMessage(int messageNum, const MessageParam &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) {
-		SetSpriteUpdate(NULL);
-		_x = 92;
-	}
-}
-
-void AsScene3009HorizontalIndicator::suMoveRight() {
-	_x += 6;
-	if (_x > 533) {
-		SetSpriteUpdate(NULL);
-		_x = 533;
-	}
-}
-
-void AsScene3009HorizontalIndicator::show() {
-	startAnimation(0xC0C12954, 0, -1);
-	setVisible(true);
-	updatePosition();
-	_enabled = true;
-}
-
-void AsScene3009HorizontalIndicator::stMoveLeft() {
-	_x = 533;
-	SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveLeft);
-}
-
-void AsScene3009HorizontalIndicator::stMoveRight() {
-	_x = 330;
-	SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight);
-}
-
-AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition)
-	: AnimatedSprite(vm, 1100), _parentScene(parentScene), _symbolPosition(symbolPosition) {
-
-	_symbolIndex = getSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition);
-
-	_x = kAsScene3009SymbolPoints[_symbolPosition].x;
-	_y = kAsScene3009SymbolPoints[_symbolPosition].y;
-	createSurface1(kAsScene3009SymbolFileHashes[_symbolPosition / 3], 1200);
-	startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1);
-	_newStickFrameIndex = _symbolIndex;
-	_needRefresh = true;
-	updatePosition();
-	SetUpdateHandler(&AnimatedSprite::update);
-	SetMessageHandler(&AsScene3009Symbol::handleMessage);
-	_ssArrowPrev = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 0);
-	_parentScene->addCollisionSprite(_ssArrowPrev);
-	_ssArrowNext = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 1);
-	_parentScene->addCollisionSprite(_ssArrowNext);
-}
-
-uint32 AsScene3009Symbol::handleMessage(int messageNum, const MessageParam &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--;
-		}
-		startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1);
-		_newStickFrameIndex = _symbolIndex;
-		setSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition, _symbolIndex);
-		if (_symbolPosition / 3 == 0) {
-			sendMessage(_parentScene, 0x2001, 0);
-		} else {
-			sendMessage(_parentScene, 0x2003, 0);
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
-void AsScene3009Symbol::hide() {
-	_ssArrowPrev->hide();
-	_ssArrowNext->hide();
-}
-
 Scene3009::Scene3009(NeverhoodEngine *vm, Module *parentModule, int which)
 	: Scene(vm, parentModule), _keepVideo(false), _moveCannonLeftFirst(false),
 	_isTurning(false), _lockSymbolsPart1Countdown(1), _lockSymbolsPart2Countdown(1) {
@@ -1015,206 +679,6 @@ static const uint32 kScene3010DeadBoltButtonFileHashes2[] = {
 	0x5000A7E8
 };
 
-static const NPoint kAsScene3010DeadBoltPoints[] = {
-	{550, 307},
-	{564, 415},
-	{560, 514}
-};
-
-static const uint32 kAsScene3010DeadBoltFileHashes2[] = {
-	0x181A0042,
-	0x580A08F2,
-	0x18420076
-};
-
-static const uint32 kAsScene3010DeadBoltFileHashes1[] = {
-	0x300E105A,
-	0x804E0052,
-	0x040E485A
-};
-
-SsScene3010DeadBoltButton::SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled)
-	: StaticSprite(vm, 900), _parentScene(parentScene), _buttonLocked(false), _countdown1(0), _countdown2(0), _buttonIndex(buttonIndex) {
-
-	_buttonEnabled = getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_buttonIndex]) != 0;
-	createSurface(400, 88, 95);
-	setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
-	if (initDisabled)
-		disableButton();
-	else if (_buttonEnabled)
-		_countdown1 = initCountdown * 12 + 1;
-	loadSound(0, 0xF4217243);
-	loadSound(1, 0x44049000);
-	loadSound(2, 0x6408107E);
-	SetUpdateHandler(&SsScene3010DeadBoltButton::update);
-	SetMessageHandler(&SsScene3010DeadBoltButton::handleMessage);
-}
-
-void SsScene3010DeadBoltButton::update() {
-
-	if (_countdown1 != 0 && (--_countdown1 == 0)) {
-		playSound(0);
-		setVisible(false);
-		setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
-	}
-
-	if (_countdown2 != 0 && (--_countdown2 == 0)) {
-		setVisible(true);
-		setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
-	}
-
-}
-
-uint32 SsScene3010DeadBoltButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
-	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
-	switch (messageNum) {
-	case 0x1011:
-		if (!_buttonLocked && _countdown1 == 0) {
-			if (_buttonEnabled) {
-				playSound(1);
-				playSound(2);
-				setVisible(true);
-				_buttonLocked = true;
-				sendMessage(_parentScene, 0x2000, _buttonIndex);
-			} else {
-				sendMessage(_parentScene, 0x2002, _buttonIndex);
-			}
-			_needRefresh = true;
-			updatePosition();
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
-void SsScene3010DeadBoltButton::disableButton() {
-	_buttonLocked = true;
-	setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
-	setVisible(true);
-}
-
-void SsScene3010DeadBoltButton::setSprite(uint32 fileHash) {
-	loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset);
-}
-
-void SsScene3010DeadBoltButton::setCountdown(int count) {
-	_countdown2 = count * 18 + 1;
-}
-
-AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked)
-	: AnimatedSprite(vm, 1100), _parentScene(parentScene), _boltIndex(boltIndex), _soundToggle(true),
-	_unlocked(false), _locked(false), _countdown(0) {
-
-	_x = kAsScene3010DeadBoltPoints[_boltIndex].x;
-	_y = kAsScene3010DeadBoltPoints[_boltIndex].y;
-
-	if (getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_boltIndex])) {
-		createSurface1(kAsScene3010DeadBoltFileHashes1[_boltIndex], 1200);
-		startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
-		loadSound(0, 0x46005BC4);
-	} else {
-		createSurface1(kAsScene3010DeadBoltFileHashes2[_boltIndex], 1200);
-		startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
-		loadSound(0, 0x420073DC);
-		loadSound(1, 0x420073DC);
-	}
-
-	setVisible(false);
-	stIdle();
-	if (initUnlocked)
-		unlock(true);
-
-	_needRefresh = true;
-	AnimatedSprite::updatePosition();
-
-}
-
-void AsScene3010DeadBolt::update() {
-	updateAnim();
-	updatePosition();
-	if (_countdown != 0 && (--_countdown == 0)) {
-		stDisabled();
-	}
-}
-
-uint32 AsScene3010DeadBolt::hmAnimation(int messageNum, const MessageParam &param, Entity *sender) {
-	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
-	switch (messageNum) {
-	case 0x3002:
-		gotoNextState();
-		break;
-	}
-	return messageResult;
-}
-
-void AsScene3010DeadBolt::stIdle() {
-	stopAnimation();
-	SetUpdateHandler(&AsScene3010DeadBolt::update);
-	SetMessageHandler(&Sprite::handleMessage);
-	_locked = false;
-}
-
-void AsScene3010DeadBolt::unlock(bool skipAnim) {
-	if (!_unlocked) {
-		setVisible(true);
-		if (skipAnim) {
-			startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0);
-			_newStickFrameIndex = STICK_LAST_FRAME;
-		} else {
-			startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
-			SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
-			FinalizeState(&AsScene3010DeadBolt::stIdleMessage);
-			NextState(&AsScene3010DeadBolt::stIdle);
-			playSound(0);
-		}
-		_unlocked = true;
-		loadSound(2, 0x4010C345);
-	}
-}
-
-void AsScene3010DeadBolt::stIdleMessage() {
-	stopAnimation();
-	SetMessageHandler(&Sprite::handleMessage);
-	sendMessage(_parentScene, 0x2001, _boltIndex);
-}
-
-void AsScene3010DeadBolt::lock() {
-	if (!_locked) {
-		_locked = true;
-		setVisible(true);
-		startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
-		SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
-		FinalizeState(&AsScene3010DeadBolt::stDisabledMessage);
-		NextState(&AsScene3010DeadBolt::stIdle);
-		if (_soundToggle) {
-			playSound(0);
-		} else {
-			playSound(1);
-		}
-		_soundToggle = !_soundToggle;
-	}
-}
-
-void AsScene3010DeadBolt::setCountdown(int count) {
-	_countdown = count * 18 + 1;
-}
-
-void AsScene3010DeadBolt::stDisabled() {
-	setVisible(true);
-	startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
-	SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
-	FinalizeState(&AsScene3010DeadBolt::stDisabledMessage);
-	NextState(&AsScene3010DeadBolt::stIdle);
-	_playBackwards = true;
-	playSound(2);
-}
-
-void AsScene3010DeadBolt::stDisabledMessage() {
-	setVisible(false);
-	sendMessage(_parentScene, 0x2003, _boltIndex);
-}
-
 Scene3010::Scene3010(NeverhoodEngine *vm, Module *parentModule, int which)
 	: Scene(vm, parentModule), _countdown(0), _doorUnlocked(false), _checkUnlocked(false) {
 
@@ -1317,127 +781,6 @@ uint32 Scene3010::handleMessage(int messageNum, const MessageParam &param, Entit
 	return 0;
 }
 
-// Scene3011
-
-static const uint32 kAsScene3011SymbolFileHashes[] = {
-	0x00C88050,
-	0x01488050,
-	0x02488050,
-	0x04488050,
-	0x08488050,
-	0x10488050,
-	0x20488050,
-	0x40488050,
-	0x80488050,
-	0x00488051,
-	0x00488052,
-	0x00488054,
-	0x008B0000,
-	0x008D0000,
-	0x00810000,
-	0x00990000,
-	0x00A90000,
-	0x00C90000,
-	0x00090000,
-	0x01890000,
-	0x02890000,
-	0x04890000,
-	0x08890000,
-	0x10890000
-};
-
-SsScene3011Button::SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag)
-	: StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) {
-
-	loadSprite(flag ? 0x11282020 : 0x994D0433, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
-	setVisible(false);
-	loadSound(0, 0x44061000);
-	SetUpdateHandler(&SsScene3011Button::update);
-	SetMessageHandler(&SsScene3011Button::handleMessage);
-}
-
-void SsScene3011Button::update() {
-	updatePosition();
-	if (_countdown != 0 && (--_countdown == 0)) {
-		setVisible(false);
-	}
-}
-
-uint32 SsScene3011Button::handleMessage(int messageNum, const MessageParam &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);
-			playSound(0);
-		}
-		messageResult = 1;
-		break;
-	}
-	return messageResult;
-}
-
-AsScene3011Symbol::AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol)
-	: AnimatedSprite(vm, 1000), _symbolIndex(symbolIndex), _largeSymbol(largeSymbol), _isNoisy(false) {
-
-	if (_largeSymbol) {
-		_x = 310;
-		_y = 200;
-		createSurface1(kAsScene3011SymbolFileHashes[_symbolIndex], 1200);
-		loadSound(0, 0x6052C60F);
-		loadSound(1, 0x6890433B);
-	} else {
-		_symbolIndex = 12;
-		_x = symbolIndex * 39 + 96;
-		_y = 225;
-		createSurface(1200, 41, 48);
-		loadSound(0, 0x64428609);
-		loadSound(1, 0x7080023B);
-	}
-	setVisible(false);
-	_needRefresh = true;
-	SetUpdateHandler(&AnimatedSprite::update);
-}
-
-void AsScene3011Symbol::show(bool isNoisy) {
-	_isNoisy = isNoisy;
-	startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1);
-	setVisible(true);
-	if (_isNoisy) {
-		playSound(1);
-	} else {
-		playSound(0);
-	}
-}
-
-void AsScene3011Symbol::hide() {
-	stopAnimation();
-	setVisible(false);
-}
-
-void AsScene3011Symbol::stopSymbolSound() {
-	if (_isNoisy) {
-		stopSound(1);
-	} else {
-		stopSound(0);
-	}
-}
-
-void AsScene3011Symbol::change(int symbolIndex, bool isNoisy) {
-	_symbolIndex = symbolIndex;
-	_isNoisy = isNoisy;
-	startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1);
-	setVisible(true);
-	if (_isNoisy) {
-		playSound(1);
-	} else {
-		playSound(0);
-	}
-}
-
 Scene3011::Scene3011(NeverhoodEngine *vm, Module *parentModule, int which)
 	: Scene(vm, parentModule), _updateStatus(0), _buttonClicked(false), _currentSymbolIndex(0), _countdown(0) {
 
diff --git a/engines/neverhood/modules/module3000.h b/engines/neverhood/modules/module3000.h
index a6cecb2..a88dea5 100644
--- a/engines/neverhood/modules/module3000.h
+++ b/engines/neverhood/modules/module3000.h
@@ -26,7 +26,6 @@
 #include "neverhood/neverhood.h"
 #include "neverhood/module.h"
 #include "neverhood/scene.h"
-#include "neverhood/modules/module1200.h"
 
 namespace Neverhood {
 
@@ -41,89 +40,11 @@ protected:
 	void updateScene();
 };
 
-// Scene3009
-
-class Scene3009;
-
-class SsScene3009FireCannonButton : public StaticSprite {
-public:
-	SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene);
-protected:
-	Scene3009 *_parentScene;
-	bool _isClicked;
-	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:
-	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 cannonTargetStatus);
-	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 symbolPosition);
-	void hide();
-protected:
-	Scene3009 *_parentScene;
-	int _symbolPosition;
-	uint32 _symbolIndex;
-	SsScene3009SymbolArrow *_ssArrowPrev;
-	SsScene3009SymbolArrow *_ssArrowNext;
-	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
-};
+class SsScene3009SymbolEdges;
+class SsScene3009TargetLine;
+class AsScene3009VerticalIndicator;
+class AsScene3009HorizontalIndicator;
+class AsScene3009Symbol;
 
 class Scene3009 : public Scene {
 public:
@@ -153,45 +74,8 @@ protected:
 	void openSmacker(uint32 fileHash, bool keepLastFrame);
 };
 
-// Scene3010
-
-class SsScene3010DeadBoltButton : public StaticSprite {
-public:
-	SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled);
-	void setCountdown(int count);
-protected:
-	Scene *_parentScene;
-	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;
-	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 SsScene3010DeadBoltButton;
+class AsScene3010DeadBolt;
 
 class Scene3010 : public Scene {
 public:
@@ -208,31 +92,7 @@ protected:
 	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;
-	int _countdown;
-	void update();
-	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
-};
-
-class AsScene3011Symbol : public AnimatedSprite {
-public:
-	AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol);
-	void show(bool isNoisy);
-	void hide();
-	void stopSymbolSound();
-	void change(int symbolIndex, bool isNoisy);
-	int getSymbolIndex() { return _largeSymbol ? _symbolIndex : _symbolIndex - 12; }
-protected:
-	bool _largeSymbol;
-	bool _isNoisy;
-	int _symbolIndex;
-};
+class AsScene3011Symbol;
 
 class Scene3011 : public Scene {
 public:
diff --git a/engines/neverhood/modules/module3000_sprites.cpp b/engines/neverhood/modules/module3000_sprites.cpp
new file mode 100644
index 0000000..420bd5e
--- /dev/null
+++ b/engines/neverhood/modules/module3000_sprites.cpp
@@ -0,0 +1,765 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "neverhood/modules/module3000.h"
+#include "neverhood/modules/module3000_sprites.h"
+#include "neverhood/gamemodule.h"
+#include "neverhood/navigationscene.h"
+
+namespace Neverhood {
+
+// Scene3009
+
+enum {
+	kCTSNull				= 0,
+	kCTSBreakWall			= 1,
+	kCTSWall				= 2,
+	kCTSEmptyness			= 3,
+	kCTSFireRobotNoTarget	= 4,
+	kCTSFireRobotIsTarget	= 5,
+	kCTSFireNoRobot			= 6,
+	kCTSRaiseCannon			= 7,
+	kCTSRightRobotNoTarget	= 8,
+	kCTSRightRobotIsTarget	= 9,
+	kCTSRightNoRobot		= 10,
+	kCTSLeftRobotNoTarget	= 11,
+	kCTSLeftRobotIsTarget	= 12,
+	kCTSLeftNoRobot			= 13,
+	kCTSLowerCannon			= 14,
+	kCTSCount				= 14
+};
+
+static const uint32 kScene3009CannonScopeVideos[] = {
+	0x1010000D,
+	0x340A0049,
+	0x340A0049,
+	0x0282081D,
+	0x0082080D,
+	0x0882080D,
+	0x0882080D,
+	0x0282081D,
+	0x004B000B,
+	0x014B000B,
+	0x044B000B,
+	0x0282081D,
+	0x0282081D,
+	0x0282081D,
+	0x340A0049
+};
+
+static const uint32 kScene3009CannonActionVideos[] = {
+	0x00000000,
+	0x8004001B,	// 1 Fire cannon at wall, it breaks (lowered)
+	0x0004001A,	// 2 Fire cannon at wall, nothing happens (lowered)
+	0x1048404B,	// 3 Fire cannon at emptyness (raised)
+	0x50200109,	// 4 Fire cannon, robot missed (raised)
+	0x12032109,	// 5 Fire cannon, robot hit (raised)
+	0x10201109,	// 6 Fire cannon, no robot (raised)
+	0x000A2030,	// 7 Raise the cannon
+	0x000A0028,	// 8
+	0x000A0028,	// 9
+	0x000A0028,	// 10
+	0x040A1069,	// 11
+	0x040A1069,	// 12
+	0x040A1069,	// 13
+	0x240A1101	// 14 Lower the cannon
+};
+
+static const uint32 kSsScene3009SymbolEdgesFileHashes[] = {
+	0x618827A0,
+	0xB1A92322
+};
+
+static const uint32 kSsScene3009TargetLineFileHashes[] = {
+	0x4011018C,
+	0x15086623
+};
+
+static const NPoint kAsScene3009SymbolPoints[] = {
+	{289, 338},
+	{285, 375},
+	{284, 419},
+	{456, 372},
+	{498, 372},
+	{541, 372}
+};
+
+static const uint32 kAsScene3009SymbolFileHashes[] = {
+	0x24542582,
+	0x1CD61D96
+};
+
+static const uint32 kSsScene3009SymbolArrowFileHashes1[] = {
+	0x24016060,
+	0x21216221,
+	0x486160A0,
+	0x42216422,
+	0x90A16120,
+	0x84216824,
+	0x08017029,
+	0x08217029,
+	0x10014032,
+	0x10214032,
+	0x20012004,
+	0x20212004
+};
+
+static const uint32 kSsScene3009SymbolArrowFileHashes2[] = {
+	0x40092024,
+	0x01636002,
+	0x8071E028,
+	0x02A56064,
+	0x00806031,
+	0x052960A8,
+	0x0A116130,
+	0x0A316130,
+	0x14216200,
+	0x14016200,
+	0x28416460,
+	0x28616460
+};
+
+SsScene3009FireCannonButton::SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene)
+	: StaticSprite(vm, 1400), _parentScene(parentScene), _isClicked(false) {
+
+	loadSprite(0x120B24B0, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
+	setVisible(false);
+	SetUpdateHandler(&SsScene3009FireCannonButton::update);
+	SetMessageHandler(&SsScene3009FireCannonButton::handleMessage);
+	loadSound(0, 0x3901B44F);
+}
+
+void SsScene3009FireCannonButton::update() {
+	updatePosition();
+	if (_isClicked && !isSoundPlaying(0)) {
+		sendMessage(_parentScene, 0x2000, 0);
+		setVisible(false);
+	}
+}
+
+uint32 SsScene3009FireCannonButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+	switch (messageNum) {
+	case 0x1011:
+		if (!_isClicked && !_parentScene->isTurning()) {
+			_isClicked = true;
+			setVisible(true);
+			playSound(0);
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+SsScene3009SymbolEdges::SsScene3009SymbolEdges(NeverhoodEngine *vm, int index)
+	: StaticSprite(vm, 1400), _blinkCountdown(0) {
+
+	loadSprite(kSsScene3009SymbolEdgesFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600);
+	if (getGlobalVar(V_ROBOT_HIT))
+		hide();
+	else
+		startBlinking();
+	SetUpdateHandler(&SsScene3009SymbolEdges::update);
+}
+
+void SsScene3009SymbolEdges::update() {
+	if (_blinkCountdown != 0 && (--_blinkCountdown == 0)) {
+		if (_blinkToggle) {
+			setVisible(true);
+		} else {
+			setVisible(false);
+		}
+		updatePosition();
+		_blinkCountdown = 3;
+		_blinkToggle = !_blinkToggle;
+	}
+}
+
+void SsScene3009SymbolEdges::show() {
+	setVisible(true);
+	updatePosition();
+	_blinkCountdown = 0;
+}
+
+void SsScene3009SymbolEdges::hide() {
+	setVisible(false);
+	updatePosition();
+	_blinkCountdown = 0;
+}
+
+void SsScene3009SymbolEdges::startBlinking() {
+	setVisible(true);
+	updatePosition();
+	_blinkCountdown = 3;
+	_blinkToggle = true;
+}
+
+SsScene3009TargetLine::SsScene3009TargetLine(NeverhoodEngine *vm, int index)
+	: StaticSprite(vm, 1400) {
+
+	loadSprite(kSsScene3009TargetLineFileHashes[index], kSLFDefDrawOffset | kSLFDefPosition, 600);
+	setVisible(false);
+}
+
+void SsScene3009TargetLine::show() {
+	setVisible(true);
+	updatePosition();
+}
+
+SsScene3009SymbolArrow::SsScene3009SymbolArrow(NeverhoodEngine *vm, Sprite *asSymbol, int index)
+	: StaticSprite(vm, 1400), _asSymbol(asSymbol), _index(index), _enabled(true), _countdown(0) {
+
+	_incrDecr = _index % 2;
+
+	createSurface(1200, 33, 31);
+	loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefPosition);
+	_drawOffset.set(0, 0, 33, 31);
+	_collisionBoundsOffset = _drawOffset;
+	updateBounds();
+	_needRefresh = true;
+
+	SetUpdateHandler(&SsScene3009SymbolArrow::update);
+	SetMessageHandler(&SsScene3009SymbolArrow::handleMessage);
+	loadSound(0, 0x2C852206);
+}
+
+void SsScene3009SymbolArrow::hide() {
+	_enabled = false;
+	setVisible(false);
+}
+
+void SsScene3009SymbolArrow::update() {
+	updatePosition();
+	if (_countdown != 0 && (--_countdown == 0)) {
+		loadSprite(kSsScene3009SymbolArrowFileHashes2[_index], kSLFDefDrawOffset);
+	}
+}
+
+uint32 SsScene3009SymbolArrow::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+	switch (messageNum) {
+	case 0x1011:
+		if (_enabled && _countdown == 0) {
+			_countdown = 2;
+			loadSprite(kSsScene3009SymbolArrowFileHashes1[_index], kSLFDefDrawOffset);
+			playSound(0);
+			sendMessage(_asSymbol, 0x2005, _incrDecr);
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+AsScene3009VerticalIndicator::AsScene3009VerticalIndicator(NeverhoodEngine *vm, Scene3009 *parentScene, int index)
+	: AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) {
+
+	_x = 300;
+	_y = getGlobalVar(V_CANNON_RAISED) ? 52 : 266;
+	createSurface1(0xC2463913, 1200);
+	_needRefresh = true;
+	updatePosition();
+	setVisible(false);
+	SetUpdateHandler(&AnimatedSprite::update);
+	SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage);
+}
+
+void AsScene3009VerticalIndicator::show() {
+	startAnimation(0xC2463913, 0, -1);
+	setVisible(true);
+	updatePosition();
+	_enabled = true;
+}
+
+uint32 AsScene3009VerticalIndicator::handleMessage(int messageNum, const MessageParam &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 cannonTargetStatus)
+	: AnimatedSprite(vm, 1000), _parentScene(parentScene), _enabled(false) {
+
+	_x = getGlobalVar(V_CANNON_TURNED) ? 533 : 92;
+	_y = 150;
+	createSurface1(0xC0C12954, 1200);
+	_needRefresh = true;
+	updatePosition();
+	setVisible(false);
+	SetUpdateHandler(&AnimatedSprite::update);
+	SetMessageHandler(&AsScene3009HorizontalIndicator::handleMessage);
+	if (cannonTargetStatus == kCTSRightRobotNoTarget || cannonTargetStatus == kCTSRightRobotIsTarget || cannonTargetStatus == kCTSRightNoRobot) {
+		SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight);
+		_x = 280;
+	}
+}
+
+uint32 AsScene3009HorizontalIndicator::handleMessage(int messageNum, const MessageParam &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) {
+		SetSpriteUpdate(NULL);
+		_x = 92;
+	}
+}
+
+void AsScene3009HorizontalIndicator::suMoveRight() {
+	_x += 6;
+	if (_x > 533) {
+		SetSpriteUpdate(NULL);
+		_x = 533;
+	}
+}
+
+void AsScene3009HorizontalIndicator::show() {
+	startAnimation(0xC0C12954, 0, -1);
+	setVisible(true);
+	updatePosition();
+	_enabled = true;
+}
+
+void AsScene3009HorizontalIndicator::stMoveLeft() {
+	_x = 533;
+	SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveLeft);
+}
+
+void AsScene3009HorizontalIndicator::stMoveRight() {
+	_x = 330;
+	SetSpriteUpdate(&AsScene3009HorizontalIndicator::suMoveRight);
+}
+
+AsScene3009Symbol::AsScene3009Symbol(NeverhoodEngine *vm, Scene3009 *parentScene, int symbolPosition)
+	: AnimatedSprite(vm, 1100), _parentScene(parentScene), _symbolPosition(symbolPosition) {
+
+	_symbolIndex = getSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition);
+
+	_x = kAsScene3009SymbolPoints[_symbolPosition].x;
+	_y = kAsScene3009SymbolPoints[_symbolPosition].y;
+	createSurface1(kAsScene3009SymbolFileHashes[_symbolPosition / 3], 1200);
+	startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1);
+	_newStickFrameIndex = _symbolIndex;
+	_needRefresh = true;
+	updatePosition();
+	SetUpdateHandler(&AnimatedSprite::update);
+	SetMessageHandler(&AsScene3009Symbol::handleMessage);
+	_ssArrowPrev = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 0);
+	_parentScene->addCollisionSprite(_ssArrowPrev);
+	_ssArrowNext = _parentScene->insertSprite<SsScene3009SymbolArrow>(this, _symbolPosition * 2 + 1);
+	_parentScene->addCollisionSprite(_ssArrowNext);
+}
+
+uint32 AsScene3009Symbol::handleMessage(int messageNum, const MessageParam &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--;
+		}
+		startAnimation(kAsScene3009SymbolFileHashes[_symbolPosition / 3], _symbolIndex, -1);
+		_newStickFrameIndex = _symbolIndex;
+		setSubVar(VA_CURR_CANNON_SYMBOLS, _symbolPosition, _symbolIndex);
+		if (_symbolPosition / 3 == 0) {
+			sendMessage(_parentScene, 0x2001, 0);
+		} else {
+			sendMessage(_parentScene, 0x2003, 0);
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+void AsScene3009Symbol::hide() {
+	_ssArrowPrev->hide();
+	_ssArrowNext->hide();
+}
+
+// Scene3010
+
+static const uint32 kScene3010ButtonNameHashes[] = {
+	0x304008D2,
+	0x40119852,
+	0x01180951
+};
+
+static const uint32 kScene3010DeadBoltButtonFileHashes1[] = {
+	0x301024C2,
+	0x20280580,
+	0x30200452
+};
+
+static const uint32 kScene3010DeadBoltButtonFileHashes2[] = {
+	0x50C025A8,
+	0x1020A0A0,
+	0x5000A7E8
+};
+
+static const NPoint kAsScene3010DeadBoltPoints[] = {
+	{550, 307},
+	{564, 415},
+	{560, 514}
+};
+
+static const uint32 kAsScene3010DeadBoltFileHashes2[] = {
+	0x181A0042,
+	0x580A08F2,
+	0x18420076
+};
+
+static const uint32 kAsScene3010DeadBoltFileHashes1[] = {
+	0x300E105A,
+	0x804E0052,
+	0x040E485A
+};
+
+SsScene3010DeadBoltButton::SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled)
+	: StaticSprite(vm, 900), _parentScene(parentScene), _buttonLocked(false), _countdown1(0), _countdown2(0), _buttonIndex(buttonIndex) {
+
+	_buttonEnabled = getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_buttonIndex]) != 0;
+	createSurface(400, 88, 95);
+	setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
+	if (initDisabled)
+		disableButton();
+	else if (_buttonEnabled)
+		_countdown1 = initCountdown * 12 + 1;
+	loadSound(0, 0xF4217243);
+	loadSound(1, 0x44049000);
+	loadSound(2, 0x6408107E);
+	SetUpdateHandler(&SsScene3010DeadBoltButton::update);
+	SetMessageHandler(&SsScene3010DeadBoltButton::handleMessage);
+}
+
+void SsScene3010DeadBoltButton::update() {
+
+	if (_countdown1 != 0 && (--_countdown1 == 0)) {
+		playSound(0);
+		setVisible(false);
+		setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
+	}
+
+	if (_countdown2 != 0 && (--_countdown2 == 0)) {
+		setVisible(true);
+		setSprite(kScene3010DeadBoltButtonFileHashes2[_buttonIndex]);
+	}
+
+}
+
+uint32 SsScene3010DeadBoltButton::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
+	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+	switch (messageNum) {
+	case 0x1011:
+		if (!_buttonLocked && _countdown1 == 0) {
+			if (_buttonEnabled) {
+				playSound(1);
+				playSound(2);
+				setVisible(true);
+				_buttonLocked = true;
+				sendMessage(_parentScene, 0x2000, _buttonIndex);
+			} else {
+				sendMessage(_parentScene, 0x2002, _buttonIndex);
+			}
+			_needRefresh = true;
+			updatePosition();
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+void SsScene3010DeadBoltButton::disableButton() {
+	_buttonLocked = true;
+	setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
+	setVisible(true);
+}
+
+void SsScene3010DeadBoltButton::setSprite(uint32 fileHash) {
+	loadSprite(fileHash, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset);
+}
+
+void SsScene3010DeadBoltButton::setCountdown(int count) {
+	_countdown2 = count * 18 + 1;
+}
+
+AsScene3010DeadBolt::AsScene3010DeadBolt(NeverhoodEngine *vm, Scene *parentScene, int boltIndex, bool initUnlocked)
+	: AnimatedSprite(vm, 1100), _parentScene(parentScene), _boltIndex(boltIndex), _soundToggle(true),
+	_unlocked(false), _locked(false), _countdown(0) {
+
+	_x = kAsScene3010DeadBoltPoints[_boltIndex].x;
+	_y = kAsScene3010DeadBoltPoints[_boltIndex].y;
+
+	if (getSubVar(VA_LOCKS_DISABLED, kScene3010ButtonNameHashes[_boltIndex])) {
+		createSurface1(kAsScene3010DeadBoltFileHashes1[_boltIndex], 1200);
+		startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
+		loadSound(0, 0x46005BC4);
+	} else {
+		createSurface1(kAsScene3010DeadBoltFileHashes2[_boltIndex], 1200);
+		startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
+		loadSound(0, 0x420073DC);
+		loadSound(1, 0x420073DC);
+	}
+
+	setVisible(false);
+	stIdle();
+	if (initUnlocked)
+		unlock(true);
+
+	_needRefresh = true;
+	AnimatedSprite::updatePosition();
+
+}
+
+void AsScene3010DeadBolt::update() {
+	updateAnim();
+	updatePosition();
+	if (_countdown != 0 && (--_countdown == 0)) {
+		stDisabled();
+	}
+}
+
+uint32 AsScene3010DeadBolt::hmAnimation(int messageNum, const MessageParam &param, Entity *sender) {
+	uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
+	switch (messageNum) {
+	case 0x3002:
+		gotoNextState();
+		break;
+	}
+	return messageResult;
+}
+
+void AsScene3010DeadBolt::stIdle() {
+	stopAnimation();
+	SetUpdateHandler(&AsScene3010DeadBolt::update);
+	SetMessageHandler(&Sprite::handleMessage);
+	_locked = false;
+}
+
+void AsScene3010DeadBolt::unlock(bool skipAnim) {
+	if (!_unlocked) {
+		setVisible(true);
+		if (skipAnim) {
+			startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0);
+			_newStickFrameIndex = STICK_LAST_FRAME;
+		} else {
+			startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
+			SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
+			FinalizeState(&AsScene3010DeadBolt::stIdleMessage);
+			NextState(&AsScene3010DeadBolt::stIdle);
+			playSound(0);
+		}
+		_unlocked = true;
+		loadSound(2, 0x4010C345);
+	}
+}
+
+void AsScene3010DeadBolt::stIdleMessage() {
+	stopAnimation();
+	SetMessageHandler(&Sprite::handleMessage);
+	sendMessage(_parentScene, 0x2001, _boltIndex);
+}
+
+void AsScene3010DeadBolt::lock() {
+	if (!_locked) {
+		_locked = true;
+		setVisible(true);
+		startAnimation(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
+		SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
+		FinalizeState(&AsScene3010DeadBolt::stDisabledMessage);
+		NextState(&AsScene3010DeadBolt::stIdle);
+		if (_soundToggle) {
+			playSound(0);
+		} else {
+			playSound(1);
+		}
+		_soundToggle = !_soundToggle;
+	}
+}
+
+void AsScene3010DeadBolt::setCountdown(int count) {
+	_countdown = count * 18 + 1;
+}
+
+void AsScene3010DeadBolt::stDisabled() {
+	setVisible(true);
+	startAnimation(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
+	SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
+	FinalizeState(&AsScene3010DeadBolt::stDisabledMessage);
+	NextState(&AsScene3010DeadBolt::stIdle);
+	_playBackwards = true;
+	playSound(2);
+}
+
+void AsScene3010DeadBolt::stDisabledMessage() {
+	setVisible(false);
+	sendMessage(_parentScene, 0x2003, _boltIndex);
+}
+
+// Scene3011
+
+static const uint32 kAsScene3011SymbolFileHashes[] = {
+	0x00C88050,
+	0x01488050,
+	0x02488050,
+	0x04488050,
+	0x08488050,
+	0x10488050,
+	0x20488050,
+	0x40488050,
+	0x80488050,
+	0x00488051,
+	0x00488052,
+	0x00488054,
+	0x008B0000,
+	0x008D0000,
+	0x00810000,
+	0x00990000,
+	0x00A90000,
+	0x00C90000,
+	0x00090000,
+	0x01890000,
+	0x02890000,
+	0x04890000,
+	0x08890000,
+	0x10890000
+};
+
+SsScene3011Button::SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag)
+	: StaticSprite(vm, 1400), _parentScene(parentScene), _countdown(0) {
+
+	loadSprite(flag ? 0x11282020 : 0x994D0433, kSLFDefDrawOffset | kSLFDefPosition | kSLFDefCollisionBoundsOffset, 400);
+	setVisible(false);
+	loadSound(0, 0x44061000);
+	SetUpdateHandler(&SsScene3011Button::update);
+	SetMessageHandler(&SsScene3011Button::handleMessage);
+}
+
+void SsScene3011Button::update() {
+	updatePosition();
+	if (_countdown != 0 && (--_countdown == 0)) {
+		setVisible(false);
+	}
+}
+
+uint32 SsScene3011Button::handleMessage(int messageNum, const MessageParam &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);
+			playSound(0);
+		}
+		messageResult = 1;
+		break;
+	}
+	return messageResult;
+}
+
+AsScene3011Symbol::AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol)
+	: AnimatedSprite(vm, 1000), _symbolIndex(symbolIndex), _largeSymbol(largeSymbol), _isNoisy(false) {
+
+	if (_largeSymbol) {
+		_x = 310;
+		_y = 200;
+		createSurface1(kAsScene3011SymbolFileHashes[_symbolIndex], 1200);
+		loadSound(0, 0x6052C60F);
+		loadSound(1, 0x6890433B);
+	} else {
+		_symbolIndex = 12;
+		_x = symbolIndex * 39 + 96;
+		_y = 225;
+		createSurface(1200, 41, 48);
+		loadSound(0, 0x64428609);
+		loadSound(1, 0x7080023B);
+	}
+	setVisible(false);
+	_needRefresh = true;
+	SetUpdateHandler(&AnimatedSprite::update);
+}
+
+void AsScene3011Symbol::show(bool isNoisy) {
+	_isNoisy = isNoisy;
+	startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1);
+	setVisible(true);
+	if (_isNoisy) {
+		playSound(1);
+	} else {
+		playSound(0);
+	}
+}
+
+void AsScene3011Symbol::hide() {
+	stopAnimation();
+	setVisible(false);
+}
+
+void AsScene3011Symbol::stopSymbolSound() {
+	if (_isNoisy) {
+		stopSound(1);
+	} else {
+		stopSound(0);
+	}
+}
+
+void AsScene3011Symbol::change(int symbolIndex, bool isNoisy) {
+	_symbolIndex = symbolIndex;
+	_isNoisy = isNoisy;
+	startAnimation(kAsScene3011SymbolFileHashes[_symbolIndex], 0, -1);
+	setVisible(true);
+	if (_isNoisy) {
+		playSound(1);
+	} else {
+		playSound(0);
+	}
+}
+
+} // End of namespace Neverhood
diff --git a/engines/neverhood/modules/module3000_sprites.h b/engines/neverhood/modules/module3000_sprites.h
new file mode 100644
index 0000000..7316613
--- /dev/null
+++ b/engines/neverhood/modules/module3000_sprites.h
@@ -0,0 +1,185 @@
+/* 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_MODULES_MODULE3000_SPRITES_H
+#define NEVERHOOD_MODULES_MODULE3000_SPRITES_H
+
+#include "neverhood/neverhood.h"
+#include "neverhood/module.h"
+#include "neverhood/scene.h"
+#include "neverhood/modules/module1200.h"
+
+namespace Neverhood {
+
+// Scene3009
+
+class Scene3009;
+
+class SsScene3009FireCannonButton : public StaticSprite {
+public:
+	SsScene3009FireCannonButton(NeverhoodEngine *vm, Scene3009 *parentScene);
+protected:
+	Scene3009 *_parentScene;
+	bool _isClicked;
+	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:
+	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 cannonTargetStatus);
+	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 symbolPosition);
+	void hide();
+protected:
+	Scene3009 *_parentScene;
+	int _symbolPosition;
+	uint32 _symbolIndex;
+	SsScene3009SymbolArrow *_ssArrowPrev;
+	SsScene3009SymbolArrow *_ssArrowNext;
+	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+// Scene3010
+
+class SsScene3010DeadBoltButton : public StaticSprite {
+public:
+	SsScene3010DeadBoltButton(NeverhoodEngine *vm, Scene *parentScene, int buttonIndex, int initCountdown, bool initDisabled);
+	void setCountdown(int count);
+protected:
+	Scene *_parentScene;
+	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;
+	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();
+};
+
+// Scene3011
+
+class SsScene3011Button : public StaticSprite {
+public:
+	SsScene3011Button(NeverhoodEngine *vm, Scene *parentScene, bool flag);
+protected:
+	Scene *_parentScene;
+	int _countdown;
+	void update();
+	uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
+};
+
+class AsScene3011Symbol : public AnimatedSprite {
+public:
+	AsScene3011Symbol(NeverhoodEngine *vm, int symbolIndex, bool largeSymbol);
+	void show(bool isNoisy);
+	void hide();
+	void stopSymbolSound();
+	void change(int symbolIndex, bool isNoisy);
+	int getSymbolIndex() { return _largeSymbol ? _symbolIndex : _symbolIndex - 12; }
+protected:
+	bool _largeSymbol;
+	bool _isNoisy;
+	int _symbolIndex;
+};
+
+} // End of namespace Neverhood
+
+#endif /* NEVERHOOD_MODULES_MODULE3000_SPRITES_H */






More information about the Scummvm-git-logs mailing list