/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "neverhood/module1600.h" #include "neverhood/gamemodule.h" #include "neverhood/module1200.h" #include "neverhood/module2200.h" namespace Neverhood { static const uint32 kModule1600SoundList[] = { 0x90805C50, 0x90804450, 0xB4005E60, 0x91835066, 0x90E14440, 0 }; Module1600::Module1600(NeverhoodEngine *vm, Module *parentModule, int which) : Module(vm, parentModule) { if (which < 0) { createScene(_vm->gameState().sceneNum, -1); } else if (which == 1) { createScene(4, 1); } else if (which == 2) { createScene(5, 0); } else if (which == 3) { createScene(6, 1); } else if (which == 4) { createScene(1, 0); } else { createScene(0, 0); } _vm->_soundMan->addSoundList(0x1A008D8, kModule1600SoundList); _vm->_soundMan->setSoundListParams(kModule1600SoundList, true, 50, 600, 5, 150); _vm->_soundMan->playTwoSounds(0x1A008D8, 0x41861371, 0x43A2507F, 0); } Module1600::~Module1600() { _vm->_soundMan->deleteGroup(0x1A008D8); } void Module1600::createScene(int sceneNum, int which) { debug("Module1600::createScene(%d, %d)", sceneNum, which); _vm->gameState().sceneNum = sceneNum; switch (_vm->gameState().sceneNum) { case 0: createNavigationScene(0x004B39D0, which); break; case 1: createNavigationScene(0x004B3A30, which); break; case 2: createNavigationScene(0x004B3A60, which); break; case 3: createNavigationScene(0x004B3A90, which); break; case 4: createNavigationScene(0x004B3B20, which); break; case 5: createNavigationScene(0x004B3B50, which); break; case 6: createNavigationScene(0x004B3B80, which); break; case 7: _childObject = new Scene1608(_vm, this, which); break; case 8: _childObject = new Scene1609(_vm, this, which); break; case 1001: if (getGlobalVar(0xA0808898) == 1) { createSmackerScene(0x80050200, true, true, false); } else if (getGlobalVar(0xA0808898) == 2) { createSmackerScene(0x80090200, true, true, false); } else { createSmackerScene(0x80000200, true, true, false); } if (getGlobalVar(0xA0808898) >= 2) setGlobalVar(0xA0808898, 0); else incGlobalVar(0xA0808898, +1); break; } SetUpdateHandler(&Module1600::updateScene); _childObject->handleUpdate(); } void Module1600::updateScene() { if (!updateChild()) { switch (_vm->gameState().sceneNum) { case 0: if (_moduleResult == 0) createScene(2, 0); else if (_moduleResult == 1) createScene(1, 0); else if (_moduleResult == 2) leaveModule(4); break; case 1: if (_moduleResult == 0) createScene(1001, -1); else if (_moduleResult == 1) createScene(0, 3); break; case 2: if (_moduleResult == 0) createScene(3, 0); else if (_moduleResult == 1) createScene(0, 2); break; case 3: if (_moduleResult == 0) createScene(5, 0); else if (_moduleResult == 2) createScene(6, 0); else if (_moduleResult == 3) createScene(2, 1); else if (_moduleResult == 4) createScene(4, 0); break; case 4: if (_moduleResult == 0) leaveModule(1); else if (_moduleResult == 1) createScene(3, 1); break; case 5: if (_moduleResult == 0) leaveModule(2); else if (_moduleResult == 1) createScene(3, 3); break; case 6: if (_moduleResult == 0) createScene(8, -1); else if (_moduleResult == 1) createScene(3, 5); break; case 7: createScene(6, 1); break; case 8: if (_moduleResult == 0) createScene(6, 0); else createScene(7, 0); break; case 1001: createScene(1, 0); break; } } } Class521::Class521(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y) : AnimatedSprite(vm, 1000), _parentScene(parentScene) { SetUpdateHandler(&Class521::update); SetMessageHandler(&Class521::handleMessage); SetSpriteUpdate(NULL); // TODO createSurface2(200, dword_4AF4C0); createSurface(200, 640, 480); //TODO: Remove once the line above is done _x = x; _y = y; _field100 = 0; _exitDirection = 0; _currPointIndex = 0; _againDestPtFlag = 0; _stepError = 0; _againDestPointFlag = 0; _steps = 0; _flag10E = 0; _moreY = 0; _flag10F = 0; _flag113 = 0; _flag114 = 1; _flag11A = 0; _newDeltaXType = -1; _field11E = 0; _pathPoints = NULL; _rectList = NULL; startAnimation(0xD4220027, 0, -1); setDoDeltaX(getGlobalVar(0x21E60190)); } Class521::~Class521() { if (_finalizeStateCb == AnimationCallback(&Class521::sub45D620)) { setGlobalVar(0x21E60190, !getGlobalVar(0x21E60190)); } } void Class521::setPathPoints(NPointArray *pathPoints) { _pathPoints = pathPoints; } void Class521::update() { if (_newDeltaXType >= 0) { setDoDeltaX(_newDeltaXType); _newDeltaXType = -1; } AnimatedSprite::update(); if (_againDestPtFlag && _moreY == 0 && !_flag10F) { _againDestPtFlag = 0; _againDestPointFlag = 0; sendPointMessage(this, 0x2004, _againDestPt); } else if (_againDestPointFlag && _moreY == 0 && !_flag10F) { _againDestPointFlag = 0; sendMessage(this, 0x2003, _againDestPointIndex); } sub45CE10(); sub45E0A0(); } void Class521::update45C790() { Class521::update(); if (++_idleCounter >= _idleCounterMax) sub45D050(); sub45E0A0(); } uint32 Class521::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x1019: SetSpriteUpdate(NULL); break; /* NOTE: Implemented in setPathPoints case 0x2000: case 0x2001: */ case 0x2002: // Set the current position without moving _currPointIndex = param.asInteger(); _stepError = 0; _x = pathPoint(_currPointIndex).x; _y = pathPoint(_currPointIndex).y; break; case 0x2003: // Move to a point by its index { int newPointIndex = param.asInteger(); if (_moreY <= 0 && !_flag10F) { _someX = pathPoint(newPointIndex).x; _someY = pathPoint(newPointIndex).y; if (_currPointIndex < newPointIndex) { moveToNextPoint(); } else if (_currPointIndex == newPointIndex && _stepError == 0) { if (_currPointIndex == 0) { _moreY = 0; sendMessage(_parentScene, 0x2005, 0); } else if (_currPointIndex == (int)_pathPoints->size()) { _moreY = 0; sendMessage(_parentScene, 0x2006, 0); } } else { moveToPrevPoint(); } } else { _againDestPointFlag = 1; _againDestPointIndex = newPointIndex; } } break; case 0x2004: // Move to the point closest to the parameter point { int minMatchIndex = -1; int minMatchDistance, distance; NPoint pt = param.asPoint(); if (_moreY <= 0 && !_flag10F) { // Check if we're already exiting (or something) if ((pt.x <= 20 && _exitDirection == 1) || (pt.x >= 620 && _exitDirection == 3) || (pt.y <= 20 && _exitDirection == 2) || (pt.y >= 460 && _exitDirection == 4)) break; _someX = pt.x; _someY = pt.y; minMatchDistance = calcDistance(_someX, _someY, _x, _y) + 1; for (int i = _currPointIndex + 1; i < (int)_pathPoints->size(); i++) { distance = calcDistance(_someX, _someY, pathPoint(i).x, pathPoint(i).y); if (distance >= minMatchDistance) break; minMatchDistance = distance; minMatchIndex = i; } for (int i = _currPointIndex; i >= 0; i--) { distance = calcDistance(_someX, _someY, pathPoint(i).x, pathPoint(i).y); if (distance >= minMatchDistance) break; minMatchDistance = distance; minMatchIndex = i; } if (minMatchIndex == -1) { if (_currPointIndex == 0) { moveToPrevPoint(); } else { SetSpriteUpdate(NULL); } } else { if (minMatchIndex > _currPointIndex) { moveToNextPoint(); } else { moveToPrevPoint(); } } } else { _againDestPtFlag = 1; _againDestPt = pt; } } break; case 0x2007: _moreY = param.asInteger(); _steps = 0; _flag10E = 0; SetSpriteUpdate(&Class521::suMoveToPrevPoint); _lastDistance = 640; break; case 0x2008: _moreY = param.asInteger(); _steps = 0; _flag10E = 0; SetSpriteUpdate(&Class521::suMoveToNextPoint); _lastDistance = 640; break; case 0x2009: sub45CF80(); break; case 0x200A: sub45CFB0(); break; /* NOTE: Implemented in setRectList case 0x200B: case 0x200C: */ case 0x200E: sub45D180(); break; case 0x200F: sub45CD00(); _newDeltaXType = param.asInteger(); break; } return messageResult; } uint32 Class521::handleMessage45CC30(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Class521::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x100D: if (_flag10F && param.asInteger() == 0x025424A2) { gotoNextState(); } break; case 0x3002: gotoNextState(); break; } return messageResult; } uint32 Class521::handleMessage45CCA0(int messageNum, const MessageParam ¶m, Entity *sender) { switch (messageNum) { case 0x2009: sub45CF80(); break; case 0x3002: sendMessage(_parentScene, 0x200A, 0); SetMessageHandler(&Class521::handleMessage); break; } return 0; } void Class521::sub45CD00() { bool doDeltaX = _doDeltaX; SetSpriteUpdate(NULL); _againDestPtFlag = 0; _againDestPointFlag = 0; _flag10E = 0; _flag10F = 0; _flag113 = 0; _flag114 = 0; _flag11A = 0; _rectList = NULL; SetMessageHandler(&Class521::handleMessage45CC30); NextState(&Class521::sub45CFE0); startAnimation(0x35698F78, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update45C790); FinalizeState(&Class521::sub45D040); setDoDeltaX(doDeltaX ? 1 : 0); _currMoveDirection = 0; _newMoveDirection = 0; _steps = 0; _idleCounter = 0; _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; } void Class521::sub45CDC0() { if (_value112 == 1) { _lastDistance = 640; _flag113 = 0; _flag10E = 0; SetSpriteUpdate(&Class521::suMoveToNextPoint); } else if (_value112 == 2) { _lastDistance = 640; _flag113 = 0; _flag10E = 0; SetSpriteUpdate(&Class521::suMoveToPrevPoint); } } void Class521::sub45CE10() { if (_flag10E && !_flag113 && !_flag10F) { gotoNextState(); _flag114 = 0; _flag113 = 1; startAnimation(0x192ADD30, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45CFE0); } else if (!_flag10E && _steps && _flag113) { gotoNextState(); _flag113 = 0; startAnimation(0x9966B138, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45D100); } else { bool flag = false; uint index = 0; if (_rectList && _rectList->size() > 0) { while (index < _rectList->size()) { NRect r = (*_rectList)[index]; if (_x >= r.x1 && _x <= r.x2 && _y >= r.y1 && _y <= r.y2) break; } if (index < _rectList->size() && !_flag11A) flag = true; _flag11A = index < _rectList->size(); } if (flag) { gotoNextState(); sub45D0A0(); } else if (_newMoveDirection != _currMoveDirection && _flag114 && !_flag10F) { gotoNextState(); _currMoveDirection = _newMoveDirection; sub45D100(); } } } void Class521::sub45CF80() { startAnimation(0xA86A9538, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45CFE0); } void Class521::sub45CFB0() { startAnimation(0xA86A9538, -1, -1); _playBackwards = true; SetMessageHandler(&Class521::handleMessage45CCA0); SetUpdateHandler(&Class521::update); } void Class521::sub45CFE0() { startAnimation(0x35698F78, 0, -1); SetMessageHandler(&Class521::handleMessage); SetUpdateHandler(&Class521::update45C790); FinalizeState(&Class521::sub45D040); _idleCounter = 0; _currMoveDirection = 0; _newMoveDirection = 0; _steps = 0; _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; } void Class521::sub45D040() { SetUpdateHandler(&Class521::update); } void Class521::sub45D050() { startAnimation(0xB579A77C, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45CFE0); _idleCounter = 0; _idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24; } void Class521::sub45D0A0() { _flag10F = 1; gotoNextState(); startAnimation(0x9C220DA4, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); FinalizeState(&Class521::sub45D0E0); } void Class521::sub45D0E0() { _flag10F = 0; _newMoveDirection = 0; sub45D100(); } void Class521::sub45D100() { _flag114 = 1; if (_currMoveDirection == 1) { startAnimation(0xD4AA03A4, 0, -1); } else if (_currMoveDirection == 3) { startAnimation(0xD00A1364, 0, -1); } else if ((_currMoveDirection == 2 && _doDeltaX) || (_currMoveDirection == 4 && !_doDeltaX)) { sub45D180(); } else { startAnimation(0xD4220027, 0, -1); } setGlobalVar(0x21E60190, _doDeltaX ? 1 : 0); } void Class521::sub45D180() { _flag10F = 1; gotoNextState(); startAnimation(0xF46A0324, 0, -1); _value112 = 0; SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); FinalizeState(&Class521::sub45D620); sub45CDC0(); } void Class521::moveToNextPoint() { if (_currPointIndex >= (int)_pathPoints->size() - 1) { _moreY = 0; sendMessage(this, 0x1019, 0); sendMessage(_parentScene, 0x2006, 0); } else { NPoint nextPt = pathPoint(_currPointIndex + 1); NPoint currPt = pathPoint(_currPointIndex); if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) && nextPt.x >= currPt.x && (_currMoveDirection == 4 || _currMoveDirection == 2)) { if (_currMoveDirection == 4) _currMoveDirection = 2; else if (_currMoveDirection == 2) _currMoveDirection = 4; if (_flag113) sub45D390(); else sub45D350(); } else { if (_steps == 0) { gotoNextState(); _flag113 = 0; startAnimation(0x9966B138, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45D100); } _flag10E = 0; SetSpriteUpdate(&Class521::suMoveToNextPoint); _lastDistance = 640; } } } void Class521::sub45D350() { gotoNextState(); _flag10F = 1; _flag10E = 1; startAnimation(0x192ADD30, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45D390); } void Class521::sub45D390() { gotoNextState(); _flag10F = 1; startAnimation(0xF46A0324, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); FinalizeState(&Class521::sub45D620); _value112 = 1; sub45CDC0(); } void Class521::moveToPrevPoint() { if (_currPointIndex == 0 && _stepError == 0) { _moreY = 0; sendMessage(this, 0x1019, 0); sendMessage(_parentScene, 0x2005, 0); } else { NPoint prevPt; NPoint currPt; if (_stepError == 0) { prevPt = pathPoint(_currPointIndex - 1); currPt = pathPoint(_currPointIndex); } else { prevPt = pathPoint(_currPointIndex); currPt = pathPoint(_currPointIndex + 1); } if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) && currPt.x >= prevPt.x && (_currMoveDirection == 2 || _currMoveDirection == 4)) { if (_currMoveDirection == 2) _currMoveDirection = 4; else if (_currMoveDirection == 4) _currMoveDirection = 2; if (_flag113) sub45D5D0(); else sub45D580(); } else { if (_steps == 0) { gotoNextState(); _flag113 = 0; startAnimation(0x9966B138, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45D100); } _flag10E = 0; SetSpriteUpdate(&Class521::suMoveToPrevPoint); _lastDistance = 640; } } } void Class521::sub45D580() { _flag10F = 1; _flag10E = 1; FinalizeState(NULL); startAnimation(0x192ADD30, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); NextState(&Class521::sub45D5D0); } void Class521::sub45D5D0() { _flag10F = 1; FinalizeState(NULL); startAnimation(0xF46A0324, 0, -1); SetMessageHandler(&Class521::handleMessage45CC30); SetUpdateHandler(&Class521::update); FinalizeState(&Class521::sub45D620); _value112 = 2; sub45CDC0(); } void Class521::sub45D620() { _flag10F = 0; _newMoveDirection = 0; setDoDeltaX(2); sub45D100(); } void Class521::suMoveToNextPoint() { int16 newX = _x, newY = _y; if (_currPointIndex >= (int)_pathPoints->size()) { _moreY = 0; sendMessage(this, 0x1019, 0); sendMessage(_parentScene, 0x2006, 0); return; } if (_flag10E) { if (_steps <= 0) { sendMessage(this, 0x1019, 0); return; } else { _steps--; } } else if (_steps < 11) { _steps++; } bool firstTime = true; _anotherY = _steps; int stepsCtr = _steps; while (stepsCtr > 0) { NPoint pt1; NPoint pt2 = pathPoint(_currPointIndex); if (_currPointIndex + 1 >= (int)_pathPoints->size()) pt1 = pathPoint(0); else pt1 = pathPoint(_currPointIndex + 1); int16 deltaX = ABS(pt1.x - pt2.x); int16 deltaY = ABS(pt1.y - pt2.y); if (deltaX >= deltaY) { _newMoveDirection = 2; if (pt1.x < pt2.x) _newMoveDirection = 4; if (stepsCtr + _stepError >= deltaX) { stepsCtr -= deltaX; stepsCtr += _stepError; _stepError = 0; _currPointIndex++; if (_currPointIndex == (int)_pathPoints->size() - 1) stepsCtr = 0; newX = pathPoint(_currPointIndex).x; newY = pathPoint(_currPointIndex).y; } else { _stepError += stepsCtr; if (pt1.x >= pt2.x) newX += stepsCtr; else newX -= stepsCtr; if (pt1.y >= pt2.y) newY = pt2.y + (deltaY * _stepError) / deltaX; else newY = pt2.y - (deltaY * _stepError) / deltaX; stepsCtr = 0; } } else { _newMoveDirection = 3; if (pt1.y < pt2.y) _newMoveDirection = 1; if (firstTime) { if (pt1.y >= pt2.y) { stepsCtr += 7; } else { stepsCtr -= 4; if (stepsCtr < 0) stepsCtr = 0; } _anotherY = stepsCtr; } if (stepsCtr + _stepError >= deltaY) { stepsCtr -= deltaY; stepsCtr += _stepError; _stepError = 0; _currPointIndex++; if (_currPointIndex == (int)_pathPoints->size() - 1) stepsCtr = 0; newX = pathPoint(_currPointIndex).x; newY = pathPoint(_currPointIndex).y; } else { _stepError += stepsCtr; if (pt1.x >= pt2.x) newX = pt2.x + (deltaX * _stepError) / deltaY; else newX = pt2.x - (deltaX * _stepError) / deltaY; if (pt1.y >= pt2.y) newY += stepsCtr; else newY -= stepsCtr; stepsCtr = 0; } } firstTime = false; } if (_moreY != 0) { _x = newX; _y = newY; _moreY -= _anotherY; if (_moreY <= 0) { _flag10E = 1; _moreY = 0; } } else { int distance = calcDistance(_someX, _someY, _x, _y); _x = newX; _y = newY; if (newX > 20 && newX < 620 && newY > 20 && newY < 460) { _exitDirection = 0; _field100 = 1; } else if (_field100) { _someX = pathPoint(_pathPoints->size() - 1).x; _someY = pathPoint(_pathPoints->size() - 1).y; _field100 = 0; if (_x <= 20) _exitDirection = 1; else if (_x >= 620) _exitDirection = 3; else if (_y <= 20) _exitDirection = 2; else if (_y >= 460) _exitDirection = 4; if (_exitDirection != 0 && _flag10E) { _flag10E = 0; _steps = 11; } } if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) || (_exitDirection == 0 && _lastDistance + 20 < distance)) _flag10E = 1; if (distance < _lastDistance) _lastDistance = distance; if (_currPointIndex == (int)_pathPoints->size() - 1) { _flag10E = 1; _moreY = 0; sendMessage(this, 0x1019, 0); sendMessage(_parentScene, 0x2006, 0); } } } void Class521::suMoveToPrevPoint() { int16 newX = _x, newY = _y; if (_currPointIndex == 0 && _stepError == 0) { _moreY = 0; sendMessage(this, 0x1019, 0); sendMessage(_parentScene, 0x2005, 0); return; } if (_flag10E) { if (_steps <= 0) { sendMessage(this, 0x1019, 0); return; } else { _steps--; } } else if (_steps < 11) { _steps++; } bool firstTime = true; _anotherY = _steps; int stepsCtr = _steps; while (stepsCtr > 0) { if (_stepError == 0) _currPointIndex--; NPoint pt1; NPoint pt2 = pathPoint(_currPointIndex); if (_currPointIndex + 1 >= (int)_pathPoints->size()) pt1 = pathPoint(0); else pt1 = pathPoint(_currPointIndex + 1); int16 deltaX = ABS(pt1.x - pt2.x); int16 deltaY = ABS(pt1.y - pt2.y); if (deltaX >= deltaY) { _newMoveDirection = 4; if (pt1.x < pt2.x) _newMoveDirection = 2; if (_stepError == 0) _stepError = deltaX; if (stepsCtr > _stepError) { stepsCtr -= _stepError; _stepError = 0; if (_currPointIndex == 0) stepsCtr = 0; newX = pathPoint(_currPointIndex).x; newY = pathPoint(_currPointIndex).y; } else { _stepError -= stepsCtr; if (pt1.x >= pt2.x) newX -= stepsCtr; else newX += stepsCtr; if (pt1.y >= pt2.y) newY = pt2.y + (deltaY * _stepError) / deltaX; else newY = pt2.y - (deltaY * _stepError) / deltaX; stepsCtr = 0; } } else { _newMoveDirection = 1; if (pt1.y < pt2.y) _newMoveDirection = 3; if (firstTime) { if (pt1.y >= pt2.y) { stepsCtr -= 4; if (stepsCtr < 0) stepsCtr = 0; } else { stepsCtr += 7; } _anotherY = stepsCtr; } if (_stepError == 0) _stepError = deltaY; if (stepsCtr > _stepError) { stepsCtr -= _stepError; _stepError = 0; if (_currPointIndex == 0) stepsCtr = 0; newX = pathPoint(_currPointIndex).x; newY = pathPoint(_currPointIndex).y; } else { _stepError -= stepsCtr; if (pt1.x >= pt2.x) newX = pt2.x + (deltaX * _stepError) / deltaY; else newX = pt2.x - (deltaX * _stepError) / deltaY; if (pt1.y >= pt2.y) newY -= stepsCtr; else newY += stepsCtr; stepsCtr = 0; } } firstTime = false; } if (_moreY != 0) { _x = newX; _y = newY; _moreY -= _anotherY; if (_moreY <= 0) { _flag10E = 1; _moreY = 0; } } else { int distance = calcDistance(_someX, _someY, _x, _y); _x = newX; _y = newY; if (newX > 20 && newX < 620 && newY > 20 && newY < 460) { _exitDirection = 0; _field100 = 1; } else if (_field100) { _someX = pathPoint(0).x; _someY = pathPoint(0).y; _field100 = 0; if (_x <= 20) _exitDirection = 1; else if (_x >= 620) _exitDirection = 3; else if (_y <= 20) _exitDirection = 2; else if (_y >= 460) _exitDirection = 4; if (_exitDirection != 0 && _flag10E) { _flag10E = 0; _steps = 11; } } if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) || (_exitDirection == 0 && _lastDistance + 20 < distance)) _flag10E = 1; if (distance < _lastDistance) _lastDistance = distance; if (_currPointIndex == 0 && _stepError == 0) { _flag10E = 1; _moreY = 0; sendMessage(this, 0x1019, 0); sendMessage(_parentScene, 0x2005, 0); } } } void Class521::sub45E0A0() { // TODO } Class546::Class546(NeverhoodEngine *vm, Scene *parentScene) : AnimatedSprite(vm, 0x08C80144, 900, 320, 240), _soundResource(vm), _parentScene(parentScene) { setVisible(false); SetMessageHandler(&Class546::handleMessage); stopAnimation(); } uint32 Class546::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { uint32 messageResult = Sprite::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x3002: gotoNextState(); break; case 0x4808: sub44D710(); break; case 0x4809: sub44D790(); break; } return messageResult; } void Class546::sub44D710() { startAnimation(0x08C80144, 0, -1); setVisible(true); NextState(&Class546::sub44D760); _soundResource.play(calcHash("fxDoorOpen23")); } void Class546::sub44D760() { sendMessage(_parentScene, 0x2033, 0); stopAnimation(); setVisible(false); } void Class546::sub44D790() { startAnimation(0x08C80144, -1, -1); setVisible(true); NextState(&Class546::sub44D7F0); _soundResource.play(calcHash("fxDoorClose23")); } void Class546::sub44D7F0() { sendMessage(_parentScene, 0x2034, 0); stopAnimation(); } Class547::Class547(NeverhoodEngine *vm, int16 x, int16 y) : AnimatedSprite(vm, 0x1209E09F, 1100, x, y) { setDoDeltaX(1); startAnimation(0x1209E09F, 1, -1); _newStickFrameIndex = 1; } Class548::Class548(NeverhoodEngine *vm, int16 x, int16 y) : AnimatedSprite(vm, 0x1209E09F, 100, x, y) { setDoDeltaX(1); _newStickFrameIndex = 0; } Class518::Class518(NeverhoodEngine *vm, Class521 *class521) : AnimatedSprite(vm, 1100), _class521(class521) { SetUpdateHandler(&Class518::update); createSurface1(0x60281C10, 150); startAnimation(0x60281C10, -1, -1); _newStickFrameIndex = -2; } void Class518::update() { _x = _class521->getX(); _y = _class521->getY(); AnimatedSprite::update(); } Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule, true), _class521(NULL), _countdown1(0) { setGlobalVar(0x21E60190, 1); _surfaceFlag = true; SetMessageHandler(&Scene1608::handleMessage44D2A0); _class545 = insertSprite(this, 1, 1100, 198, 220); _vm->_collisionMan->addSprite(_class545); if (which < 0) { if (_vm->gameState().which == 1) which = 1; else { setRectList(0x004B47D0); insertKlayman(380, 438); _klayman2 = _klayman; _flag4 = false; _class546 = insertSprite(this); _sprite1 = insertStaticSprite(0x7D0404E8, 1100); setMessageList(0x004B46A8); setBackground(0x10080E01); setPalette(0x10080E01); _asTape = insertSprite(this, 13, 1100, 412, 443, 0x9148A011); _vm->_collisionMan->addSprite(_asTape); _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480); SetUpdateHandler(&Scene1608::update44CE90); insertMouse433(0x80E05108); insertStaticSprite(0x4B18F868, 1200); } } else if (which == 0) { _vm->gameState().which = 0; setRectList(0x004B47D0); insertKlayman(0, 438); _klayman2 = _klayman; _flag4 = false; setMessageList(0x004B46B0); setBackground(0x10080E01); setPalette(0x10080E01); _asTape = insertSprite(this, 13, 1100, 412, 443, 0x9148A011); _vm->_collisionMan->addSprite(_asTape); insertMouse433(0x80E05108); _sprite1 = insertStaticSprite(0x7D0404E8, 1100); _class546 = insertSprite(this); _klayman->setClipRect(_sprite1->getDrawRect().x, 0, 640, 480); SetUpdateHandler(&Scene1608::update44CE90); sendMessage(_class546, 0x4808, 0); insertStaticSprite(0x4B18F868, 1200); } else if (which == 2) { _vm->gameState().which = 1; _dataResource.load(0x003C0492); _roomPathPoints = _dataResource.getPointArray(calcHash("meArchroArchRoomPath")); setBackground(0x98001604); setPalette(0x98001604); _palette->addPalette("paPodRed", 65, 31, 65); insertMouse433(0x01600988); _sprite2 = insertStaticSprite(0x491F38A8, 1100); _class521 = createSprite(this, 375, 227); // Create but don't add to the sprite list yet _class547 = insertSprite(375, 227); _class548 = insertSprite(375, 227); _class521->setVisible(false); if (getGlobalVar(0xC0418A02)) { insertKlayman(373, 220); _klayman->setDoDeltaX(1); } else { insertKlayman(283, 220); } _klayman2 = _klayman; setMessageList(0x004B47A8); SetMessageHandler(&Scene1608::handleMessage44D3C0); SetUpdateHandler(&Scene1608::update44CED0); // NOTE: Setting the point array was handled by messages 0x2000 (array) and 0x2001 (count) in the original _class521->setPathPoints(_roomPathPoints); sendMessage(_class521, 0x2002, _roomPathPoints->size() - 1); _sprite3 = insertStaticSprite(0xB47026B0, 1100); _rect1.set(_sprite3->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2()); _rect3.set(_sprite2->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2()); _rect2 = _rect1; _rect2.y2 = 215; _klayman->setClipRect(_rect1); _class521->setClipRect(_rect1); _class547->setClipRect(_rect1); _class548->setClipRect(_rect1); _asTape = insertSprite(this, 13, 1100, 412, 443, 0x9148A011); _vm->_collisionMan->addSprite(_asTape); insertSprite(_class521)->setClipRect(_rect1); _flag4 = false; _flag2 = false; _flag1 = 0; setRectList(0x004B4810); } // NOTE: Not in the else because 'which' is set to 1 in the true branch if (which == 1) { _vm->gameState().which = 1; _dataResource.load(0x003C0492); _roomPathPoints = _dataResource.getPointArray(calcHash("meArchroArchRoomPath")); setBackground(0x98001604); setPalette(0x98001604); _palette->addPalette("paPodRed", 65, 31, 65); insertMouse433(0x01600988); _class521 = insertSprite(this, 375, 227); _class547 = insertSprite(375, 227); _class548 = insertSprite(375, 227); _sprite2 = insertStaticSprite(0x491F38A8, 1100); _klayman2 = createSprite(this, 439, 220); // Special Klayman handling... sendMessage(_klayman2, 0x2032, 1); _klayman2->setDoDeltaX(1); SetMessageHandler(&Scene1608::handleMessage44D470); SetUpdateHandler(&Scene1608::update44D1E0); _class547->setVisible(false); _class548->setVisible(false); // NOTE: Setting the point array was handled by messages 0x2000 (array) and 0x2001 (count) in the original _class521->setPathPoints(_roomPathPoints); sendMessage(_class521, 0x2002, 0); sendMessage(_class521, 0x2008, 90); _sprite3 = insertStaticSprite(0xB47026B0, 1100); _rect1.set(_sprite3->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2()); _rect3.set(_sprite2->getDrawRect().x, _sprite3->getDrawRect().y, 640, _sprite2->getDrawRect().y2()); _rect2 = _rect1; _rect2.y2 = 215; _klayman2->setClipRect(_rect1); _class521->setClipRect(_rect1); _class547->setClipRect(_rect1); _class548->setClipRect(_rect1); _asTape = insertSprite(this, 13, 1100, 412, 443, 0x9148A011); // ... _vm->_collisionMan->addSprite(_asTape); insertSprite(_class521)->setClipRect(_rect1); _flag4 = true; _flag2 = true; _flag1 = 0; } _palette->addPalette("paKlayRed", 0, 64, 0); } Scene1608::~Scene1608() { setGlobalVar(0xC0418A02, _klayman2->isDoDeltaX() ? 1 : 0); // Weird if (_flag4) { delete _klayman2; } else { delete _class521; } } void Scene1608::update44CE90() { Scene::update(); if (_countdown1 != 0 && (--_countdown1 == 0)) { leaveScene(0); } } void Scene1608::update44CED0() { Scene::update(); if (_flag1 == 1) { removeSurface(_klayman->getSurface()); removeEntity(_klayman); addSprite(_class521); _flag4 = true; clearRectList(); SetUpdateHandler(&Scene1608::update44CFE0); SetMessageHandler(&Scene1608::handleMessage44D510); _class547->setVisible(false); _class548->setVisible(false); _class521->setVisible(true); sendMessage(_class521, 0x2009, 0); _class521->handleUpdate(); _klayman = NULL; _flag1 = 0; } if (_klayman2->getX() <= 375) { _klayman2->setClipRect(_rect1); } else { _klayman2->setClipRect(_rect2); } } void Scene1608::update44CFE0() { Scene::update(); if (_mouseClicked) { if (_mouseClickPos.x <= 329 && _class521->getX() == 375 && _class521->getY() == 227) { sendMessage(_class521, 0x200A, 0); SetUpdateHandler(&Scene1608::update44D0C0); } else { sendPointMessage(_class521, 0x2004, _mouseClickPos); SetMessageHandler(&Scene1608::handleMessage44D470); SetUpdateHandler(&Scene1608::update44D1E0); } _mouseClicked = false; } if (_klayman2->getX() <= 375) { _klayman2->setClipRect(_rect1); } else { _klayman2->setClipRect(_rect2); } } void Scene1608::update44D0C0() { Scene::update(); if (_flag1 == 2) { _klayman = _klayman2; removeSurface(_class521->getSurface()); removeEntity(_class521); addSprite(_klayman); _flag4 = false; SetMessageHandler(&Scene1608::handleMessage44D3C0); SetUpdateHandler(&Scene1608::update44CED0); setRectList(0x004B4810); _class547->setVisible(true); _class548->setVisible(true); _class521->setVisible(false); setMessageList(0x004B4748); runMessageList(); _klayman->handleUpdate(); _flag1 = 0; } if (_klayman2->getX() <= 375) { _klayman2->setClipRect(_rect1); } else { _klayman2->setClipRect(_rect2); } } void Scene1608::update44D1E0() { Scene::update(); if (_mouseClicked) { sendPointMessage(_class521, 0x2004, _mouseClickPos); _mouseClicked = false; } if (_class521->getX() < 300) { if (_flag2) { _flag2 = false; _class521->setClipRect(_rect1); if (!_class521->isDoDeltaX()) sendMessage(_class521, 0x200E, 0); } } else if (!_flag2) { _flag2 = true; _class521->setClipRect(_rect3); } } uint32 Scene1608::handleMessage44D2A0(int messageNum, const MessageParam ¶m, Entity *sender) { Scene::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x100D: if (param.asInteger() == 0x20250B1A) { clearRectList(); _klayman->setVisible(false); showMouse(false); _sprite1->setVisible(false); sendMessage(_class546, 0x4809, 0); _countdown1 = 28; } break; case 0x200D: sendMessage(_parentModule, 0x200D, 0); break; case 0x4826: if (sender == _asTape) { sendEntityMessage(_klayman2, 0x1014, _asTape); setMessageList(0x004B4770); } else if (sender == _class545) { setMessageList(0x004B46C8); } break; } return 0; } uint32 Scene1608::handleMessage44D3C0(int messageNum, const MessageParam ¶m, Entity *sender) { Scene::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x100D: if (param.asInteger() == 0x60842040) { _flag1 = true; } break; case 0x200D: sendMessage(_parentModule, 0x200D, 0); break; case 0x4826: if (sender == _class545) { sendEntityMessage(_klayman2, 0x1014, _class545); setMessageList(0x004B4760); } break; } return 0; } uint32 Scene1608::handleMessage44D470(int messageNum, const MessageParam ¶m, Entity *sender) { Scene::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x2005: leaveScene(1); break; case 0x2006: SetMessageHandler(&Scene1608::handleMessage44D510); SetUpdateHandler(&Scene1608::update44CFE0); sendMessage(_class521, 0x200F, 1); break; case 0x200D: sendMessage(_parentModule, 0x200D, 0); break; } return 0; } uint32 Scene1608::handleMessage44D510(int messageNum, const MessageParam ¶m, Entity *sender) { Scene::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x200A: _flag1 = 2; break; case 0x200D: sendMessage(_parentModule, 0x200D, 0); break; } return 0; } Scene1609::Scene1609(NeverhoodEngine *vm, Module *parentModule, int which) : Scene(vm, parentModule, true), _soundResource(vm), _countdown1(1), _index1(0), _index3(0), _flag5(true), _flag6(false) { // TODO _vm->gameModule()->initScene3011Vars(); _index2 = getGlobalVar(0x2414C2F2); _surfaceFlag = true; SetMessageHandler(&Scene1609::handleMessage); SetUpdateHandler(&Scene1609::update); setBackground(0x92124A14); setPalette(0x92124A14); for (int i = 0; i < 12; i++) _asSymbols[i] = insertSprite(i, false); _ssButton = insertSprite(this, true); _vm->_collisionMan->addSprite(_ssButton); insertMouse435(0x24A10929, 20, 620); _soundResource.load(0x68E25540); } void Scene1609::update() { if (!_flag6 && _countdown1 != 0 && (--_countdown1 == 0)) { if (_flag5) { _index1++; if (_index1 >= 12) _index1 = 0; _asSymbols[_index3]->change(_index1 + 12, _index1 == (int)getSubVar(0x04909A50, _index2)); _flag5 = false; _countdown1 = 36; } else { _asSymbols[_index3]->hide(); _flag5 = true; _countdown1 = 12; } } if (_flag6 && !_soundResource.isPlaying()) { leaveScene(1); } Scene::update(); } uint32 Scene1609::handleMessage(int messageNum, const MessageParam ¶m, Entity *sender) { Scene::handleMessage(messageNum, param, sender); switch (messageNum) { case 0x0001: // TODO: Debug stuff if (param.asPoint().x <= 20 || param.asPoint().x >= 620) leaveScene(0); break; // TODO: Debug stuff case 0x2000: if (!_flag6) { if (_flag5) _asSymbols[_index3]->change(_index1 + 12, false); _asSymbols[_index3]->stopSound(); _index3++; if (_index3 >= 12) { if (testVars()) { _soundResource.play(); setGlobalVar(0x2C531AF8, 1); _flag6 = true; } else { _index3 = 0; for (int i = 0; i < 12; i++) _asSymbols[i]->hide(); } } _flag5 = true; _countdown1 = 1; } break; } return 0; } bool Scene1609::testVars() { int index1 = 0; do { int cmpIndex = _asSymbols[0]->getIndex(); if (!_asSymbols[0]->getFlag1()) cmpIndex -= 12; if ((int)getSubVar(0x04909A50, index1) == cmpIndex) break; index1++; } while(1); for (int index2 = 0; index2 < 12; index2++) { int cmpIndex = _asSymbols[index2]->getIndex(); if (!_asSymbols[index2]->getFlag1()) cmpIndex -= 12; if ((int)getSubVar(0x04909A50, index1) != cmpIndex) return false; _index1++; if (_index1 >= 12) _index1 = 0; _index2++; } return true; } } // End of namespace Neverhood