aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/engine/scene_lok.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/engine/scene_lok.cpp')
-rw-r--r--engines/kyra/engine/scene_lok.cpp1301
1 files changed, 1301 insertions, 0 deletions
diff --git a/engines/kyra/engine/scene_lok.cpp b/engines/kyra/engine/scene_lok.cpp
new file mode 100644
index 0000000000..51348c5392
--- /dev/null
+++ b/engines/kyra/engine/scene_lok.cpp
@@ -0,0 +1,1301 @@
+/* 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 "kyra/engine/kyra_lok.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+#include "kyra/engine/sprites.h"
+#include "kyra/graphics/animator_lok.h"
+#include "kyra/engine/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void KyraEngine_LoK::enterNewScene(int sceneId, int facing, int unk1, int unk2, int brandonAlive) {
+ int unkVar1 = 1;
+ _screen->hideMouse();
+
+ // TODO: Check how the original handled sfx still playing
+ _sound->stopAllSoundEffects();
+
+ if (_flags.platform == Common::kPlatformFMTowns) {
+ int newSfxFile = -1;
+ if (_currentCharacter->sceneId == 7 && sceneId == 24)
+ newSfxFile = 2;
+ else if (_currentCharacter->sceneId == 25 && sceneId == 109)
+ newSfxFile = 3;
+ else if (_currentCharacter->sceneId == 120 && sceneId == 37)
+ newSfxFile = 4;
+ else if (_currentCharacter->sceneId == 52 && sceneId == 199)
+ newSfxFile = 5;
+ else if (_currentCharacter->sceneId == 37 && sceneId == 120)
+ newSfxFile = 3;
+ else if (_currentCharacter->sceneId == 109 && sceneId == 25)
+ newSfxFile = 2;
+ else if (_currentCharacter->sceneId == 24 && sceneId == 7)
+ newSfxFile = 1;
+
+ if (newSfxFile != -1) {
+ _curSfxFile = newSfxFile;
+ _sound->loadSoundFile(_curSfxFile);
+ }
+ }
+
+ switch (_currentCharacter->sceneId) {
+ case 1:
+ if (sceneId == 0) {
+ moveCharacterToPos(0, 0, _currentCharacter->x1, 84);
+ unkVar1 = 0;
+ }
+ break;
+
+ case 3:
+ if (sceneId == 2) {
+ moveCharacterToPos(0, 6, 155, _currentCharacter->y1);
+ unkVar1 = 0;
+ }
+ break;
+
+ case 26:
+ if (sceneId == 27) {
+ moveCharacterToPos(0, 6, 155, _currentCharacter->y1);
+ unkVar1 = 0;
+ }
+ break;
+
+ case 44:
+ if (sceneId == 45) {
+ moveCharacterToPos(0, 2, 192, _currentCharacter->y1);
+ unkVar1 = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (unkVar1 && unk1) {
+ int xpos = _currentCharacter->x1;
+ int ypos = _currentCharacter->y1;
+ switch (facing) {
+ case 0:
+ ypos = _currentCharacter->y1 - 6;
+ break;
+
+ case 2:
+ xpos = 336;
+ break;
+
+ case 4:
+ ypos = 143;
+ break;
+
+ case 6:
+ xpos = -16;
+ break;
+
+ default:
+ break;
+ }
+
+ moveCharacterToPos(0, facing, xpos, ypos);
+ }
+
+ for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i)
+ _movieObjects[i]->close();
+
+ if (!brandonAlive) {
+ _emc->init(&_scriptClick, &_scriptClickData);
+ _emc->start(&_scriptClick, 5);
+ while (_emc->isValid(&_scriptClick))
+ _emc->run(&_scriptClick);
+ }
+
+ memset(_entranceMouseCursorTracks, 0xFF, sizeof(_entranceMouseCursorTracks));
+ _currentCharacter->sceneId = sceneId;
+
+ assert(sceneId < _roomTableSize);
+ assert(_roomTable[sceneId].nameIndex < _roomFilenameTableSize);
+
+ Room *currentRoom = &_roomTable[sceneId];
+
+ setupSceneResource(sceneId);
+
+ _currentRoom = sceneId;
+
+ int tableId = _roomTable[sceneId].nameIndex;
+ char fileNameBuffer[32];
+ strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
+ strcat(fileNameBuffer, ".DAT");
+ _sprites->loadDat(fileNameBuffer, _sceneExits);
+ _sprites->setupSceneAnims();
+ _emc->unload(&_scriptClickData);
+ loadSceneMsc();
+
+ _walkBlockNorth = currentRoom->northExit;
+ _walkBlockEast = currentRoom->eastExit;
+ _walkBlockSouth = currentRoom->southExit;
+ _walkBlockWest = currentRoom->westExit;
+
+ if (_walkBlockNorth == 0xFFFF)
+ _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF) + 3);
+ if (_walkBlockEast == 0xFFFF)
+ _screen->blockOutRegion(312, 0, 8, 139);
+ if (_walkBlockSouth == 0xFFFF)
+ _screen->blockOutRegion(0, 135, 320, 8);
+ if (_walkBlockWest == 0xFFFF)
+ _screen->blockOutRegion(0, 0, 8, 139);
+
+ if (!brandonAlive)
+ updatePlayerItemsForScene();
+
+ startSceneScript(brandonAlive);
+ setupSceneItems();
+
+ initSceneData(facing, unk2, brandonAlive);
+
+ _loopFlag2 = 0;
+ _screen->showMouse();
+ if (!brandonAlive)
+ seq_poisonDeathNow(0);
+ updateMousePointer(true);
+ _changedScene = true;
+}
+
+void KyraEngine_LoK::transcendScenes(int roomIndex, int roomName) {
+ assert(roomIndex < _roomTableSize);
+
+ if (_flags.isTalkie) {
+ char file[32];
+ assert(roomIndex < _roomTableSize);
+ int tableId = _roomTable[roomIndex].nameIndex;
+ assert(tableId < _roomFilenameTableSize);
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".VRM");
+ _res->unloadPakFile(file);
+ }
+
+ _roomTable[roomIndex].nameIndex = roomName;
+ _unkScreenVar2 = 1;
+ _unkScreenVar3 = 1;
+ _unkScreenVar1 = 0;
+ _brandonPosX = _currentCharacter->x1;
+ _brandonPosY = _currentCharacter->y1;
+ enterNewScene(roomIndex, _currentCharacter->facing, 0, 0, 0);
+ _unkScreenVar1 = 1;
+ _unkScreenVar2 = 0;
+ _unkScreenVar3 = 0;
+}
+
+void KyraEngine_LoK::setSceneFile(int roomIndex, int roomName) {
+ assert(roomIndex < _roomTableSize);
+ _roomTable[roomIndex].nameIndex = roomName;
+}
+
+void KyraEngine_LoK::moveCharacterToPos(int character, int facing, int xpos, int ypos) {
+ Character *ch = &_characterList[character];
+ ch->facing = facing;
+ _screen->hideMouse();
+ xpos = (int16)(xpos & 0xFFFC);
+ ypos = (int16)(ypos & 0xFFFE);
+ _timer->disable(19);
+ _timer->disable(14);
+ _timer->disable(18);
+ uint32 nextFrame = 0;
+
+ switch (facing) {
+ case 0:
+ while (ypos < ch->y1) {
+ nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
+ setCharacterPositionWithUpdate(character);
+ delayUntil(nextFrame, true);
+ }
+ break;
+
+ case 2:
+ while (ch->x1 < xpos) {
+ nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
+ setCharacterPositionWithUpdate(character);
+ delayUntil(nextFrame, true);
+ }
+ break;
+
+ case 4:
+ while (ypos > ch->y1) {
+ nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
+ setCharacterPositionWithUpdate(character);
+ delayUntil(nextFrame, true);
+ }
+ break;
+
+ case 6:
+ while (ch->x1 > xpos) {
+ nextFrame = _timer->getDelay(5 + character) * _tickLength + _system->getMillis();
+ setCharacterPositionWithUpdate(character);
+ delayUntil(nextFrame, true);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ _timer->enable(19);
+ _timer->enable(14);
+ _timer->enable(18);
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::setCharacterPositionWithUpdate(int character) {
+ setCharacterPosition(character, 0);
+ _sprites->updateSceneAnims();
+ _timer->update();
+ _animator->updateAllObjectShapes();
+ updateTextFade();
+
+ if (_currentCharacter->sceneId == 210)
+ updateKyragemFading();
+}
+
+int KyraEngine_LoK::setCharacterPosition(int character, int *facingTable) {
+ if (character == 0) {
+ _currentCharacter->x1 += _charAddXPosTable[_currentCharacter->facing];
+ _currentCharacter->y1 += _charAddYPosTable[_currentCharacter->facing];
+ setCharacterPositionHelper(0, facingTable);
+ return 1;
+ } else {
+ _characterList[character].x1 += _charAddXPosTable[_characterList[character].facing];
+ _characterList[character].y1 += _charAddYPosTable[_characterList[character].facing];
+ if (_characterList[character].sceneId == _currentCharacter->sceneId)
+ setCharacterPositionHelper(character, 0);
+ }
+ return 0;
+}
+
+void KyraEngine_LoK::setCharacterPositionHelper(int character, int *facingTable) {
+ Character *ch = &_characterList[character];
+ ++ch->currentAnimFrame;
+ int facing = ch->facing;
+ if (facingTable) {
+ if (*facingTable != *(facingTable - 1)) {
+ if (*(facingTable - 1) == *(facingTable + 1)) {
+ facing = getOppositeFacingDirection(*(facingTable - 1));
+ *facingTable = *(facingTable - 1);
+ }
+ }
+ }
+
+ if (facing == 0) {
+ ++_characterFacingZeroCount[character];
+ } else {
+ bool resetTables = false;
+ if (facing != 7) {
+ if (facing - 1 != 0) {
+ if (facing != 4) {
+ if (facing == 3 || facing == 5) {
+ if (_characterFacingFourCount[character] > 2)
+ facing = 4;
+ resetTables = true;
+ }
+ } else {
+ ++_characterFacingFourCount[character];
+ }
+ } else {
+ if (_characterFacingZeroCount[character] > 2)
+ facing = 0;
+ resetTables = true;
+ }
+ } else {
+ if (_characterFacingZeroCount[character] > 2)
+ facing = 0;
+ resetTables = true;
+ }
+
+ if (resetTables) {
+ _characterFacingZeroCount[character] = 0;
+ _characterFacingFourCount[character] = 0;
+ }
+ }
+
+ static const uint16 maxAnimationFrame[] = {
+ 0x000F, 0x0031, 0x0055, 0x0000, 0x0000, 0x0000,
+ 0x0008, 0x002A, 0x004E, 0x0000, 0x0000, 0x0000,
+ 0x0022, 0x0046, 0x006A, 0x0000, 0x0000, 0x0000,
+ 0x001D, 0x0041, 0x0065, 0x0000, 0x0000, 0x0000,
+ 0x001F, 0x0043, 0x0067, 0x0000, 0x0000, 0x0000,
+ 0x0028, 0x004C, 0x0070, 0x0000, 0x0000, 0x0000,
+ 0x0023, 0x0047, 0x006B, 0x0000, 0x0000, 0x0000
+ };
+
+ if (facing == 0) {
+ if (maxAnimationFrame[36 + character] > ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[36 + character];
+ if (maxAnimationFrame[30 + character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[36 + character];
+ } else if (facing == 4) {
+ if (maxAnimationFrame[18 + character] > ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[18 + character];
+ if (maxAnimationFrame[12 + character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[18 + character];
+ } else {
+ if (maxAnimationFrame[18 + character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[30 + character];
+ if (maxAnimationFrame[character] == ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[6 + character];
+ if (maxAnimationFrame[character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[6 + character] + 2;
+ }
+
+ if (character == 0 && (_brandonStatusBit & 0x10))
+ ch->currentAnimFrame = 88;
+
+ _animator->animRefreshNPC(character);
+}
+
+void KyraEngine_LoK::loadSceneMsc() {
+ assert(_currentCharacter->sceneId < _roomTableSize);
+ int tableId = _roomTable[_currentCharacter->sceneId].nameIndex;
+ assert(tableId < _roomFilenameTableSize);
+ char fileNameBuffer[32];
+ strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
+ strcat(fileNameBuffer, ".MSC");
+ _screen->fillRect(0, 0, 319, 199, 0, 5);
+ _res->exists(fileNameBuffer, true);
+ _screen->loadBitmap(fileNameBuffer, 3, 5, 0);
+}
+
+void KyraEngine_LoK::startSceneScript(int brandonAlive) {
+ assert(_currentCharacter->sceneId < _roomTableSize);
+ int tableId = _roomTable[_currentCharacter->sceneId].nameIndex;
+ assert(tableId < _roomFilenameTableSize);
+ char fileNameBuffer[32];
+ strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
+ strcat(fileNameBuffer, ".CPS");
+ _screen->clearPage(3);
+ _res->exists(fileNameBuffer, true);
+ // FIXME: check this hack for amiga version
+ _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? &_screen->getPalette(0) : 0));
+ _sprites->loadSceneShapes();
+ _exitListPtr = 0;
+
+ _scaleMode = 1;
+ for (int i = 0; i < 145; ++i)
+ _scaleTable[i] = 256;
+
+ clearNoDropRects();
+ _emc->init(&_scriptClick, &_scriptClickData);
+ strcpy(fileNameBuffer, _roomFilenameTable[tableId]);
+ strcat(fileNameBuffer, ".EMC");
+ _res->exists(fileNameBuffer, true);
+ _emc->unload(&_scriptClickData);
+ _emc->load(fileNameBuffer, &_scriptClickData, &_opcodes);
+ _emc->start(&_scriptClick, 0);
+ _scriptClick.regs[0] = _currentCharacter->sceneId;
+ _scriptClick.regs[7] = brandonAlive;
+
+ while (_emc->isValid(&_scriptClick))
+ _emc->run(&_scriptClick);
+}
+
+void KyraEngine_LoK::initSceneData(int facing, int unk1, int brandonAlive) {
+ int16 xpos2 = 0;
+ int setFacing = 1;
+
+ int16 xpos = 0, ypos = 0;
+
+ if (_brandonPosX == -1 && _brandonPosY == -1) {
+ switch (facing + 1) {
+ case 0:
+ xpos = ypos = -1;
+ break;
+
+ case 1: case 2: case 8:
+ xpos = _sceneExits.southXPos;
+ ypos = _sceneExits.southYPos;
+ break;
+
+ case 3:
+ xpos = _sceneExits.westXPos;
+ ypos = _sceneExits.westYPos;
+ break;
+
+ case 4: case 5: case 6:
+ xpos = _sceneExits.northXPos;
+ ypos = _sceneExits.northYPos;
+ break;
+
+ case 7:
+ xpos = _sceneExits.eastXPos;
+ ypos = _sceneExits.eastYPos;
+ break;
+
+ default:
+ break;
+ }
+
+ if ((uint8)(_northExitHeight & 0xFF) + 2 >= ypos)
+ ypos = (_northExitHeight & 0xFF) + 4;
+ if (xpos >= 308)
+ xpos = 304;
+ if ((uint8)(_northExitHeight >> 8) - 2 <= ypos)
+ ypos = (_northExitHeight >> 8) - 4;
+ if (xpos <= 12)
+ xpos = 16;
+ }
+
+ if (_brandonPosX > -1)
+ xpos = _brandonPosX;
+ if (_brandonPosY > -1)
+ ypos = _brandonPosY;
+
+ int16 ypos2 = 0;
+ if (_brandonPosX > -1 && _brandonPosY > -1) {
+ switch (_currentCharacter->sceneId) {
+ case 1:
+ _currentCharacter->x1 = xpos;
+ _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = ypos;
+ _currentCharacter->y2 = ypos;
+ facing = 4;
+ xpos2 = 192;
+ ypos2 = 104;
+ setFacing = 0;
+ unk1 = 1;
+ break;
+
+ case 3:
+ _currentCharacter->x1 = xpos;
+ _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = ypos;
+ _currentCharacter->y2 = ypos;
+ facing = 2;
+ xpos2 = 204;
+ ypos2 = 94;
+ setFacing = 0;
+ unk1 = 1;
+ break;
+
+ case 26:
+ _currentCharacter->x1 = xpos;
+ _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = ypos;
+ _currentCharacter->y2 = ypos;
+ facing = 2;
+ xpos2 = 192;
+ ypos2 = 128;
+ setFacing = 0;
+ unk1 = 1;
+ break;
+
+ case 44:
+ _currentCharacter->x1 = xpos;
+ _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = ypos;
+ _currentCharacter->y2 = ypos;
+ facing = 6;
+ xpos2 = 156;
+ ypos2 = 96;
+ setFacing = 0;
+ unk1 = 1;
+ break;
+
+ case 37:
+ _currentCharacter->x1 = xpos;
+ _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = ypos;
+ _currentCharacter->y2 = ypos;
+ facing = 2;
+ xpos2 = 148;
+ ypos2 = 114;
+ setFacing = 0;
+ unk1 = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ _brandonPosX = _brandonPosY = -1;
+
+ if (unk1 && setFacing) {
+ ypos2 = ypos;
+ xpos2 = xpos;
+ switch (facing) {
+ case 0:
+ ypos = 142;
+ break;
+
+ case 2:
+ xpos = -16;
+ break;
+
+ case 4:
+ ypos = (uint8)(_northExitHeight & 0xFF) - 4;
+ break;
+
+ case 6:
+ xpos = 336;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ xpos2 = (int16)(xpos2 & 0xFFFC);
+ ypos2 = (int16)(ypos2 & 0xFFFE);
+ xpos = (int16)(xpos & 0xFFFC);
+ ypos = (int16)(ypos & 0xFFFE);
+ _currentCharacter->facing = facing;
+ _currentCharacter->x1 = xpos;
+ _currentCharacter->x2 = xpos;
+ _currentCharacter->y1 = ypos;
+ _currentCharacter->y2 = ypos;
+
+ initSceneObjectList(brandonAlive);
+
+ if (unk1 && brandonAlive == 0)
+ moveCharacterToPos(0, facing, xpos2, ypos2);
+
+ _scriptClick.regs[4] = _itemInHand;
+ _scriptClick.regs[7] = brandonAlive;
+ _emc->start(&_scriptClick, 3);
+ while (_emc->isValid(&_scriptClick))
+ _emc->run(&_scriptClick);
+}
+
+void KyraEngine_LoK::initSceneObjectList(int brandonAlive) {
+ for (int i = 0; i < 28; ++i)
+ _animator->actors()[i].active = 0;
+
+ int startAnimFrame = 0;
+
+ Animator_LoK::AnimObject *curAnimState = _animator->actors();
+ curAnimState->active = 1;
+ curAnimState->drawY = _currentCharacter->y1;
+ curAnimState->sceneAnimPtr = _shapes[_currentCharacter->currentAnimFrame];
+ curAnimState->animFrameNumber = _currentCharacter->currentAnimFrame;
+ startAnimFrame = _currentCharacter->currentAnimFrame - 7;
+ int xOffset = _defaultShapeTable[startAnimFrame].xOffset;
+ int yOffset = _defaultShapeTable[startAnimFrame].yOffset;
+
+ if (_scaleMode) {
+ curAnimState->x1 = _currentCharacter->x1;
+ curAnimState->y1 = _currentCharacter->y1;
+
+ _animator->_brandonScaleX = _scaleTable[_currentCharacter->y1];
+ _animator->_brandonScaleY = _scaleTable[_currentCharacter->y1];
+
+ curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8;
+ curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8;
+ } else {
+ curAnimState->x1 = _currentCharacter->x1 + xOffset;
+ curAnimState->y1 = _currentCharacter->y1 + yOffset;
+ }
+
+ curAnimState->x2 = curAnimState->x1;
+ curAnimState->y2 = curAnimState->y1;
+ curAnimState->refreshFlag = 1;
+ curAnimState->bkgdChangeFlag = 1;
+ _animator->clearQueue();
+ _animator->addObjectToQueue(curAnimState);
+
+ int listAdded = 0;
+ int addedObjects = 1;
+
+ for (int i = 1; i < 5; ++i) {
+ Character *ch = &_characterList[i];
+ curAnimState = &_animator->actors()[addedObjects];
+ if (ch->sceneId != _currentCharacter->sceneId) {
+ curAnimState->active = 0;
+ curAnimState->refreshFlag = 0;
+ curAnimState->bkgdChangeFlag = 0;
+ ++addedObjects;
+ continue;
+ }
+
+ curAnimState->drawY = ch->y1;
+ curAnimState->sceneAnimPtr = _shapes[ch->currentAnimFrame];
+ curAnimState->animFrameNumber = ch->currentAnimFrame;
+ startAnimFrame = ch->currentAnimFrame - 7;
+ xOffset = _defaultShapeTable[startAnimFrame].xOffset;
+ yOffset = _defaultShapeTable[startAnimFrame].yOffset;
+ if (_scaleMode) {
+ curAnimState->x1 = ch->x1;
+ curAnimState->y1 = ch->y1;
+
+ _animator->_brandonScaleX = _scaleTable[ch->y1];
+ _animator->_brandonScaleY = _scaleTable[ch->y1];
+
+ curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8;
+ curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8;
+ } else {
+ curAnimState->x1 = ch->x1 + xOffset;
+ curAnimState->y1 = ch->y1 + yOffset;
+ }
+ curAnimState->x2 = curAnimState->x1;
+ curAnimState->y2 = curAnimState->y1;
+ curAnimState->active = 1;
+ curAnimState->refreshFlag = 1;
+ curAnimState->bkgdChangeFlag = 1;
+
+ if (ch->facing >= 1 && ch->facing <= 3)
+ curAnimState->flags |= 1;
+ else if (ch->facing >= 5 && ch->facing <= 7)
+ curAnimState->flags &= 0xFFFFFFFE;
+
+ _animator->addObjectToQueue(curAnimState);
+
+ ++addedObjects;
+ ++listAdded;
+ if (listAdded < 2)
+ i = 5;
+ }
+
+ for (int i = 0; i < 11; ++i) {
+ curAnimState = &_animator->sprites()[i];
+
+ if (_sprites->_anims[i].play) {
+ curAnimState->active = 1;
+ curAnimState->refreshFlag = 1;
+ curAnimState->bkgdChangeFlag = 1;
+ } else {
+ curAnimState->active = 0;
+ curAnimState->refreshFlag = 0;
+ curAnimState->bkgdChangeFlag = 0;
+ }
+ curAnimState->height = _sprites->_anims[i].height;
+ curAnimState->height2 = _sprites->_anims[i].height2;
+ curAnimState->width = _sprites->_anims[i].width + 1;
+ curAnimState->width2 = _sprites->_anims[i].width2;
+ curAnimState->drawY = _sprites->_anims[i].drawY;
+ curAnimState->x1 = curAnimState->x2 = _sprites->_anims[i].x;
+ curAnimState->y1 = curAnimState->y2 = _sprites->_anims[i].y;
+ curAnimState->background = _sprites->_anims[i].background;
+ curAnimState->sceneAnimPtr = _sprites->_sceneShapes[_sprites->_anims[i].sprite];
+
+ curAnimState->disable = _sprites->_anims[i].disable;
+
+ if (_sprites->_anims[i].unk2)
+ curAnimState->flags = 0x800;
+ else
+ curAnimState->flags = 0;
+
+ if (_sprites->_anims[i].flipX)
+ curAnimState->flags |= 0x1;
+
+ _animator->addObjectToQueue(curAnimState);
+ }
+
+ for (int i = 0; i < 12; ++i) {
+ curAnimState = &_animator->items()[i];
+ Room *curRoom = &_roomTable[_currentCharacter->sceneId];
+ byte curItem = curRoom->itemsTable[i];
+ if (curItem != 0xFF) {
+ curAnimState->drawY = curRoom->itemsYPos[i];
+ curAnimState->sceneAnimPtr = _shapes[216 + curItem];
+ curAnimState->animFrameNumber = (int16)0xFFFF;
+ curAnimState->y1 = curRoom->itemsYPos[i];
+ curAnimState->x1 = curRoom->itemsXPos[i];
+
+ curAnimState->x1 -= (_animator->fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1;
+ curAnimState->y1 -= _animator->fetchAnimHeight(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY]);
+
+ curAnimState->x2 = curAnimState->x1;
+ curAnimState->y2 = curAnimState->y1;
+
+ curAnimState->active = 1;
+ curAnimState->refreshFlag = 1;
+ curAnimState->bkgdChangeFlag = 1;
+
+ _animator->addObjectToQueue(curAnimState);
+ } else {
+ curAnimState->active = 0;
+ curAnimState->refreshFlag = 0;
+ curAnimState->bkgdChangeFlag = 0;
+ }
+ }
+
+ _animator->preserveAnyChangedBackgrounds();
+ curAnimState = _animator->actors();
+ curAnimState->bkgdChangeFlag = 1;
+ curAnimState->refreshFlag = 1;
+ for (int i = 1; i < 28; ++i) {
+ curAnimState = &_animator->objects()[i];
+ if (curAnimState->active) {
+ curAnimState->bkgdChangeFlag = 1;
+ curAnimState->refreshFlag = 1;
+ }
+ }
+ _animator->restoreAllObjectBackgrounds();
+ _animator->preserveAnyChangedBackgrounds();
+ _animator->prepDrawAllObjects();
+ initSceneScreen(brandonAlive);
+ _animator->copyChangedObjectsForward(0);
+}
+
+void KyraEngine_LoK::initSceneScreen(int brandonAlive) {
+ if (_flags.platform == Common::kPlatformAmiga) {
+ if (_unkScreenVar1 && !queryGameFlag(0xF0)) {
+ _screen->getPalette(2).clear();
+ if (_currentCharacter->sceneId != 117 || !queryGameFlag(0xB3))
+ _screen->setScreenPalette(_screen->getPalette(2));
+ }
+
+ if (_unkScreenVar2 == 1)
+ _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false);
+ else
+ _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0, Screen::CR_NO_P_CHECK);
+
+ if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
+ if (_currentCharacter->sceneId == 45 && _cauldronState)
+ _screen->getPalette(0).copy(_screen->getPalette(4), 12, 1);
+
+ if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245 && (_brandonStatusBit & 1))
+ _screen->copyPalette(0, 10);
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+ } else {
+ if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
+ for (int i = 0; i < 60; ++i) {
+ uint16 col = _screen->getPalette(0)[684 + i];
+ col += _screen->getPalette(1)[684 + i] << 1;
+ col >>= 2;
+ _screen->getPalette(0)[684 + i] = col;
+ }
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+
+ if (_unkScreenVar2 == 1)
+ _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false);
+ else
+ _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0);
+
+ if (_unkScreenVar1 && _paletteChanged) {
+ if (!queryGameFlag(0xA0)) {
+ _screen->getPalette(0).copy(_screen->getPalette(1), 228, 20);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ _screen->getPalette(0).clear();
+ }
+ }
+ }
+
+ if (!_emc->start(&_scriptClick, 2))
+ error("Could not start script function 2 of scene script");
+
+ _scriptClick.regs[7] = brandonAlive;
+
+ while (_emc->isValid(&_scriptClick))
+ _emc->run(&_scriptClick);
+
+ setTextFadeTimerCountdown(-1);
+
+ if (_currentCharacter->sceneId == 210) {
+ if (_itemInHand != kItemNone)
+ magicOutMouseItem(2, -1);
+
+ _screen->hideMouse();
+ for (int i = 0; i < 10; ++i) {
+ if (_currentCharacter->inventoryItems[i] != kItemNone)
+ magicOutMouseItem(2, i);
+ }
+ _screen->showMouse();
+ }
+}
+
+int KyraEngine_LoK::handleSceneChange(int xpos, int ypos, int unk1, int frameReset) {
+ if (queryGameFlag(0xEF))
+ unk1 = 0;
+
+ int sceneId = _currentCharacter->sceneId;
+ _pathfinderFlag = 0;
+
+ if (xpos < 12) {
+ if (_roomTable[sceneId].westExit != 0xFFFF) {
+ xpos = 12;
+ ypos = _sceneExits.westYPos;
+ _pathfinderFlag = 7;
+ }
+ } else if (xpos >= 308) {
+ if (_roomTable[sceneId].eastExit != 0xFFFF) {
+ xpos = 307;
+ ypos = _sceneExits.eastYPos;
+ _pathfinderFlag = 13;
+ }
+ }
+
+ if (ypos <= (_northExitHeight & 0xFF) + 2) {
+ if (_roomTable[sceneId].northExit != 0xFFFF) {
+ xpos = _sceneExits.northXPos;
+ ypos = _northExitHeight & 0xFF;
+ _pathfinderFlag = 14;
+ }
+ } else if (ypos >= 136) {
+ if (_roomTable[sceneId].southExit != 0xFFFF) {
+ xpos = _sceneExits.southXPos;
+ ypos = 136;
+ _pathfinderFlag = 11;
+ }
+ }
+
+ int temp = xpos - _currentCharacter->x1;
+ if (ABS(temp) < 4) {
+ temp = ypos - _currentCharacter->y1;
+ if (ABS(temp) < 2)
+ return 0;
+ }
+
+ int x = (int16)(_currentCharacter->x1 & 0xFFFC);
+ int y = (int16)(_currentCharacter->y1 & 0xFFFE);
+ xpos = (int16)(xpos & 0xFFFC);
+ ypos = (int16)(ypos & 0xFFFE);
+
+ int ret = findWay(x, y, xpos, ypos, _movFacingTable, 150);
+ _pathfinderFlag = 0;
+
+ if (ret >= _lastFindWayRet)
+ _lastFindWayRet = ret;
+
+ if (ret == 0x7D00 || ret == 0)
+ return 0;
+
+ return processSceneChange(_movFacingTable, unk1, frameReset);
+}
+
+int KyraEngine_LoK::processSceneChange(int *table, int unk1, int frameReset) {
+ if (queryGameFlag(0xEF))
+ unk1 = 0;
+
+ int *tableStart = table;
+ _sceneChangeState = 0;
+ _loopFlag2 = 0;
+ bool running = true;
+ int returnValue = 0;
+ uint32 nextFrame = 0;
+
+ while (running) {
+ bool forceContinue = false;
+ switch (*table) {
+ case 0: case 1: case 2:
+ case 3: case 4: case 5:
+ case 6: case 7:
+ _currentCharacter->facing = getOppositeFacingDirection(*table);
+ break;
+
+ case 8:
+ forceContinue = true;
+ running = false;
+ break;
+
+ default:
+ ++table;
+ forceContinue = true;
+ }
+
+ returnValue = changeScene(_currentCharacter->facing);
+ if (returnValue)
+ running = false;
+
+ if (unk1) {
+ if (skipFlag()) {
+ resetSkipFlag(false);
+ running = false;
+ _sceneChangeState = 1;
+ }
+ }
+
+ if (forceContinue || !running)
+ continue;
+
+ int temp = 0;
+ if (table == tableStart || table[1] == 8)
+ temp = setCharacterPosition(0, 0);
+ else
+ temp = setCharacterPosition(0, table);
+
+ if (temp)
+ ++table;
+
+ nextFrame = _timer->getDelay(5) * _tickLength + _system->getMillis();
+ while (_system->getMillis() < nextFrame) {
+ _timer->update();
+
+ if (_currentCharacter->sceneId == 210) {
+ updateKyragemFading();
+ if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) {
+ *table = 8;
+ running = false;
+ break;
+ }
+ }
+
+ if ((nextFrame - _system->getMillis()) >= 10)
+ delay(10, true);
+ }
+ }
+
+ if (frameReset && !(_brandonStatusBit & 2))
+ _currentCharacter->currentAnimFrame = 7;
+
+ _animator->animRefreshNPC(0);
+ _animator->updateAllObjectShapes();
+ return returnValue;
+}
+
+int KyraEngine_LoK::changeScene(int facing) {
+ if (queryGameFlag(0xEF)) {
+ if (_currentCharacter->sceneId == 5)
+ return 0;
+ }
+
+ int xpos = _charAddXPosTable[facing] + _currentCharacter->x1;
+ int ypos = _charAddYPosTable[facing] + _currentCharacter->y1;
+
+ if (xpos >= 12 && xpos <= 308) {
+ if (!lineIsPassable(xpos, ypos))
+ return false;
+ }
+
+ if (_exitListPtr) {
+ int16 *ptr = _exitListPtr;
+ // this loop should be only entered one time, seems to be some hack in the original
+ while (true) {
+ if (*ptr == -1)
+ break;
+
+ if (*ptr > _currentCharacter->x1 || _currentCharacter->y1 < ptr[1] || _currentCharacter->x1 > ptr[2] || _currentCharacter->y1 > ptr[3]) {
+ ptr += 10;
+ break;
+ }
+
+ _brandonPosX = ptr[6];
+ _brandonPosY = ptr[7];
+ uint16 sceneId = ptr[5];
+ facing = ptr[4];
+ int unk1 = ptr[8];
+ int unk2 = ptr[9];
+
+ if (sceneId == 0xFFFF) {
+ switch (facing) {
+ case 0:
+ sceneId = _roomTable[_currentCharacter->sceneId].northExit;
+ break;
+
+ case 2:
+ sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
+ break;
+
+ case 4:
+ sceneId = _roomTable[_currentCharacter->sceneId].southExit;
+ break;
+
+ case 6:
+ sceneId = _roomTable[_currentCharacter->sceneId].westExit;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ _currentCharacter->facing = facing;
+ _animator->animRefreshNPC(0);
+ _animator->updateAllObjectShapes();
+ enterNewScene(sceneId, facing, unk1, unk2, 0);
+ resetGameFlag(0xEE);
+ return 1;
+ }
+ }
+
+ int returnValue = 0;
+ facing = 0;
+
+ if ((_northExitHeight & 0xFF) + 2 >= ypos || (_northExitHeight & 0xFF) + 2 >= _currentCharacter->y1) {
+ facing = 0;
+ returnValue = 1;
+ }
+
+ if (xpos >= 308 || (_currentCharacter->x1 + 4) >= 308) {
+ facing = 2;
+ returnValue = 1;
+ }
+
+ if (((_northExitHeight >> 8) & 0xFF) - 2 < ypos || ((_northExitHeight >> 8) & 0xFF) - 2 < _currentCharacter->y1) {
+ facing = 4;
+ returnValue = 1;
+ }
+
+ if (xpos <= 12 || _currentCharacter->y1 <= 12) {
+ facing = 6;
+ returnValue = 1;
+ }
+
+ if (!returnValue)
+ return 0;
+
+ uint16 sceneId = 0xFFFF;
+ switch (facing) {
+ case 0:
+ sceneId = _roomTable[_currentCharacter->sceneId].northExit;
+ break;
+
+ case 2:
+ sceneId = _roomTable[_currentCharacter->sceneId].eastExit;
+ break;
+
+ case 4:
+ sceneId = _roomTable[_currentCharacter->sceneId].southExit;
+ break;
+
+ default:
+ sceneId = _roomTable[_currentCharacter->sceneId].westExit;
+ }
+
+ if (sceneId == 0xFFFF)
+ return 0;
+
+ enterNewScene(sceneId, facing, 1, 1, 0);
+ return returnValue;
+}
+
+void KyraEngine_LoK::setCharactersInDefaultScene() {
+ static const uint32 defaultSceneTable[][4] = {
+ { 0xFFFF, 0x0004, 0x0003, 0xFFFF },
+ { 0xFFFF, 0x0022, 0xFFFF, 0x0000 },
+ { 0xFFFF, 0x001D, 0x0021, 0xFFFF },
+ { 0xFFFF, 0x0000, 0x0000, 0xFFFF }
+ };
+
+ for (int i = 1; i < 5; ++i) {
+ Character *cur = &_characterList[i];
+ //cur->field_20 = 0;
+
+ const uint32 *curTable = defaultSceneTable[i - 1];
+ cur->sceneId = curTable[0];
+
+ if (cur->sceneId == _currentCharacter->sceneId)
+ //++cur->field_20;
+ cur->sceneId = curTable[1/*cur->field_20*/];
+
+ //cur->field_23 = curTable[cur->field_20+1];
+ }
+}
+
+void KyraEngine_LoK::setCharactersPositions(int character) {
+ static const uint16 initXPosTable[] = {
+ 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B,
+ 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042
+ };
+ static const uint8 initYPosTable[] = {
+ 0x00, 0xA2, 0x00, 0x42, 0x00,
+ 0x67, 0x67, 0x60, 0x5A, 0x71,
+ 0x76
+ };
+
+ assert(character < ARRAYSIZE(initXPosTable));
+ Character *edit = &_characterList[character];
+ edit->x1 = edit->x2 = initXPosTable[character];
+ edit->y1 = edit->y2 = initYPosTable[character];
+}
+
+#pragma mark -
+#pragma mark - Pathfinder
+#pragma mark -
+
+int KyraEngine_LoK::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) {
+ int ret = KyraEngine_v1::findWay(x, y, toX, toY, moveTable, moveTableSize);
+ if (ret == 0x7D00)
+ return 0;
+ return getMoveTableSize(moveTable);
+}
+
+bool KyraEngine_LoK::lineIsPassable(int x, int y) {
+ if (queryGameFlag(0xEF)) {
+ if (_currentCharacter->sceneId == 5)
+ return true;
+ }
+
+ if (_pathfinderFlag & 2) {
+ if (x >= 312)
+ return false;
+ }
+
+ if (_pathfinderFlag & 4) {
+ if (y >= 136)
+ return false;
+ }
+
+ if (_pathfinderFlag & 8) {
+ if (x < 8)
+ return false;
+ }
+
+ if (_pathfinderFlag2) {
+ if (x <= 8 || x >= 312)
+ return true;
+ if (y < (_northExitHeight & 0xFF) || y > 135)
+ return true;
+ }
+
+ if (y > 137)
+ return false;
+
+ if (y < 0)
+ y = 0;
+
+ int ypos = 8;
+ if (_scaleMode) {
+ ypos = (_scaleTable[y] >> 5) + 1;
+ if (8 < ypos)
+ ypos = 8;
+ }
+
+ x -= (ypos >> 1);
+
+ int xpos = x;
+ int xtemp = xpos + ypos - 1;
+ if (x < 0)
+ xpos = 0;
+
+ if (xtemp > 319)
+ xtemp = 319;
+
+ for (; xpos < xtemp; ++xpos) {
+ if (!_screen->getShapeFlag1(xpos, y))
+ return false;
+ }
+ return true;
+}
+
+#pragma mark -
+
+void KyraEngine_LoK::setupZanthiaPalette(int pal) {
+ uint8 r, g, b;
+
+ switch (pal - 17) {
+ case 0:
+ // 0x88F
+ r = 33;
+ g = 33;
+ b = 63;
+ break;
+
+ case 1:
+ // 0x00F
+ r = 0;
+ g = 0;
+ b = 63;
+ break;
+
+ case 2:
+ // 0xF88
+ r = 63;
+ g = 33;
+ b = 33;
+ break;
+
+ case 3:
+ // 0xF00
+ r = 63;
+ g = 0;
+ b = 0;
+ break;
+
+ case 4:
+ // 0xFF9
+ r = 63;
+ g = 63;
+ b = 37;
+ break;
+
+ case 5:
+ // 0xFF1
+ r = 63;
+ g = 63;
+ b = 4;
+ break;
+
+ default:
+ // 0xFFF
+ r = 63;
+ g = 63;
+ b = 63;
+ }
+
+ _screen->getPalette(4)[12 * 3 + 0] = r;
+ _screen->getPalette(4)[12 * 3 + 1] = g;
+ _screen->getPalette(4)[12 * 3 + 2] = b;
+}
+
+#pragma mark -
+
+void KyraEngine_LoK::setupSceneResource(int sceneId) {
+ if (!_flags.isTalkie)
+ return;
+
+ if (_currentRoom != 0xFFFF) {
+ assert(_currentRoom < _roomTableSize);
+ int tableId = _roomTable[_currentRoom].nameIndex;
+ assert(tableId < _roomFilenameTableSize);
+
+ // unload our old room
+ char file[64];
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".VRM");
+ _res->unloadPakFile(file);
+
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".PAK");
+ _res->unloadPakFile(file);
+
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".APK");
+ _res->unloadPakFile(file);
+ }
+
+ assert(sceneId < _roomTableSize);
+ int tableId = _roomTable[sceneId].nameIndex;
+ assert(tableId < _roomFilenameTableSize);
+
+ // load our new room
+ char file[64];
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".VRM");
+ if (_res->exists(file))
+ _res->loadPakFile(file);
+
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".PAK");
+ if (_res->exists(file))
+ _res->loadPakFile(file);
+
+ strcpy(file, _roomFilenameTable[tableId]);
+ strcat(file, ".APK");
+ if (_res->exists(file))
+ _res->loadPakFile(file);
+}
+
+} // End of namespace Kyra