/* 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), _moduleDone(false), _soundVolume(0) {
	
	debug("Create Module3000(%d)", which);

	// 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) {
		switch (_vm->gameState().sceneNum) {
		default:
		case 1:
			createScene3002(-1);
			break;
		case 2:
			createScene3003(-1);
			break;
		case 3:
			createScene3004(-1);
			break;
		case 4:
			createScene3005(-1);
			break;
		case 5:
			createScene3006(-1);
			break;
		case 6:
			createScene3007(-1);
			break;
		case 7:
			createScene3008(-1);
			break;
		case 8:
			createScene3009(-1);
			break;
		case 9:
			createScene3010(-1);
			break;
		case 10:
			createScene3011(-1);
			break;
		case 11:
			createScene3012(-1);
			break;
		case 12:
			createScene3013(-1);
			break;
		}
	} else if (which == 0) {
		createScene3002(0);
	} else if (which == 1) {
		createScene3005(2);
	} else if (which == 2) {
		createScene3005(1);
	} else if (which == 3) {
		createScene3006(1);
	}

	SetMessageHandler(&Module3000::handleMessage);

}

Module3000::~Module3000() {
	// TODO Sound1ChList_sub_407A50(0x81293110);
}

uint32 Module3000::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
	uint32 messageResult = Module::handleMessage(messageNum, param, sender);
	switch (messageNum) {
	case 0x1009:
		_moduleDone = true;
		_moduleDoneStatus = param.asInteger();
		break;
	}
	return messageResult;
}

void Module3000::createScene3002(int which) {
	_vm->gameState().sceneNum = 1;
	if (!getGlobalVar(0x01BA1A52)) {
		createNavigationScene(0x004B7C80, which);
	} else if (getGlobalVar(0x10938830)) {
		createNavigationScene(0x004B7CE0, which);
	} else {
		createNavigationScene(0x004B7CB0, which);
	}
	SetUpdateHandler(&Module3000::updateScene3002);
}

void Module3000::createScene3002b(int which) {
	_vm->gameState().sceneNum = 1;
	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);
		}
	}
	SetUpdateHandler(&Module3000::updateScene3002b);
	setGlobalVar(0x01BA1A52, getGlobalVar(0x01BA1A52) ? 0 : 1);
}

void Module3000::createScene3003(int which) {
	_vm->gameState().sceneNum = 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);
	}
	SetUpdateHandler(&Module3000::updateScene3003);
}

void Module3000::createScene3004(int which) {
	_vm->gameState().sceneNum = 3;
	if (getGlobalVar(0x09221A62)) {
		createNavigationScene(0x004B7E60, which);
	} else if (getGlobalVar(0x10938830)) {
		createNavigationScene(0x004B7DA0, which);
	} else {
		createNavigationScene(0x004B7E00, which);
	}
	SetUpdateHandler(&Module3000::updateScene3004);
}

void Module3000::createScene3005(int which) {
	_vm->gameState().sceneNum = 4;
	if (getGlobalVar(0x09221A62)) {
		createNavigationScene(0x004B7F20, which);
	} else {
		createNavigationScene(0x004B7EC0, which);
	}
	SetUpdateHandler(&Module3000::updateScene3005);
}

void Module3000::createScene3006(int which) {
	static const byte kNavigationTypes[] = {3, 0};
	_vm->gameState().sceneNum = 5;
	createNavigationScene(0x004B7F80, which, kNavigationTypes);
	SetUpdateHandler(&Module3000::updateScene3006);
}

void Module3000::createScene3007(int which) {
	static const byte kNavigationTypes[] = {5};
	_vm->gameState().sceneNum = 6;
	createNavigationScene(0x004B7FB0, which, kNavigationTypes);
	SetUpdateHandler(&Module3000::updateScene3007);
}

void Module3000::createScene3008(int which) {
	_vm->gameState().sceneNum = 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);
	}
	SetUpdateHandler(&Module3000::updateScene3002b);
}

void Module3000::createScene3009(int which) {
	_vm->gameState().sceneNum = 8;
	_childObject = new Scene3009(_vm, this, which);
	SetUpdateHandler(&Module3000::updateScene3009);
}

void Module3000::createScene3010(int which) {
	_vm->gameState().sceneNum = 9;
	_childObject = new Scene3010(_vm, this, 0);
	SetUpdateHandler(&Module3000::updateScene3010);
}

void Module3000::createScene3011(int which) {
	_vm->gameState().sceneNum = 10;
	_childObject = new Scene3011(_vm, this, 0);
	SetUpdateHandler(&Module3000::updateScene3011);
}

void Module3000::createScene3012(int which) {
	_vm->gameState().sceneNum = 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);
	}
	SetUpdateHandler(&Module3000::updateScene3002b);
}

void Module3000::createScene3013(int which) {
	_vm->gameState().sceneNum = 12;
	_childObject = new Scene3010(_vm, this, 1);
	SetUpdateHandler(&Module3000::updateScene3002b);
}

void Module3000::updateScene3002() {
	_childObject->handleUpdate();
#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
	if (_moduleDone) {
		int areaType = navigationScene()->getNavigationAreaType();
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		if (!getGlobalVar(0x01BA1A52)) {
			if (_moduleDoneStatus == 0) {
				createScene3010(-1);
				_childObject->handleUpdate();
			} else if (_moduleDoneStatus == 1) {
				_parentModule->sendMessage(0x1009, 0, this);
			}
		} else {
			if (_moduleDoneStatus == 0) {
				if (areaType == 2) {
					createScene3003(0);
					_childObject->handleUpdate();
				} else {
					//createScene3002b(-1);
					_childObject->handleUpdate();
				}
			} else if (_moduleDoneStatus == 1) {
				_parentModule->sendMessage(0x1009, 0, this);
			}
		}
	}
}

void Module3000::updateScene3002b() {
	_childObject->handleUpdate();
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		switch (_vm->gameState().sceneNum) {
		case 1:
			if (getGlobalVar(0x01BA1A52)) {
				createScene3002(0);
				_childObject->handleUpdate();
			} else {
				createScene3013(-1);
				_childObject->handleUpdate();
			}
			break;
		case 7:
		case 8:
			createScene3009(-1);
			break;
		case 11:
			_parentModule->sendMessage(0x1009, 3, this);
			break;
		case 12:
			createScene3002(0);
			_childObject->handleUpdate();
			break;
		default:
			createScene3006(0);
			break;
		}
	}
}

void Module3000::updateScene3003() {
	_childObject->handleUpdate();
#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
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		// TODO Sound1ChList_sub_407C70(0x81293110, 0x41861371, 0x43A2507F, 0);
		if (_flag) {
			_soundVolume = 0;
			// TODO Sound1ChList_setVolume(0x90F0D1C3, 0);
		}
		if (_moduleDoneStatus == 0) {
			createScene3004(0);
			_childObject->handleUpdate();
		} else if (_moduleDoneStatus == 1) {
			setGlobalVar(0x01BA1A52, 0);
			createScene3002(1);
			_childObject->handleUpdate();
		}
	}
}

void Module3000::updateScene3004() {
	_childObject->handleUpdate();
#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
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		
		debug("_moduleDoneStatus = %d", _moduleDoneStatus);
		
		if (_moduleDoneStatus == 1) {
			createScene3005(0);
			_childObject->handleUpdate();
		} else if (_moduleDoneStatus == 3) {
			createScene3011(-1);
			_childObject->handleUpdate();
		} else if (getGlobalVar(0x09221A62)) {
			createScene3006(0);
			_childObject->handleUpdate();
		} else {
			createScene3003(1);
			_childObject->handleUpdate();
		}
	}
}

void Module3000::updateScene3005() {
	_childObject->handleUpdate();
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		if (_moduleDoneStatus == 0) {
			_parentModule->sendMessage(0x1009, 1, this);
		} else if (_moduleDoneStatus == 1) {
			createScene3008(-1);
			_childObject->handleUpdate();
		} else if (_moduleDoneStatus == 2) {
			createScene3004(3);
			_childObject->handleUpdate();
		}
	}
	// NOTE: Skipped resource preloading stuff
}

void Module3000::updateScene3006() {
	_childObject->handleUpdate();
#if 0 // ALL TODO
	if (navigationScene()->getSoundFlag1() && navigationScene()->getIndex() == 0) {
		// TODO Sound1ChList_sub_4080B0(false);
	}
#endif
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		if (_moduleDoneStatus == 0) {
			createScene3007(0);
			_childObject->handleUpdate();
		} else if (_moduleDoneStatus == 1) {
			createScene3004(0);
			_childObject->handleUpdate();
		}
	}
}

void Module3000::updateScene3007() {
	_childObject->handleUpdate();
	if (_moduleDone) {
		int areaType = navigationScene()->getNavigationAreaType();
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		if (areaType == 4) {
			createScene3012(-1);
			_childObject->handleUpdate();
		} else {
			createSmackerScene(0x080810C5, true, true, false);
			SetUpdateHandler(&Module3000::updateScene3002b);
		}
	}
}

void Module3000::updateScene3009() {
	_childObject->handleUpdate();
	// TODO...
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		_flag = getGlobalVar(0x10938830); // CHECKME
		if (_moduleDoneStatus != 1) {
			// TODO: Sound1ChList_setSoundValuesMulti(dword_4B7FC8, true, 0, 0, 0, 0):
			createScene3005(1);
			_childObject->handleUpdate();
		} else if (getGlobalVar(0xF0402B0A)) {
			createSmackerScene(getGlobalVar(0xF0402B0A), true, true, false);
			SetUpdateHandler(&Module3000::updateScene3002b);
		} else {
			// TODO: Sound1ChList_setSoundValuesMulti(dword_4B7FC8, true, 0, 0, 0, 0);
			createScene3005(1);
			_childObject->handleUpdate();
		}
	}
}

void Module3000::updateScene3010() {
	_childObject->handleUpdate();
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		if (_moduleDoneStatus == 0 || _moduleDoneStatus == 2) {
			createScene3002(0);
			_childObject->handleUpdate();
		} else if (_moduleDoneStatus == 1) {
			createScene3002b(-1);
			_childObject->handleUpdate();
		}
	}
}

void Module3000::updateScene3011() {
	_childObject->handleUpdate();
	if (_moduleDone) {
		_moduleDone = false;
		delete _childObject;
		_childObject = NULL;
		createScene3004(3);
		_childObject->handleUpdate();
	}
}

// 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;
	_surface->setVisible(false);
	processDelta();
	_needRefresh = true;
	SetUpdateHandler(&SsScene3009FireCannonButton::update);
	SetMessageHandler(&SsScene3009FireCannonButton::handleMessage);
	_soundResource.load(0x3901B44F);
}

void SsScene3009FireCannonButton::update() {
	StaticSprite::update();
	if (_flag1 && !_soundResource.isPlaying()) {
		_parentScene->sendMessage(0x2000, 0, this);
		_surface->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;
			_surface->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) {
			_surface->setVisible(true);
		} else {
			_surface->setVisible(false);
		}
		StaticSprite::update();
		_blinkCountdown = 3;
		_blinkToggle = !_blinkToggle;
	}
}

void SsScene3009SymbolEdges::show() {
	_surface->setVisible(true);
	StaticSprite::update();
	_blinkCountdown = 0;
}

void SsScene3009SymbolEdges::hide() {
	_surface->setVisible(false);
	StaticSprite::update();
	_blinkCountdown = 0;
}

void SsScene3009SymbolEdges::startBlinking() {
	_surface->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;
	_surface->setVisible(false);
	_needRefresh = true;
}

void SsScene3009TargetLine::show() {
	_surface->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;
	_surface->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();
			_asSymbol->sendMessage(0x2005, _incrDecr, this);
		}
		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();
	_surface->setVisible(false);
	SetUpdateHandler(&AnimatedSprite::update);
	SetMessageHandler(&AsScene3009VerticalIndicator::handleMessage);
}

void AsScene3009VerticalIndicator::show() {
	setFileHash(0xC2463913, 0, -1);
	_surface->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) {
			_parentScene->sendMessage(0x2002, 0, this);
		}
		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();
	_surface->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) {
			_parentScene->sendMessage(0x2004, 0, this);
		}
		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);
	_surface->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 = new SsScene3009SymbolArrow(_vm, this, _index * 2 + 0);
	_parentScene->addSprite(_ssArrowPrev);
	_vm->_collisionMan->addSprite(_ssArrowPrev);

	_ssArrowNext = new SsScene3009SymbolArrow(_vm, this, _index * 2 + 1);
	_parentScene->addSprite(_ssArrowNext);
	_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) {
			_parentScene->sendMessage(0x2001, 0, this);
		} else {
			_parentScene->sendMessage(0x2003, 0, this);
		}
		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();
	
	_background = addBackground(new DirtyBackground(_vm, 0xD000420C, 0, 0));
	_palette = new Palette(_vm, 0xD000420C);
	_mouseCursor = addSprite(new Mouse435(_vm, 0x04208D08, 20, 620));

	_ssFireCannonButton = addSprite(new SsScene3009FireCannonButton(_vm, this));
	_vm->_collisionMan->addSprite(_ssFireCannonButton);

	_asVerticalIndicator = new AsScene3009VerticalIndicator(_vm, this, _cannonLocation);
	addSprite(_asVerticalIndicator);
	_vm->_collisionMan->addSprite(_asVerticalIndicator);

	_asHorizontalIndicator = new AsScene3009HorizontalIndicator(_vm, this, _cannonLocation);
	addSprite(_asHorizontalIndicator);
	_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();

	addSprite(new StaticSprite(_vm, 0x8540252C, 400));

	for (int i = 0; i < 2; i++) {
		_ssSymbolEdges[i] = new SsScene3009SymbolEdges(_vm, i);
		addSprite(_ssSymbolEdges[i]);
		_ssTargetLines[i] = new SsScene3009TargetLine(_vm, i);
		addSprite(_ssTargetLines[i]);
	}


	for (int i = 0; i < 6; i++) {
		_asSymbols[i] = new AsScene3009Symbol(_vm, this, i);
		addSprite(_asSymbols[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(0x2003, 0, this);
	//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);
			_parentModule->sendMessage(0x1009, 0, this);
		}
		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]);
	_parentModule->sendMessage(0x1009, 1, this);
}

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 /*_flag3 || */_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();
		_surface->setVisible(false);
		setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
	}

	if (_countdown2 != 0 && (--_countdown2 == 0)) {
		_surface->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();
				_surface->setVisible(true);
				_buttonLocked = true;
				_parentScene->sendMessage(0x2000, _buttonIndex, this);
			} else {
				_parentScene->sendMessage(0x2002, _buttonIndex, this);
			}
			_needRefresh = true;
			StaticSprite::update();
		}
		messageResult = 1;
		break;
	}
	return messageResult;
}

void SsScene3010DeadBoltButton::disableButton() {
	_buttonLocked = true;
	setSprite(kScene3010DeadBoltButtonFileHashes1[_buttonIndex]);
	_surface->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.x = 0;
	_deltaRect.y = 0;
	_deltaRect.width = _spriteResource.getDimensions().width;
	_deltaRect.height = _spriteResource.getDimensions().height;
	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);
	}
	
	_surface->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() {
	setFileHash1();
	SetUpdateHandler(&AsScene3010DeadBolt::update);
	SetMessageHandler(&Sprite::handleMessage);
	_locked = false;
}

void AsScene3010DeadBolt::unlock(bool skipAnim) {
	if (!_unlocked) {
		_surface->setVisible(true);
		if (skipAnim) {
			setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], -1, 0);
			_newHashListIndex = -2;
		} else {
			setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
			SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
			setCallback1(AnimationCallback(&AsScene3010DeadBolt::stIdleMessage));
			SetAnimationCallback3(&AsScene3010DeadBolt::stIdle);
			_soundResource1.play();
		}
		_unlocked = true;
		_soundResource3.load(0x4010C345);
	}
}

void AsScene3010DeadBolt::stIdleMessage() {
	setFileHash1();
	SetMessageHandler(&Sprite::handleMessage);
	_parentScene->sendMessage(0x2001, _boltIndex, this);
}

void AsScene3010DeadBolt::lock() {
	if (!_locked) {
		_locked = true;
		_surface->setVisible(true);
		setFileHash(kAsScene3010DeadBoltFileHashes2[_boltIndex], 0, -1);
		SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
		setCallback1(AnimationCallback(&AsScene3010DeadBolt::stDisabledMessage));
		SetAnimationCallback3(&AsScene3010DeadBolt::stIdle);
		if (_soundToggle) {
			_soundResource1.play();
		} else {
			_soundResource2.play();
		}
		_soundToggle = !_soundToggle;
	}
}

void AsScene3010DeadBolt::setCountdown(int count) {
	_countdown = count * 18 + 1;
}

void AsScene3010DeadBolt::stDisabled() {
	_surface->setVisible(true);
	setFileHash(kAsScene3010DeadBoltFileHashes1[_boltIndex], 0, -1);
	SetMessageHandler(&AsScene3010DeadBolt::hmAnimation);
	setCallback1(AnimationCallback(&AsScene3010DeadBolt::stDisabledMessage));
	SetAnimationCallback3(&AsScene3010DeadBolt::stIdle);
	_playBackwards = true;
	_soundResource3.play();
}

void AsScene3010DeadBolt::stDisabledMessage() {
	_surface->setVisible(false);
	_parentScene->sendMessage(0x2003, _boltIndex, this);
}

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;

	_background = addBackground(new DirtyBackground(_vm, 0x80802626, 0, 0));
	_palette = new Palette(_vm, 0x80802626);
	_palette->usePalette();

	for (int i = 0; i < 3; i++) {
		_asDeadBolts[i] = new AsScene3010DeadBolt(_vm, this, i, which == 1);//CHECKME
		addSprite(_asDeadBolts[i]);
		_ssDeadBoltButtons[i] = new SsScene3010DeadBoltButton(_vm, this, i, initCountdown, which == 1);//CHECKME
		addSprite(_ssDeadBoltButtons[i]);
		_vm->_collisionMan->addSprite(_ssDeadBoltButtons[i]);
		if (getSubVar(0x14800353, kScene3010ButtonNameHashes[i]))
			initCountdown++;
		_boltUnlocking[i] = false;
		_boltUnlocked[i] = false;
	}

	if (which == 0) {
		_mouseCursor = addSprite(new Mouse435(_vm, 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)) {
		_parentModule->sendMessage(0x1009, _doorUnlocked ? 1 : 0, this);
	}
}

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]) {
				_mouseCursor->getSurface()->setVisible(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.x = 0;
	_deltaRect.y = 0;
	_deltaRect.width = _spriteResource.getDimensions().width;
	_deltaRect.height = _spriteResource.getDimensions().height;
	_surface->setVisible(false);
	processDelta();
	_needRefresh = true;
	SetUpdateHandler(&SsScene3011Button::update);
	SetMessageHandler(&SsScene3011Button::handleMessage);
}

void SsScene3011Button::update() {
	StaticSprite::update();
	if (_countdown != 0 && (--_countdown == 0)) {
		_surface->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) {
			_surface->setVisible(true);
			_countdown = 4;
			_parentScene->sendMessage(0x2000, 0, this);
			_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);
	}
	_surface->setVisible(false);
	_needRefresh = true;
	SetUpdateHandler(&AnimatedSprite::update);
}

void AsScene3011Symbol::show(bool flag) {
	_flag2 = flag;
	setFileHash(kAsScene3011SymbolFileHashes[_index], 0, -1);
	_surface->setVisible(true);
	if (flag) {
		_soundResource2.play();
	} else {
		_soundResource1.play();
	}
}

void AsScene3011Symbol::hide() {
	setFileHash1();
	_surface->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);
	_surface->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) {

	Palette2 *palette2;
	
	_surfaceFlag = true;

	// TODO _vm->gameModule()->initScene3011Vars();
	_index1 = getGlobalVar(0x2414C2F2);

	_background = addBackground(new DirtyBackground(_vm, 0x92124A04, 0, 0));

	palette2 = new Palette2(_vm, 0xA4070114);
	addEntity(palette2);
	palette2->usePalette();
	_palette = palette2;

	_mouseCursor = addSprite(new Mouse435(_vm, 0x24A00929, 20, 620));

	for (int i = 0; i < 12; i++) {
		_asSymbols[i] = new AsScene3011Symbol(_vm, i, true);
		addSprite(_asSymbols[i]);
	}

	_ssButton = addSprite(new SsScene3011Button(_vm, this, true));
	_vm->_collisionMan->addSprite(_ssButton);
	
	SetUpdateHandler(&Scene3011::update);
	SetMessageHandler(&Scene3011::handleMessage);
	
}

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) {
			_parentModule->sendMessage(0x1009, 0, this);
		}
		break;
	case 0x2000:
		_buttonClicked = true;
		if (_countdown == 0)
			_countdown = 1;
		break;
	}
	return 0;
}

void Scene3011::fadeIn() {
	Palette2 *palette2 = (Palette2*)_palette;
	palette2->addPalette(0x92124A04, 0, 256, 0);
	palette2->startFadeToPalette(24);
}

void Scene3011::fadeOut() {
	Palette2 *palette2 = (Palette2*)_palette;
	palette2->addPalette(0xA4070114, 0, 256, 0);
	palette2->startFadeToPalette(24);
}

} // End of namespace Neverhood