diff options
Diffstat (limited to 'kyra')
-rw-r--r-- | kyra/animator.cpp | 42 | ||||
-rw-r--r-- | kyra/animator.h | 1 | ||||
-rw-r--r-- | kyra/gui.cpp | 8 | ||||
-rw-r--r-- | kyra/items.cpp | 981 | ||||
-rw-r--r-- | kyra/kyra.cpp | 4252 | ||||
-rw-r--r-- | kyra/kyra.h | 20 | ||||
-rw-r--r-- | kyra/module.mk | 3 | ||||
-rw-r--r-- | kyra/resource.cpp | 44 | ||||
-rw-r--r-- | kyra/scene.cpp | 1579 | ||||
-rw-r--r-- | kyra/screen.cpp | 154 | ||||
-rw-r--r-- | kyra/screen.h | 14 | ||||
-rw-r--r-- | kyra/script_v1.cpp | 8 | ||||
-rw-r--r-- | kyra/seqplayer.cpp | 3 | ||||
-rw-r--r-- | kyra/sequences.cpp | 968 | ||||
-rw-r--r-- | kyra/sound.cpp | 85 | ||||
-rw-r--r-- | kyra/staticres.cpp | 140 | ||||
-rw-r--r-- | kyra/text.cpp | 332 |
17 files changed, 4361 insertions, 4273 deletions
diff --git a/kyra/animator.cpp b/kyra/animator.cpp index df616f5965..057bb0cbeb 100644 --- a/kyra/animator.cpp +++ b/kyra/animator.cpp @@ -65,6 +65,48 @@ void ScreenAnimator::close() { } } +void ScreenAnimator::initAnimStateList() { + AnimObject *animStates = _screenObjects; + animStates[0].index = 0; + animStates[0].active = 1; + animStates[0].flags = 0x800; + animStates[0].background = _vm->_shapes[2]; + animStates[0].rectSize = _screen->getRectSize(4, 48); + animStates[0].width = 4; + animStates[0].height = 48; + animStates[0].width2 = 4; + animStates[0].height2 = 3; + + for (int i = 1; i <= 4; ++i) { + animStates[i].index = i; + animStates[i].active = 0; + animStates[i].flags = 0x800; + animStates[i].background = _vm->_shapes[3]; + animStates[i].rectSize = _screen->getRectSize(4, 64); + animStates[i].width = 4; + animStates[i].height = 48; + animStates[i].width2 = 4; + animStates[i].height2 = 3; + } + + for (int i = 5; i < 16; ++i) { + animStates[i].index = i; + animStates[i].active = 0; + animStates[i].flags = 0; + } + + for (int i = 16; i < 28; ++i) { + animStates[i].index = i; + animStates[i].flags = 0; + animStates[i].background = _vm->_shapes[349+i]; + animStates[i].rectSize = _screen->getRectSize(3, 24); + animStates[i].width = 3; + animStates[i].height = 16; + animStates[i].width2 = 0; + animStates[i].height2 = 0; + } +} + void ScreenAnimator::preserveAllBackgrounds() { debug(9, "ScreenAnimator::preserveAllBackgrounds()"); uint8 curPage = _screen->_curPage; diff --git a/kyra/animator.h b/kyra/animator.h index cb6b8e2609..a20e2ae193 100644 --- a/kyra/animator.h +++ b/kyra/animator.h @@ -62,6 +62,7 @@ public: AnimObject *items() { return _items; } AnimObject *sprites() { return _sprites; } + void initAnimStateList(); void preserveAllBackgrounds(); void flagAllObjectsForBkgdChange(); void flagAllObjectsForRefresh(); diff --git a/kyra/gui.cpp b/kyra/gui.cpp index 668e33459d..990b91cf6b 100644 --- a/kyra/gui.cpp +++ b/kyra/gui.cpp @@ -29,6 +29,14 @@ #include "common/system.h" namespace Kyra { + +void KyraEngine::initMainButtonList() { + _buttonList = &_buttonData[0]; + for (int i = 0; _buttonDataListPtr[i]; ++i) { + _buttonList = initButton(_buttonList, _buttonDataListPtr[i]); + } +} + Button *KyraEngine::initButton(Button *list, Button *newButton) { if (!newButton) return list; diff --git a/kyra/items.cpp b/kyra/items.cpp new file mode 100644 index 0000000000..2f48433d7e --- /dev/null +++ b/kyra/items.cpp @@ -0,0 +1,981 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * 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. + * + * $Header$ + * + */ + +#include "kyra/kyra.h" +#include "kyra/seqplayer.h" +#include "kyra/screen.h" +#include "kyra/resource.h" +#include "kyra/sound.h" +#include "kyra/sprites.h" +#include "kyra/wsamovie.h" +#include "kyra/animator.h" +#include "kyra/text.h" + +#include "common/system.h" +#include "common/savefile.h" + +namespace Kyra { + +int KyraEngine::findDuplicateItemShape(int shape) { + static uint8 dupTable[] = { + 0x48, 0x46, 0x49, 0x47, 0x4a, 0x46, 0x4b, 0x47, + 0x4c, 0x46, 0x4d, 0x47, 0x5b, 0x5a, 0x5c, 0x5a, + 0x5d, 0x5a, 0x5e, 0x5a, 0xFF, 0xFF + }; + + int i = 0; + + while (dupTable[i] != 0xFF) { + if (dupTable[i] == shape) + return dupTable[i+1]; + i += 2; + } + return -1; +} + +void KyraEngine::addToNoDropRects(int x, int y, int w, int h) { + debug(9, "KyraEngine::addToNoDropRects(%d, %d, %d, %d)", x, y, w, h); + for (int rect = 0; rect < 11; ++rect) { + if (_noDropRects[rect].x == -1) { + _noDropRects[rect].x = x; + _noDropRects[rect].y = y; + _noDropRects[rect].x2 = x + w - 1; + _noDropRects[rect].y2 = y + h - 1; + break; + } + } +} + +void KyraEngine::clearNoDropRects() { + debug(9, "KyraEngine::clearNoDropRects()"); + memset(_noDropRects, -1, sizeof(_noDropRects)); +} + +byte KyraEngine::findFreeItemInScene(int scene) { + debug(9, "KyraEngine::findFreeItemInScene(%d)", scene); + assert(scene < _roomTableSize); + Room *room = &_roomTable[scene]; + for (int i = 0; i < 12; ++i) { + if (room->itemsTable[i] == 0xFF) + return i; + } + return 0xFF; +} + +byte KyraEngine::findItemAtPos(int x, int y) { + debug(9, "KyraEngine::findItemAtPos(%d, %d)", x, y); + assert(_currentCharacter->sceneId < _roomTableSize); + const uint8 *itemsTable = _roomTable[_currentCharacter->sceneId].itemsTable; + const uint16 *xposOffset = _roomTable[_currentCharacter->sceneId].itemsXPos; + const uint8 *yposOffset = _roomTable[_currentCharacter->sceneId].itemsYPos; + + int highestYPos = -1; + byte returnValue = 0xFF; + + for (int i = 0; i < 12; ++i) { + if (*itemsTable != 0xFF) { + int xpos = *xposOffset - 11; + int xpos2 = *xposOffset + 10; + if (x > xpos && x < xpos2) { + assert(*itemsTable < ARRAYSIZE(_itemTable)); + int itemHeight = _itemTable[*itemsTable].height; + int ypos = *yposOffset + 3; + int ypos2 = ypos - itemHeight - 3; + + if (y > ypos2 && ypos > y) { + if (highestYPos <= ypos) { + returnValue = i; + highestYPos = ypos; + } + } + } + } + ++xposOffset; + ++yposOffset; + ++itemsTable; + } + + return returnValue; +} + +void KyraEngine::placeItemInGenericMapScene(int item, int index) { + debug(9, "KyraEngine::placeItemInGenericMapScene(%d, %d)", item, index); + static const uint16 itemMapSceneMinTable[] = { + 0x0000, 0x0011, 0x006D, 0x0025, 0x00C7, 0x0000 + }; + static const uint16 itemMapSceneMaxTable[] = { + 0x0010, 0x0024, 0x00C6, 0x006C, 0x00F5, 0x0000 + }; + + int minValue = itemMapSceneMinTable[index]; + int maxValue = itemMapSceneMaxTable[index]; + + while (true) { + int room = _rnd.getRandomNumberRng(minValue, maxValue); + assert(room < _roomTableSize); + int nameIndex = _roomTable[room].nameIndex; + bool placeItem = false; + + switch (nameIndex) { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 11: + case 12: case 16: case 17: case 20: + case 22: case 23: case 25: case 26: + case 27: case 31: case 33: case 34: + case 36: case 37: case 58: case 59: + case 60: case 61: case 83: case 84: + case 85: case 104: case 105: case 106: + placeItem = true; + break; + + case 51: + if (room != 46) { + placeItem = true; + break; + } + default: + placeItem = false; + break; + } + + if (placeItem) { + Room *roomPtr = &_roomTable[room]; + if (roomPtr->northExit == 0xFFFF && roomPtr->eastExit == 0xFFFF && roomPtr->southExit == 0xFFFF && roomPtr->westExit == 0xFFFF) { + placeItem = false; + } else if (_currentCharacter->sceneId == room) { + placeItem = false; + } + } + + if (placeItem) { + if (!processItemDrop(room, item, -1, -1, 2, 0)) + continue; + break; + } + } +} + +void KyraEngine::createMouseItem(int item) { + debug(9, "KyraEngine::createMouseItem(%d)", item); + _screen->hideMouse(); + setMouseItem(item); + _itemInHand = item; + _screen->showMouse(); +} + +void KyraEngine::destroyMouseItem() { + debug(9, "KyraEngine::destroyMouseItem()"); + _screen->hideMouse(); + _screen->setMouseCursor(1, 1, _shapes[4]); + _itemInHand = -1; + _screen->showMouse(); +} + +void KyraEngine::setMouseItem(int item) { + debug(9, "KyraEngine::setMouseItem(%d)", item); + if (item == -1) { + _screen->setMouseCursor(1, 1, _shapes[10]); + } else { + _screen->setMouseCursor(8, 15, _shapes[220+item]); + } +} + +void KyraEngine::wipeDownMouseItem(int xpos, int ypos) { + debug(9, "KyraEngine::wipeDownMouseItem(%d, %d)", xpos, ypos); + if (_itemInHand == -1) + return; + xpos -= 8; + ypos -= 15; + _screen->hideMouse(); + _screen->backUpRect1(xpos, ypos); + int y = ypos; + int height = 16; + + while (height >= 0) { + _screen->restoreRect1(xpos, ypos); + _screen->setNewShapeHeight(_shapes[220+_itemInHand], height); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, _shapes[220+_itemInHand], xpos, y, 0, 0); + _screen->updateScreen(); + y += 2; + height -= 2; + while (_system->getMillis() < nextTime) {} + } + _screen->restoreRect1(xpos, ypos); + _screen->resetShapeHeight(_shapes[220+_itemInHand]); + destroyMouseItem(); + _screen->showMouse(); +} + +void KyraEngine::setupSceneItems() { + debug(9, "KyraEngine::setupSceneItems()"); + uint16 sceneId = _currentCharacter->sceneId; + assert(sceneId < _roomTableSize); + Room *currentRoom = &_roomTable[sceneId]; + for (int i = 0; i < 12; ++i) { + uint8 item = currentRoom->itemsTable[i]; + if (item == 0xFF || !currentRoom->needInit[i]) { + continue; + } + + int xpos = 0; + int ypos = 0; + + if (currentRoom->itemsXPos[i] == 0xFFFF) { + xpos = currentRoom->itemsXPos[i] = _rnd.getRandomNumberRng(24, 296); + ypos = currentRoom->itemsYPos[i] = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 130); + } else { + xpos = currentRoom->itemsXPos[i]; + ypos = currentRoom->itemsYPos[i]; + } + + _lastProcessedItem = i; + + int stop = 0; + while (!stop) { + stop = processItemDrop(sceneId, item, xpos, ypos, 3, 0); + if (!stop) { + xpos = currentRoom->itemsXPos[i] = _rnd.getRandomNumberRng(24, 296); + ypos = currentRoom->itemsYPos[i] = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 130); + if (countItemsInScene(sceneId) >= 12) { + break; + } + } else { + currentRoom->needInit[i] = 0; + } + } + } +} + +int KyraEngine::countItemsInScene(uint16 sceneId) { + debug(9, "KyraEngine::countItemsInScene(%d)", sceneId); + assert(sceneId < _roomTableSize); + Room *currentRoom = &_roomTable[sceneId]; + + int items = 0; + + for (int i = 0; i < 12; ++i) { + if (currentRoom->itemsTable[i] != 0xFF) { + ++items; + } + } + + return items; +} + +int KyraEngine::processItemDrop(uint16 sceneId, uint8 item, int x, int y, int unk1, int unk2) { + debug(9, "KyraEngine::processItemDrop(%d, %d, %d, %d, %d, %d)", sceneId, item, x, y, unk1, unk2); + int freeItem = -1; + uint8 itemIndex = findItemAtPos(x, y); + if (unk1) { + itemIndex = 0xFF; + } + + if (itemIndex != 0xFF) { + exchangeItemWithMouseItem(sceneId, itemIndex); + return 0; + } + + assert(sceneId < _roomTableSize); + Room *currentRoom = &_roomTable[sceneId]; + + if (unk1 != 3) { + for (int i = 0; i < 12; ++i) { + if (currentRoom->itemsTable[i] == 0xFF) { + freeItem = i; + break; + } + } + } else { + freeItem = _lastProcessedItem; + } + + if (freeItem == -1) { + return 0; + } + + if (sceneId != _currentCharacter->sceneId) { + addItemToRoom(sceneId, item, freeItem, x, y); + return 1; + } + + int itemHeight = _itemTable[item].height; + _lastProcessedItemHeight = itemHeight; + + if (x == -1 && x == -1) { + x = _rnd.getRandomNumberRng(16, 304); + y = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 135); + } + + int xpos = x; + int ypos = y; + int destY = -1; + int destX = -1; + int running = 1; + + while (running) { + if ((_northExitHeight & 0xFF) <= ypos) { + bool running2 = true; + + if (_screen->getDrawLayer(xpos, ypos) > 1) { + if (((_northExitHeight >> 8) & 0xFF) != ypos) { + running2 = false; + } + } + + if (_screen->getDrawLayer2(xpos, ypos, itemHeight) > 1) { + if (((_northExitHeight >> 8) & 0xFF) != ypos) { + running2 = false; + } + } + + if (!isDropable(xpos, ypos)) { + if (((_northExitHeight >> 8) & 0xFF) != ypos) { + running2 = false; + } + } + + int xpos2 = xpos; + int xpos3 = xpos; + + while (running2) { + if (isDropable(xpos2, ypos)) { + if (_screen->getDrawLayer2(xpos2, ypos, itemHeight) < 7) { + if (findItemAtPos(xpos2, ypos) == 0xFF) { + destX = xpos2; + destY = ypos; + running = 0; + running2 = false; + } + } + } + + if (isDropable(xpos3, ypos)) { + if (_screen->getDrawLayer2(xpos3, ypos, itemHeight) < 7) { + if (findItemAtPos(xpos3, ypos) == 0xFF) { + destX = xpos3; + destY = ypos; + running = 0; + running2 = false; + } + } + } + + if (!running2) + continue; + + xpos2 -= 2; + if (xpos2 < 16) { + xpos2 = 16; + } + + xpos3 += 2; + if (xpos3 > 304) { + xpos3 = 304; + } + + if (xpos2 > 16) + continue; + if (xpos3 < 304) + continue; + running2 = false; + } + } + + if (((_northExitHeight >> 8) & 0xFF) == ypos) { + running = 0; + destY -= _rnd.getRandomNumberRng(0, 3); + + if ((_northExitHeight & 0xFF) < destY) { + continue; + } + + destY = (_northExitHeight & 0xFF) + 1; + continue; + } + ypos += 2; + if (((_northExitHeight >> 8) & 0xFF) >= ypos) { + continue; + } + ypos = (_northExitHeight >> 8) & 0xFF; + } + + if (destX == -1 || destY == -1) { + return 0; + } + + if (unk1 == 3) { + currentRoom->itemsXPos[freeItem] = destX; + currentRoom->itemsYPos[freeItem] = destY; + return 1; + } + + if (unk1 == 2) { + itemSpecialFX(x, y, item); + } + + if (unk1 == 0) { + destroyMouseItem(); + } + + itemDropDown(x, y, destX, destY, freeItem, item); + + if (unk1 == 0 && unk2 != 0) { + assert(_itemList && _droppedList); + updateSentenceCommand(_itemList[item], _droppedList[0], 179); + } + + return 1; +} + +void KyraEngine::exchangeItemWithMouseItem(uint16 sceneId, int itemIndex) { + debug(9, "KyraEngine::exchangeItemWithMouseItem(%d, %d)", sceneId, itemIndex); + _screen->hideMouse(); + _animator->animRemoveGameItem(itemIndex); + assert(sceneId < _roomTableSize); + Room *currentRoom = &_roomTable[sceneId]; + + int item = currentRoom->itemsTable[itemIndex]; + currentRoom->itemsTable[itemIndex] = _itemInHand; + _itemInHand = item; + _animator->animAddGameItem(itemIndex, sceneId); + snd_playSoundEffect(53); + + setMouseItem(_itemInHand); + assert(_itemList && _takenList); + updateSentenceCommand(_itemList[_itemInHand], _takenList[1], 179); + _screen->showMouse(); + clickEventHandler2(); +} + +void KyraEngine::addItemToRoom(uint16 sceneId, uint8 item, int itemIndex, int x, int y) { + debug(9, "KyraEngine::addItemToRoom(%d, %d, %d, %d, %d)", sceneId, item, itemIndex, x, y); + assert(sceneId < _roomTableSize); + Room *currentRoom = &_roomTable[sceneId]; + currentRoom->itemsTable[itemIndex] = item; + currentRoom->itemsXPos[itemIndex] = x; + currentRoom->itemsYPos[itemIndex] = y; + currentRoom->needInit[itemIndex] = 1; +} + +int KyraEngine::checkNoDropRects(int x, int y) { + debug(9, "KyraEngine::checkNoDropRects(%d, %d)", x, y); + if (_lastProcessedItemHeight < 1 || _lastProcessedItemHeight > 16) { + _lastProcessedItemHeight = 16; + } + if (_noDropRects[0].x == -1) { + return 0; + } + + for (int i = 0; i < 11; ++i) { + if (_noDropRects[i].x == -1) { + break; + } + + int xpos = _noDropRects[i].x; + int ypos = _noDropRects[i].y; + int xpos2 = _noDropRects[i].x2; + int ypos2 = _noDropRects[i].y2; + + if (xpos > x + 16) + continue; + if (xpos2 < x) + continue; + if (y < ypos) + continue; + if (ypos2 < y - _lastProcessedItemHeight) + continue; + return 1; + } + + return 0; +} + +int KyraEngine::isDropable(int x, int y) { + debug(9, "KyraEngine::isDropable(%d, %d)", x, y); + x -= 8; + y -= 1; + + if (checkNoDropRects(x, y)) { + return 0; + } + + for (int xpos = x; xpos < x + 16; ++xpos) { + if (_screen->getShapeFlag1(xpos, y) == 0) { + return 0; + } + } + return 1; +} + +void KyraEngine::itemDropDown(int x, int y, int destX, int destY, byte freeItem, int item) { + debug(9, "KyraEngine::itemDropDown(%d, %d, %d, %d, %d, %d)", x, y, destX, destY, freeItem, item); + assert(_currentCharacter->sceneId < _roomTableSize); + Room *currentRoom = &_roomTable[_currentCharacter->sceneId]; + if (x == destX && y == destY) { + currentRoom->itemsXPos[freeItem] = destX; + currentRoom->itemsYPos[freeItem] = destY; + currentRoom->itemsTable[freeItem] = item; + snd_playSoundEffect(0x32); + _animator->animAddGameItem(freeItem, _currentCharacter->sceneId); + return; + } + _screen->hideMouse(); + if (y <= destY) { + int tempY = y; + int addY = 2; + int drawX = x - 8; + int drawY = 0; + + _screen->backUpRect0(drawX, y - 16); + + while (tempY < destY) { + _screen->restoreRect0(drawX, tempY - 16); + tempY += addY; + if (tempY > destY) { + tempY = destY; + } + ++addY; + drawY = tempY - 16; + _screen->backUpRect0(drawX, drawY); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, _shapes[220+item], drawX, drawY, 0, 0); + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if ((nextTime - _system->getMillis()) >= 10) + delay(10); + } + } + + bool skip = false; + if (x == destX) { + if (destY - y <= 16) { + skip = true; + } + } + + if (!skip) { + snd_playSoundEffect(0x47); + if (addY < 6) + addY = 6; + + int xDiff = (destX - x) << 4; + xDiff /= addY; + int startAddY = addY; + addY >>= 1; + if (destY - y <= 8) { + addY >>= 1; + } + addY = -addY; + int unkX = x << 4; + while (--startAddY) { + drawX = (unkX >> 4) - 8; + drawY = tempY - 16; + _screen->restoreRect0(drawX, drawY); + tempY += addY; + unkX += xDiff; + if (tempY > destY) { + tempY = destY; + } + ++addY; + drawX = (unkX >> 4) - 8; + drawY = tempY - 16; + _screen->backUpRect0(drawX, drawY); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, _shapes[220+item], drawX, drawY, 0, 0); + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if ((nextTime - _system->getMillis()) >= 10) + delay(10); + } + } + _screen->restoreRect0(drawX, drawY); + } else { + _screen->restoreRect0(drawX, tempY - 16); + } + } + currentRoom->itemsXPos[freeItem] = destX; + currentRoom->itemsYPos[freeItem] = destY; + currentRoom->itemsTable[freeItem] = item; + snd_playSoundEffect(0x32); + _animator->animAddGameItem(freeItem, _currentCharacter->sceneId); + _screen->showMouse(); +} + +void KyraEngine::dropItem(int unk1, int item, int x, int y, int unk2) { + debug(9, "KyraEngine::dropItem(%d, %d, %d, %d, %d)", unk1, item, x, y, unk2); + if (processItemDrop(_currentCharacter->sceneId, item, x, y, unk1, unk2)) + return; + snd_playSoundEffect(54); + if (12 == countItemsInScene(_currentCharacter->sceneId)) { + assert(_noDropList); + drawSentenceCommand(_noDropList[0], 6); + } else { + assert(_noDropList); + drawSentenceCommand(_noDropList[1], 6); + } +} + +void KyraEngine::itemSpecialFX(int x, int y, int item) { + debug(9, "KyraEngine::itemSpecialFX(%d, %d, %d)", x, y, item); + if (item == 41) { + itemSpecialFX1(x, y, item); + } else { + itemSpecialFX2(x, y, item); + } +} + +void KyraEngine::itemSpecialFX1(int x, int y, int item) { + debug(9, "KyraEngine::itemSpecialFX1(%d, %d, %d)", x, y, item); + uint8 *shape = _shapes[220+item]; + x -= 8; + int startY = y; + y -= 15; + _screen->hideMouse(); + _screen->backUpRect0(x, y); + for (int i = 1; i <= 16; ++i) { + _screen->setNewShapeHeight(shape, i); + --startY; + _screen->restoreRect0(x, y); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, shape, x, startY, 0, 0); + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if ((nextTime - _system->getMillis()) >= 10) + delay(10); + } + } + _screen->restoreRect0(x, y); + _screen->showMouse(); +} + +void KyraEngine::itemSpecialFX2(int x, int y, int item) { + debug(9, "KyraEngine::itemSpecialFX2(%d, %d, %d)", x, y, item); + x -= 8; + y -= 15; + int yAdd = (int8)(((16 - _itemTable[item].height) >> 1) & 0xFF); + _screen->backUpRect0(x, y); + if (item >= 80 && item <= 89) { + snd_playSoundEffect(55); + } + + for (int i = 201; i <= 205; ++i) { + _screen->restoreRect0(x, y); + uint32 nextTime = _system->getMillis() + 3 * _tickLength; + _screen->drawShape(0, _shapes[4+i], x, y + yAdd, 0, 0); + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if ((nextTime - _system->getMillis()) >= 10) + delay(10); + } + } + + for (int i = 204; i >= 201; --i) { + _screen->restoreRect0(x, y); + uint32 nextTime = _system->getMillis() + 3 * _tickLength; + _screen->drawShape(0, _shapes[220+item], x, y, 0, 0); + _screen->drawShape(0, _shapes[4+i], x, y + yAdd, 0, 0); + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if ((nextTime - _system->getMillis()) >= 10) + delay(10); + } + } + _screen->restoreRect0(x, y); +} + +void KyraEngine::magicOutMouseItem(int animIndex, int itemPos) { + debug(9, "KyraEngine::magicOutMouseItem(%d, %d)", animIndex, itemPos); + int videoPageBackUp = _screen->_curPage; + _screen->_curPage = 0; + int x = 0, y = 0; + if (itemPos == -1) { + x = _mouseX - 12; + y = _mouseY - 18; + } else { + x = _itemPosX[itemPos] - 4; + y = _itemPosY[itemPos] - 3; + } + + if (_itemInHand == -1 && itemPos == -1) { + return; + } + + int tableIndex = 0, loopStart = 0, maxLoops = 0; + if (animIndex == 0) { + tableIndex = _rnd.getRandomNumberRng(0, 5); + loopStart = 35; + maxLoops = 9; + } else if (animIndex == 1) { + tableIndex = _rnd.getRandomNumberRng(0, 11); + loopStart = 115; + maxLoops = 8; + } else if (animIndex == 2) { + tableIndex = 0; + loopStart = 124; + maxLoops = 4; + } else { + tableIndex = -1; + } + + if (animIndex == 2) { + snd_playSoundEffect(0x5E); + } else { + snd_playSoundEffect(0x37); + } + _screen->hideMouse(); + _screen->backUpRect1(x, y); + + for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { + _screen->restoreRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + _screen->drawShape(0, _shapes[220+_itemInHand], x + 4, y + 3, 0, 0); + if (tableIndex == -1) { + _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); + } else { + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + } + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if (nextTime - _system->getMillis() >= 10) + delay(10); + } + } + + if (itemPos != -1) { + _screen->restoreRect1(x, y); + _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, 12, 0); + _screen->backUpRect1(x, y); + } + + for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { + _screen->restoreRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + _screen->drawShape(0, _shapes[220+_itemInHand], x + 4, y + 3, 0, 0); + if (tableIndex == -1) { + _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); + } else { + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + } + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if (nextTime - _system->getMillis() >= 10) + delay(10); + } + } + _screen->restoreRect1(x, y); + if (itemPos == -1) { + _screen->setMouseCursor(1, 1, _shapes[4]); + _itemInHand = -1; + } else { + _characterList[0].inventoryItems[itemPos] = 0xFF; + _screen->hideMouse(); + _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, 12, 0); + _screen->showMouse(); + } + _screen->showMouse(); + _screen->_curPage = videoPageBackUp; +} + +void KyraEngine::magicInMouseItem(int animIndex, int item, int itemPos) { + debug(9, "KyraEngine::magicInMouseItem(%d, %d, %d)", animIndex, item, itemPos); + int videoPageBackUp = _screen->_curPage; + _screen->_curPage = 0; + int x = 0, y = 0; + if (itemPos == -1) { + x = _mouseX - 12; + y = _mouseY - 18; + } else { + x = _itemPosX[itemPos] - 4; + y = _itemPosX[itemPos] - 3; + } + if (item < 0) + return; + + int tableIndex = -1, loopStart = 0, maxLoops = 0; + if (animIndex == 0) { + tableIndex = _rnd.getRandomNumberRng(0, 5); + loopStart = 35; + maxLoops = 9; + } else if (animIndex == 1) { + tableIndex = _rnd.getRandomNumberRng(0, 11); + loopStart = 115; + maxLoops = 8; + } else if (animIndex == 2) { + tableIndex = 0; + loopStart = 124; + maxLoops = 4; + } + + _screen->hideMouse(); + _screen->backUpRect1(x, y); + if (animIndex == 2) { + snd_playSoundEffect(0x5E); + } else { + snd_playSoundEffect(0x37); + } + + for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { + _screen->restoreRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + if (tableIndex == -1) { + _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); + } else { + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + } + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if (nextTime - _system->getMillis() >= 10) + delay(10); + } + } + + for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { + _screen->restoreRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + if (tableIndex == -1) { + _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); + } else { + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + } + _screen->updateScreen(); + while (_system->getMillis() < nextTime) { + if (nextTime - _system->getMillis() >= 10) + delay(10); + } + } + _screen->restoreRect1(x, y); + if (itemPos == -1) { + _screen->setMouseCursor(8, 15, _shapes[220+item]); + _itemInHand = item; + } else { + _characterList[0].inventoryItems[itemPos] = item; + _screen->hideMouse(); + _screen->drawShape(0, _shapes[220+item], _itemPosX[itemPos], _itemPosY[itemPos], 0, 0); + _screen->showMouse(); + } + _screen->showMouse(); + _screen->_curPage = videoPageBackUp; +} + +void KyraEngine::specialMouseItemFX(int shape, int x, int y, int animIndex, int tableIndex, int loopStart, int maxLoops) { + debug(9, "KyraEngine::specialMouseItemFX(%d, %d, %d, %d, %d, %d, %d)", shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + static const uint8 table1[] = { + 0x23, 0x45, 0x55, 0x72, 0x84, 0xCF, 0x00, 0x00 + }; + static const uint8 table2[] = { + 0x73, 0xB5, 0x80, 0x21, 0x13, 0x39, 0x45, 0x55, 0x62, 0xB4, 0xCF, 0xD8 + }; + static const uint8 table3[] = { + 0x7C, 0xD0, 0x74, 0x84, 0x87, 0x00, 0x00, 0x00 + }; + int tableValue = 0; + if (animIndex == 0) { + tableValue = table1[tableIndex]; + } else if (animIndex == 1) { + tableValue = table2[tableIndex]; + } else if (animIndex == 2) { + tableValue = table3[tableIndex]; + } else { + return; + } + processSpecialMouseItemFX(shape, x, y, tableValue, loopStart, maxLoops); +} + +void KyraEngine::processSpecialMouseItemFX(int shape, int x, int y, int tableValue, int loopStart, int maxLoops) { + debug(9, "KyraEngine::processSpecialMouseItemFX(%d, %d, %d, %d, %d, %d)", shape, x, y, tableValue, loopStart, maxLoops); + uint8 shapeColorTable[16]; + uint8 *shapePtr = _shapes[4+shape] + 10; + if (_features & GF_TALKIE) + shapePtr += 2; + for (int i = 0; i < 16; ++i) { + shapeColorTable[i] = shapePtr[i]; + } + for (int i = loopStart; i < loopStart + maxLoops; ++i) { + for (int i2 = 0; i2 < 16; ++i2) { + if (shapePtr[i2] == i) { + shapeColorTable[i2] = (i + tableValue) - loopStart; + } + } + } + _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0x8000, shapeColorTable); +} + +void KyraEngine::updatePlayerItemsForScene() { + debug(9, "KyraEngine::updatePlayerItemsForScene()"); + if (_itemInHand >= 29 && _itemInHand < 33) { + ++_itemInHand; + if (_itemInHand > 33) + _itemInHand = 33; + _screen->hideMouse(); + _screen->setMouseCursor(8, 15, _shapes[220+_itemInHand]); + _screen->showMouse(); + } + + bool redraw = false; + for (int i = 0; i < 10; ++i) { + uint8 item = _currentCharacter->inventoryItems[i]; + if (item >= 29 && item < 33) { + ++item; + if (item > 33) + item = 33; + _currentCharacter->inventoryItems[i] = item; + redraw = true; + } + } + + if (redraw) { + _screen->hideMouse(); + redrawInventory(0); + _screen->showMouse(); + } + + if (_itemInHand == 33) { + magicOutMouseItem(2, -1); + } + + _screen->hideMouse(); + for (int i = 0; i < 10; ++i) { + uint8 item = _currentCharacter->inventoryItems[i]; + if (item == 33) { + magicOutMouseItem(2, i); + } + } + _screen->showMouse(); +} + +void KyraEngine::redrawInventory(int page) { + int videoPageBackUp = _screen->_curPage; + _screen->_curPage = page; + _screen->hideMouse(); + for (int i = 0; i < 10; ++i) { + _screen->fillRect(_itemPosX[i], _itemPosY[i], _itemPosX[i] + 15, _itemPosY[i] + 15, 12, page); + if (_currentCharacter->inventoryItems[i] != 0xFF) { + uint8 item = _currentCharacter->inventoryItems[i]; + _screen->drawShape(page, _shapes[220+item], _itemPosX[i], _itemPosY[i], 0, 0); + } + } + _screen->showMouse(); + _screen->_curPage = videoPageBackUp; + _screen->updateScreen(); +} + +} // end of namespace Kyra diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp index 4d988e907f..6969e3309e 100644 --- a/kyra/kyra.cpp +++ b/kyra/kyra.cpp @@ -466,8 +466,6 @@ KyraEngine::~KyraEngine() { for (int i = 0; i < ARRAYSIZE(_sceneAnimTable); ++i) { free(_sceneAnimTable[i]); } - free(_unkPtr1); - free(_unkPtr2); } void KyraEngine::errorString(const char *buf1, char *buf2) { @@ -518,7 +516,7 @@ void KyraEngine::startup() { for (int i = 5; i <= 10; ++i) setCharactersPositions(i); setCharactersHeight(); - resetBrandonPosionFlags(); + resetBrandonPoisonFlags(); _maskBuffer = _screen->getPagePtr(5); _screen->_curPage = 0; // XXX @@ -526,10 +524,6 @@ void KyraEngine::startup() { int size = _screen->getRectSize(3, 24); _shapes[365+i] = (byte*)malloc(size); } - _unkPtr1 = (uint8*)malloc(_screen->getRectSize(1, 144)); - memset(_unkPtr1, 0, _screen->getRectSize(1, 144)); - _unkPtr2 = (uint8*)malloc(_screen->getRectSize(1, 144)); - memset(_unkPtr2, 0, _screen->getRectSize(1, 144)); _shapes[0] = (uint8*)malloc(_screen->getRectSize(3, 24)); memset(_shapes[0], 0, _screen->getRectSize(3, 24)); _shapes[1] = (uint8*)malloc(_screen->getRectSize(4, 32)); @@ -556,7 +550,7 @@ void KyraEngine::startup() { loadPalette("PALETTE.COL", _screen->_currentPalette); // XXX - initAnimStateList(); + _animator->initAnimStateList(); setCharactersInDefaultScene(); _gameSpeed = 50; @@ -752,48 +746,6 @@ void KyraEngine::quitGame() { _system->quit(); } -void KyraEngine::loadPalette(const char *filename, uint8 *palData) { - debug(9, "KyraEngine::loadPalette('%s' 0x%X)", filename, palData); - uint32 fileSize = 0; - uint8 *srcData = _res->fileData(filename, &fileSize); - - if (palData && fileSize) { - debug(9, "Loading a palette of size %i from '%s'", fileSize, filename); - memcpy(palData, srcData, fileSize); - } - delete [] srcData; -} - -void KyraEngine::loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData) { - debug(9, "KyraEngine::copyBitmap('%s', %d, %d, 0x%X)", filename, tempPage, dstPage, palData); - uint32 fileSize; - uint8 *srcData = _res->fileData(filename, &fileSize); - uint8 compType = srcData[2]; - uint32 imgSize = READ_LE_UINT32(srcData + 4); - uint16 palSize = READ_LE_UINT16(srcData + 8); - if (palData && palSize) { - debug(9, "Loading a palette of size %i from %s", palSize, filename); - memcpy(palData, srcData + 10, palSize); - } - uint8 *srcPtr = srcData + 10 + palSize; - uint8 *dstData = _screen->getPagePtr(dstPage); - switch (compType) { - case 0: - memcpy(dstData, srcPtr, imgSize); - break; - case 3: - Screen::decodeFrame3(srcPtr, dstData, imgSize); - break; - case 4: - Screen::decodeFrame4(srcPtr, dstData, imgSize); - break; - default: - error("Unhandled bitmap compression %d", compType); - break; - } - delete[] srcData; -} - void KyraEngine::waitTicks(int ticks) { debug(9, "KyraEngine::waitTicks(%d)", ticks); const uint32 end = _system->getMillis() + ticks * 1000 / 60; @@ -834,1225 +786,6 @@ void KyraEngine::delayWithTicks(int ticks) { } } -void KyraEngine::seq_demo() { - debug(9, "KyraEngine::seq_demo()"); - - snd_playTheme(MUSIC_INTRO, 2); - - loadBitmap("START.CPS", 7, 7, _screen->_currentPalette); - _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0); - _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); - _screen->fadeFromBlack(); - waitTicks(60); - _screen->fadeToBlack(); - - _screen->clearPage(0); - loadBitmap("TOP.CPS", 7, 7, NULL); - loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); - _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0); - _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0); - _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); - _screen->fadeFromBlack(); - - _seq->playSequence(_seq_WestwoodLogo, true); - waitTicks(60); - - _seq->playSequence(_seq_KyrandiaLogo, true); - - _screen->fadeToBlack(); - _screen->clearPage(2); - _screen->clearPage(0); - - _seq->playSequence(_seq_Demo1, true); - - _screen->clearPage(0); - _seq->playSequence(_seq_Demo2, true); - - _screen->clearPage(0); - _seq->playSequence(_seq_Demo3, true); - - _screen->clearPage(0); - _seq->playSequence(_seq_Demo4, true); - - _screen->clearPage(0); - loadBitmap("FINAL.CPS", 7, 7, _screen->_currentPalette); - _screen->_curPage = 0; - _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0); - _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); - _screen->fadeFromBlack(); - waitTicks(60); - _screen->fadeToBlack(); - _sound->stopMusic(); -} - -void KyraEngine::seq_intro() { - debug(9, "KyraEngine::seq_intro()"); - if (_features & GF_TALKIE) { - _res->loadPakFile("INTRO.VRM"); - } - - static const IntroProc introProcTable[] = { - &KyraEngine::seq_introLogos, - &KyraEngine::seq_introStory, - &KyraEngine::seq_introMalcolmTree, - &KyraEngine::seq_introKallakWriting, - &KyraEngine::seq_introKallakMalcolm - }; - - Common::InSaveFile *in; - if ((in = _saveFileMan->openForLoading(getSavegameFilename(0)))) { - delete in; - _skipIntroFlag = true; - } else - _skipIntroFlag = false; - - _seq->setCopyViewOffs(true); - _screen->setFont(Screen::FID_8_FNT); - snd_playTheme(MUSIC_INTRO, 2); - snd_setSoundEffectFile(MUSIC_INTRO); - _text->setTalkCoords(144); - for (int i = 0; i < ARRAYSIZE(introProcTable) && !seq_skipSequence(); ++i) { - (this->*introProcTable[i])(); - } - _text->setTalkCoords(136); - waitTicks(30); - _seq->setCopyViewOffs(false); - _sound->stopMusic(); - if (_features & GF_TALKIE) { - _res->unloadPakFile("INTRO.VRM"); - } - res_unloadResources(RES_INTRO | RES_OUTRO); -} - -void KyraEngine::seq_introLogos() { - debug(9, "KyraEngine::seq_introLogos()"); - _screen->clearPage(0); - loadBitmap("TOP.CPS", 7, 7, NULL); - loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); - _screen->_curPage = 0; - _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0); - _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0); - _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); - _screen->fadeFromBlack(); - - if (_seq->playSequence(_seq_WestwoodLogo, _skipIntroFlag)) { - _screen->fadeToBlack(); - _screen->clearPage(0); - return; - } - waitTicks(60); - if (_seq->playSequence(_seq_KyrandiaLogo, _skipIntroFlag)) { - _screen->fadeToBlack(); - _screen->clearPage(0); - return; - } - _screen->fillRect(0, 179, 319, 199, 0); - - int y1 = 8; - int h1 = 175; - int y2 = 176; - int h2 = 0; - _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 2); - _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 2); - do { - if (h1 > 0) { - _screen->copyRegion(0, y1, 0, 8, 320, h1, 2, 0); - } - ++y1; - --h1; - if (h2 > 0) { - _screen->copyRegion(0, 64, 0, y2, 320, h2, 4, 0); - } - --y2; - ++h2; - _screen->updateScreen(); - waitTicks(1); - } while (y2 >= 64); - - _seq->playSequence(_seq_Forest, true); -} - -void KyraEngine::seq_introStory() { - debug(9, "KyraEngine::seq_introStory()"); - _screen->clearPage(3); - _screen->clearPage(0); - if ((_features & GF_ENGLISH) && (_features & GF_TALKIE)) { - loadBitmap("TEXT_ENG.CPS", 3, 3, 0); - } else if (_features & GF_GERMAN) { - loadBitmap("TEXT_GER.CPS", 3, 3, 0); - } else if (_features & GF_FRENCH) { - loadBitmap("TEXT_FRE.CPS", 3, 3, 0); - } else if (_features & GF_SPANISH) { - loadBitmap("TEXT_SPA.CPS", 3, 3, 0); - } else if ((_features & GF_ENGLISH) && (_features & GF_FLOPPY)) { - loadBitmap("TEXT.CPS", 3, 3, 0); - } else { - warning("no story graphics file found"); - } - _screen->copyRegion(0, 0, 0, 0, 320, 200, 3, 0); - _screen->updateScreen(); - waitTicks(360); -} - -void KyraEngine::seq_introMalcolmTree() { - debug(9, "KyraEngine::seq_introMalcolmTree()"); - _screen->_curPage = 0; - _screen->clearPage(3); - _seq->playSequence(_seq_MalcolmTree, true); -} - -void KyraEngine::seq_introKallakWriting() { - debug(9, "KyraEngine::seq_introKallakWriting()"); - _seq->makeHandShapes(); - _screen->setAnimBlockPtr(5060); - _screen->_charWidth = -2; - _screen->clearPage(3); - _seq->playSequence(_seq_KallakWriting, true); -} - -void KyraEngine::seq_introKallakMalcolm() { - debug(9, "KyraEngine::seq_introKallakMalcolm()"); - _screen->clearPage(3); - _seq->playSequence(_seq_KallakMalcolm, true); -} - -void KyraEngine::seq_createAmuletJewel(int jewel, int page, int noSound, int drawOnly) { - debug(9, "seq_createAmuletJewel(%d, %d, %d, %d)", jewel, page, noSound, drawOnly); - static const uint16 specialJewelTable[] = { - 0x167, 0x162, 0x15D, 0x158, 0x153, 0xFFFF - }; - static const uint16 specialJewelTable1[] = { - 0x14F, 0x154, 0x159, 0x15E, 0x163, 0xFFFF - }; - static const uint16 specialJewelTable2[] = { - 0x150, 0x155, 0x15A, 0x15F, 0x164, 0xFFFF - }; - static const uint16 specialJewelTable3[] = { - 0x151, 0x156, 0x15B, 0x160, 0x165, 0xFFFF - }; - static const uint16 specialJewelTable4[] = { - 0x152, 0x157, 0x15C, 0x161, 0x166, 0xFFFF - }; - if (!noSound) - snd_playSoundEffect(0x5F); - _screen->hideMouse(); - if (!drawOnly) { - for (int i = 0; specialJewelTable[i] != 0xFFFF; ++i) { - _screen->drawShape(page, _shapes[4+specialJewelTable[i]], _amuletX2[jewel], _amuletY2[jewel], 0, 0); - _screen->updateScreen(); - delayWithTicks(3); - } - - const uint16 *opcodes = 0; - switch (jewel - 1) { - case 0: - opcodes = specialJewelTable1; - break; - - case 1: - opcodes = specialJewelTable2; - break; - - case 2: - opcodes = specialJewelTable3; - break; - - case 3: - opcodes = specialJewelTable4; - break; - } - - if (opcodes) { - for (int i = 0; opcodes[i] != 0xFFFF; ++i) { - _screen->drawShape(page, _shapes[4+opcodes[i]], _amuletX2[jewel], _amuletY2[jewel], 0, 0); - _screen->updateScreen(); - delayWithTicks(3); - } - } - } - _screen->drawShape(page, _shapes[327+jewel], _amuletX2[jewel], _amuletY2[jewel], 0, 0); - _screen->updateScreen(); - _screen->showMouse(); - setGameFlag(0x55+jewel); -} - -void KyraEngine::seq_brandonHealing() { - debug(9, "seq_brandonHealing()"); - if (!(_deathHandler & 8)) - return; - if (_currentCharacter->sceneId == 210) { - if (_beadStateVar == 4 || _beadStateVar == 6) - return; - } - _screen->hideMouse(); - checkAmuletAnimFlags(); - assert(_healingShapeTable); - setupShapes123(_healingShapeTable, 22, 0); - setBrandonAnimSeqSize(3, 48); - snd_playSoundEffect(0x53); - for (int i = 123; i <= 144; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - for (int i = 125; i >= 123; --i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_brandonHealing2() { - debug(9, "seq_brandonHealing2()"); - _screen->hideMouse(); - checkAmuletAnimFlags(); - assert(_healingShape2Table); - setupShapes123(_healingShape2Table, 30, 0); - resetBrandonPoisonFlags(); - setBrandonAnimSeqSize(3, 48); - snd_playSoundEffect(0x50); - for (int i = 123; i <= 152; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); - assert(_poisonGone); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(2010); - } - characterSays(_poisonGone[0], 0, -2); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(2011); - } - characterSays(_poisonGone[1], 0, -2); -} - -void KyraEngine::seq_poisonDeathNow(int now) { - debug(9, "seq_poisonDeathNow(%d)", now); - if (!(_brandonStatusBit & 1)) - return; - ++_poisonDeathCounter; - if (now) - _poisonDeathCounter = 2; - if (_poisonDeathCounter >= 2) { - snd_playWanderScoreViaMap(1, 1); - assert(_thePoison); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(7000); - } - characterSays(_thePoison[0], 0, -2); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(7001); - } - characterSays(_thePoison[1], 0, -2); - seq_poisonDeathNowAnim(); - _deathHandler = 3; - } else { - assert(_thePoison); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(7002); - } - characterSays(_thePoison[2], 0, -2); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(7004); - } - characterSays(_thePoison[3], 0, -2); - } -} - -void KyraEngine::seq_poisonDeathNowAnim() { - debug(9, "seq_poisonDeathNowAnim()"); - _screen->hideMouse(); - checkAmuletAnimFlags(); - assert(_posionDeathShapeTable); - setupShapes123(_posionDeathShapeTable, 20, 0); - setBrandonAnimSeqSize(8, 48); - - _currentCharacter->currentAnimFrame = 124; - animRefreshNPC(0); - delayWithTicks(30); - - _currentCharacter->currentAnimFrame = 123; - animRefreshNPC(0); - delayWithTicks(30); - - for (int i = 125; i <= 139; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - delayWithTicks(60); - - for (int i = 140; i <= 142; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - delayWithTicks(60); - - resetBrandonAnimSeqSize(); - freeShapes123(); - _animator->restoreAllObjectBackgrounds(); - _currentCharacter->x1 = _currentCharacter->x2 = -1; - _currentCharacter->y1 = _currentCharacter->y2 = -1; - _animator->preserveAllBackgrounds(); - _screen->showMouse(); -} - -void KyraEngine::seq_playFluteAnimation() { - debug(9, "seq_playFluteAnimation()"); - _screen->hideMouse(); - checkAmuletAnimFlags(); - setupShapes123(_fluteAnimShapeTable, 36, 0); - setBrandonAnimSeqSize(3, 75); - for (int i = 123; i <= 130; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(2); - } - - int delayTime = 0, soundType = 0; - if (queryGameFlag(0x85)) { - snd_playSoundEffect(0x63); - delayTime = 9; - soundType = 3; - } else if (!queryGameFlag(0x86)) { - snd_playSoundEffect(0x61); - delayTime = 2; - soundType = 1; - setGameFlag(0x86); - } else { - snd_playSoundEffect(0x62); - delayTime = 2; - soundType = 2; - } - - for (int i = 131; i <= 158; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(delayTime); - } - - for (int i = 126; i >= 123; --i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(delayTime); - } - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); - - if (soundType == 1) { - assert(_fluteString); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(1000); - } - characterSays(_fluteString[0], 0, -2); - } else if (soundType == 2) { - assert(_fluteString); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(1001); - } - characterSays(_fluteString[1], 0, -2); - } -} - -void KyraEngine::seq_winterScroll1() { - debug(9, "seq_winterScroll1()"); - _screen->hideMouse(); - checkAmuletAnimFlags(); - assert(_winterScrollTable); - assert(_winterScroll1Table); - assert(_winterScroll2Table); - setupShapes123(_winterScrollTable, 7, 0); - setBrandonAnimSeqSize(5, 66); - - for (int i = 123; i <= 129; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - freeShapes123(); - snd_playSoundEffect(0x20); - setupShapes123(_winterScroll1Table, 35, 0); - - for (int i = 123; i <= 146; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - if (_currentCharacter->sceneId == 41 && !queryGameFlag(0xA2)) { - snd_playSoundEffect(0x20); - _sprites->_anims[0].play = false; - _animator->sprites()[0].active = 0; - _sprites->_anims[1].play = true; - _animator->sprites()[1].active = 1; - setGameFlag(0xA2); - } - - for (int i = 147; i <= 157; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - if (_currentCharacter->sceneId == 117 && !queryGameFlag(0xB3)) { - for (int i = 0; i <= 7; ++i) { - _sprites->_anims[i].play = false; - _animator->sprites()[i].active = 0; - } - uint8 tmpPal[768]; - memcpy(tmpPal, _screen->_currentPalette, 768); - memcpy(&tmpPal[684], palTable2()[0], 60); - _screen->fadePalette(tmpPal, 72); - memcpy(&_screen->_currentPalette[684], palTable2()[0], 60); - _screen->setScreenPalette(_screen->_currentPalette); - setGameFlag(0xB3); - } else { - delayWithTicks(120); - } - - freeShapes123(); - setupShapes123(_winterScroll2Table, 4, 0); - - for (int i = 123; i <= 126; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_winterScroll2() { - debug(9, "seq_winterScroll2()"); - _screen->hideMouse(); - checkAmuletAnimFlags(); - assert(_winterScrollTable); - setupShapes123(_winterScrollTable, 7, 0); - setBrandonAnimSeqSize(5, 66); - - for (int i = 123; i <= 128; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - delayWithTicks(120); - - for (int i = 127; i >= 123; --i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_makeBrandonInv() { - debug(9, "seq_makeBrandonInv()"); - if (_deathHandler == 8) - return; - - if (_currentCharacter->sceneId == 210) { - if (_beadStateVar == 4 || _beadStateVar == 6) - return; - } - - _screen->hideMouse(); - checkAmuletAnimFlags(); - _brandonStatusBit |= 0x20; - setTimerCountdown(18, 2700); - _brandonStatusBit |= 0x40; - snd_playSoundEffect(0x77); - _brandonInvFlag = 0; - while (_brandonInvFlag <= 0x100) { - animRefreshNPC(0); - delayWithTicks(10); - _brandonInvFlag += 0x10; - } - _brandonStatusBit &= 0xFFBF; - _screen->showMouse(); -} - -void KyraEngine::seq_makeBrandonNormal() { - debug(9, "seq_makeBrandonNormal()"); - _screen->hideMouse(); - _brandonStatusBit |= 0x40; - snd_playSoundEffect(0x77); - _brandonInvFlag = 0x100; - while (_brandonInvFlag >= 0) { - animRefreshNPC(0); - delayWithTicks(10); - _brandonInvFlag -= 0x10; - } - _brandonInvFlag = 0; - _brandonStatusBit &= 0xFF9F; - _screen->showMouse(); -} - -void KyraEngine::seq_makeBrandonNormal2() { - debug(9, "seq_makeBrandonNormal2()"); - _screen->hideMouse(); - assert(_brandonToWispTable); - setupShapes123(_brandonToWispTable, 26, 0); - setBrandonAnimSeqSize(5, 48); - _brandonStatusBit &= 0xFFFD; - snd_playSoundEffect(0x6C); - for (int i = 138; i >= 123; --i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - setBrandonAnimSeqSize(4, 48); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245) { - _screen->fadeSpecialPalette(31, 234, 13, 4); - } else if (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186) { - _screen->fadeSpecialPalette(14, 228, 15, 4); - } - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_makeBrandonWisp() { - debug(9, "seq_makeBrandonWisp()"); - if (_deathHandler == 8) - return; - - if (_currentCharacter->sceneId == 210) { - if (_beadStateVar == 4 || _beadStateVar == 6) - return; - } - _screen->hideMouse(); - checkAmuletAnimFlags(); - assert(_brandonToWispTable); - setupShapes123(_brandonToWispTable, 26, 0); - setBrandonAnimSeqSize(5, 48); - snd_playSoundEffect(0x6C); - for (int i = 123; i <= 138; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - _brandonStatusBit |= 2; - if (_currentCharacter->sceneId >= 109 && _currentCharacter->sceneId <= 198) { - setTimerCountdown(14, 18000); - } else { - setTimerCountdown(14, 7200); - } - _brandonDrawFrame = 113; - _brandonStatusBit0x02Flag = 1; - _currentCharacter->currentAnimFrame = 113; - animRefreshNPC(0); - _animator->updateAllObjectShapes(); - if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245) { - _screen->fadeSpecialPalette(30, 234, 13, 4); - } else if (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186) { - _screen->fadeSpecialPalette(14, 228, 15, 4); - } - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_dispelMagicAnimation() { - debug(9, "seq_dispelMagicAnimation()"); - if (_deathHandler == 8) - return; - if (_currentCharacter->sceneId == 210) { - if (_beadStateVar == 4 || _beadStateVar == 6) - return; - } - _screen->hideMouse(); - if (_currentCharacter->sceneId == 210 && _currentCharacter->sceneId < 160) - _currentCharacter->facing = 3; - if (_malcolmFlag == 7 && _beadStateVar == 3) { - _beadStateVar = 6; - _unkEndSeqVar5 = 2; - _malcolmFlag = 10; - } - checkAmuletAnimFlags(); - setGameFlag(0xEE); - assert(_magicAnimationTable); - setupShapes123(_magicAnimationTable, 5, 0); - setBrandonAnimSeqSize(8, 49); - snd_playSoundEffect(0x15); - for (int i = 123; i <= 127; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - - delayWithTicks(120); - - for (int i = 127; i >= 123; --i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(10); - } - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_fillFlaskWithWater(int item, int type) { - debug(9, "seq_fillFlaskWithWater(%d, %d)", item, type); - int newItem = -1; - static const uint8 flaskTable1[] = { 0x46, 0x48, 0x4A, 0x4C }; - static const uint8 flaskTable2[] = { 0x47, 0x49, 0x4B, 0x4D }; - - if (item >= 60 && item <= 77) { - assert(_flaskFull); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - snd_playVoiceFile(8006); - } - characterSays(_flaskFull[0], 0, -2); - } else if (item == 78) { - assert(type >= 0 && type < ARRAYSIZE(flaskTable1)); - newItem = flaskTable1[type]; - } else if (item == 79) { - assert(type >= 0 && type < ARRAYSIZE(flaskTable2)); - newItem = flaskTable2[type]; - } - - if (newItem == -1) - return; - - _screen->hideMouse(); - setMouseItem(newItem); - _screen->showMouse(); - _itemInHand = newItem; - assert(_fullFlask); - assert(type < _fullFlask_Size && type >= 0); - if (_features & GF_TALKIE) { - snd_voiceWaitForFinish(); - static const uint16 voiceEntries[] = { - 0x1F40, 0x1F41, 0x1F42, 0x1F45 - }; - assert(type < ARRAYSIZE(voiceEntries)); - snd_playVoiceFile(voiceEntries[type]); - } - characterSays(_fullFlask[type], 0, -2); -} - -void KyraEngine::seq_playDrinkPotionAnim(int unk1, int unk2, int flags) { - debug(9, "KyraEngine::seq_playDrinkPotionAnim(%d, %d, %d)", unk1, unk2, flags); - // XXX - _screen->hideMouse(); - checkAmuletAnimFlags(); - _currentCharacter->facing = 5; - animRefreshNPC(0); - assert(_drinkAnimationTable); - setupShapes123(_drinkAnimationTable, 9, flags); - setBrandonAnimSeqSize(5, 54); - - for (int i = 123; i <= 131; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(5); - } - snd_playSoundEffect(0x34); - for (int i = 0; i < 2; ++i) { - _currentCharacter->currentAnimFrame = 130; - animRefreshNPC(0); - delayWithTicks(7); - _currentCharacter->currentAnimFrame = 131; - animRefreshNPC(0); - delayWithTicks(7); - } - - if (unk2) { - // XXX - } - - for (int i = 131; i >= 123; --i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(5); - } - - resetBrandonAnimSeqSize(); - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - freeShapes123(); - _screen->showMouse(); -} - -int KyraEngine::seq_playEnd() { - debug(9, "KyraEngine::seq_playEnd()"); - if (_endSequenceSkipFlag) { - return 0; - } - if (_deathHandler == 8) { - return 0; - } - _screen->_curPage = 2; - if (_endSequenceNeedLoading) { - snd_playWanderScoreViaMap(50, 1); - setupPanPages(); - _finalA = new WSAMovieV1(this); - assert(_finalA); - _finalA->open("finala.wsa", 1, 0); - _finalB = new WSAMovieV1(this); - assert(_finalB); - _finalB->open("finalb.wsa", 1, 0); - _finalC = new WSAMovieV1(this); - assert(_finalC); - _endSequenceNeedLoading = 0; - _finalC->open("finalc.wsa", 1, 0); - _screen->_curPage = 0; - _beadStateVar = 0; - _malcolmFlag = 0; - // wired stuff with _unkEndSeqVar2 which needs timer handling - _screen->copyRegion(312, 0, 312, 0, 8, 136, 0, 2); - } - if (handleMalcolmFlag()) { - _beadStateVar = 0; - _malcolmFlag = 12; - handleMalcolmFlag(); - handleBeadState(); - closeFinalWsa(); - if (_deathHandler == 8) { - _screen->_curPage = 0; - checkAmuletAnimFlags(); - seq_brandonToStone(); - waitTicks(60); - return 1; - } else { - _endSequenceSkipFlag = 1; - if (_text->printed()) { - _text->restoreTalkTextMessageBkgd(2, 0); - } - _screen->_curPage = 0; - _screen->hideMouse(); - _screen->fadeSpecialPalette(32, 228, 20, 60); - waitTicks(60); - loadBitmap("GEMHEAL.CPS", 3, 3, _screen->_currentPalette); - _screen->setScreenPalette(_screen->_currentPalette); - _screen->shuffleScreen(8, 8, 304, 128, 2, 0, 1, 0); - uint32 nextTime = _system->getMillis() + 120 * _tickLength; - _finalA = new WSAMovieV1(this); - assert(_finalA); - _finalA->open("finald.wsa", 1, 0); - _finalA->_x = _finalA->_y = 8; - _finalA->_drawPage = 0; - while (_system->getMillis() < nextTime) {} - snd_playSoundEffect(0x40); - for (int i = 0; i < 22; ++i) { - while (_system->getMillis() < nextTime) {} - if (i == 4) { - snd_playSoundEffect(0x3E); - } else if (i == 20) { - snd_playSoundEffect(0x0E); - } - nextTime = _system->getMillis() + 8 * _tickLength; - _finalA->displayFrame(i); - _screen->updateScreen(); - } - delete _finalA; - _finalA = 0; - seq_playEnding(); - return 1; - } - } else { - handleBeadState(); - _screen->bitBlitRects(); - _screen->updateScreen(); - _screen->_curPage = 0; - } - return 0; -} - -void KyraEngine::seq_brandonToStone() { - debug(9, "KyraEngine::seq_brandonToStone()"); - _screen->hideMouse(); - assert(_brandonStoneTable); - setupShapes123(_brandonStoneTable, 14, 0); - setBrandonAnimSeqSize(5, 51); - for (int i = 123; i <= 136; ++i) { - _currentCharacter->currentAnimFrame = i; - animRefreshNPC(0); - delayWithTicks(8); - } - resetBrandonAnimSeqSize(); - freeShapes123(); - _screen->showMouse(); -} - -void KyraEngine::seq_playEnding() { - debug(9, "KyraEngine::seq_playEnding()"); - _screen->hideMouse(); - res_unloadResources(RES_INGAME); - res_loadResources(RES_OUTRO); - loadBitmap("REUNION.CPS", 3, 3, _screen->_currentPalette); - _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); - _screen->_curPage = 0; - // XXX - assert(_homeString); - drawSentenceCommand(_homeString[0], 179); - _screen->_curPage = 0; - _screen->fadeToBlack(); - _seq->playSequence(_seq_Reunion, false); - _screen->fadeToBlack(); - _screen->showMouse(); - seq_playCredits(); -} - -void KyraEngine::seq_playCredits() { - debug(9, "KyraEngine::seq_playCredits()"); - static const uint8 colorMap[] = { 0, 0, 0xC, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - _screen->hideMouse(); - uint32 sz = 0; - if (_features & GF_FLOPPY) { - _screen->loadFont(Screen::FID_CRED6_FNT, _res->fileData("CREDIT6.FNT", &sz)); - _screen->loadFont(Screen::FID_CRED8_FNT, _res->fileData("CREDIT8.FNT", &sz)); - } - loadBitmap("CHALET.CPS", 2, 2, _screen->_currentPalette); - _screen->setScreenPalette(_screen->_currentPalette); - _screen->setCurPage(0); - _screen->clearCurPage(); - _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); - _screen->setTextColorMap(colorMap); - _screen->_charWidth = -1; - snd_playWanderScoreViaMap(53, 1); - // delete - _screen->updateScreen(); - // XXX - waitTicks(120); // wait until user presses escape normally - _screen->fadeToBlack(); - _screen->clearCurPage(); - _screen->showMouse(); -} - -bool KyraEngine::seq_skipSequence() const { - debug(9, "KyraEngine::seq_skipSequence()"); - return _quitFlag || _abortIntroFlag; -} - -void KyraEngine::snd_playTheme(int file, int track) { - debug(9, "KyraEngine::snd_playTheme(%d)", file); - assert(file < _xmidiFilesCount); - _curMusicTheme = _newMusicTheme = file; - _sound->playMusic(_xmidiFiles[file]); - _sound->playTrack(track, false); -} - -void KyraEngine::snd_playTrack(int track, bool looping) { - debug(9, "KyraEngine::snd_playTrack(%d, %d)", track, looping); - _sound->playTrack(track, looping); -} - -void KyraEngine::snd_setSoundEffectFile(int file) { - debug(9, "KyraEngine::snd_setSoundEffectFile(%d)", file); - assert(file < _xmidiFilesCount); - _sound->loadSoundEffectFile(_xmidiFiles[file]); -} - -void KyraEngine::snd_playSoundEffect(int track) { - debug(9, "KyraEngine::snd_playSoundEffect(%d)", track); - if (track == 49) { - snd_playWanderScoreViaMap(56, 1); - } else { - _sound->playSoundEffect(track); - } -} - -void KyraEngine::snd_playWanderScoreViaMap(int command, int restart) { - debug(9, "KyraEngine::snd_playWanderScoreViaMap(%d, %d)", command, restart); - static const int8 soundTable[] = { - -1, 0, -1, 1, 0, 3, 0, 2, - 0, 4, 1, 2, 1, 3, 1, 4, - 1, 0x5C, 1, 6, 1, 7, 2, 2, - 2, 3, 2, 4, 2, 5, 2, 6, - 2, 7, 3, 3, 3, 4, 1, 8, - 1, 9, 4, 2, 4, 3, 4, 4, - 4, 5, 4, 6, 4, 7, 4, 8, - 1, 0x0B, 1, 0x0C, 1, 0x0E, 1, 0x0D, - 4, 9, 5, 0x0C, 6, 2, 6, 6, - 6, 7, 6, 8, 6, 9, 6, 3, - 6, 4, 6, 5, 7, 2, 7, 3, - 7, 4, 7, 5, 7, 6, 7, 7, - 7, 8, 7, 9, 8, 2, 8, 3, - 8, 4, 8, 5, 6, 0x0B, 5, 0x0B - }; - //if (!_disableSound) { - // XXX - //} - assert(command*2+1 < ARRAYSIZE(soundTable)); - if (_curMusicTheme != soundTable[command*2]+1) { - if (soundTable[command*2] != -1) { - snd_playTheme(soundTable[command*2]+1); - } - } - - if (restart) - _lastMusicCommand = -1; - - if (command != 1) { - if (_lastMusicCommand != command) { - _lastMusicCommand = command; - snd_playTrack(soundTable[command*2+1], true); - } - } else { - _lastMusicCommand = 1; - _sound->beginFadeOut(); - } -} - -void KyraEngine::snd_playVoiceFile(int id) { - debug(9, "KyraEngine::snd_playVoiceFile(%d)", id); - char vocFile[9]; - assert(id >= 0 && id < 9999); - sprintf(vocFile, "%03d.VOC", id); - _sound->voicePlay(vocFile); -} - -bool KyraEngine::snd_voicePlaying() { - return _sound->voiceIsPlaying(); -} - -void KyraEngine::snd_voiceWaitForFinish(bool ingame) { - debug(9, "KyraEngine::snd_voiceWaitForFinish(%d)", ingame); - while (snd_voicePlaying() && !_fastMode) { - if (ingame) { - delay(10, true); - } else { - _system->delayMillis(10); - } - } -} - -void KyraEngine::snd_startTrack() { - debug(9, "KyraEngine::snd_startTrack()"); - _sound->startTrack(); -} - -void KyraEngine::snd_haltTrack() { - debug(9, "KyraEngine::snd_haltTrack()"); - _sound->haltTrack(); -} - -void KyraEngine::loadMouseShapes() { - loadBitmap("MOUSE.CPS", 3, 3, 0); - _screen->_curPage = 2; - _shapes[4] = _screen->encodeShape(0, 0, 8, 10, 0); - _shapes[5] = _screen->encodeShape(0, 0x17, 0x20, 7, 0); - _shapes[6] = _screen->encodeShape(0x50, 0x12, 0x10, 9, 0); - _shapes[7] = _screen->encodeShape(0x60, 0x12, 0x10, 11, 0); - _shapes[8] = _screen->encodeShape(0x70, 0x12, 0x10, 9, 0); - _shapes[9] = _screen->encodeShape(0x80, 0x12, 0x10, 11, 0); - _shapes[10] = _screen->encodeShape(0x90, 0x12, 0x10, 10, 0); - _shapes[364] = _screen->encodeShape(0x28, 0, 0x10, 13, 0); - _screen->setMouseCursor(1, 1, 0); - _screen->setMouseCursor(1, 1, _shapes[4]); - _screen->setShapePages(5, 3); -} - -void KyraEngine::loadCharacterShapes() { - int curImage = 0xFF; - int videoPage = _screen->_curPage; - _screen->_curPage = 2; - for (int i = 0; i < 115; ++i) { - assert(i < _defaultShapeTableSize); - Shape *shape = &_defaultShapeTable[i]; - if (shape->imageIndex == 0xFF) { - _shapes[i+7+4] = 0; - continue; - } - if (shape->imageIndex != curImage) { - assert(shape->imageIndex < _characterImageTableSize); - loadBitmap(_characterImageTable[shape->imageIndex], 3, 3, 0); - curImage = shape->imageIndex; - } - _shapes[i+7+4] = _screen->encodeShape(shape->x<<3, shape->y, shape->w<<3, shape->h, 1); - } - _screen->_curPage = videoPage; -} - -void KyraEngine::loadSpecialEffectShapes() { - loadBitmap("EFFECTS.CPS", 3, 3, 0); - _screen->_curPage = 2; - - int currShape; - for (currShape = 173; currShape < 183; currShape++) - _shapes[4 + currShape] = _screen->encodeShape((currShape-173) * 24, 0, 24, 24, 1); - - for (currShape = 183; currShape < 190; currShape++) - _shapes[4 + currShape] = _screen->encodeShape((currShape-183) * 24, 24, 24, 24, 1); - - for (currShape = 190; currShape < 201; currShape++) - _shapes[4 + currShape] = _screen->encodeShape((currShape-190) * 24, 48, 24, 24, 1); - - for (currShape = 201; currShape < 206; currShape++) - _shapes[4 + currShape] = _screen->encodeShape((currShape-201) * 16, 106, 16, 16, 1); -} - -int KyraEngine::findDuplicateItemShape(int shape) { - static uint8 dupTable[] = { - 0x48, 0x46, 0x49, 0x47, 0x4a, 0x46, 0x4b, 0x47, - 0x4c, 0x46, 0x4d, 0x47, 0x5b, 0x5a, 0x5c, 0x5a, - 0x5d, 0x5a, 0x5e, 0x5a, 0xFF, 0xFF - }; - - int i = 0; - - while (dupTable[i] != 0xFF) { - if (dupTable[i] == shape) - return dupTable[i+1]; - i += 2; - } - return -1; -} - -void KyraEngine::loadItems() { - int shape; - - loadBitmap("JEWELS3.CPS", 3, 3, 0); - _screen->_curPage = 2; - - _shapes[327] = 0; - - for (shape = 1; shape < 6; shape++ ) - _shapes[327 + shape] = _screen->encodeShape((shape - 1) * 32, 0, 32, 17, 0); - - for (shape = 330; shape <= 334; shape++) - _shapes[4 + shape] = _screen->encodeShape((shape-330) * 32, 102, 32, 17, 0); - - for (shape = 335; shape <= 339; shape++) - _shapes[4 + shape] = _screen->encodeShape((shape-335) * 32, 17, 32, 17, 0); - - for (shape = 340; shape <= 344; shape++) - _shapes[4 + shape] = _screen->encodeShape((shape-340) * 32, 34, 32, 17, 0); - - for (shape = 345; shape <= 349; shape++) - _shapes[4 + shape] = _screen->encodeShape((shape-345) * 32, 51, 32, 17, 0); - - for (shape = 350; shape <= 354; shape++) - _shapes[4 + shape] = _screen->encodeShape((shape-350) * 32, 68, 32, 17, 0); - - for (shape = 355; shape <= 359; shape++) - _shapes[4 + shape] = _screen->encodeShape((shape-355) * 32, 85, 32, 17, 0); - - - loadBitmap("ITEMS.CPS", 3, 3, 0); - _screen->_curPage = 2; - - for (int i = 0; i < 107; i++) { - shape = findDuplicateItemShape(i); - - if (shape != -1) - _shapes[220 + i] = _shapes[220 + shape]; - else - _shapes[220 + i] = _screen->encodeShape( (i % 20) * 16, i/20 * 16, 16, 16, 0); - } - - uint32 size; - uint8 *fileData = _res->fileData("_ITEM_HT.DAT", &size); - assert(fileData); - - for (int i = 0; i < 107; i++) { - _itemTable[i].height = fileData[i]; - _itemTable[i].unk1 = _itemTable[i].unk2 = 0; - } - - delete[] fileData; -} - -void KyraEngine::loadButtonShapes() { - loadBitmap("BUTTONS2.CPS", 3, 3, 0); - _screen->_curPage = 2; - _scrollUpButton.process0PtrShape = _screen->encodeShape(0, 0, 24, 14, 1); - _scrollUpButton.process1PtrShape = _screen->encodeShape(24, 0, 24, 14, 1); - _scrollUpButton.process2PtrShape = _screen->encodeShape(48, 0, 24, 14, 1); - _scrollDownButton.process0PtrShape = _screen->encodeShape(0, 15, 24, 14, 1); - _scrollDownButton.process1PtrShape = _screen->encodeShape(24, 15, 24, 14, 1); - _scrollDownButton.process2PtrShape = _screen->encodeShape(48, 15, 24, 14, 1); - _screen->_curPage = 0; -} - -void KyraEngine::initMainButtonList() { - _buttonList = &_buttonData[0]; - for (int i = 0; _buttonDataListPtr[i]; ++i) { - _buttonList = initButton(_buttonList, _buttonDataListPtr[i]); - } -} - -void KyraEngine::loadMainScreen(int page) { - if ((_features & GF_ENGLISH) && (_features & GF_TALKIE)) - loadBitmap("MAIN_ENG.CPS", page, page, 0); - else if(_features & GF_FRENCH) - loadBitmap("MAIN_FRE.CPS", page, page, 0); - else if(_features & GF_GERMAN) - loadBitmap("MAIN_GER.CPS", page, page, 0); - else if ((_features & GF_ENGLISH) && (_features & GF_FLOPPY)) - loadBitmap("MAIN15.CPS", page, page, 0); - else if (_features & GF_SPANISH) - loadBitmap("MAIN_SPA.CPS", page, page, 0); - else - warning("no main graphics file found"); - - uint8 *_pageSrc = _screen->getPagePtr(page); - uint8 *_pageDst = _screen->getPagePtr(0); - memcpy(_pageDst, _pageSrc, 320*200); -} - -void KyraEngine::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::setCharacterDefaultFrame(int character) { static uint16 initFrameTable[] = { 7, 41, 77, 0, 0 @@ -2065,22 +798,6 @@ void KyraEngine::setCharacterDefaultFrame(int character) { // edit->unk6 = 1; } -void KyraEngine::setCharactersPositions(int character) { - static uint16 initXPosTable[] = { - 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B, - 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042 - }; - static 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]; -} - void KyraEngine::setCharactersHeight() { static int8 initHeightTable[] = { 48, 40, 48, 47, 56, @@ -2106,2183 +823,6 @@ int KyraEngine::resetGameFlag(int flag) { return 0; } -void KyraEngine::enterNewScene(int sceneId, int facing, int unk1, int unk2, int brandonAlive) { - debug(9, "KyraEngine::enterNewScene(%d, %d, %d, %d, %d)", sceneId, facing, unk1, unk2, brandonAlive); - int unkVar1 = 1; - _screen->hideMouse(); - _handleInput = false; - _abortWalkFlag = false; - _abortWalkFlag2 = false; - if (_currentCharacter->sceneId == 7 && sceneId == 24) { - _newMusicTheme = 3; - } else if (_currentCharacter->sceneId == 25 && sceneId == 109) { - _newMusicTheme = 4; - } else if (_currentCharacter->sceneId == 120 && sceneId == 37) { - _newMusicTheme = 5; - } else if (_currentCharacter->sceneId == 52 && sceneId == 199) { - _newMusicTheme = 6; - } else if (_currentCharacter->sceneId == 37 && sceneId == 120) { - _newMusicTheme = 4; - } else if (_currentCharacter->sceneId == 109 && sceneId == 25) { - _newMusicTheme = 3; - } else if (_currentCharacter->sceneId == 24 && sceneId == 7) { - _newMusicTheme = 2; - } - if (_newMusicTheme != _curMusicTheme) { - snd_playTheme(_newMusicTheme); - } - - 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) { - _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - _scriptInterpreter->startScript(_scriptClick, 5); - while (_scriptInterpreter->validScript(_scriptClick)) { - _scriptInterpreter->runScript(_scriptClick); - } - } - - memset(_entranceMouseCursorTracks, 0xFFFF, sizeof(uint16)*4); - _currentCharacter->sceneId = sceneId; - - assert(sceneId < _roomTableSize); - assert(_roomTable[sceneId].nameIndex < _roomFilenameTableSize); - - Room *currentRoom = &_roomTable[sceneId]; - - if (_currentRoom != 0xFFFF && (_features & GF_TALKIE)) { - char file[32]; - assert(_currentRoom < _roomTableSize); - int tableId = _roomTable[_currentRoom].nameIndex; - assert(tableId < _roomFilenameTableSize); - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".VRM"); - _res->unloadPakFile(file); - } - - _currentRoom = sceneId; - - int tableId = _roomTable[_currentCharacter->sceneId].nameIndex; - char fileNameBuffer[32]; - strcpy(fileNameBuffer, _roomFilenameTable[tableId]); - strcat(fileNameBuffer, ".DAT"); - _sprites->loadDAT(fileNameBuffer, _sceneExits); - _sprites->setupSceneAnims(); - _scriptInterpreter->unloadScript(_scriptClickData); - loadSceneMSC(); - - if ((_features & GF_TALKIE)) { - strcpy(fileNameBuffer, _roomFilenameTable[tableId]); - strcat(fileNameBuffer, ".VRM"); - _res->loadPakFile(fileNameBuffer); - } - - _walkBlockNorth = currentRoom->northExit; - _walkBlockEast = currentRoom->eastExit; - _walkBlockSouth = currentRoom->southExit; - _walkBlockWest = currentRoom->westExit; - - if (_walkBlockNorth == 0xFFFF) { - blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF)+3); - } - if (_walkBlockEast == 0xFFFF) { - blockOutRegion(312, 0, 8, 139); - } - if (_walkBlockSouth == 0xFFFF) { - blockOutRegion(0, 135, 320, 8); - } - if (_walkBlockWest == 0xFFFF) { - 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::transcendScenes(int roomIndex, int roomName) { - debug(9, "KyraEngine::transcendScenes(%d, %d)", roomIndex, roomName); - assert(roomIndex < _roomTableSize); - if (_features & GF_TALKIE) { - 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::setSceneFile(int roomIndex, int roomName) { - debug(9, "KyraEngine::setSceneFile(%d, %d)", roomIndex, roomName); - assert(roomIndex < _roomTableSize); - _roomTable[roomIndex].nameIndex = roomName; -} - -void KyraEngine::moveCharacterToPos(int character, int facing, int xpos, int ypos) { - debug(9, "KyraEngine::moveCharacterToPos(%d, %d, %d, %d)", character, facing, xpos, ypos); - Character *ch = &_characterList[character]; - ch->facing = facing; - _screen->hideMouse(); - xpos = (int16)(xpos & 0xFFFC); - ypos = (int16)(ypos & 0xFFFE); - disableTimer(19); - disableTimer(14); - disableTimer(18); - uint32 nextFrame = 0; - switch (facing) { - case 0: - while (ypos < ch->y1) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - while (_system->getMillis() < nextFrame) { updateGameTimers(); } - } - break; - - case 2: - while (ch->x1 < xpos) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - while (_system->getMillis() < nextFrame) { updateGameTimers(); } - } - break; - - case 4: - while (ypos > ch->y1) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - while (_system->getMillis() < nextFrame) { updateGameTimers(); } - } - break; - - case 6: - while (ch->x1 > xpos) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - while (_system->getMillis() < nextFrame) { updateGameTimers(); } - } - break; - - default: - break; - } - enableTimer(19); - enableTimer(14); - enableTimer(18); - _screen->showMouse(); -} - -void KyraEngine::setCharacterPositionWithUpdate(int character) { - debug(9, "KyraEngine::setCharacterPositionWithUpdate(%d)", character); - setCharacterPosition(character, 0); - _sprites->updateSceneAnims(); - updateGameTimers(); - _animator->updateAllObjectShapes(); - updateTextFade(); - - if (_currentCharacter->sceneId == 210) { - _animator->updateKyragemFading(); - } -} - -int KyraEngine::setCharacterPosition(int character, int *facingTable) { - debug(9, "KyraEngine::setCharacterPosition(%d, 0x%X)", character, facingTable); - if (character == 0) { - _currentCharacter->x1 += _charXPosTable[_currentCharacter->facing]; - _currentCharacter->y1 += _charYPosTable[_currentCharacter->facing]; - setCharacterPositionHelper(0, facingTable); - return 1; - } else { - _characterList[character].x1 += _charXPosTable[_characterList[character].facing]; - _characterList[character].y1 += _charYPosTable[_characterList[character].facing]; - if (_characterList[character].sceneId == _currentCharacter->sceneId) { - setCharacterPositionHelper(character, 0); - } - } - return 0; -} - -void KyraEngine::setCharacterPositionHelper(int character, int *facingTable) { - debug(9, "KyraEngine::setCharacterPositionHelper(%d, 0x%X)", character, 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); - } - } - } - - static uint8 facingIsZero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - static uint8 facingIsFour[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - if (facing == 0) { - ++facingIsZero[character]; - } else { - bool resetTables = false; - if (facing != 7) { - if (facing - 1 != 0) { - if (facing != 4) { - if (facing == 3 || facing == 5) { - if (facingIsFour[character] > 2) { - facing = 4; - } - resetTables = true; - } - } else { - ++facingIsFour[character]; - } - } else { - if (facingIsZero[character] > 2) { - facing = 0; - } - resetTables = true; - } - } else { - if (facingIsZero[character] > 2) { - facing = 0; - } - resetTables = true; - } - - if (resetTables) { - facingIsZero[character] = 0; - facingIsFour[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) { - if (_brandonStatusBit & 0x10) - ch->currentAnimFrame = 88; - } - - animRefreshNPC(character); -} - -int KyraEngine::getOppositeFacingDirection(int dir) { - debug(9, "KyraEngine::getOppositeFacingDirection(%d)", dir); - switch (dir) { - case 0: - return 2; - break; - - case 1: - return 1; - break; - - case 3: - return 7; - break; - - case 4: - return 6; - break; - - case 5: - return 5; - break; - - case 6: - return 4; - break; - - case 7: - return 3; - break; - - default: - break; - } - return 0; -} - -void KyraEngine::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); - loadBitmap(fileNameBuffer, 3, 5, 0); -} - -// maybe move these two functions to Screen -void KyraEngine::blockInRegion(int x, int y, int width, int height) { - debug(9, "KyraEngine::blockInRegion(%d, %d, %d, %d)", x, y, width, height); - assert(_screen->_shapePages[0]); - byte *toPtr = _screen->_shapePages[0] + (y * 320 + x); - for (int i = 0; i < height; ++i) { - byte *backUpTo = toPtr; - for (int i2 = 0; i2 < width; ++i2) { - *toPtr++ &= 0x7F; - } - toPtr = (backUpTo + 320); - } -} - -void KyraEngine::blockOutRegion(int x, int y, int width, int height) { - debug(9, "KyraEngine::blockOutRegion(%d, %d, %d, %d)", x, y, width, height); - assert(_screen->_shapePages[0]); - byte *toPtr = _screen->_shapePages[0] + (y * 320 + x); - for (int i = 0; i < height; ++i) { - byte *backUpTo = toPtr; - for (int i2 = 0; i2 < width; ++i2) { - *toPtr++ |= 0x80; - } - toPtr = (backUpTo + 320); - } -} - -void KyraEngine::startSceneScript(int brandonAlive) { - debug(9, "KyraEngine::startSceneScript(%d)", brandonAlive); - assert(_currentCharacter->sceneId < _roomTableSize); - int tableId = _roomTable[_currentCharacter->sceneId].nameIndex; - assert(tableId < _roomFilenameTableSize); - char fileNameBuffer[32]; - strcpy(fileNameBuffer, _roomFilenameTable[tableId]); - strcat(fileNameBuffer, ".CPS"); - loadBitmap(fileNameBuffer, 3, 3, 0); - _sprites->loadSceneShapes(); - _exitListPtr = 0; - - _screen->setScreenPalette(_screen->_currentPalette); - - _scaleMode = 1; - for (int i = 0; i < 145; ++i) { - _scaleTable[i] = 256; - } - - clearNoDropRects(); - _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - strcpy(fileNameBuffer, _roomFilenameTable[tableId]); - strcat(fileNameBuffer, ".EMC"); - _scriptInterpreter->unloadScript(_scriptClickData); - _scriptInterpreter->loadScript(fileNameBuffer, _scriptClickData, _opcodeTable, _opcodeTableSize, 0); - _scriptInterpreter->startScript(_scriptClick, 0); - _scriptClick->variables[0] = _currentCharacter->sceneId; - _scriptClick->variables[7] = brandonAlive; - - while (_scriptInterpreter->validScript(_scriptClick)) { - _scriptInterpreter->runScript(_scriptClick); - } -} - -void KyraEngine::initSceneData(int facing, int unk1, int brandonAlive) { - debug(9, "KyraEngine::initSceneData(%d, %d, %d)", facing, unk1, 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->variables[4] = _itemInHand; - _scriptClick->variables[7] = brandonAlive; - _scriptInterpreter->startScript(_scriptClick, 3); - while (_scriptInterpreter->validScript(_scriptClick)) { - _scriptInterpreter->runScript(_scriptClick); - } -} - -void KyraEngine::resetBrandonPosionFlags() { - _brandonStatusBit = 0; - for (int i = 0; i < 256; ++i) { - _brandonPoisonFlagsGFX[i] = i; - } -} - -void KyraEngine::initAnimStateList() { - AnimObject *animStates = _animator->objects(); - animStates[0].index = 0; - animStates[0].active = 1; - animStates[0].flags = 0x800; - animStates[0].background = _shapes[2]; - animStates[0].rectSize = _screen->getRectSize(4, 48); - animStates[0].width = 4; - animStates[0].height = 48; - animStates[0].width2 = 4; - animStates[0].height2 = 3; - - for (int i = 1; i <= 4; ++i) { - animStates[i].index = i; - animStates[i].active = 0; - animStates[i].flags = 0x800; - animStates[i].background = _shapes[3]; - animStates[i].rectSize = _screen->getRectSize(4, 64); - animStates[i].width = 4; - animStates[i].height = 48; - animStates[i].width2 = 4; - animStates[i].height2 = 3; - } - - for (int i = 5; i < 16; ++i) { - animStates[i].index = i; - animStates[i].active = 0; - animStates[i].flags = 0; - } - - for (int i = 16; i < 28; ++i) { - animStates[i].index = i; - animStates[i].flags = 0; - animStates[i].background = _shapes[349+i]; - animStates[i].rectSize = _screen->getRectSize(3, 24); - animStates[i].width = 3; - animStates[i].height = 16; - animStates[i].width2 = 0; - animStates[i].height2 = 0; - } -} - -void KyraEngine::initSceneObjectList(int brandonAlive) { - debug(9, "KyraEngine::initSceneObjectList(%d)", brandonAlive); - for (int i = 0; i < 28; ++i) { - _animator->actors()[i].active = 0; - } - - int startAnimFrame = 0; - - AnimObject *curAnimState = _animator->actors(); - curAnimState->active = 1; - curAnimState->drawY = _currentCharacter->y1; - curAnimState->sceneAnimPtr = _shapes[4+_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; - - _brandonScaleX = _scaleTable[_currentCharacter->y1]; - _brandonScaleY = _scaleTable[_currentCharacter->y1]; - - curAnimState->x1 += (_brandonScaleX * xOffset) >> 8; - curAnimState->y1 += (_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[4+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; - - _brandonScaleX = _scaleTable[ch->y1]; - _brandonScaleY = _scaleTable[ch->y1]; - - curAnimState->x1 += (_brandonScaleX * xOffset) >> 8; - curAnimState->y1 += (_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]; - - 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[220+curItem]; - curAnimState->animFrameNumber = (int16)0xFFFF; - curAnimState->y1 = curRoom->itemsYPos[i]; - curAnimState->x1 = curRoom->itemsXPos[i]; - - curAnimState->x1 -= (fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1; - curAnimState->y1 -= 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::initSceneScreen(int brandonAlive) { - // XXX (Pointless?) Palette stuff - 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->updateScreen(); - // XXX More (pointless?) palette stuff - - if (!_scriptInterpreter->startScript(_scriptClick, 2)) - error("Could not start script function 2 of scene script"); - - _scriptClick->variables[7] = brandonAlive; - - while (_scriptInterpreter->validScript(_scriptClick)) - _scriptInterpreter->runScript(_scriptClick); - - setTextFadeTimerCountdown(-1); - if (_currentCharacter->sceneId == 210) { - if (_itemInHand != -1) - magicOutMouseItem(2, -1); - - _screen->hideMouse(); - for (int i = 0; i < 10; ++i) { - if (_currentCharacter->inventoryItems[i] != 0xFF) - magicOutMouseItem(2, i); - } - _screen->showMouse(); - } -} - -#pragma mark - -#pragma mark - Text handling -#pragma mark - - -void KyraEngine::waitForChatToFinish(int16 chatDuration, char *chatStr, uint8 charNum) { - debug(9, "KyraEngine::waitForChatToFinish(%i, %s, %i)", chatDuration, chatStr, charNum); - bool hasUpdatedNPCs = false; - bool runLoop = true; - uint8 currPage; - OSystem::Event event; - int16 delayTime; - - //while( towns_isEscKeyPressed() ) - //towns_getKey(); - - uint32 timeToEnd = strlen(chatStr) * 8 * _tickLength + _system->getMillis(); - - if (chatDuration != -1 ) { - switch (_configTalkspeed) { - case 0: chatDuration *= 2; - break; - case 2: chatDuration /= 4; - break; - case 3: chatDuration = -1; - } - } - - if (chatDuration != -1) - chatDuration *= _tickLength; - - disableTimer(14); - disableTimer(18); - disableTimer(19); - - uint32 timeAtStart = _system->getMillis(); - uint32 loopStart; - while (runLoop) { - loopStart = _system->getMillis(); - if (_currentCharacter->sceneId == 210) - if (seq_playEnd()) - break; - - if (_system->getMillis() > timeToEnd && !hasUpdatedNPCs) { - hasUpdatedNPCs = true; - disableTimer(15); - _currHeadShape = 4; - animRefreshNPC(0); - animRefreshNPC(_talkingCharNum); - - if (_charSayUnk2 != -1) { - _animator->sprites()[_charSayUnk2].active = 0; - _sprites->_anims[_charSayUnk2].play = false; - _charSayUnk2 = -1; - } - } - - updateGameTimers(); - _sprites->updateSceneAnims(); - _animator->restoreAllObjectBackgrounds(); - _animator->preserveAnyChangedBackgrounds(); - _animator->prepDrawAllObjects(); - - currPage = _screen->_curPage; - _screen->_curPage = 2; - _text->printCharacterText(chatStr, charNum, _characterList[charNum].x1); - _screen->_curPage = currPage; - - _animator->copyChangedObjectsForward(0); - updateTextFade(); - - if ((chatDuration < (int16)(_system->getMillis() - timeAtStart)) && chatDuration != -1) - break; - - while (_system->pollEvent(event)) { - switch (event.type) { - case OSystem::EVENT_KEYDOWN: - if (event.kbd.keycode == '.') - runLoop = false; - break; - case OSystem::EVENT_QUIT: - quitGame(); - case OSystem::EVENT_LBUTTONDOWN: - runLoop = false; - break; - default: - break; - } - } - - if (_fastMode) - runLoop = false; - - delayTime = (loopStart + _gameSpeed) - _system->getMillis(); - if (delayTime > 0) - _system->delayMillis(delayTime); - } - - enableTimer(14); - enableTimer(15); - enableTimer(18); - enableTimer(19); - //clearKyrandiaButtonIO(); -} - -void KyraEngine::endCharacterChat(int8 charNum, int16 convoInitialized) { - _charSayUnk3 = -1; - - if (charNum > 4 && charNum < 11) { - //TODO: weird _game_inventory stuff here - warning("STUB: endCharacterChat() for high charnums"); - } - - if (convoInitialized != 0) { - _talkingCharNum = -1; - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - _animator->updateAllObjectShapes(); - } -} - -void KyraEngine::restoreChatPartnerAnimFrame(int8 charNum) { - _talkingCharNum = -1; - - if (charNum > 0 && charNum < 5) { - _characterList[charNum].currentAnimFrame = _currentChatPartnerBackupFrame; - animRefreshNPC(charNum); - } - - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - _animator->updateAllObjectShapes(); -} - -void KyraEngine::backupChatPartnerAnimFrame(int8 charNum) { - _talkingCharNum = 0; - - if (charNum < 5 && charNum > 0) - _currentChatPartnerBackupFrame = _characterList[charNum].currentAnimFrame; - - if (_scaleMode != 0) - _currentCharacter->currentAnimFrame = 7; - else - _currentCharacter->currentAnimFrame = _currentCharAnimFrame; - - animRefreshNPC(0); - _animator->updateAllObjectShapes(); -} - -int8 KyraEngine::getChatPartnerNum() { - uint8 sceneTable[] = {0x2, 0x5, 0x2D, 0x7, 0x1B, 0x8, 0x22, 0x9, 0x30, 0x0A}; - int pos = 0; - int partner = -1; - - for (int i = 1; i < 6; i++) { - if (_currentCharacter->sceneId == sceneTable[pos]) { - partner = sceneTable[pos+1]; - break; - } - pos += 2; - } - - for (int i = 1; i < 5; i++) { - if (_characterList[i].sceneId == _currentCharacter->sceneId) { - partner = i; - break; - } - } - return partner; -} - -int KyraEngine::initCharacterChat(int8 charNum) { - if (_talkingCharNum == -1) { - _talkingCharNum = 0; - - if (_scaleMode != 0) - _currentCharacter->currentAnimFrame = 7; - else - _currentCharacter->currentAnimFrame = 16; - - animRefreshNPC(0); - _animator->updateAllObjectShapes(); - } - - _charSayUnk2 = -1; - _animator->flagAllObjectsForBkgdChange(); - _animator->restoreAllObjectBackgrounds(); - - if (charNum > 4 && charNum < 11) { - // TODO: Fill in weird _game_inventory stuff here - warning("STUB: initCharacterChat() for high charnums"); - } - - _animator->flagAllObjectsForRefresh(); - _animator->flagAllObjectsForBkgdChange(); - _animator->preserveAnyChangedBackgrounds(); - _charSayUnk3 = charNum; - - return 1; -} - -void KyraEngine::characterSays(char *chatStr, int8 charNum, int8 chatDuration) { - debug(9, "KyraEngine::characterSays('%s', %i, %d)", chatStr, charNum, chatDuration); - uint8 startAnimFrames[] = { 0x10, 0x32, 0x56, 0x0, 0x0, 0x0 }; - - uint16 chatTicks; - int16 convoInitialized; - int8 chatPartnerNum; - - if (_currentCharacter->sceneId == 210) - return; - - convoInitialized = initCharacterChat(charNum); - chatPartnerNum = getChatPartnerNum(); - - if (chatPartnerNum != -1 && chatPartnerNum < 5) - backupChatPartnerAnimFrame(chatPartnerNum); - - if (charNum < 5) { - _characterList[charNum].currentAnimFrame = startAnimFrames[charNum]; - _charSayUnk3 = charNum; - _talkingCharNum = charNum; - animRefreshNPC(charNum); - } - - char *processedString = _text->preprocessString(chatStr); - int lineNum = _text->buildMessageSubstrings(processedString); - - int16 yPos = _characterList[charNum].y1; - yPos -= _scaleTable[charNum] * _characterList[charNum].height; - yPos -= 8; - yPos -= lineNum * 10; - - if (yPos < 11) - yPos = 11; - - if (yPos > 100) - yPos = 100; - - _text->_talkMessageY = yPos; - _text->_talkMessageH = lineNum * 10; - _animator->restoreAllObjectBackgrounds(); - - _screen->copyRegion(12, _text->_talkMessageY, 12, 136, 308, _text->_talkMessageH, 2, 2); - _screen->hideMouse(); - - _text->printCharacterText(processedString, charNum, _characterList[charNum].x1); - _screen->showMouse(); - - if (chatDuration == -2) - chatTicks = strlen(processedString) * 9; - else - chatTicks = chatDuration; - - waitForChatToFinish(chatTicks, chatStr, charNum); - - _animator->restoreAllObjectBackgrounds(); - - _screen->copyRegion(12, 136, 12, _text->_talkMessageY, 308, _text->_talkMessageH, 2, 2); - _animator->preserveAllBackgrounds(); - _animator->prepDrawAllObjects(); - _screen->hideMouse(); - - _screen->copyRegion(12, _text->_talkMessageY, 12, _text->_talkMessageY, 308, _text->_talkMessageH, 2, 0); - _screen->showMouse(); - _animator->flagAllObjectsForRefresh(); - _animator->copyChangedObjectsForward(0); - - if (chatPartnerNum != -1 && chatPartnerNum < 5) - restoreChatPartnerAnimFrame(chatPartnerNum); - - endCharacterChat(charNum, convoInitialized); -} - -void KyraEngine::drawSentenceCommand(char *sentence, int color) { - debug(9, "KyraEngine::drawSentenceCommand('%s', %i)", sentence, color); - _screen->hideMouse(); - _screen->fillRect(8, 143, 311, 152, 12); - - if (_startSentencePalIndex != color || _fadeText != false) { - _currSentenceColor[0] = _screen->_currentPalette[765] = _screen->_currentPalette[color*3]; - _currSentenceColor[1] = _screen->_currentPalette[766] = _screen->_currentPalette[color*3+1]; - _currSentenceColor[2] = _screen->_currentPalette[767] = _screen->_currentPalette[color*3+2]; - - _screen->setScreenPalette(_screen->_currentPalette); - _startSentencePalIndex = 0; - } - - _text->printText(sentence, 8, 143, 0xFF, 12, 0); - _screen->showMouse(); - setTextFadeTimerCountdown(15); - _fadeText = false; -} - -void KyraEngine::updateSentenceCommand(char *str1, char *str2, int color) { - debug(9, "KyraEngine::updateSentenceCommand('%s', '%s', %i)", str1, str2, color); - char sentenceCommand[500]; - strncpy(sentenceCommand, str1, 500); - if (str2) - strncat(sentenceCommand, str2, 500 - strlen(sentenceCommand)); - - drawSentenceCommand(sentenceCommand, color); - _screen->updateScreen(); -} - -void KyraEngine::updateTextFade() { - debug(9, "KyraEngine::updateTextFade()"); - if (!_fadeText) - return; - - bool finished = false; - for (int i = 0; i < 3; i++) - if (_currSentenceColor[i] > 4) - _currSentenceColor[i] -= 4; - else - if (_currSentenceColor[i]) { - _currSentenceColor[i] = 0; - finished = true; - } - - _screen->_currentPalette[765] = _currSentenceColor[0]; - _screen->_currentPalette[766] = _currSentenceColor[1]; - _screen->_currentPalette[767] = _currSentenceColor[2]; - _screen->setScreenPalette(_screen->_currentPalette); - - if (finished) { - _fadeText = false; - _startSentencePalIndex = -1; - } -} - -#pragma mark - -#pragma mark - Item handling -#pragma mark - - -void KyraEngine::addToNoDropRects(int x, int y, int w, int h) { - debug(9, "KyraEngine::addToNoDropRects(%d, %d, %d, %d)", x, y, w, h); - for (int rect = 0; rect < 11; ++rect) { - if (_noDropRects[rect].x == -1) { - _noDropRects[rect].x = x; - _noDropRects[rect].y = y; - _noDropRects[rect].x2 = x + w - 1; - _noDropRects[rect].y2 = y + h - 1; - break; - } - } -} - -void KyraEngine::clearNoDropRects() { - debug(9, "KyraEngine::clearNoDropRects()"); - memset(_noDropRects, -1, sizeof(_noDropRects)); -} - -byte KyraEngine::findFreeItemInScene(int scene) { - debug(9, "KyraEngine::findFreeItemInScene(%d)", scene); - assert(scene < _roomTableSize); - Room *room = &_roomTable[scene]; - for (int i = 0; i < 12; ++i) { - if (room->itemsTable[i] == 0xFF) - return i; - } - return 0xFF; -} - -byte KyraEngine::findItemAtPos(int x, int y) { - debug(9, "KyraEngine::findItemAtPos(%d, %d)", x, y); - assert(_currentCharacter->sceneId < _roomTableSize); - const uint8 *itemsTable = _roomTable[_currentCharacter->sceneId].itemsTable; - const uint16 *xposOffset = _roomTable[_currentCharacter->sceneId].itemsXPos; - const uint8 *yposOffset = _roomTable[_currentCharacter->sceneId].itemsYPos; - - int highestYPos = -1; - byte returnValue = 0xFF; - - for (int i = 0; i < 12; ++i) { - if (*itemsTable != 0xFF) { - int xpos = *xposOffset - 11; - int xpos2 = *xposOffset + 10; - if (x > xpos && x < xpos2) { - assert(*itemsTable < ARRAYSIZE(_itemTable)); - int itemHeight = _itemTable[*itemsTable].height; - int ypos = *yposOffset + 3; - int ypos2 = ypos - itemHeight - 3; - - if (y > ypos2 && ypos > y) { - if (highestYPos <= ypos) { - returnValue = i; - highestYPos = ypos; - } - } - } - } - ++xposOffset; - ++yposOffset; - ++itemsTable; - } - - return returnValue; -} - -void KyraEngine::placeItemInGenericMapScene(int item, int index) { - debug(9, "KyraEngine::placeItemInGenericMapScene(%d, %d)", item, index); - static const uint16 itemMapSceneMinTable[] = { - 0x0000, 0x0011, 0x006D, 0x0025, 0x00C7, 0x0000 - }; - static const uint16 itemMapSceneMaxTable[] = { - 0x0010, 0x0024, 0x00C6, 0x006C, 0x00F5, 0x0000 - }; - - int minValue = itemMapSceneMinTable[index]; - int maxValue = itemMapSceneMaxTable[index]; - - while (true) { - int room = _rnd.getRandomNumberRng(minValue, maxValue); - assert(room < _roomTableSize); - int nameIndex = _roomTable[room].nameIndex; - bool placeItem = false; - - switch (nameIndex) { - case 0: case 1: case 2: case 3: - case 4: case 5: case 6: case 11: - case 12: case 16: case 17: case 20: - case 22: case 23: case 25: case 26: - case 27: case 31: case 33: case 34: - case 36: case 37: case 58: case 59: - case 60: case 61: case 83: case 84: - case 85: case 104: case 105: case 106: - placeItem = true; - break; - - case 51: - if (room != 46) { - placeItem = true; - break; - } - default: - placeItem = false; - break; - } - - if (placeItem) { - Room *roomPtr = &_roomTable[room]; - if (roomPtr->northExit == 0xFFFF && roomPtr->eastExit == 0xFFFF && roomPtr->southExit == 0xFFFF && roomPtr->westExit == 0xFFFF) { - placeItem = false; - } else if (_currentCharacter->sceneId == room) { - placeItem = false; - } - } - - if (placeItem) { - if (!processItemDrop(room, item, -1, -1, 2, 0)) - continue; - break; - } - } -} - -void KyraEngine::createMouseItem(int item) { - debug(9, "KyraEngine::createMouseItem(%d)", item); - _screen->hideMouse(); - setMouseItem(item); - _itemInHand = item; - _screen->showMouse(); -} - -void KyraEngine::destroyMouseItem() { - debug(9, "KyraEngine::destroyMouseItem()"); - _screen->hideMouse(); - _screen->setMouseCursor(1, 1, _shapes[4]); - _itemInHand = -1; - _screen->showMouse(); -} - -void KyraEngine::setMouseItem(int item) { - debug(9, "KyraEngine::setMouseItem(%d)", item); - if (item == -1) { - _screen->setMouseCursor(1, 1, _shapes[10]); - } else { - _screen->setMouseCursor(8, 15, _shapes[220+item]); - } -} - -void KyraEngine::wipeDownMouseItem(int xpos, int ypos) { - debug(9, "KyraEngine::wipeDownMouseItem(%d, %d)", xpos, ypos); - if (_itemInHand == -1) - return; - xpos -= 8; - ypos -= 15; - _screen->hideMouse(); - backUpRect1(xpos, ypos); - int y = ypos; - int height = 16; - - while (height >= 0) { - restoreRect1(xpos, ypos); - _screen->setNewShapeHeight(_shapes[220+_itemInHand], height); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, _shapes[220+_itemInHand], xpos, y, 0, 0); - _screen->updateScreen(); - y += 2; - height -= 2; - while (_system->getMillis() < nextTime) {} - } - restoreRect1(xpos, ypos); - _screen->resetShapeHeight(_shapes[220+_itemInHand]); - destroyMouseItem(); - _screen->showMouse(); -} - -void KyraEngine::setupSceneItems() { - debug(9, "KyraEngine::setupSceneItems()"); - uint16 sceneId = _currentCharacter->sceneId; - assert(sceneId < _roomTableSize); - Room *currentRoom = &_roomTable[sceneId]; - for (int i = 0; i < 12; ++i) { - uint8 item = currentRoom->itemsTable[i]; - if (item == 0xFF || !currentRoom->needInit[i]) { - continue; - } - - int xpos = 0; - int ypos = 0; - - if (currentRoom->itemsXPos[i] == 0xFFFF) { - xpos = currentRoom->itemsXPos[i] = _rnd.getRandomNumberRng(24, 296); - ypos = currentRoom->itemsYPos[i] = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 130); - } else { - xpos = currentRoom->itemsXPos[i]; - ypos = currentRoom->itemsYPos[i]; - } - - _lastProcessedItem = i; - - int stop = 0; - while (!stop) { - stop = processItemDrop(sceneId, item, xpos, ypos, 3, 0); - if (!stop) { - xpos = currentRoom->itemsXPos[i] = _rnd.getRandomNumberRng(24, 296); - ypos = currentRoom->itemsYPos[i] = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 130); - if (countItemsInScene(sceneId) >= 12) { - break; - } - } else { - currentRoom->needInit[i] = 0; - } - } - } -} - -int KyraEngine::countItemsInScene(uint16 sceneId) { - debug(9, "KyraEngine::countItemsInScene(%d)", sceneId); - assert(sceneId < _roomTableSize); - Room *currentRoom = &_roomTable[sceneId]; - - int items = 0; - - for (int i = 0; i < 12; ++i) { - if (currentRoom->itemsTable[i] != 0xFF) { - ++items; - } - } - - return items; -} - -int KyraEngine::processItemDrop(uint16 sceneId, uint8 item, int x, int y, int unk1, int unk2) { - debug(9, "KyraEngine::processItemDrop(%d, %d, %d, %d, %d, %d)", sceneId, item, x, y, unk1, unk2); - int freeItem = -1; - uint8 itemIndex = findItemAtPos(x, y); - if (unk1) { - itemIndex = 0xFF; - } - - if (itemIndex != 0xFF) { - exchangeItemWithMouseItem(sceneId, itemIndex); - return 0; - } - - assert(sceneId < _roomTableSize); - Room *currentRoom = &_roomTable[sceneId]; - - if (unk1 != 3) { - for (int i = 0; i < 12; ++i) { - if (currentRoom->itemsTable[i] == 0xFF) { - freeItem = i; - break; - } - } - } else { - freeItem = _lastProcessedItem; - } - - if (freeItem == -1) { - return 0; - } - - if (sceneId != _currentCharacter->sceneId) { - addItemToRoom(sceneId, item, freeItem, x, y); - return 1; - } - - int itemHeight = _itemTable[item].height; - _lastProcessedItemHeight = itemHeight; - - if (x == -1 && x == -1) { - x = _rnd.getRandomNumberRng(16, 304); - y = _rnd.getRandomNumberRng(_northExitHeight & 0xFF, 135); - } - - int xpos = x; - int ypos = y; - int destY = -1; - int destX = -1; - int running = 1; - - while (running) { - if ((_northExitHeight & 0xFF) <= ypos) { - bool running2 = true; - - if (getDrawLayer(xpos, ypos) > 1) { - if (((_northExitHeight >> 8) & 0xFF) != ypos) { - running2 = false; - } - } - - if (getDrawLayer2(xpos, ypos, itemHeight) > 1) { - if (((_northExitHeight >> 8) & 0xFF) != ypos) { - running2 = false; - } - } - - if (!isDropable(xpos, ypos)) { - if (((_northExitHeight >> 8) & 0xFF) != ypos) { - running2 = false; - } - } - - int xpos2 = xpos; - int xpos3 = xpos; - - while (running2) { - if (isDropable(xpos2, ypos)) { - if (getDrawLayer2(xpos2, ypos, itemHeight) < 7) { - if (findItemAtPos(xpos2, ypos) == 0xFF) { - destX = xpos2; - destY = ypos; - running = 0; - running2 = false; - } - } - } - - if (isDropable(xpos3, ypos)) { - if (getDrawLayer2(xpos3, ypos, itemHeight) < 7) { - if (findItemAtPos(xpos3, ypos) == 0xFF) { - destX = xpos3; - destY = ypos; - running = 0; - running2 = false; - } - } - } - - if (!running2) - continue; - - xpos2 -= 2; - if (xpos2 < 16) { - xpos2 = 16; - } - - xpos3 += 2; - if (xpos3 > 304) { - xpos3 = 304; - } - - if (xpos2 > 16) - continue; - if (xpos3 < 304) - continue; - running2 = false; - } - } - - if (((_northExitHeight >> 8) & 0xFF) == ypos) { - running = 0; - destY -= _rnd.getRandomNumberRng(0, 3); - - if ((_northExitHeight & 0xFF) < destY) { - continue; - } - - destY = (_northExitHeight & 0xFF) + 1; - continue; - } - ypos += 2; - if (((_northExitHeight >> 8) & 0xFF) >= ypos) { - continue; - } - ypos = (_northExitHeight >> 8) & 0xFF; - } - - if (destX == -1 || destY == -1) { - return 0; - } - - if (unk1 == 3) { - currentRoom->itemsXPos[freeItem] = destX; - currentRoom->itemsYPos[freeItem] = destY; - return 1; - } - - if (unk1 == 2) { - itemSpecialFX(x, y, item); - } - - if (unk1 == 0) { - destroyMouseItem(); - } - - itemDropDown(x, y, destX, destY, freeItem, item); - - if (unk1 == 0 && unk2 != 0) { - assert(_itemList && _droppedList); - updateSentenceCommand(_itemList[item], _droppedList[0], 179); - } - - return 1; -} - -void KyraEngine::exchangeItemWithMouseItem(uint16 sceneId, int itemIndex) { - debug(9, "KyraEngine::exchangeItemWithMouseItem(%d, %d)", sceneId, itemIndex); - _screen->hideMouse(); - _animator->animRemoveGameItem(itemIndex); - assert(sceneId < _roomTableSize); - Room *currentRoom = &_roomTable[sceneId]; - - int item = currentRoom->itemsTable[itemIndex]; - currentRoom->itemsTable[itemIndex] = _itemInHand; - _itemInHand = item; - _animator->animAddGameItem(itemIndex, sceneId); - snd_playSoundEffect(53); - - setMouseItem(_itemInHand); - assert(_itemList && _takenList); - updateSentenceCommand(_itemList[_itemInHand], _takenList[1], 179); - _screen->showMouse(); - clickEventHandler2(); -} - -void KyraEngine::addItemToRoom(uint16 sceneId, uint8 item, int itemIndex, int x, int y) { - debug(9, "KyraEngine::addItemToRoom(%d, %d, %d, %d, %d)", sceneId, item, itemIndex, x, y); - assert(sceneId < _roomTableSize); - Room *currentRoom = &_roomTable[sceneId]; - currentRoom->itemsTable[itemIndex] = item; - currentRoom->itemsXPos[itemIndex] = x; - currentRoom->itemsYPos[itemIndex] = y; - currentRoom->needInit[itemIndex] = 1; -} - -int KyraEngine::checkNoDropRects(int x, int y) { - debug(9, "KyraEngine::checkNoDropRects(%d, %d)", x, y); - if (_lastProcessedItemHeight < 1 || _lastProcessedItemHeight > 16) { - _lastProcessedItemHeight = 16; - } - if (_noDropRects[0].x == -1) { - return 0; - } - - for (int i = 0; i < 11; ++i) { - if (_noDropRects[i].x == -1) { - break; - } - - int xpos = _noDropRects[i].x; - int ypos = _noDropRects[i].y; - int xpos2 = _noDropRects[i].x2; - int ypos2 = _noDropRects[i].y2; - - if (xpos > x + 16) - continue; - if (xpos2 < x) - continue; - if (y < ypos) - continue; - if (ypos2 < y - _lastProcessedItemHeight) - continue; - return 1; - } - - return 0; -} - -int KyraEngine::isDropable(int x, int y) { - debug(9, "KyraEngine::isDropable(%d, %d)", x, y); - x -= 8; - y -= 1; - - if (checkNoDropRects(x, y)) { - return 0; - } - - for (int xpos = x; xpos < x + 16; ++xpos) { - if (_screen->getShapeFlag1(xpos, y) == 0) { - return 0; - } - } - return 1; -} - -void KyraEngine::itemDropDown(int x, int y, int destX, int destY, byte freeItem, int item) { - debug(9, "KyraEngine::itemDropDown(%d, %d, %d, %d, %d, %d)", x, y, destX, destY, freeItem, item); - assert(_currentCharacter->sceneId < _roomTableSize); - Room *currentRoom = &_roomTable[_currentCharacter->sceneId]; - if (x == destX && y == destY) { - currentRoom->itemsXPos[freeItem] = destX; - currentRoom->itemsYPos[freeItem] = destY; - currentRoom->itemsTable[freeItem] = item; - snd_playSoundEffect(0x32); - _animator->animAddGameItem(freeItem, _currentCharacter->sceneId); - return; - } - _screen->hideMouse(); - if (y <= destY) { - int tempY = y; - int addY = 2; - int drawX = x - 8; - int drawY = 0; - - backUpRect0(drawX, y - 16); - - while (tempY < destY) { - restoreRect0(drawX, tempY - 16); - tempY += addY; - if (tempY > destY) { - tempY = destY; - } - ++addY; - drawY = tempY - 16; - backUpRect0(drawX, drawY); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, _shapes[220+item], drawX, drawY, 0, 0); - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if ((nextTime - _system->getMillis()) >= 10) - delay(10); - } - } - - bool skip = false; - if (x == destX) { - if (destY - y <= 16) { - skip = true; - } - } - - if (!skip) { - snd_playSoundEffect(0x47); - if (addY < 6) - addY = 6; - - int xDiff = (destX - x) << 4; - xDiff /= addY; - int startAddY = addY; - addY >>= 1; - if (destY - y <= 8) { - addY >>= 1; - } - addY = -addY; - int unkX = x << 4; - while (--startAddY) { - drawX = (unkX >> 4) - 8; - drawY = tempY - 16; - restoreRect0(drawX, drawY); - tempY += addY; - unkX += xDiff; - if (tempY > destY) { - tempY = destY; - } - ++addY; - drawX = (unkX >> 4) - 8; - drawY = tempY - 16; - backUpRect0(drawX, drawY); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, _shapes[220+item], drawX, drawY, 0, 0); - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if ((nextTime - _system->getMillis()) >= 10) - delay(10); - } - } - restoreRect0(drawX, drawY); - } else { - restoreRect0(drawX, tempY - 16); - } - } - currentRoom->itemsXPos[freeItem] = destX; - currentRoom->itemsYPos[freeItem] = destY; - currentRoom->itemsTable[freeItem] = item; - snd_playSoundEffect(0x32); - _animator->animAddGameItem(freeItem, _currentCharacter->sceneId); - _screen->showMouse(); -} - -void KyraEngine::dropItem(int unk1, int item, int x, int y, int unk2) { - debug(9, "KyraEngine::dropItem(%d, %d, %d, %d, %d)", unk1, item, x, y, unk2); - if (processItemDrop(_currentCharacter->sceneId, item, x, y, unk1, unk2)) - return; - snd_playSoundEffect(54); - if (12 == countItemsInScene(_currentCharacter->sceneId)) { - assert(_noDropList); - drawSentenceCommand(_noDropList[0], 6); - } else { - assert(_noDropList); - drawSentenceCommand(_noDropList[1], 6); - } -} - -void KyraEngine::itemSpecialFX(int x, int y, int item) { - debug(9, "KyraEngine::itemSpecialFX(%d, %d, %d)", x, y, item); - if (item == 41) { - itemSpecialFX1(x, y, item); - } else { - itemSpecialFX2(x, y, item); - } -} - -void KyraEngine::itemSpecialFX1(int x, int y, int item) { - debug(9, "KyraEngine::itemSpecialFX1(%d, %d, %d)", x, y, item); - uint8 *shape = _shapes[220+item]; - x -= 8; - int startY = y; - y -= 15; - _screen->hideMouse(); - backUpRect0(x, y); - for (int i = 1; i <= 16; ++i) { - _screen->setNewShapeHeight(shape, i); - --startY; - restoreRect0(x, y); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, shape, x, startY, 0, 0); - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if ((nextTime - _system->getMillis()) >= 10) - delay(10); - } - } - restoreRect0(x, y); - _screen->showMouse(); -} - -void KyraEngine::itemSpecialFX2(int x, int y, int item) { - debug(9, "KyraEngine::itemSpecialFX2(%d, %d, %d)", x, y, item); - x -= 8; - y -= 15; - int yAdd = (int8)(((16 - _itemTable[item].height) >> 1) & 0xFF); - backUpRect0(x, y); - if (item >= 80 && item <= 89) { - snd_playSoundEffect(55); - } - - for (int i = 201; i <= 205; ++i) { - restoreRect0(x, y); - uint32 nextTime = _system->getMillis() + 3 * _tickLength; - _screen->drawShape(0, _shapes[4+i], x, y + yAdd, 0, 0); - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if ((nextTime - _system->getMillis()) >= 10) - delay(10); - } - } - - for (int i = 204; i >= 201; --i) { - restoreRect0(x, y); - uint32 nextTime = _system->getMillis() + 3 * _tickLength; - _screen->drawShape(0, _shapes[220+item], x, y, 0, 0); - _screen->drawShape(0, _shapes[4+i], x, y + yAdd, 0, 0); - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if ((nextTime - _system->getMillis()) >= 10) - delay(10); - } - } - restoreRect0(x, y); -} - -void KyraEngine::magicOutMouseItem(int animIndex, int itemPos) { - debug(9, "KyraEngine::magicOutMouseItem(%d, %d)", animIndex, itemPos); - int videoPageBackUp = _screen->_curPage; - _screen->_curPage = 0; - int x = 0, y = 0; - if (itemPos == -1) { - x = _mouseX - 12; - y = _mouseY - 18; - } else { - x = _itemPosX[itemPos] - 4; - y = _itemPosY[itemPos] - 3; - } - - if (_itemInHand == -1 && itemPos == -1) { - return; - } - - int tableIndex = 0, loopStart = 0, maxLoops = 0; - if (animIndex == 0) { - tableIndex = _rnd.getRandomNumberRng(0, 5); - loopStart = 35; - maxLoops = 9; - } else if (animIndex == 1) { - tableIndex = _rnd.getRandomNumberRng(0, 11); - loopStart = 115; - maxLoops = 8; - } else if (animIndex == 2) { - tableIndex = 0; - loopStart = 124; - maxLoops = 4; - } else { - tableIndex = -1; - } - - if (animIndex == 2) { - snd_playSoundEffect(0x5E); - } else { - snd_playSoundEffect(0x37); - } - _screen->hideMouse(); - backUpRect1(x, y); - - for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { - restoreRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - _screen->drawShape(0, _shapes[220+_itemInHand], x + 4, y + 3, 0, 0); - if (tableIndex == -1) { - _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); - } else { - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - } - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if (nextTime - _system->getMillis() >= 10) - delay(10); - } - } - - if (itemPos != -1) { - restoreRect1(x, y); - _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, 12, 0); - backUpRect1(x, y); - } - - for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { - restoreRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - _screen->drawShape(0, _shapes[220+_itemInHand], x + 4, y + 3, 0, 0); - if (tableIndex == -1) { - _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); - } else { - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - } - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if (nextTime - _system->getMillis() >= 10) - delay(10); - } - } - restoreRect1(x, y); - if (itemPos == -1) { - _screen->setMouseCursor(1, 1, _shapes[4]); - _itemInHand = -1; - } else { - _characterList[0].inventoryItems[itemPos] = 0xFF; - _screen->hideMouse(); - _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, 12, 0); - _screen->showMouse(); - } - _screen->showMouse(); - _screen->_curPage = videoPageBackUp; -} - -void KyraEngine::magicInMouseItem(int animIndex, int item, int itemPos) { - debug(9, "KyraEngine::magicInMouseItem(%d, %d, %d)", animIndex, item, itemPos); - int videoPageBackUp = _screen->_curPage; - _screen->_curPage = 0; - int x = 0, y = 0; - if (itemPos == -1) { - x = _mouseX - 12; - y = _mouseY - 18; - } else { - x = _itemPosX[itemPos] - 4; - y = _itemPosX[itemPos] - 3; - } - if (item < 0) - return; - - int tableIndex = -1, loopStart = 0, maxLoops = 0; - if (animIndex == 0) { - tableIndex = _rnd.getRandomNumberRng(0, 5); - loopStart = 35; - maxLoops = 9; - } else if (animIndex == 1) { - tableIndex = _rnd.getRandomNumberRng(0, 11); - loopStart = 115; - maxLoops = 8; - } else if (animIndex == 2) { - tableIndex = 0; - loopStart = 124; - maxLoops = 4; - } - - _screen->hideMouse(); - backUpRect1(x, y); - if (animIndex == 2) { - snd_playSoundEffect(0x5E); - } else { - snd_playSoundEffect(0x37); - } - - for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { - restoreRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - if (tableIndex == -1) { - _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); - } else { - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - } - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if (nextTime - _system->getMillis() >= 10) - delay(10); - } - } - - for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { - restoreRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - if (tableIndex == -1) { - _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0); - } else { - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - } - _screen->updateScreen(); - while (_system->getMillis() < nextTime) { - if (nextTime - _system->getMillis() >= 10) - delay(10); - } - } - restoreRect1(x, y); - if (itemPos == -1) { - _screen->setMouseCursor(8, 15, _shapes[220+item]); - _itemInHand = item; - } else { - _characterList[0].inventoryItems[itemPos] = item; - _screen->hideMouse(); - _screen->drawShape(0, _shapes[220+item], _itemPosX[itemPos], _itemPosY[itemPos], 0, 0); - _screen->showMouse(); - } - _screen->showMouse(); - _screen->_curPage = videoPageBackUp; -} - -void KyraEngine::specialMouseItemFX(int shape, int x, int y, int animIndex, int tableIndex, int loopStart, int maxLoops) { - debug(9, "KyraEngine::specialMouseItemFX(%d, %d, %d, %d, %d, %d, %d)", shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - static const uint8 table1[] = { - 0x23, 0x45, 0x55, 0x72, 0x84, 0xCF, 0x00, 0x00 - }; - static const uint8 table2[] = { - 0x73, 0xB5, 0x80, 0x21, 0x13, 0x39, 0x45, 0x55, 0x62, 0xB4, 0xCF, 0xD8 - }; - static const uint8 table3[] = { - 0x7C, 0xD0, 0x74, 0x84, 0x87, 0x00, 0x00, 0x00 - }; - int tableValue = 0; - if (animIndex == 0) { - tableValue = table1[tableIndex]; - } else if (animIndex == 1) { - tableValue = table2[tableIndex]; - } else if (animIndex == 2) { - tableValue = table3[tableIndex]; - } else { - return; - } - processSpecialMouseItemFX(shape, x, y, tableValue, loopStart, maxLoops); -} - -void KyraEngine::processSpecialMouseItemFX(int shape, int x, int y, int tableValue, int loopStart, int maxLoops) { - debug(9, "KyraEngine::processSpecialMouseItemFX(%d, %d, %d, %d, %d, %d)", shape, x, y, tableValue, loopStart, maxLoops); - uint8 shapeColorTable[16]; - uint8 *shapePtr = _shapes[4+shape] + 10; - if (_features & GF_TALKIE) - shapePtr += 2; - for (int i = 0; i < 16; ++i) { - shapeColorTable[i] = shapePtr[i]; - } - for (int i = loopStart; i < loopStart + maxLoops; ++i) { - for (int i2 = 0; i2 < 16; ++i2) { - if (shapePtr[i2] == i) { - shapeColorTable[i2] = (i + tableValue) - loopStart; - } - } - } - _screen->drawShape(0, _shapes[4+shape], x, y, 0, 0x8000, shapeColorTable); -} - -void KyraEngine::updatePlayerItemsForScene() { - debug(9, "KyraEngine::updatePlayerItemsForScene()"); - if (_itemInHand >= 29 && _itemInHand < 33) { - ++_itemInHand; - if (_itemInHand > 33) - _itemInHand = 33; - _screen->hideMouse(); - _screen->setMouseCursor(8, 15, _shapes[220+_itemInHand]); - _screen->showMouse(); - } - - bool redraw = false; - for (int i = 0; i < 10; ++i) { - uint8 item = _currentCharacter->inventoryItems[i]; - if (item >= 29 && item < 33) { - ++item; - if (item > 33) - item = 33; - _currentCharacter->inventoryItems[i] = item; - redraw = true; - } - } - - if (redraw) { - _screen->hideMouse(); - redrawInventory(0); - _screen->showMouse(); - } - - if (_itemInHand == 33) { - magicOutMouseItem(2, -1); - } - - _screen->hideMouse(); - for (int i = 0; i < 10; ++i) { - uint8 item = _currentCharacter->inventoryItems[i]; - if (item == 33) { - magicOutMouseItem(2, i); - } - } - _screen->showMouse(); -} - -void KyraEngine::redrawInventory(int page) { - int videoPageBackUp = _screen->_curPage; - _screen->_curPage = page; - _screen->hideMouse(); - for (int i = 0; i < 10; ++i) { - _screen->fillRect(_itemPosX[i], _itemPosY[i], _itemPosX[i] + 15, _itemPosY[i] + 15, 12, page); - if (_currentCharacter->inventoryItems[i] != 0xFF) { - uint8 item = _currentCharacter->inventoryItems[i]; - _screen->drawShape(page, _shapes[220+item], _itemPosX[i], _itemPosY[i], 0, 0); - } - } - _screen->showMouse(); - _screen->_curPage = videoPageBackUp; - _screen->updateScreen(); -} - #pragma mark - #pragma mark - Animation/shape specific code #pragma mark - @@ -4507,126 +1047,6 @@ int16 KyraEngine::fetchAnimHeight(const uint8 *shape, int16 mult) { return (int16)(((int8)*(shape+2)) * mult) >> 8; } -void KyraEngine::rectClip(int &x, int &y, int w, int h) { - if (x < 0) { - x = 0; - } else if (x + w >= 320) { - x = 320 - w; - } - if (y < 0) { - y = 0; - } else if (y + h >= 200) { - y = 200 - h; - } -} - -void KyraEngine::backUpRect0(int xpos, int ypos) { - debug(9, "KyraEngine::backUpRect0(%d, %d)", xpos, ypos); - rectClip(xpos, ypos, 3<<3, 24); - _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 3<<3, 24, _shapes[0]); -} - -void KyraEngine::restoreRect0(int xpos, int ypos) { - debug(9, "KyraEngine::restoreRect0(%d, %d)", xpos, ypos); - rectClip(xpos, ypos, 3<<3, 24); - _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 3<<3, 24, _shapes[0]); -} - -void KyraEngine::backUpRect1(int xpos, int ypos) { - debug(9, "KyraEngine::backUpRect1(%d, %d)", xpos, ypos); - rectClip(xpos, ypos, 4<<3, 32); - _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 4<<3, 32, _shapes[1]); -} - -void KyraEngine::restoreRect1(int xpos, int ypos) { - debug(9, "KyraEngine::restoreRect1(%d, %d)", xpos, ypos); - rectClip(xpos, ypos, 4<<3, 32); - _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 4<<3, 32, _shapes[1]); -} - -int KyraEngine::getDrawLayer(int x, int y) { - debug(9, "KyraEngine::getDrawLayer(%d, %d)", x, y); - int xpos = x - 8; - int ypos = y - 1; - int layer = 1; - for (int curX = xpos; curX < xpos + 16; ++curX) { - int tempLayer = _screen->getShapeFlag2(curX, ypos); - if (layer < tempLayer) { - layer = tempLayer; - } - if (layer >= 7) { - return 7; - } - } - return layer; -} - -int KyraEngine::getDrawLayer2(int x, int y, int height) { - debug(9, "KyraEngine::getDrawLayer2(%d, %d, %d)", x, y, height); - int xpos = x - 8; - int ypos = y - 1; - int layer = 1; - - for (int useX = xpos; useX < xpos + 16; ++useX) { - for (int useY = ypos - height; useY < ypos; ++useY) { - int tempLayer = _screen->getShapeFlag2(useX, useY); - if (tempLayer > layer) { - layer = tempLayer; - } - - if (tempLayer >= 7) { - return 7; - } - } - } - return layer; -} - -void KyraEngine::copyBackgroundBlock(int x, int page, int flag) { - debug(9, "KyraEngine::copyBackgroundBlock(%d, %d, %d)", x, page, flag); - - if (x < 1) - return; - - int height = 128; - if (flag) - height += 8; - if (!(x & 1)) - ++x; - if (x == 19) - x = 17; - uint8 *ptr1 = _unkPtr1; - uint8 *ptr2 = _unkPtr2; - int oldVideoPage = _screen->_curPage; - _screen->_curPage = page; - - int curX = x; - _screen->hideMouse(); - _screen->copyRegionToBuffer(_screen->_curPage, 8, 8, 8, height, ptr2); - for (int i = 0; i < 19; ++i) { - int tempX = curX + 1; - _screen->copyRegionToBuffer(_screen->_curPage, tempX<<3, 8, 8, height, ptr1); - _screen->copyBlockToPage(_screen->_curPage, tempX<<3, 8, 8, height, ptr2); - int newXPos = curX + x; - if (newXPos > 37) { - newXPos = newXPos % 38; - } - tempX = newXPos + 1; - _screen->copyRegionToBuffer(_screen->_curPage, tempX<<3, 8, 8, height, ptr2); - _screen->copyBlockToPage(_screen->_curPage, tempX<<3, 8, 8, height, ptr1); - curX += x*2; - if (curX > 37) { - curX = curX % 38; - } - } - _screen->showMouse(); - _screen->_curPage = oldVideoPage; -} - -void KyraEngine::copyBackgroundBlock2(int x) { - copyBackgroundBlock(x, 4, 1); -} - void KyraEngine::makeBrandonFaceMouse() { debug(9, "KyraEngine::makeBrandonFaceMouse()"); if (_mouseX >= _currentCharacter->x1) { @@ -5150,674 +1570,6 @@ int KyraEngine::processBead(int x, int y, int &x2, int &y2, BeadState *ptr) { } #pragma mark - -#pragma mark - Pathfinder -#pragma mark - - -int KyraEngine::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) { - debug(9, "KyraEngine::findWay(%d, %d, %d, %d, 0x%X, %d)", x, y, toX, toY, moveTable, moveTableSize); - x &= 0xFFFC; toX &= 0xFFFC; - y &= 0xFFFE; toY &= 0xFFFE; - x = (int16)x; y = (int16)y; toX = (int16)toX; toY = (int16)toY; - - if (x == toY && y == toY) { - moveTable[0] = 8; - return 0; - } - - int curX = x; - int curY = y; - int lastUsedEntry = 0; - int tempValue = 0; - int *pathTable1 = new int[0x7D0]; - int *pathTable2 = new int[0x7D0]; - assert(pathTable1 && pathTable2); - - while (true) { - int newFacing = getFacingFromPointToPoint(x, y, toX, toY); - changePosTowardsFacing(curX, curY, newFacing); - - if (curX == toX && curY == toY) { - if (!lineIsPassable(curX, curY)) - break; - moveTable[lastUsedEntry++] = newFacing; - break; - } - - if (lineIsPassable(curX, curY)) { - if (lastUsedEntry == moveTableSize) { - delete [] pathTable1; - delete [] pathTable2; - return 0x7D00; - } - // debug drawing - //if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { - // _screen->setPagePixel(0, curX, curY, 11); - // _screen->updateScreen(); - // waitTicks(5); - //} - moveTable[lastUsedEntry++] = newFacing; - x = curX; - y = curY; - continue; - } - - int temp = 0; - while (true) { - newFacing = getFacingFromPointToPoint(curX, curY, toX, toY); - changePosTowardsFacing(curX, curY, newFacing); - // debug drawing - //if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { - // _screen->setPagePixel(0, curX, curY, 8); - // _screen->updateScreen(); - // waitTicks(5); - //} - - if (!lineIsPassable(curX, curY)) { - if (curX != toX || curY != toY) - continue; - } - - if (curX == toX && curY == toY) { - if (!lineIsPassable(curX, curY)) { - tempValue = 0; - temp = 0; - break; - } - } - - temp = findSubPath(x, y, curX, curY, pathTable1, 1, 0x7D0); - tempValue = findSubPath(x, y, curX, curY, pathTable2, 0, 0x7D0); - if (curX == toX && curY == toY) { - if (temp == 0x7D00 && tempValue == 0x7D00) { - delete [] pathTable1; - delete [] pathTable2; - return 0x7D00; - } - } - - if (temp != 0x7D00 || tempValue != 0x7D00) { - break; - } - } - - if (temp < tempValue) { - if (lastUsedEntry + temp > moveTableSize) { - delete [] pathTable1; - delete [] pathTable2; - return 0x7D00; - } - memcpy(&moveTable[lastUsedEntry], pathTable1, temp*sizeof(int)); - lastUsedEntry += temp; - } else { - if (lastUsedEntry + tempValue > moveTableSize) { - delete [] pathTable1; - delete [] pathTable2; - return 0x7D00; - } - memcpy(&moveTable[lastUsedEntry], pathTable2, tempValue*sizeof(int)); - lastUsedEntry += tempValue; - } - x = curX; - y = curY; - if (curX == toX && curY == toY) { - break; - } - } - delete [] pathTable1; - delete [] pathTable2; - moveTable[lastUsedEntry] = 8; - return getMoveTableSize(moveTable); -} - -int KyraEngine::findSubPath(int x, int y, int toX, int toY, int *moveTable, int start, int end) { - debug(9, "KyraEngine::findSubPath(%d, %d, %d, %d, 0x%X, %d, %d)", x, y, toX, toY, moveTable, start, end); - // only used for debug specific code - //static uint16 unkTable[] = { 8, 5 }; - static const int8 facingTable1[] = { 7, 0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 0 }; - static const int8 facingTable2[] = { -1, 0, -1, 2, -1, 4, -1, 6, -1, 2, -1, 4, -1, 6, -1, 0 }; - static const int8 facingTable3[] = { 2, 4, 4, 6, 6, 0, 0, 2, 6, 6, 0, 0, 2, 2, 4, 4 }; - static const int8 addPosTableX[] = { -1, 0, -1, 4, -1, 0, -1, -4, -1, -4, -1, 0, -1, 4, -1, 0 }; - static const int8 addPosTableY[] = { -1, 2, -1, 0, -1, -2, -1, 0, -1, 0, -1, 2, -1, 0, -1, -2 }; - - // debug specific - //++unkTable[start]; - //while (_screen->getPalette(0)[unkTable[start]] != 0x0F) { - // ++unkTable[start]; - //} - - int xpos1 = x, xpos2 = x; - int ypos1 = y, ypos2 = y; - int newFacing = getFacingFromPointToPoint(x, y, toX, toY); - int position = 0; - - while (position != end) { - int newFacing2 = newFacing; - while (true) { - changePosTowardsFacing(xpos1, ypos1, facingTable1[start*8 + newFacing2]); - if (!lineIsPassable(xpos1, ypos1)) { - if (facingTable1[start*8 + newFacing2] == newFacing) { - return 0x7D00; - } - newFacing2 = facingTable1[start*8 + newFacing2]; - xpos1 = x; - ypos1 = y; - continue; - } - newFacing = facingTable1[start*8 + newFacing2]; - break; - } - // debug drawing - //if (xpos1 >= 0 && ypos1 >= 0 && xpos1 < 320 && ypos1 < 200) { - // _screen->setPagePixel(0, xpos1, ypos1, unkTable[start]); - // _screen->updateScreen(); - // waitTicks(5); - //} - if (newFacing & 1) { - int temp = xpos1 + addPosTableX[newFacing + start * 8]; - if (toX == temp) { - temp = ypos1 + addPosTableY[newFacing + start * 8]; - if (toY == temp) { - moveTable[position++] = facingTable2[newFacing + start * 8]; - return position; - } - } - } - moveTable[position++] = newFacing; - x = xpos1; - y = ypos1; - if (x == toX && y == toY) { - return position; - } - - if (xpos1 == xpos2 && ypos1 == ypos2) { - break; - } - - newFacing = facingTable3[start*8 + newFacing]; - } - return 0x7D00; -} - -int KyraEngine::getFacingFromPointToPoint(int x, int y, int toX, int toY) { - debug(9, "KyraEngine::getFacingFromPointToPoint(%d, %d, %d, %d)", x, y, toX, toY); - static const int facingTable[] = { - 1, 0, 1, 2, 3, 4, 3, 2, 7, 0, 7, 6, 5, 4, 5, 6 - }; - - int facingEntry = 0; - int ydiff = y - toY; - if (ydiff < 0) { - ++facingEntry; - ydiff = -ydiff; - } - facingEntry <<= 1; - - int xdiff = toX - x; - if (xdiff < 0) { - ++facingEntry; - xdiff = -xdiff; - } - - if (xdiff >= ydiff) { - int temp = ydiff; - ydiff = xdiff; - xdiff = temp; - - facingEntry <<= 1; - } else { - facingEntry <<= 1; - facingEntry += 1; - } - int temp = (ydiff + 1) >> 1; - - if (xdiff < temp) { - facingEntry <<= 1; - facingEntry += 1; - } else { - facingEntry <<= 1; - } - assert(facingEntry < ARRAYSIZE(facingTable)); - return facingTable[facingEntry]; -} - -void KyraEngine::changePosTowardsFacing(int &x, int &y, int facing) { - debug(9, "KyraEngine::changePosTowardsFacing(%d, %d, %d)", x, y, facing); - x += _addXPosTable[facing]; - y += _addYPosTable[facing]; -} - -bool KyraEngine::lineIsPassable(int x, int y) { - debug(9, "KyraEngine::lineIsPassable(%d, %d)", x, 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; - } - - int ypos = 8; - if (_scaleMode) { - ypos = (_scaleTable[y] >> 5) + 1; - if (8 < ypos) - ypos = 8; - } - - x -= (ypos >> 1); - if (y < 0) - y = 0; - - 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; -} - -int KyraEngine::getMoveTableSize(int *moveTable) { - debug(9, "KyraEngine::getMoveTableSize(0x%X)", moveTable); - int retValue = 0; - if (moveTable[0] == 8) - return 0; - - static const int facingTable[] = { - 4, 5, 6, 7, 0, 1, 2, 3 - }; - static const int unkTable[] = { - -1, -1, 1, 2, -1, 6, 7, -1, - -1, -1, -1, -1, 2, -1, 0, -1, - 1, -1, -1, -1, 3, 4, -1, 0, - 2, -1, -1, -1, -1, -1, 4, -1, - -1, 2, 3, -1, -1, -1, 5, 6, - 6, -1, 4, -1, -1, -1, -1, -1, - 7, 0, -1, 4, 5, -1, -1, -1, - -1, -1, 0, -1, 6, -1, -1, -1 - }; - - int *oldPosition = moveTable; - int *tempPosition = moveTable; - int *curPosition = moveTable + 1; - retValue = 1; - - while (*curPosition != 8) { - if (*oldPosition == facingTable[*curPosition]) { - retValue -= 2; - *oldPosition = 9; - *curPosition = 9; - - while (tempPosition != moveTable) { - --tempPosition; - if (*tempPosition != 9) - break; - } - - if (tempPosition == moveTable && *tempPosition == 9) { - while (*tempPosition != 8 && *tempPosition == 9) { - ++tempPosition; - } - if (*tempPosition == 8) { - return 0; - } - } - - oldPosition = tempPosition; - curPosition = oldPosition+1; - while (*curPosition != 8 && *curPosition == 9) { - ++curPosition; - } - continue; - } - - if (unkTable[*curPosition+((*oldPosition)*8)] != -1) { - --retValue; - *oldPosition = unkTable[*curPosition+((*oldPosition)*8)]; - *curPosition = 9; - - if (tempPosition != oldPosition) { - curPosition = oldPosition; - oldPosition = tempPosition; - while (true) { - if (tempPosition == moveTable) { - break; - } - --tempPosition; - if (*tempPosition != 9) { - break; - } - } - } else { - while (true) { - ++curPosition; - if (*curPosition != 9) { - break; - } - } - } - continue; - } - - tempPosition = oldPosition; - oldPosition = curPosition; - ++retValue; - while (true) { - ++curPosition; - if (*curPosition != 9) { - break; - } - } - } - - return retValue; -} - -#pragma mark - -#pragma mark - Scene handling -#pragma mark - - -int KyraEngine::handleSceneChange(int xpos, int ypos, int unk1, int frameReset) { - debug(9, "KyraEngine::handleSceneChange(%d, %d, %d, %d)", xpos, ypos, unk1, 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::processSceneChange(int *table, int unk1, int frameReset) { - debug(9, "KyraEngine::processSceneChange(0x%X, %d, %d)", table, unk1, frameReset); - if (queryGameFlag(0xEF)) { - unk1 = 0; - } - int *tableStart = table; - _sceneChangeState = 0; - _loopFlag2 = 0; - bool running = true; - int returnValue = 0; - uint32 nextFrame = 0; - _abortWalkFlag = false; - _mousePressFlag = false; - - while (running) { - if (_abortWalkFlag) { - *table = 8; - _currentCharacter->currentAnimFrame = 7; - animRefreshNPC(0); - _animator->updateAllObjectShapes(); - processInput(_mouseX, _mouseY); - return 0; - } - 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; - break; - } - - returnValue = changeScene(_currentCharacter->facing); - if (returnValue) { - running = false; - _abortWalkFlag = false; - } - - if (unk1) { - if (_mousePressFlag) { - 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 = getTimerDelay(5) * _tickLength + _system->getMillis(); - while (_system->getMillis() < nextFrame) { - _sprites->updateSceneAnims(); - updateMousePointer(); - updateGameTimers(); - _animator->updateAllObjectShapes(); - updateTextFade(); - if (_currentCharacter->sceneId == 210) { - _animator->updateKyragemFading(); - if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) { - *table = 8; - running = false; - break; - } - } - if ((nextFrame - _system->getMillis()) >= 10) - delay(10); - } - } - - if (frameReset && !(_brandonStatusBit & 2)) { - _currentCharacter->currentAnimFrame = 7; - } - animRefreshNPC(0); - _animator->updateAllObjectShapes(); - return returnValue; -} - -int KyraEngine::changeScene(int facing) { - debug(9, "KyraEngine::changeScene(%d)", facing); - if (queryGameFlag(0xEF)) { - if (_currentCharacter->sceneId == 5) { - return 0; - } - } - - int xpos = _charXPosTable[facing] + _currentCharacter->x1; - int ypos = _charYPosTable[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 on 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; - 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; - break; - } - - if (sceneId == 0xFFFF) - return 0; - - enterNewScene(sceneId, facing, 1, 1, 0); - return returnValue; -} - -#pragma mark - #pragma mark - Input #pragma mark - diff --git a/kyra/kyra.h b/kyra/kyra.h index f981ae8c75..51838068c3 100644 --- a/kyra/kyra.h +++ b/kyra/kyra.h @@ -245,6 +245,8 @@ public: uint8 game() const { return _game; } uint32 features() const { return _features; } + + uint8 **shapes() { return _shapes; } Common::RandomSource _rnd; int16 _northExitHeight; @@ -268,9 +270,7 @@ public: void loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData); void snd_playTheme(int file, int track = 0); - void snd_playTrack(int track, bool looping = false); void snd_playVoiceFile(int id); - bool snd_voicePlaying(); void snd_voiceWaitForFinish(bool ingame = true); void snd_playSoundEffect(int track); void snd_playWanderScoreViaMap(int command, int restart); @@ -489,8 +489,6 @@ protected: void setCharacterPositionHelper(int character, int *facingTable); int getOppositeFacingDirection(int dir); void loadSceneMSC(); - void blockInRegion(int x, int y, int width, int height); - void blockOutRegion(int x, int y, int width, int height); void startSceneScript(int brandonAlive); void setupSceneItems(); void initSceneData(int facing, int unk1, int brandonAlive); @@ -515,13 +513,6 @@ protected: void destroyMouseItem(); void setMouseItem(int item); void wipeDownMouseItem(int xpos, int ypos); - void rectClip(int &x, int &y, int w, int h); - void backUpRect0(int xpos, int ypos); - void restoreRect0(int xpos, int ypos); - void backUpRect1(int xpos, int ypos); - void restoreRect1(int xpos, int ypos); - void copyBackgroundBlock(int x, int page, int flag); - void copyBackgroundBlock2(int x); void makeBrandonFaceMouse(); void setBrandonPoisonFlags(int reset); void resetBrandonPoisonFlags(); @@ -539,8 +530,6 @@ protected: int processItemDrop(uint16 sceneId, uint8 item, int x, int y, int unk1, int unk2); void exchangeItemWithMouseItem(uint16 sceneId, int itemIndex); void addItemToRoom(uint16 sceneId, uint8 item, int itemIndex, int x, int y); - int getDrawLayer(int x, int y); - int getDrawLayer2(int x, int y, int height); int checkNoDropRects(int x, int y); int isDropable(int x, int y); void itemDropDown(int x, int y, int destX, int destY, byte freeItem, int item); @@ -590,8 +579,6 @@ protected: void seq_playEnding(); void seq_playCredits(); - void snd_startTrack(); - void snd_haltTrack(); void snd_setSoundEffectFile(int file); static OpcodeProc _opcodeTable[]; @@ -623,8 +610,6 @@ protected: void initMainButtonList(); void loadMainScreen(int page = 3); void setCharactersInDefaultScene(); - void resetBrandonPosionFlags(); - void initAnimStateList(); void setupPanPages(); void freePanPages(); void closeFinalWsa(); @@ -700,7 +685,6 @@ protected: bool _abortWalkFlag2; bool _mousePressFlag; uint8 _flagsTable[53]; - uint8 *_unkPtr1, *_unkPtr2; uint8 *_shapes[377]; uint16 _gameSpeed; uint16 _tickLength; diff --git a/kyra/module.mk b/kyra/module.mk index bf9a5aba49..ac11dbf32f 100644 --- a/kyra/module.mk +++ b/kyra/module.mk @@ -14,6 +14,9 @@ MODULE_OBJS := \ kyra/debugger.o \ kyra/animator.o \ kyra/gui.o \ + kyra/sequences.o \ + kyra/items.o \ + kyra/scene.o \ kyra/text.o \ kyra/timer.o \ kyra/saveload.o diff --git a/kyra/resource.cpp b/kyra/resource.cpp index 6e33a49422..50062726ea 100644 --- a/kyra/resource.cpp +++ b/kyra/resource.cpp @@ -24,6 +24,7 @@ #include "kyra/resource.h" #include "kyra/script.h" #include "kyra/wsamovie.h" +#include "kyra/screen.h" namespace Kyra { Resource::Resource(KyraEngine* engine) { @@ -279,5 +280,48 @@ uint32 PAKFile::getFileSize(const char* file) { } return 0; } + +void KyraEngine::loadPalette(const char *filename, uint8 *palData) { + debug(9, "KyraEngine::loadPalette('%s' 0x%X)", filename, palData); + uint32 fileSize = 0; + uint8 *srcData = _res->fileData(filename, &fileSize); + + if (palData && fileSize) { + debug(9, "Loading a palette of size %i from '%s'", fileSize, filename); + memcpy(palData, srcData, fileSize); + } + delete [] srcData; +} + +void KyraEngine::loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData) { + debug(9, "KyraEngine::copyBitmap('%s', %d, %d, 0x%X)", filename, tempPage, dstPage, palData); + uint32 fileSize; + uint8 *srcData = _res->fileData(filename, &fileSize); + uint8 compType = srcData[2]; + uint32 imgSize = READ_LE_UINT32(srcData + 4); + uint16 palSize = READ_LE_UINT16(srcData + 8); + if (palData && palSize) { + debug(9, "Loading a palette of size %i from %s", palSize, filename); + memcpy(palData, srcData + 10, palSize); + } + uint8 *srcPtr = srcData + 10 + palSize; + uint8 *dstData = _screen->getPagePtr(dstPage); + switch (compType) { + case 0: + memcpy(dstData, srcPtr, imgSize); + break; + case 3: + Screen::decodeFrame3(srcPtr, dstData, imgSize); + break; + case 4: + Screen::decodeFrame4(srcPtr, dstData, imgSize); + break; + default: + error("Unhandled bitmap compression %d", compType); + break; + } + delete[] srcData; +} + } // end of namespace Kyra diff --git a/kyra/scene.cpp b/kyra/scene.cpp new file mode 100644 index 0000000000..daf44f4135 --- /dev/null +++ b/kyra/scene.cpp @@ -0,0 +1,1579 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * 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. + * + * $Header$ + * + */ + +#include "kyra/kyra.h" +#include "kyra/seqplayer.h" +#include "kyra/screen.h" +#include "kyra/resource.h" +#include "kyra/sound.h" +#include "kyra/sprites.h" +#include "kyra/wsamovie.h" +#include "kyra/animator.h" +#include "kyra/text.h" +#include "kyra/script.h" + +#include "common/system.h" +#include "common/savefile.h" + +namespace Kyra { + +void KyraEngine::enterNewScene(int sceneId, int facing, int unk1, int unk2, int brandonAlive) { + debug(9, "KyraEngine::enterNewScene(%d, %d, %d, %d, %d)", sceneId, facing, unk1, unk2, brandonAlive); + int unkVar1 = 1; + _screen->hideMouse(); + _handleInput = false; + _abortWalkFlag = false; + _abortWalkFlag2 = false; + if (_currentCharacter->sceneId == 7 && sceneId == 24) { + _newMusicTheme = 3; + } else if (_currentCharacter->sceneId == 25 && sceneId == 109) { + _newMusicTheme = 4; + } else if (_currentCharacter->sceneId == 120 && sceneId == 37) { + _newMusicTheme = 5; + } else if (_currentCharacter->sceneId == 52 && sceneId == 199) { + _newMusicTheme = 6; + } else if (_currentCharacter->sceneId == 37 && sceneId == 120) { + _newMusicTheme = 4; + } else if (_currentCharacter->sceneId == 109 && sceneId == 25) { + _newMusicTheme = 3; + } else if (_currentCharacter->sceneId == 24 && sceneId == 7) { + _newMusicTheme = 2; + } + if (_newMusicTheme != _curMusicTheme) { + snd_playTheme(_newMusicTheme); + } + + 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) { + _scriptInterpreter->initScript(_scriptClick, _scriptClickData); + _scriptInterpreter->startScript(_scriptClick, 5); + while (_scriptInterpreter->validScript(_scriptClick)) { + _scriptInterpreter->runScript(_scriptClick); + } + } + + memset(_entranceMouseCursorTracks, 0xFFFF, sizeof(uint16)*4); + _currentCharacter->sceneId = sceneId; + + assert(sceneId < _roomTableSize); + assert(_roomTable[sceneId].nameIndex < _roomFilenameTableSize); + + Room *currentRoom = &_roomTable[sceneId]; + + if (_currentRoom != 0xFFFF && (_features & GF_TALKIE)) { + char file[32]; + assert(_currentRoom < _roomTableSize); + int tableId = _roomTable[_currentRoom].nameIndex; + assert(tableId < _roomFilenameTableSize); + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".VRM"); + _res->unloadPakFile(file); + } + + _currentRoom = sceneId; + + int tableId = _roomTable[_currentCharacter->sceneId].nameIndex; + char fileNameBuffer[32]; + strcpy(fileNameBuffer, _roomFilenameTable[tableId]); + strcat(fileNameBuffer, ".DAT"); + _sprites->loadDAT(fileNameBuffer, _sceneExits); + _sprites->setupSceneAnims(); + _scriptInterpreter->unloadScript(_scriptClickData); + loadSceneMSC(); + + if ((_features & GF_TALKIE)) { + strcpy(fileNameBuffer, _roomFilenameTable[tableId]); + strcat(fileNameBuffer, ".VRM"); + _res->loadPakFile(fileNameBuffer); + } + + _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::transcendScenes(int roomIndex, int roomName) { + debug(9, "KyraEngine::transcendScenes(%d, %d)", roomIndex, roomName); + assert(roomIndex < _roomTableSize); + if (_features & GF_TALKIE) { + 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::setSceneFile(int roomIndex, int roomName) { + debug(9, "KyraEngine::setSceneFile(%d, %d)", roomIndex, roomName); + assert(roomIndex < _roomTableSize); + _roomTable[roomIndex].nameIndex = roomName; +} + +void KyraEngine::moveCharacterToPos(int character, int facing, int xpos, int ypos) { + debug(9, "KyraEngine::moveCharacterToPos(%d, %d, %d, %d)", character, facing, xpos, ypos); + Character *ch = &_characterList[character]; + ch->facing = facing; + _screen->hideMouse(); + xpos = (int16)(xpos & 0xFFFC); + ypos = (int16)(ypos & 0xFFFE); + disableTimer(19); + disableTimer(14); + disableTimer(18); + uint32 nextFrame = 0; + switch (facing) { + case 0: + while (ypos < ch->y1) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + while (_system->getMillis() < nextFrame) { updateGameTimers(); } + } + break; + + case 2: + while (ch->x1 < xpos) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + while (_system->getMillis() < nextFrame) { updateGameTimers(); } + } + break; + + case 4: + while (ypos > ch->y1) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + while (_system->getMillis() < nextFrame) { updateGameTimers(); } + } + break; + + case 6: + while (ch->x1 > xpos) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + while (_system->getMillis() < nextFrame) { updateGameTimers(); } + } + break; + + default: + break; + } + enableTimer(19); + enableTimer(14); + enableTimer(18); + _screen->showMouse(); +} + +void KyraEngine::setCharacterPositionWithUpdate(int character) { + debug(9, "KyraEngine::setCharacterPositionWithUpdate(%d)", character); + setCharacterPosition(character, 0); + _sprites->updateSceneAnims(); + updateGameTimers(); + _animator->updateAllObjectShapes(); + updateTextFade(); + + if (_currentCharacter->sceneId == 210) { + _animator->updateKyragemFading(); + } +} + +int KyraEngine::setCharacterPosition(int character, int *facingTable) { + debug(9, "KyraEngine::setCharacterPosition(%d, 0x%X)", character, facingTable); + if (character == 0) { + _currentCharacter->x1 += _charXPosTable[_currentCharacter->facing]; + _currentCharacter->y1 += _charYPosTable[_currentCharacter->facing]; + setCharacterPositionHelper(0, facingTable); + return 1; + } else { + _characterList[character].x1 += _charXPosTable[_characterList[character].facing]; + _characterList[character].y1 += _charYPosTable[_characterList[character].facing]; + if (_characterList[character].sceneId == _currentCharacter->sceneId) { + setCharacterPositionHelper(character, 0); + } + } + return 0; +} + +void KyraEngine::setCharacterPositionHelper(int character, int *facingTable) { + debug(9, "KyraEngine::setCharacterPositionHelper(%d, 0x%X)", character, 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); + } + } + } + + static uint8 facingIsZero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static uint8 facingIsFour[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + if (facing == 0) { + ++facingIsZero[character]; + } else { + bool resetTables = false; + if (facing != 7) { + if (facing - 1 != 0) { + if (facing != 4) { + if (facing == 3 || facing == 5) { + if (facingIsFour[character] > 2) { + facing = 4; + } + resetTables = true; + } + } else { + ++facingIsFour[character]; + } + } else { + if (facingIsZero[character] > 2) { + facing = 0; + } + resetTables = true; + } + } else { + if (facingIsZero[character] > 2) { + facing = 0; + } + resetTables = true; + } + + if (resetTables) { + facingIsZero[character] = 0; + facingIsFour[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) { + if (_brandonStatusBit & 0x10) + ch->currentAnimFrame = 88; + } + + animRefreshNPC(character); +} + +int KyraEngine::getOppositeFacingDirection(int dir) { + debug(9, "KyraEngine::getOppositeFacingDirection(%d)", dir); + switch (dir) { + case 0: + return 2; + break; + + case 1: + return 1; + break; + + case 3: + return 7; + break; + + case 4: + return 6; + break; + + case 5: + return 5; + break; + + case 6: + return 4; + break; + + case 7: + return 3; + break; + + default: + break; + } + return 0; +} + +void KyraEngine::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); + loadBitmap(fileNameBuffer, 3, 5, 0); +} + +void KyraEngine::startSceneScript(int brandonAlive) { + debug(9, "KyraEngine::startSceneScript(%d)", brandonAlive); + assert(_currentCharacter->sceneId < _roomTableSize); + int tableId = _roomTable[_currentCharacter->sceneId].nameIndex; + assert(tableId < _roomFilenameTableSize); + char fileNameBuffer[32]; + strcpy(fileNameBuffer, _roomFilenameTable[tableId]); + strcat(fileNameBuffer, ".CPS"); + loadBitmap(fileNameBuffer, 3, 3, 0); + _sprites->loadSceneShapes(); + _exitListPtr = 0; + + _screen->setScreenPalette(_screen->_currentPalette); + + _scaleMode = 1; + for (int i = 0; i < 145; ++i) { + _scaleTable[i] = 256; + } + + clearNoDropRects(); + _scriptInterpreter->initScript(_scriptClick, _scriptClickData); + strcpy(fileNameBuffer, _roomFilenameTable[tableId]); + strcat(fileNameBuffer, ".EMC"); + _scriptInterpreter->unloadScript(_scriptClickData); + _scriptInterpreter->loadScript(fileNameBuffer, _scriptClickData, _opcodeTable, _opcodeTableSize, 0); + _scriptInterpreter->startScript(_scriptClick, 0); + _scriptClick->variables[0] = _currentCharacter->sceneId; + _scriptClick->variables[7] = brandonAlive; + + while (_scriptInterpreter->validScript(_scriptClick)) { + _scriptInterpreter->runScript(_scriptClick); + } +} + +void KyraEngine::initSceneData(int facing, int unk1, int brandonAlive) { + debug(9, "KyraEngine::initSceneData(%d, %d, %d)", facing, unk1, 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->variables[4] = _itemInHand; + _scriptClick->variables[7] = brandonAlive; + _scriptInterpreter->startScript(_scriptClick, 3); + while (_scriptInterpreter->validScript(_scriptClick)) { + _scriptInterpreter->runScript(_scriptClick); + } +} + +void KyraEngine::initSceneObjectList(int brandonAlive) { + debug(9, "KyraEngine::initSceneObjectList(%d)", brandonAlive); + for (int i = 0; i < 28; ++i) { + _animator->actors()[i].active = 0; + } + + int startAnimFrame = 0; + + AnimObject *curAnimState = _animator->actors(); + curAnimState->active = 1; + curAnimState->drawY = _currentCharacter->y1; + curAnimState->sceneAnimPtr = _shapes[4+_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; + + _brandonScaleX = _scaleTable[_currentCharacter->y1]; + _brandonScaleY = _scaleTable[_currentCharacter->y1]; + + curAnimState->x1 += (_brandonScaleX * xOffset) >> 8; + curAnimState->y1 += (_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[4+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; + + _brandonScaleX = _scaleTable[ch->y1]; + _brandonScaleY = _scaleTable[ch->y1]; + + curAnimState->x1 += (_brandonScaleX * xOffset) >> 8; + curAnimState->y1 += (_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]; + + 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[220+curItem]; + curAnimState->animFrameNumber = (int16)0xFFFF; + curAnimState->y1 = curRoom->itemsYPos[i]; + curAnimState->x1 = curRoom->itemsXPos[i]; + + curAnimState->x1 -= (fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1; + curAnimState->y1 -= 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::initSceneScreen(int brandonAlive) { + // XXX (Pointless?) Palette stuff + 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->updateScreen(); + // XXX More (pointless?) palette stuff + + if (!_scriptInterpreter->startScript(_scriptClick, 2)) + error("Could not start script function 2 of scene script"); + + _scriptClick->variables[7] = brandonAlive; + + while (_scriptInterpreter->validScript(_scriptClick)) + _scriptInterpreter->runScript(_scriptClick); + + setTextFadeTimerCountdown(-1); + if (_currentCharacter->sceneId == 210) { + if (_itemInHand != -1) + magicOutMouseItem(2, -1); + + _screen->hideMouse(); + for (int i = 0; i < 10; ++i) { + if (_currentCharacter->inventoryItems[i] != 0xFF) + magicOutMouseItem(2, i); + } + _screen->showMouse(); + } +} + +int KyraEngine::handleSceneChange(int xpos, int ypos, int unk1, int frameReset) { + debug(9, "KyraEngine::handleSceneChange(%d, %d, %d, %d)", xpos, ypos, unk1, 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::processSceneChange(int *table, int unk1, int frameReset) { + debug(9, "KyraEngine::processSceneChange(0x%X, %d, %d)", table, unk1, frameReset); + if (queryGameFlag(0xEF)) { + unk1 = 0; + } + int *tableStart = table; + _sceneChangeState = 0; + _loopFlag2 = 0; + bool running = true; + int returnValue = 0; + uint32 nextFrame = 0; + _abortWalkFlag = false; + _mousePressFlag = false; + + while (running) { + if (_abortWalkFlag) { + *table = 8; + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + _animator->updateAllObjectShapes(); + processInput(_mouseX, _mouseY); + return 0; + } + 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; + break; + } + + returnValue = changeScene(_currentCharacter->facing); + if (returnValue) { + running = false; + _abortWalkFlag = false; + } + + if (unk1) { + if (_mousePressFlag) { + 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 = getTimerDelay(5) * _tickLength + _system->getMillis(); + while (_system->getMillis() < nextFrame) { + _sprites->updateSceneAnims(); + updateMousePointer(); + updateGameTimers(); + _animator->updateAllObjectShapes(); + updateTextFade(); + if (_currentCharacter->sceneId == 210) { + _animator->updateKyragemFading(); + if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) { + *table = 8; + running = false; + break; + } + } + if ((nextFrame - _system->getMillis()) >= 10) + delay(10); + } + } + + if (frameReset && !(_brandonStatusBit & 2)) { + _currentCharacter->currentAnimFrame = 7; + } + animRefreshNPC(0); + _animator->updateAllObjectShapes(); + return returnValue; +} + +int KyraEngine::changeScene(int facing) { + debug(9, "KyraEngine::changeScene(%d)", facing); + if (queryGameFlag(0xEF)) { + if (_currentCharacter->sceneId == 5) { + return 0; + } + } + + int xpos = _charXPosTable[facing] + _currentCharacter->x1; + int ypos = _charYPosTable[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 on 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; + 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; + break; + } + + if (sceneId == 0xFFFF) + return 0; + + enterNewScene(sceneId, facing, 1, 1, 0); + return returnValue; +} + +void KyraEngine::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::setCharactersPositions(int character) { + static uint16 initXPosTable[] = { + 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B, + 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042 + }; + static 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::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) { + debug(9, "KyraEngine::findWay(%d, %d, %d, %d, 0x%X, %d)", x, y, toX, toY, moveTable, moveTableSize); + x &= 0xFFFC; toX &= 0xFFFC; + y &= 0xFFFE; toY &= 0xFFFE; + x = (int16)x; y = (int16)y; toX = (int16)toX; toY = (int16)toY; + + if (x == toY && y == toY) { + moveTable[0] = 8; + return 0; + } + + int curX = x; + int curY = y; + int lastUsedEntry = 0; + int tempValue = 0; + int *pathTable1 = new int[0x7D0]; + int *pathTable2 = new int[0x7D0]; + assert(pathTable1 && pathTable2); + + while (true) { + int newFacing = getFacingFromPointToPoint(x, y, toX, toY); + changePosTowardsFacing(curX, curY, newFacing); + + if (curX == toX && curY == toY) { + if (!lineIsPassable(curX, curY)) + break; + moveTable[lastUsedEntry++] = newFacing; + break; + } + + if (lineIsPassable(curX, curY)) { + if (lastUsedEntry == moveTableSize) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + // debug drawing + //if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { + // _screen->setPagePixel(0, curX, curY, 11); + // _screen->updateScreen(); + // waitTicks(5); + //} + moveTable[lastUsedEntry++] = newFacing; + x = curX; + y = curY; + continue; + } + + int temp = 0; + while (true) { + newFacing = getFacingFromPointToPoint(curX, curY, toX, toY); + changePosTowardsFacing(curX, curY, newFacing); + // debug drawing + //if (curX >= 0 && curY >= 0 && curX < 320 && curY < 200) { + // _screen->setPagePixel(0, curX, curY, 8); + // _screen->updateScreen(); + // waitTicks(5); + //} + + if (!lineIsPassable(curX, curY)) { + if (curX != toX || curY != toY) + continue; + } + + if (curX == toX && curY == toY) { + if (!lineIsPassable(curX, curY)) { + tempValue = 0; + temp = 0; + break; + } + } + + temp = findSubPath(x, y, curX, curY, pathTable1, 1, 0x7D0); + tempValue = findSubPath(x, y, curX, curY, pathTable2, 0, 0x7D0); + if (curX == toX && curY == toY) { + if (temp == 0x7D00 && tempValue == 0x7D00) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + } + + if (temp != 0x7D00 || tempValue != 0x7D00) { + break; + } + } + + if (temp < tempValue) { + if (lastUsedEntry + temp > moveTableSize) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + memcpy(&moveTable[lastUsedEntry], pathTable1, temp*sizeof(int)); + lastUsedEntry += temp; + } else { + if (lastUsedEntry + tempValue > moveTableSize) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + memcpy(&moveTable[lastUsedEntry], pathTable2, tempValue*sizeof(int)); + lastUsedEntry += tempValue; + } + x = curX; + y = curY; + if (curX == toX && curY == toY) { + break; + } + } + delete [] pathTable1; + delete [] pathTable2; + moveTable[lastUsedEntry] = 8; + return getMoveTableSize(moveTable); +} + +int KyraEngine::findSubPath(int x, int y, int toX, int toY, int *moveTable, int start, int end) { + debug(9, "KyraEngine::findSubPath(%d, %d, %d, %d, 0x%X, %d, %d)", x, y, toX, toY, moveTable, start, end); + // only used for debug specific code + //static uint16 unkTable[] = { 8, 5 }; + static const int8 facingTable1[] = { 7, 0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 0 }; + static const int8 facingTable2[] = { -1, 0, -1, 2, -1, 4, -1, 6, -1, 2, -1, 4, -1, 6, -1, 0 }; + static const int8 facingTable3[] = { 2, 4, 4, 6, 6, 0, 0, 2, 6, 6, 0, 0, 2, 2, 4, 4 }; + static const int8 addPosTableX[] = { -1, 0, -1, 4, -1, 0, -1, -4, -1, -4, -1, 0, -1, 4, -1, 0 }; + static const int8 addPosTableY[] = { -1, 2, -1, 0, -1, -2, -1, 0, -1, 0, -1, 2, -1, 0, -1, -2 }; + + // debug specific + //++unkTable[start]; + //while (_screen->getPalette(0)[unkTable[start]] != 0x0F) { + // ++unkTable[start]; + //} + + int xpos1 = x, xpos2 = x; + int ypos1 = y, ypos2 = y; + int newFacing = getFacingFromPointToPoint(x, y, toX, toY); + int position = 0; + + while (position != end) { + int newFacing2 = newFacing; + while (true) { + changePosTowardsFacing(xpos1, ypos1, facingTable1[start*8 + newFacing2]); + if (!lineIsPassable(xpos1, ypos1)) { + if (facingTable1[start*8 + newFacing2] == newFacing) { + return 0x7D00; + } + newFacing2 = facingTable1[start*8 + newFacing2]; + xpos1 = x; + ypos1 = y; + continue; + } + newFacing = facingTable1[start*8 + newFacing2]; + break; + } + // debug drawing + //if (xpos1 >= 0 && ypos1 >= 0 && xpos1 < 320 && ypos1 < 200) { + // _screen->setPagePixel(0, xpos1, ypos1, unkTable[start]); + // _screen->updateScreen(); + // waitTicks(5); + //} + if (newFacing & 1) { + int temp = xpos1 + addPosTableX[newFacing + start * 8]; + if (toX == temp) { + temp = ypos1 + addPosTableY[newFacing + start * 8]; + if (toY == temp) { + moveTable[position++] = facingTable2[newFacing + start * 8]; + return position; + } + } + } + moveTable[position++] = newFacing; + x = xpos1; + y = ypos1; + if (x == toX && y == toY) { + return position; + } + + if (xpos1 == xpos2 && ypos1 == ypos2) { + break; + } + + newFacing = facingTable3[start*8 + newFacing]; + } + return 0x7D00; +} + +int KyraEngine::getFacingFromPointToPoint(int x, int y, int toX, int toY) { + debug(9, "KyraEngine::getFacingFromPointToPoint(%d, %d, %d, %d)", x, y, toX, toY); + static const int facingTable[] = { + 1, 0, 1, 2, 3, 4, 3, 2, 7, 0, 7, 6, 5, 4, 5, 6 + }; + + int facingEntry = 0; + int ydiff = y - toY; + if (ydiff < 0) { + ++facingEntry; + ydiff = -ydiff; + } + facingEntry <<= 1; + + int xdiff = toX - x; + if (xdiff < 0) { + ++facingEntry; + xdiff = -xdiff; + } + + if (xdiff >= ydiff) { + int temp = ydiff; + ydiff = xdiff; + xdiff = temp; + + facingEntry <<= 1; + } else { + facingEntry <<= 1; + facingEntry += 1; + } + int temp = (ydiff + 1) >> 1; + + if (xdiff < temp) { + facingEntry <<= 1; + facingEntry += 1; + } else { + facingEntry <<= 1; + } + assert(facingEntry < ARRAYSIZE(facingTable)); + return facingTable[facingEntry]; +} + +void KyraEngine::changePosTowardsFacing(int &x, int &y, int facing) { + debug(9, "KyraEngine::changePosTowardsFacing(%d, %d, %d)", x, y, facing); + x += _addXPosTable[facing]; + y += _addYPosTable[facing]; +} + +bool KyraEngine::lineIsPassable(int x, int y) { + debug(9, "KyraEngine::lineIsPassable(%d, %d)", x, 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; + } + + int ypos = 8; + if (_scaleMode) { + ypos = (_scaleTable[y] >> 5) + 1; + if (8 < ypos) + ypos = 8; + } + + x -= (ypos >> 1); + if (y < 0) + y = 0; + + 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; +} + +int KyraEngine::getMoveTableSize(int *moveTable) { + debug(9, "KyraEngine::getMoveTableSize(0x%X)", moveTable); + int retValue = 0; + if (moveTable[0] == 8) + return 0; + + static const int facingTable[] = { + 4, 5, 6, 7, 0, 1, 2, 3 + }; + static const int unkTable[] = { + -1, -1, 1, 2, -1, 6, 7, -1, + -1, -1, -1, -1, 2, -1, 0, -1, + 1, -1, -1, -1, 3, 4, -1, 0, + 2, -1, -1, -1, -1, -1, 4, -1, + -1, 2, 3, -1, -1, -1, 5, 6, + 6, -1, 4, -1, -1, -1, -1, -1, + 7, 0, -1, 4, 5, -1, -1, -1, + -1, -1, 0, -1, 6, -1, -1, -1 + }; + + int *oldPosition = moveTable; + int *tempPosition = moveTable; + int *curPosition = moveTable + 1; + retValue = 1; + + while (*curPosition != 8) { + if (*oldPosition == facingTable[*curPosition]) { + retValue -= 2; + *oldPosition = 9; + *curPosition = 9; + + while (tempPosition != moveTable) { + --tempPosition; + if (*tempPosition != 9) + break; + } + + if (tempPosition == moveTable && *tempPosition == 9) { + while (*tempPosition != 8 && *tempPosition == 9) { + ++tempPosition; + } + if (*tempPosition == 8) { + return 0; + } + } + + oldPosition = tempPosition; + curPosition = oldPosition+1; + while (*curPosition != 8 && *curPosition == 9) { + ++curPosition; + } + continue; + } + + if (unkTable[*curPosition+((*oldPosition)*8)] != -1) { + --retValue; + *oldPosition = unkTable[*curPosition+((*oldPosition)*8)]; + *curPosition = 9; + + if (tempPosition != oldPosition) { + curPosition = oldPosition; + oldPosition = tempPosition; + while (true) { + if (tempPosition == moveTable) { + break; + } + --tempPosition; + if (*tempPosition != 9) { + break; + } + } + } else { + while (true) { + ++curPosition; + if (*curPosition != 9) { + break; + } + } + } + continue; + } + + tempPosition = oldPosition; + oldPosition = curPosition; + ++retValue; + while (true) { + ++curPosition; + if (*curPosition != 9) { + break; + } + } + } + + return retValue; +} + +} // end of namespace Kyra diff --git a/kyra/screen.cpp b/kyra/screen.cpp index 40a3936ae6..bd93646d36 100644 --- a/kyra/screen.cpp +++ b/kyra/screen.cpp @@ -71,6 +71,11 @@ Screen::Screen(KyraEngine *vm, OSystem *system) memset(_bitBlitRects, 0, sizeof(Rect)*BITBLIT_RECTS); _bitBlitNum = 0; memset(_saveLoadPage, 0, sizeof(_saveLoadPage)); + + _unkPtr1 = (uint8*)malloc(getRectSize(1, 144)); + memset(_unkPtr1, 0, getRectSize(1, 144)); + _unkPtr2 = (uint8*)malloc(getRectSize(1, 144)); + memset(_unkPtr2, 0, getRectSize(1, 144)); } Screen::~Screen() { @@ -94,6 +99,9 @@ Screen::~Screen() { delete [] _saveLoadPage[i]; _saveLoadPage[i] = 0; } + + free(_unkPtr1); + free(_unkPtr2); } void Screen::updateScreen() { @@ -1916,4 +1924,150 @@ void Screen::deletePageFromDisk(int page) { _saveLoadPage[page/2] = 0; } +void Screen::blockInRegion(int x, int y, int width, int height) { + debug(9, "Screen::blockInRegion(%d, %d, %d, %d)", x, y, width, height); + assert(_shapePages[0]); + byte *toPtr = _shapePages[0] + (y * 320 + x); + for (int i = 0; i < height; ++i) { + byte *backUpTo = toPtr; + for (int i2 = 0; i2 < width; ++i2) { + *toPtr++ &= 0x7F; + } + toPtr = (backUpTo + 320); + } +} + +void Screen::blockOutRegion(int x, int y, int width, int height) { + debug(9, "Screen::blockOutRegion(%d, %d, %d, %d)", x, y, width, height); + assert(_shapePages[0]); + byte *toPtr = _shapePages[0] + (y * 320 + x); + for (int i = 0; i < height; ++i) { + byte *backUpTo = toPtr; + for (int i2 = 0; i2 < width; ++i2) { + *toPtr++ |= 0x80; + } + toPtr = (backUpTo + 320); + } +} + +void Screen::rectClip(int &x, int &y, int w, int h) { + if (x < 0) { + x = 0; + } else if (x + w >= 320) { + x = 320 - w; + } + if (y < 0) { + y = 0; + } else if (y + h >= 200) { + y = 200 - h; + } +} + +void Screen::backUpRect0(int xpos, int ypos) { + debug(9, "Screen::backUpRect0(%d, %d)", xpos, ypos); + rectClip(xpos, ypos, 3<<3, 24); + copyRegionToBuffer(_curPage, xpos, ypos, 3<<3, 24, _vm->shapes()[0]); +} + +void Screen::restoreRect0(int xpos, int ypos) { + debug(9, "Screen::restoreRect0(%d, %d)", xpos, ypos); + rectClip(xpos, ypos, 3<<3, 24); + copyBlockToPage(_curPage, xpos, ypos, 3<<3, 24, _vm->shapes()[0]); +} + +void Screen::backUpRect1(int xpos, int ypos) { + debug(9, "Screen::backUpRect1(%d, %d)", xpos, ypos); + rectClip(xpos, ypos, 4<<3, 32); + copyRegionToBuffer(_curPage, xpos, ypos, 4<<3, 32, _vm->shapes()[1]); +} + +void Screen::restoreRect1(int xpos, int ypos) { + debug(9, "Screen::restoreRect1(%d, %d)", xpos, ypos); + rectClip(xpos, ypos, 4<<3, 32); + copyBlockToPage(_curPage, xpos, ypos, 4<<3, 32, _vm->shapes()[1]); +} + +int Screen::getDrawLayer(int x, int y) { + debug(9, "Screen::getDrawLayer(%d, %d)", x, y); + int xpos = x - 8; + int ypos = y - 1; + int layer = 1; + for (int curX = xpos; curX < xpos + 16; ++curX) { + int tempLayer = getShapeFlag2(curX, ypos); + if (layer < tempLayer) { + layer = tempLayer; + } + if (layer >= 7) { + return 7; + } + } + return layer; +} + +int Screen::getDrawLayer2(int x, int y, int height) { + debug(9, "Screen::getDrawLayer2(%d, %d, %d)", x, y, height); + int xpos = x - 8; + int ypos = y - 1; + int layer = 1; + + for (int useX = xpos; useX < xpos + 16; ++useX) { + for (int useY = ypos - height; useY < ypos; ++useY) { + int tempLayer = getShapeFlag2(useX, useY); + if (tempLayer > layer) { + layer = tempLayer; + } + + if (tempLayer >= 7) { + return 7; + } + } + } + return layer; +} + +void Screen::copyBackgroundBlock(int x, int page, int flag) { + debug(9, "Screen::copyBackgroundBlock(%d, %d, %d)", x, page, flag); + + if (x < 1) + return; + + int height = 128; + if (flag) + height += 8; + if (!(x & 1)) + ++x; + if (x == 19) + x = 17; + uint8 *ptr1 = _unkPtr1; + uint8 *ptr2 = _unkPtr2; + int oldVideoPage = _curPage; + _curPage = page; + + int curX = x; + hideMouse(); + copyRegionToBuffer(_curPage, 8, 8, 8, height, ptr2); + for (int i = 0; i < 19; ++i) { + int tempX = curX + 1; + copyRegionToBuffer(_curPage, tempX<<3, 8, 8, height, ptr1); + copyBlockToPage(_curPage, tempX<<3, 8, 8, height, ptr2); + int newXPos = curX + x; + if (newXPos > 37) { + newXPos = newXPos % 38; + } + tempX = newXPos + 1; + copyRegionToBuffer(_curPage, tempX<<3, 8, 8, height, ptr2); + copyBlockToPage(_curPage, tempX<<3, 8, 8, height, ptr1); + curX += x*2; + if (curX > 37) { + curX = curX % 38; + } + } + showMouse(); + _curPage = oldVideoPage; +} + +void Screen::copyBackgroundBlock2(int x) { + copyBackgroundBlock(x, 4, 1); +} + } // End of namespace Kyra diff --git a/kyra/screen.h b/kyra/screen.h index ac3e8e0b51..dc0095351a 100644 --- a/kyra/screen.h +++ b/kyra/screen.h @@ -149,6 +149,19 @@ public: void loadPageFromDisk(const char *file, int page); void deletePageFromDisk(int page); + void blockInRegion(int x, int y, int width, int height); + void blockOutRegion(int x, int y, int width, int height); + + void backUpRect0(int xpos, int ypos); + void restoreRect0(int xpos, int ypos); + void backUpRect1(int xpos, int ypos); + void restoreRect1(int xpos, int ypos); + void copyBackgroundBlock(int x, int page, int flag); + void copyBackgroundBlock2(int x); + void rectClip(int &x, int &y, int w, int h); + int getDrawLayer(int x, int y); + int getDrawLayer2(int x, int y, int height); + int _charWidth; int _charOffset; int _curPage; @@ -181,6 +194,7 @@ private: Rect *_bitBlitRects; int _bitBlitNum; + uint8 *_unkPtr1, *_unkPtr2; OSystem *_system; KyraEngine *_vm; diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp index b3e1c4eeb8..53310f1237 100644 --- a/kyra/script_v1.cpp +++ b/kyra/script_v1.cpp @@ -112,13 +112,13 @@ int KyraEngine::cmd_setSpecialExitList(ScriptState *script) { int KyraEngine::cmd_blockInWalkableRegion(ScriptState *script) { debug(3, "cmd_blockInWalkableRegion(0x%X) (%d, %d, %d, %d)", script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); - blockInRegion(stackPos(0), stackPos(1), stackPos(2)-stackPos(0)+1, stackPos(3)-stackPos(1)+1); + _screen->blockInRegion(stackPos(0), stackPos(1), stackPos(2)-stackPos(0)+1, stackPos(3)-stackPos(1)+1); return 0; } int KyraEngine::cmd_blockOutWalkableRegion(ScriptState *script) { debug(3, "cmd_blockOutWalkableRegion(0x%X) (%d, %d, %d, %d)", script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); - blockOutRegion(stackPos(0), stackPos(1), stackPos(2)-stackPos(0)+1, stackPos(3)-stackPos(1)+1); + _screen->blockOutRegion(stackPos(0), stackPos(1), stackPos(2)-stackPos(0)+1, stackPos(3)-stackPos(1)+1); return 0; } @@ -1113,8 +1113,8 @@ int KyraEngine::cmd_getCharactersFacing(ScriptState *script) { int KyraEngine::cmd_bkgdScrollSceneAndMasksRight(ScriptState *script) { debug(3, "cmd_bkgdScrollSceneAndMasksRight(0x%X) (%d)", script, stackPos(0)); - copyBackgroundBlock(stackPos(0), 2, 0); - copyBackgroundBlock2(stackPos(0)); + _screen->copyBackgroundBlock(stackPos(0), 2, 0); + _screen->copyBackgroundBlock2(stackPos(0)); // update the whole screen _screen->copyRegion(7, 7, 7, 7, 305, 129, 3, 0); _screen->updateScreen(); diff --git a/kyra/seqplayer.cpp b/kyra/seqplayer.cpp index ae36ad65df..5f1223bd8a 100644 --- a/kyra/seqplayer.cpp +++ b/kyra/seqplayer.cpp @@ -408,7 +408,7 @@ void SeqPlayer::s1_playTrack() { } else if (msg == 1) { _sound->beginFadeOut(); } else { - _vm->snd_playTrack(msg); + _sound->playTrack(msg); } // } } @@ -635,4 +635,5 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) { return seqSkippedFlag; } + } // End of namespace Kyra diff --git a/kyra/sequences.cpp b/kyra/sequences.cpp new file mode 100644 index 0000000000..1ac3574a47 --- /dev/null +++ b/kyra/sequences.cpp @@ -0,0 +1,968 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2005-2006 The ScummVM project + * + * 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. + * + * $Header$ + * + */ + +#include "kyra/kyra.h" +#include "kyra/seqplayer.h" +#include "kyra/screen.h" +#include "kyra/resource.h" +#include "kyra/sound.h" +#include "kyra/sprites.h" +#include "kyra/wsamovie.h" +#include "kyra/animator.h" +#include "kyra/text.h" + +#include "common/system.h" +#include "common/savefile.h" + +namespace Kyra { + +void KyraEngine::seq_demo() { + debug(9, "KyraEngine::seq_demo()"); + + snd_playTheme(MUSIC_INTRO, 2); + + loadBitmap("START.CPS", 7, 7, _screen->_currentPalette); + _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0); + _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); + _screen->fadeFromBlack(); + waitTicks(60); + _screen->fadeToBlack(); + + _screen->clearPage(0); + loadBitmap("TOP.CPS", 7, 7, NULL); + loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); + _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0); + _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0); + _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); + _screen->fadeFromBlack(); + + _seq->playSequence(_seq_WestwoodLogo, true); + waitTicks(60); + + _seq->playSequence(_seq_KyrandiaLogo, true); + + _screen->fadeToBlack(); + _screen->clearPage(2); + _screen->clearPage(0); + + _seq->playSequence(_seq_Demo1, true); + + _screen->clearPage(0); + _seq->playSequence(_seq_Demo2, true); + + _screen->clearPage(0); + _seq->playSequence(_seq_Demo3, true); + + _screen->clearPage(0); + _seq->playSequence(_seq_Demo4, true); + + _screen->clearPage(0); + loadBitmap("FINAL.CPS", 7, 7, _screen->_currentPalette); + _screen->_curPage = 0; + _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0); + _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); + _screen->fadeFromBlack(); + waitTicks(60); + _screen->fadeToBlack(); + _sound->stopMusic(); +} + +void KyraEngine::seq_intro() { + debug(9, "KyraEngine::seq_intro()"); + if (_features & GF_TALKIE) { + _res->loadPakFile("INTRO.VRM"); + } + + static const IntroProc introProcTable[] = { + &KyraEngine::seq_introLogos, + &KyraEngine::seq_introStory, + &KyraEngine::seq_introMalcolmTree, + &KyraEngine::seq_introKallakWriting, + &KyraEngine::seq_introKallakMalcolm + }; + + Common::InSaveFile *in; + if ((in = _saveFileMan->openForLoading(getSavegameFilename(0)))) { + delete in; + _skipIntroFlag = true; + } else + _skipIntroFlag = false; + + _seq->setCopyViewOffs(true); + _screen->setFont(Screen::FID_8_FNT); + snd_playTheme(MUSIC_INTRO, 2); + snd_setSoundEffectFile(MUSIC_INTRO); + _text->setTalkCoords(144); + for (int i = 0; i < ARRAYSIZE(introProcTable) && !seq_skipSequence(); ++i) { + (this->*introProcTable[i])(); + } + _text->setTalkCoords(136); + waitTicks(30); + _seq->setCopyViewOffs(false); + _sound->stopMusic(); + if (_features & GF_TALKIE) { + _res->unloadPakFile("INTRO.VRM"); + } + res_unloadResources(RES_INTRO | RES_OUTRO); +} + +void KyraEngine::seq_introLogos() { + debug(9, "KyraEngine::seq_introLogos()"); + _screen->clearPage(0); + loadBitmap("TOP.CPS", 7, 7, NULL); + loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); + _screen->_curPage = 0; + _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0); + _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0); + _system->copyRectToScreen(_screen->getPagePtr(0), 320, 0, 0, 320, 200); + _screen->fadeFromBlack(); + + if (_seq->playSequence(_seq_WestwoodLogo, _skipIntroFlag)) { + _screen->fadeToBlack(); + _screen->clearPage(0); + return; + } + waitTicks(60); + if (_seq->playSequence(_seq_KyrandiaLogo, _skipIntroFlag)) { + _screen->fadeToBlack(); + _screen->clearPage(0); + return; + } + _screen->fillRect(0, 179, 319, 199, 0); + + int y1 = 8; + int h1 = 175; + int y2 = 176; + int h2 = 0; + _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 2); + _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 2); + do { + if (h1 > 0) { + _screen->copyRegion(0, y1, 0, 8, 320, h1, 2, 0); + } + ++y1; + --h1; + if (h2 > 0) { + _screen->copyRegion(0, 64, 0, y2, 320, h2, 4, 0); + } + --y2; + ++h2; + _screen->updateScreen(); + waitTicks(1); + } while (y2 >= 64); + + _seq->playSequence(_seq_Forest, true); +} + +void KyraEngine::seq_introStory() { + debug(9, "KyraEngine::seq_introStory()"); + _screen->clearPage(3); + _screen->clearPage(0); + if ((_features & GF_ENGLISH) && (_features & GF_TALKIE)) { + loadBitmap("TEXT_ENG.CPS", 3, 3, 0); + } else if (_features & GF_GERMAN) { + loadBitmap("TEXT_GER.CPS", 3, 3, 0); + } else if (_features & GF_FRENCH) { + loadBitmap("TEXT_FRE.CPS", 3, 3, 0); + } else if (_features & GF_SPANISH) { + loadBitmap("TEXT_SPA.CPS", 3, 3, 0); + } else if ((_features & GF_ENGLISH) && (_features & GF_FLOPPY)) { + loadBitmap("TEXT.CPS", 3, 3, 0); + } else { + warning("no story graphics file found"); + } + _screen->copyRegion(0, 0, 0, 0, 320, 200, 3, 0); + _screen->updateScreen(); + waitTicks(360); +} + +void KyraEngine::seq_introMalcolmTree() { + debug(9, "KyraEngine::seq_introMalcolmTree()"); + _screen->_curPage = 0; + _screen->clearPage(3); + _seq->playSequence(_seq_MalcolmTree, true); +} + +void KyraEngine::seq_introKallakWriting() { + debug(9, "KyraEngine::seq_introKallakWriting()"); + _seq->makeHandShapes(); + _screen->setAnimBlockPtr(5060); + _screen->_charWidth = -2; + _screen->clearPage(3); + _seq->playSequence(_seq_KallakWriting, true); +} + +void KyraEngine::seq_introKallakMalcolm() { + debug(9, "KyraEngine::seq_introKallakMalcolm()"); + _screen->clearPage(3); + _seq->playSequence(_seq_KallakMalcolm, true); +} + +void KyraEngine::seq_createAmuletJewel(int jewel, int page, int noSound, int drawOnly) { + debug(9, "seq_createAmuletJewel(%d, %d, %d, %d)", jewel, page, noSound, drawOnly); + static const uint16 specialJewelTable[] = { + 0x167, 0x162, 0x15D, 0x158, 0x153, 0xFFFF + }; + static const uint16 specialJewelTable1[] = { + 0x14F, 0x154, 0x159, 0x15E, 0x163, 0xFFFF + }; + static const uint16 specialJewelTable2[] = { + 0x150, 0x155, 0x15A, 0x15F, 0x164, 0xFFFF + }; + static const uint16 specialJewelTable3[] = { + 0x151, 0x156, 0x15B, 0x160, 0x165, 0xFFFF + }; + static const uint16 specialJewelTable4[] = { + 0x152, 0x157, 0x15C, 0x161, 0x166, 0xFFFF + }; + if (!noSound) + snd_playSoundEffect(0x5F); + _screen->hideMouse(); + if (!drawOnly) { + for (int i = 0; specialJewelTable[i] != 0xFFFF; ++i) { + _screen->drawShape(page, _shapes[4+specialJewelTable[i]], _amuletX2[jewel], _amuletY2[jewel], 0, 0); + _screen->updateScreen(); + delayWithTicks(3); + } + + const uint16 *opcodes = 0; + switch (jewel - 1) { + case 0: + opcodes = specialJewelTable1; + break; + + case 1: + opcodes = specialJewelTable2; + break; + + case 2: + opcodes = specialJewelTable3; + break; + + case 3: + opcodes = specialJewelTable4; + break; + } + + if (opcodes) { + for (int i = 0; opcodes[i] != 0xFFFF; ++i) { + _screen->drawShape(page, _shapes[4+opcodes[i]], _amuletX2[jewel], _amuletY2[jewel], 0, 0); + _screen->updateScreen(); + delayWithTicks(3); + } + } + } + _screen->drawShape(page, _shapes[327+jewel], _amuletX2[jewel], _amuletY2[jewel], 0, 0); + _screen->updateScreen(); + _screen->showMouse(); + setGameFlag(0x55+jewel); +} + +void KyraEngine::seq_brandonHealing() { + debug(9, "seq_brandonHealing()"); + if (!(_deathHandler & 8)) + return; + if (_currentCharacter->sceneId == 210) { + if (_beadStateVar == 4 || _beadStateVar == 6) + return; + } + _screen->hideMouse(); + checkAmuletAnimFlags(); + assert(_healingShapeTable); + setupShapes123(_healingShapeTable, 22, 0); + setBrandonAnimSeqSize(3, 48); + snd_playSoundEffect(0x53); + for (int i = 123; i <= 144; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + for (int i = 125; i >= 123; --i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_brandonHealing2() { + debug(9, "seq_brandonHealing2()"); + _screen->hideMouse(); + checkAmuletAnimFlags(); + assert(_healingShape2Table); + setupShapes123(_healingShape2Table, 30, 0); + resetBrandonPoisonFlags(); + setBrandonAnimSeqSize(3, 48); + snd_playSoundEffect(0x50); + for (int i = 123; i <= 152; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); + assert(_poisonGone); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(2010); + } + characterSays(_poisonGone[0], 0, -2); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(2011); + } + characterSays(_poisonGone[1], 0, -2); +} + +void KyraEngine::seq_poisonDeathNow(int now) { + debug(9, "seq_poisonDeathNow(%d)", now); + if (!(_brandonStatusBit & 1)) + return; + ++_poisonDeathCounter; + if (now) + _poisonDeathCounter = 2; + if (_poisonDeathCounter >= 2) { + snd_playWanderScoreViaMap(1, 1); + assert(_thePoison); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(7000); + } + characterSays(_thePoison[0], 0, -2); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(7001); + } + characterSays(_thePoison[1], 0, -2); + seq_poisonDeathNowAnim(); + _deathHandler = 3; + } else { + assert(_thePoison); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(7002); + } + characterSays(_thePoison[2], 0, -2); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(7004); + } + characterSays(_thePoison[3], 0, -2); + } +} + +void KyraEngine::seq_poisonDeathNowAnim() { + debug(9, "seq_poisonDeathNowAnim()"); + _screen->hideMouse(); + checkAmuletAnimFlags(); + assert(_posionDeathShapeTable); + setupShapes123(_posionDeathShapeTable, 20, 0); + setBrandonAnimSeqSize(8, 48); + + _currentCharacter->currentAnimFrame = 124; + animRefreshNPC(0); + delayWithTicks(30); + + _currentCharacter->currentAnimFrame = 123; + animRefreshNPC(0); + delayWithTicks(30); + + for (int i = 125; i <= 139; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + delayWithTicks(60); + + for (int i = 140; i <= 142; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + delayWithTicks(60); + + resetBrandonAnimSeqSize(); + freeShapes123(); + _animator->restoreAllObjectBackgrounds(); + _currentCharacter->x1 = _currentCharacter->x2 = -1; + _currentCharacter->y1 = _currentCharacter->y2 = -1; + _animator->preserveAllBackgrounds(); + _screen->showMouse(); +} + +void KyraEngine::seq_playFluteAnimation() { + debug(9, "seq_playFluteAnimation()"); + _screen->hideMouse(); + checkAmuletAnimFlags(); + setupShapes123(_fluteAnimShapeTable, 36, 0); + setBrandonAnimSeqSize(3, 75); + for (int i = 123; i <= 130; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(2); + } + + int delayTime = 0, soundType = 0; + if (queryGameFlag(0x85)) { + snd_playSoundEffect(0x63); + delayTime = 9; + soundType = 3; + } else if (!queryGameFlag(0x86)) { + snd_playSoundEffect(0x61); + delayTime = 2; + soundType = 1; + setGameFlag(0x86); + } else { + snd_playSoundEffect(0x62); + delayTime = 2; + soundType = 2; + } + + for (int i = 131; i <= 158; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(delayTime); + } + + for (int i = 126; i >= 123; --i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(delayTime); + } + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); + + if (soundType == 1) { + assert(_fluteString); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(1000); + } + characterSays(_fluteString[0], 0, -2); + } else if (soundType == 2) { + assert(_fluteString); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(1001); + } + characterSays(_fluteString[1], 0, -2); + } +} + +void KyraEngine::seq_winterScroll1() { + debug(9, "seq_winterScroll1()"); + _screen->hideMouse(); + checkAmuletAnimFlags(); + assert(_winterScrollTable); + assert(_winterScroll1Table); + assert(_winterScroll2Table); + setupShapes123(_winterScrollTable, 7, 0); + setBrandonAnimSeqSize(5, 66); + + for (int i = 123; i <= 129; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + freeShapes123(); + snd_playSoundEffect(0x20); + setupShapes123(_winterScroll1Table, 35, 0); + + for (int i = 123; i <= 146; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + if (_currentCharacter->sceneId == 41 && !queryGameFlag(0xA2)) { + snd_playSoundEffect(0x20); + _sprites->_anims[0].play = false; + _animator->sprites()[0].active = 0; + _sprites->_anims[1].play = true; + _animator->sprites()[1].active = 1; + setGameFlag(0xA2); + } + + for (int i = 147; i <= 157; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + if (_currentCharacter->sceneId == 117 && !queryGameFlag(0xB3)) { + for (int i = 0; i <= 7; ++i) { + _sprites->_anims[i].play = false; + _animator->sprites()[i].active = 0; + } + uint8 tmpPal[768]; + memcpy(tmpPal, _screen->_currentPalette, 768); + memcpy(&tmpPal[684], palTable2()[0], 60); + _screen->fadePalette(tmpPal, 72); + memcpy(&_screen->_currentPalette[684], palTable2()[0], 60); + _screen->setScreenPalette(_screen->_currentPalette); + setGameFlag(0xB3); + } else { + delayWithTicks(120); + } + + freeShapes123(); + setupShapes123(_winterScroll2Table, 4, 0); + + for (int i = 123; i <= 126; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_winterScroll2() { + debug(9, "seq_winterScroll2()"); + _screen->hideMouse(); + checkAmuletAnimFlags(); + assert(_winterScrollTable); + setupShapes123(_winterScrollTable, 7, 0); + setBrandonAnimSeqSize(5, 66); + + for (int i = 123; i <= 128; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + delayWithTicks(120); + + for (int i = 127; i >= 123; --i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_makeBrandonInv() { + debug(9, "seq_makeBrandonInv()"); + if (_deathHandler == 8) + return; + + if (_currentCharacter->sceneId == 210) { + if (_beadStateVar == 4 || _beadStateVar == 6) + return; + } + + _screen->hideMouse(); + checkAmuletAnimFlags(); + _brandonStatusBit |= 0x20; + setTimerCountdown(18, 2700); + _brandonStatusBit |= 0x40; + snd_playSoundEffect(0x77); + _brandonInvFlag = 0; + while (_brandonInvFlag <= 0x100) { + animRefreshNPC(0); + delayWithTicks(10); + _brandonInvFlag += 0x10; + } + _brandonStatusBit &= 0xFFBF; + _screen->showMouse(); +} + +void KyraEngine::seq_makeBrandonNormal() { + debug(9, "seq_makeBrandonNormal()"); + _screen->hideMouse(); + _brandonStatusBit |= 0x40; + snd_playSoundEffect(0x77); + _brandonInvFlag = 0x100; + while (_brandonInvFlag >= 0) { + animRefreshNPC(0); + delayWithTicks(10); + _brandonInvFlag -= 0x10; + } + _brandonInvFlag = 0; + _brandonStatusBit &= 0xFF9F; + _screen->showMouse(); +} + +void KyraEngine::seq_makeBrandonNormal2() { + debug(9, "seq_makeBrandonNormal2()"); + _screen->hideMouse(); + assert(_brandonToWispTable); + setupShapes123(_brandonToWispTable, 26, 0); + setBrandonAnimSeqSize(5, 48); + _brandonStatusBit &= 0xFFFD; + snd_playSoundEffect(0x6C); + for (int i = 138; i >= 123; --i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + setBrandonAnimSeqSize(4, 48); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245) { + _screen->fadeSpecialPalette(31, 234, 13, 4); + } else if (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186) { + _screen->fadeSpecialPalette(14, 228, 15, 4); + } + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_makeBrandonWisp() { + debug(9, "seq_makeBrandonWisp()"); + if (_deathHandler == 8) + return; + + if (_currentCharacter->sceneId == 210) { + if (_beadStateVar == 4 || _beadStateVar == 6) + return; + } + _screen->hideMouse(); + checkAmuletAnimFlags(); + assert(_brandonToWispTable); + setupShapes123(_brandonToWispTable, 26, 0); + setBrandonAnimSeqSize(5, 48); + snd_playSoundEffect(0x6C); + for (int i = 123; i <= 138; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + _brandonStatusBit |= 2; + if (_currentCharacter->sceneId >= 109 && _currentCharacter->sceneId <= 198) { + setTimerCountdown(14, 18000); + } else { + setTimerCountdown(14, 7200); + } + _brandonDrawFrame = 113; + _brandonStatusBit0x02Flag = 1; + _currentCharacter->currentAnimFrame = 113; + animRefreshNPC(0); + _animator->updateAllObjectShapes(); + if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245) { + _screen->fadeSpecialPalette(30, 234, 13, 4); + } else if (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186) { + _screen->fadeSpecialPalette(14, 228, 15, 4); + } + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_dispelMagicAnimation() { + debug(9, "seq_dispelMagicAnimation()"); + if (_deathHandler == 8) + return; + if (_currentCharacter->sceneId == 210) { + if (_beadStateVar == 4 || _beadStateVar == 6) + return; + } + _screen->hideMouse(); + if (_currentCharacter->sceneId == 210 && _currentCharacter->sceneId < 160) + _currentCharacter->facing = 3; + if (_malcolmFlag == 7 && _beadStateVar == 3) { + _beadStateVar = 6; + _unkEndSeqVar5 = 2; + _malcolmFlag = 10; + } + checkAmuletAnimFlags(); + setGameFlag(0xEE); + assert(_magicAnimationTable); + setupShapes123(_magicAnimationTable, 5, 0); + setBrandonAnimSeqSize(8, 49); + snd_playSoundEffect(0x15); + for (int i = 123; i <= 127; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + + delayWithTicks(120); + + for (int i = 127; i >= 123; --i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(10); + } + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_fillFlaskWithWater(int item, int type) { + debug(9, "seq_fillFlaskWithWater(%d, %d)", item, type); + int newItem = -1; + static const uint8 flaskTable1[] = { 0x46, 0x48, 0x4A, 0x4C }; + static const uint8 flaskTable2[] = { 0x47, 0x49, 0x4B, 0x4D }; + + if (item >= 60 && item <= 77) { + assert(_flaskFull); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + snd_playVoiceFile(8006); + } + characterSays(_flaskFull[0], 0, -2); + } else if (item == 78) { + assert(type >= 0 && type < ARRAYSIZE(flaskTable1)); + newItem = flaskTable1[type]; + } else if (item == 79) { + assert(type >= 0 && type < ARRAYSIZE(flaskTable2)); + newItem = flaskTable2[type]; + } + + if (newItem == -1) + return; + + _screen->hideMouse(); + setMouseItem(newItem); + _screen->showMouse(); + _itemInHand = newItem; + assert(_fullFlask); + assert(type < _fullFlask_Size && type >= 0); + if (_features & GF_TALKIE) { + snd_voiceWaitForFinish(); + static const uint16 voiceEntries[] = { + 0x1F40, 0x1F41, 0x1F42, 0x1F45 + }; + assert(type < ARRAYSIZE(voiceEntries)); + snd_playVoiceFile(voiceEntries[type]); + } + characterSays(_fullFlask[type], 0, -2); +} + +void KyraEngine::seq_playDrinkPotionAnim(int unk1, int unk2, int flags) { + debug(9, "KyraEngine::seq_playDrinkPotionAnim(%d, %d, %d)", unk1, unk2, flags); + // XXX + _screen->hideMouse(); + checkAmuletAnimFlags(); + _currentCharacter->facing = 5; + animRefreshNPC(0); + assert(_drinkAnimationTable); + setupShapes123(_drinkAnimationTable, 9, flags); + setBrandonAnimSeqSize(5, 54); + + for (int i = 123; i <= 131; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(5); + } + snd_playSoundEffect(0x34); + for (int i = 0; i < 2; ++i) { + _currentCharacter->currentAnimFrame = 130; + animRefreshNPC(0); + delayWithTicks(7); + _currentCharacter->currentAnimFrame = 131; + animRefreshNPC(0); + delayWithTicks(7); + } + + if (unk2) { + // XXX + } + + for (int i = 131; i >= 123; --i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(5); + } + + resetBrandonAnimSeqSize(); + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + freeShapes123(); + _screen->showMouse(); +} + +int KyraEngine::seq_playEnd() { + debug(9, "KyraEngine::seq_playEnd()"); + if (_endSequenceSkipFlag) { + return 0; + } + if (_deathHandler == 8) { + return 0; + } + _screen->_curPage = 2; + if (_endSequenceNeedLoading) { + snd_playWanderScoreViaMap(50, 1); + setupPanPages(); + _finalA = new WSAMovieV1(this); + assert(_finalA); + _finalA->open("finala.wsa", 1, 0); + _finalB = new WSAMovieV1(this); + assert(_finalB); + _finalB->open("finalb.wsa", 1, 0); + _finalC = new WSAMovieV1(this); + assert(_finalC); + _endSequenceNeedLoading = 0; + _finalC->open("finalc.wsa", 1, 0); + _screen->_curPage = 0; + _beadStateVar = 0; + _malcolmFlag = 0; + // wired stuff with _unkEndSeqVar2 which needs timer handling + _screen->copyRegion(312, 0, 312, 0, 8, 136, 0, 2); + } + if (handleMalcolmFlag()) { + _beadStateVar = 0; + _malcolmFlag = 12; + handleMalcolmFlag(); + handleBeadState(); + closeFinalWsa(); + if (_deathHandler == 8) { + _screen->_curPage = 0; + checkAmuletAnimFlags(); + seq_brandonToStone(); + waitTicks(60); + return 1; + } else { + _endSequenceSkipFlag = 1; + if (_text->printed()) { + _text->restoreTalkTextMessageBkgd(2, 0); + } + _screen->_curPage = 0; + _screen->hideMouse(); + _screen->fadeSpecialPalette(32, 228, 20, 60); + waitTicks(60); + loadBitmap("GEMHEAL.CPS", 3, 3, _screen->_currentPalette); + _screen->setScreenPalette(_screen->_currentPalette); + _screen->shuffleScreen(8, 8, 304, 128, 2, 0, 1, 0); + uint32 nextTime = _system->getMillis() + 120 * _tickLength; + _finalA = new WSAMovieV1(this); + assert(_finalA); + _finalA->open("finald.wsa", 1, 0); + _finalA->_x = _finalA->_y = 8; + _finalA->_drawPage = 0; + while (_system->getMillis() < nextTime) {} + snd_playSoundEffect(0x40); + for (int i = 0; i < 22; ++i) { + while (_system->getMillis() < nextTime) {} + if (i == 4) { + snd_playSoundEffect(0x3E); + } else if (i == 20) { + snd_playSoundEffect(0x0E); + } + nextTime = _system->getMillis() + 8 * _tickLength; + _finalA->displayFrame(i); + _screen->updateScreen(); + } + delete _finalA; + _finalA = 0; + seq_playEnding(); + return 1; + } + } else { + handleBeadState(); + _screen->bitBlitRects(); + _screen->updateScreen(); + _screen->_curPage = 0; + } + return 0; +} + +void KyraEngine::seq_brandonToStone() { + debug(9, "KyraEngine::seq_brandonToStone()"); + _screen->hideMouse(); + assert(_brandonStoneTable); + setupShapes123(_brandonStoneTable, 14, 0); + setBrandonAnimSeqSize(5, 51); + for (int i = 123; i <= 136; ++i) { + _currentCharacter->currentAnimFrame = i; + animRefreshNPC(0); + delayWithTicks(8); + } + resetBrandonAnimSeqSize(); + freeShapes123(); + _screen->showMouse(); +} + +void KyraEngine::seq_playEnding() { + debug(9, "KyraEngine::seq_playEnding()"); + _screen->hideMouse(); + res_unloadResources(RES_INGAME); + res_loadResources(RES_OUTRO); + loadBitmap("REUNION.CPS", 3, 3, _screen->_currentPalette); + _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); + _screen->_curPage = 0; + // XXX + assert(_homeString); + drawSentenceCommand(_homeString[0], 179); + _screen->_curPage = 0; + _screen->fadeToBlack(); + _seq->playSequence(_seq_Reunion, false); + _screen->fadeToBlack(); + _screen->showMouse(); + seq_playCredits(); +} + +void KyraEngine::seq_playCredits() { + debug(9, "KyraEngine::seq_playCredits()"); + static const uint8 colorMap[] = { 0, 0, 0xC, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + _screen->hideMouse(); + uint32 sz = 0; + if (_features & GF_FLOPPY) { + _screen->loadFont(Screen::FID_CRED6_FNT, _res->fileData("CREDIT6.FNT", &sz)); + _screen->loadFont(Screen::FID_CRED8_FNT, _res->fileData("CREDIT8.FNT", &sz)); + } + loadBitmap("CHALET.CPS", 2, 2, _screen->_currentPalette); + _screen->setScreenPalette(_screen->_currentPalette); + _screen->setCurPage(0); + _screen->clearCurPage(); + _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); + _screen->setTextColorMap(colorMap); + _screen->_charWidth = -1; + snd_playWanderScoreViaMap(53, 1); + // delete + _screen->updateScreen(); + // XXX + waitTicks(120); // wait until user presses escape normally + _screen->fadeToBlack(); + _screen->clearCurPage(); + _screen->showMouse(); +} + +bool KyraEngine::seq_skipSequence() const { + debug(9, "KyraEngine::seq_skipSequence()"); + return _quitFlag || _abortIntroFlag; +} + +} // end of namespace Kyra diff --git a/kyra/sound.cpp b/kyra/sound.cpp index 31c947f12f..535a29a3b8 100644 --- a/kyra/sound.cpp +++ b/kyra/sound.cpp @@ -345,4 +345,89 @@ void SoundPC::voicePlay(const char *file) { bool SoundPC::voiceIsPlaying() { return _mixer->isSoundHandleActive(_vocHandle); } + +void KyraEngine::snd_playTheme(int file, int track) { + debug(9, "KyraEngine::snd_playTheme(%d)", file); + assert(file < _xmidiFilesCount); + _curMusicTheme = _newMusicTheme = file; + _sound->playMusic(_xmidiFiles[file]); + _sound->playTrack(track, false); +} + +void KyraEngine::snd_setSoundEffectFile(int file) { + debug(9, "KyraEngine::snd_setSoundEffectFile(%d)", file); + assert(file < _xmidiFilesCount); + _sound->loadSoundEffectFile(_xmidiFiles[file]); +} + +void KyraEngine::snd_playSoundEffect(int track) { + debug(9, "KyraEngine::snd_playSoundEffect(%d)", track); + if (track == 49) { + snd_playWanderScoreViaMap(56, 1); + } else { + _sound->playSoundEffect(track); + } +} + +void KyraEngine::snd_playWanderScoreViaMap(int command, int restart) { + debug(9, "KyraEngine::snd_playWanderScoreViaMap(%d, %d)", command, restart); + static const int8 soundTable[] = { + -1, 0, -1, 1, 0, 3, 0, 2, + 0, 4, 1, 2, 1, 3, 1, 4, + 1, 0x5C, 1, 6, 1, 7, 2, 2, + 2, 3, 2, 4, 2, 5, 2, 6, + 2, 7, 3, 3, 3, 4, 1, 8, + 1, 9, 4, 2, 4, 3, 4, 4, + 4, 5, 4, 6, 4, 7, 4, 8, + 1, 0x0B, 1, 0x0C, 1, 0x0E, 1, 0x0D, + 4, 9, 5, 0x0C, 6, 2, 6, 6, + 6, 7, 6, 8, 6, 9, 6, 3, + 6, 4, 6, 5, 7, 2, 7, 3, + 7, 4, 7, 5, 7, 6, 7, 7, + 7, 8, 7, 9, 8, 2, 8, 3, + 8, 4, 8, 5, 6, 0x0B, 5, 0x0B + }; + //if (!_disableSound) { + // XXX + //} + assert(command*2+1 < ARRAYSIZE(soundTable)); + if (_curMusicTheme != soundTable[command*2]+1) { + if (soundTable[command*2] != -1) { + snd_playTheme(soundTable[command*2]+1); + } + } + + if (restart) + _lastMusicCommand = -1; + + if (command != 1) { + if (_lastMusicCommand != command) { + _lastMusicCommand = command; + _sound->playTrack(soundTable[command*2+1], true); + } + } else { + _lastMusicCommand = 1; + _sound->beginFadeOut(); + } +} + +void KyraEngine::snd_playVoiceFile(int id) { + debug(9, "KyraEngine::snd_playVoiceFile(%d)", id); + char vocFile[9]; + assert(id >= 0 && id < 9999); + sprintf(vocFile, "%03d.VOC", id); + _sound->voicePlay(vocFile); +} + +void KyraEngine::snd_voiceWaitForFinish(bool ingame) { + debug(9, "KyraEngine::snd_voiceWaitForFinish(%d)", ingame); + while (_sound->voiceIsPlaying() && !_fastMode) { + if (ingame) { + delay(10, true); + } else { + _system->delayMillis(10); + } + } +} + } // end of namespace Kyra diff --git a/kyra/staticres.cpp b/kyra/staticres.cpp index ebf9edb4c3..2720af4c03 100644 --- a/kyra/staticres.cpp +++ b/kyra/staticres.cpp @@ -453,6 +453,146 @@ void KyraEngine::res_freeLangTable(char ***string, int *size) { *string = 0; } +void KyraEngine::loadMouseShapes() { + loadBitmap("MOUSE.CPS", 3, 3, 0); + _screen->_curPage = 2; + _shapes[4] = _screen->encodeShape(0, 0, 8, 10, 0); + _shapes[5] = _screen->encodeShape(0, 0x17, 0x20, 7, 0); + _shapes[6] = _screen->encodeShape(0x50, 0x12, 0x10, 9, 0); + _shapes[7] = _screen->encodeShape(0x60, 0x12, 0x10, 11, 0); + _shapes[8] = _screen->encodeShape(0x70, 0x12, 0x10, 9, 0); + _shapes[9] = _screen->encodeShape(0x80, 0x12, 0x10, 11, 0); + _shapes[10] = _screen->encodeShape(0x90, 0x12, 0x10, 10, 0); + _shapes[364] = _screen->encodeShape(0x28, 0, 0x10, 13, 0); + _screen->setMouseCursor(1, 1, 0); + _screen->setMouseCursor(1, 1, _shapes[4]); + _screen->setShapePages(5, 3); +} + +void KyraEngine::loadCharacterShapes() { + int curImage = 0xFF; + int videoPage = _screen->_curPage; + _screen->_curPage = 2; + for (int i = 0; i < 115; ++i) { + assert(i < _defaultShapeTableSize); + Shape *shape = &_defaultShapeTable[i]; + if (shape->imageIndex == 0xFF) { + _shapes[i+7+4] = 0; + continue; + } + if (shape->imageIndex != curImage) { + assert(shape->imageIndex < _characterImageTableSize); + loadBitmap(_characterImageTable[shape->imageIndex], 3, 3, 0); + curImage = shape->imageIndex; + } + _shapes[i+7+4] = _screen->encodeShape(shape->x<<3, shape->y, shape->w<<3, shape->h, 1); + } + _screen->_curPage = videoPage; +} + +void KyraEngine::loadSpecialEffectShapes() { + loadBitmap("EFFECTS.CPS", 3, 3, 0); + _screen->_curPage = 2; + + int currShape; + for (currShape = 173; currShape < 183; currShape++) + _shapes[4 + currShape] = _screen->encodeShape((currShape-173) * 24, 0, 24, 24, 1); + + for (currShape = 183; currShape < 190; currShape++) + _shapes[4 + currShape] = _screen->encodeShape((currShape-183) * 24, 24, 24, 24, 1); + + for (currShape = 190; currShape < 201; currShape++) + _shapes[4 + currShape] = _screen->encodeShape((currShape-190) * 24, 48, 24, 24, 1); + + for (currShape = 201; currShape < 206; currShape++) + _shapes[4 + currShape] = _screen->encodeShape((currShape-201) * 16, 106, 16, 16, 1); +} + +void KyraEngine::loadItems() { + int shape; + + loadBitmap("JEWELS3.CPS", 3, 3, 0); + _screen->_curPage = 2; + + _shapes[327] = 0; + + for (shape = 1; shape < 6; shape++ ) + _shapes[327 + shape] = _screen->encodeShape((shape - 1) * 32, 0, 32, 17, 0); + + for (shape = 330; shape <= 334; shape++) + _shapes[4 + shape] = _screen->encodeShape((shape-330) * 32, 102, 32, 17, 0); + + for (shape = 335; shape <= 339; shape++) + _shapes[4 + shape] = _screen->encodeShape((shape-335) * 32, 17, 32, 17, 0); + + for (shape = 340; shape <= 344; shape++) + _shapes[4 + shape] = _screen->encodeShape((shape-340) * 32, 34, 32, 17, 0); + + for (shape = 345; shape <= 349; shape++) + _shapes[4 + shape] = _screen->encodeShape((shape-345) * 32, 51, 32, 17, 0); + + for (shape = 350; shape <= 354; shape++) + _shapes[4 + shape] = _screen->encodeShape((shape-350) * 32, 68, 32, 17, 0); + + for (shape = 355; shape <= 359; shape++) + _shapes[4 + shape] = _screen->encodeShape((shape-355) * 32, 85, 32, 17, 0); + + + loadBitmap("ITEMS.CPS", 3, 3, 0); + _screen->_curPage = 2; + + for (int i = 0; i < 107; i++) { + shape = findDuplicateItemShape(i); + + if (shape != -1) + _shapes[220 + i] = _shapes[220 + shape]; + else + _shapes[220 + i] = _screen->encodeShape( (i % 20) * 16, i/20 * 16, 16, 16, 0); + } + + uint32 size; + uint8 *fileData = _res->fileData("_ITEM_HT.DAT", &size); + assert(fileData); + + for (int i = 0; i < 107; i++) { + _itemTable[i].height = fileData[i]; + _itemTable[i].unk1 = _itemTable[i].unk2 = 0; + } + + delete[] fileData; +} + +void KyraEngine::loadButtonShapes() { + loadBitmap("BUTTONS2.CPS", 3, 3, 0); + _screen->_curPage = 2; + _scrollUpButton.process0PtrShape = _screen->encodeShape(0, 0, 24, 14, 1); + _scrollUpButton.process1PtrShape = _screen->encodeShape(24, 0, 24, 14, 1); + _scrollUpButton.process2PtrShape = _screen->encodeShape(48, 0, 24, 14, 1); + _scrollDownButton.process0PtrShape = _screen->encodeShape(0, 15, 24, 14, 1); + _scrollDownButton.process1PtrShape = _screen->encodeShape(24, 15, 24, 14, 1); + _scrollDownButton.process2PtrShape = _screen->encodeShape(48, 15, 24, 14, 1); + _screen->_curPage = 0; +} + +void KyraEngine::loadMainScreen(int page) { + if ((_features & GF_ENGLISH) && (_features & GF_TALKIE)) + loadBitmap("MAIN_ENG.CPS", page, page, 0); + else if(_features & GF_FRENCH) + loadBitmap("MAIN_FRE.CPS", page, page, 0); + else if(_features & GF_GERMAN) + loadBitmap("MAIN_GER.CPS", page, page, 0); + else if ((_features & GF_ENGLISH) && (_features & GF_FLOPPY)) + loadBitmap("MAIN15.CPS", page, page, 0); + else if (_features & GF_SPANISH) + loadBitmap("MAIN_SPA.CPS", page, page, 0); + else + warning("no main graphics file found"); + + uint8 *_pageSrc = _screen->getPagePtr(page); + uint8 *_pageDst = _screen->getPagePtr(0); + memcpy(_pageDst, _pageSrc, 320*200); +} + const ScreenDim Screen::_screenDimTable[] = { { 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 }, { 0x08, 0x48, 0x18, 0x38, 0x0F, 0x0C, 0x00, 0x00 }, diff --git a/kyra/text.cpp b/kyra/text.cpp index db4f737d61..b39a589f12 100644 --- a/kyra/text.cpp +++ b/kyra/text.cpp @@ -21,10 +21,342 @@ #include "common/stdafx.h" +#include "kyra/kyra.h" #include "kyra/screen.h" #include "kyra/text.h" +#include "kyra/animator.h" +#include "kyra/sprites.h" + +#include "common/system.h" namespace Kyra { + +void KyraEngine::waitForChatToFinish(int16 chatDuration, char *chatStr, uint8 charNum) { + debug(9, "KyraEngine::waitForChatToFinish(%i, %s, %i)", chatDuration, chatStr, charNum); + bool hasUpdatedNPCs = false; + bool runLoop = true; + uint8 currPage; + OSystem::Event event; + int16 delayTime; + + //while( towns_isEscKeyPressed() ) + //towns_getKey(); + + uint32 timeToEnd = strlen(chatStr) * 8 * _tickLength + _system->getMillis(); + + if (chatDuration != -1 ) { + switch (_configTalkspeed) { + case 0: chatDuration *= 2; + break; + case 2: chatDuration /= 4; + break; + case 3: chatDuration = -1; + } + } + + if (chatDuration != -1) + chatDuration *= _tickLength; + + disableTimer(14); + disableTimer(18); + disableTimer(19); + + uint32 timeAtStart = _system->getMillis(); + uint32 loopStart; + while (runLoop) { + loopStart = _system->getMillis(); + if (_currentCharacter->sceneId == 210) + if (seq_playEnd()) + break; + + if (_system->getMillis() > timeToEnd && !hasUpdatedNPCs) { + hasUpdatedNPCs = true; + disableTimer(15); + _currHeadShape = 4; + animRefreshNPC(0); + animRefreshNPC(_talkingCharNum); + + if (_charSayUnk2 != -1) { + _animator->sprites()[_charSayUnk2].active = 0; + _sprites->_anims[_charSayUnk2].play = false; + _charSayUnk2 = -1; + } + } + + updateGameTimers(); + _sprites->updateSceneAnims(); + _animator->restoreAllObjectBackgrounds(); + _animator->preserveAnyChangedBackgrounds(); + _animator->prepDrawAllObjects(); + + currPage = _screen->_curPage; + _screen->_curPage = 2; + _text->printCharacterText(chatStr, charNum, _characterList[charNum].x1); + _screen->_curPage = currPage; + + _animator->copyChangedObjectsForward(0); + updateTextFade(); + + if ((chatDuration < (int16)(_system->getMillis() - timeAtStart)) && chatDuration != -1) + break; + + while (_system->pollEvent(event)) { + switch (event.type) { + case OSystem::EVENT_KEYDOWN: + if (event.kbd.keycode == '.') + runLoop = false; + break; + case OSystem::EVENT_QUIT: + quitGame(); + case OSystem::EVENT_LBUTTONDOWN: + runLoop = false; + break; + default: + break; + } + } + + if (_fastMode) + runLoop = false; + + delayTime = (loopStart + _gameSpeed) - _system->getMillis(); + if (delayTime > 0) + _system->delayMillis(delayTime); + } + + enableTimer(14); + enableTimer(15); + enableTimer(18); + enableTimer(19); + //clearKyrandiaButtonIO(); +} + +void KyraEngine::endCharacterChat(int8 charNum, int16 convoInitialized) { + _charSayUnk3 = -1; + + if (charNum > 4 && charNum < 11) { + //TODO: weird _game_inventory stuff here + warning("STUB: endCharacterChat() for high charnums"); + } + + if (convoInitialized != 0) { + _talkingCharNum = -1; + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + _animator->updateAllObjectShapes(); + } +} + +void KyraEngine::restoreChatPartnerAnimFrame(int8 charNum) { + _talkingCharNum = -1; + + if (charNum > 0 && charNum < 5) { + _characterList[charNum].currentAnimFrame = _currentChatPartnerBackupFrame; + animRefreshNPC(charNum); + } + + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + _animator->updateAllObjectShapes(); +} + +void KyraEngine::backupChatPartnerAnimFrame(int8 charNum) { + _talkingCharNum = 0; + + if (charNum < 5 && charNum > 0) + _currentChatPartnerBackupFrame = _characterList[charNum].currentAnimFrame; + + if (_scaleMode != 0) + _currentCharacter->currentAnimFrame = 7; + else + _currentCharacter->currentAnimFrame = _currentCharAnimFrame; + + animRefreshNPC(0); + _animator->updateAllObjectShapes(); +} + +int8 KyraEngine::getChatPartnerNum() { + uint8 sceneTable[] = {0x2, 0x5, 0x2D, 0x7, 0x1B, 0x8, 0x22, 0x9, 0x30, 0x0A}; + int pos = 0; + int partner = -1; + + for (int i = 1; i < 6; i++) { + if (_currentCharacter->sceneId == sceneTable[pos]) { + partner = sceneTable[pos+1]; + break; + } + pos += 2; + } + + for (int i = 1; i < 5; i++) { + if (_characterList[i].sceneId == _currentCharacter->sceneId) { + partner = i; + break; + } + } + return partner; +} + +int KyraEngine::initCharacterChat(int8 charNum) { + if (_talkingCharNum == -1) { + _talkingCharNum = 0; + + if (_scaleMode != 0) + _currentCharacter->currentAnimFrame = 7; + else + _currentCharacter->currentAnimFrame = 16; + + animRefreshNPC(0); + _animator->updateAllObjectShapes(); + } + + _charSayUnk2 = -1; + _animator->flagAllObjectsForBkgdChange(); + _animator->restoreAllObjectBackgrounds(); + + if (charNum > 4 && charNum < 11) { + // TODO: Fill in weird _game_inventory stuff here + warning("STUB: initCharacterChat() for high charnums"); + } + + _animator->flagAllObjectsForRefresh(); + _animator->flagAllObjectsForBkgdChange(); + _animator->preserveAnyChangedBackgrounds(); + _charSayUnk3 = charNum; + + return 1; +} + +void KyraEngine::characterSays(char *chatStr, int8 charNum, int8 chatDuration) { + debug(9, "KyraEngine::characterSays('%s', %i, %d)", chatStr, charNum, chatDuration); + uint8 startAnimFrames[] = { 0x10, 0x32, 0x56, 0x0, 0x0, 0x0 }; + + uint16 chatTicks; + int16 convoInitialized; + int8 chatPartnerNum; + + if (_currentCharacter->sceneId == 210) + return; + + convoInitialized = initCharacterChat(charNum); + chatPartnerNum = getChatPartnerNum(); + + if (chatPartnerNum != -1 && chatPartnerNum < 5) + backupChatPartnerAnimFrame(chatPartnerNum); + + if (charNum < 5) { + _characterList[charNum].currentAnimFrame = startAnimFrames[charNum]; + _charSayUnk3 = charNum; + _talkingCharNum = charNum; + animRefreshNPC(charNum); + } + + char *processedString = _text->preprocessString(chatStr); + int lineNum = _text->buildMessageSubstrings(processedString); + + int16 yPos = _characterList[charNum].y1; + yPos -= _scaleTable[charNum] * _characterList[charNum].height; + yPos -= 8; + yPos -= lineNum * 10; + + if (yPos < 11) + yPos = 11; + + if (yPos > 100) + yPos = 100; + + _text->_talkMessageY = yPos; + _text->_talkMessageH = lineNum * 10; + _animator->restoreAllObjectBackgrounds(); + + _screen->copyRegion(12, _text->_talkMessageY, 12, 136, 308, _text->_talkMessageH, 2, 2); + _screen->hideMouse(); + + _text->printCharacterText(processedString, charNum, _characterList[charNum].x1); + _screen->showMouse(); + + if (chatDuration == -2) + chatTicks = strlen(processedString) * 9; + else + chatTicks = chatDuration; + + waitForChatToFinish(chatTicks, chatStr, charNum); + + _animator->restoreAllObjectBackgrounds(); + + _screen->copyRegion(12, 136, 12, _text->_talkMessageY, 308, _text->_talkMessageH, 2, 2); + _animator->preserveAllBackgrounds(); + _animator->prepDrawAllObjects(); + _screen->hideMouse(); + + _screen->copyRegion(12, _text->_talkMessageY, 12, _text->_talkMessageY, 308, _text->_talkMessageH, 2, 0); + _screen->showMouse(); + _animator->flagAllObjectsForRefresh(); + _animator->copyChangedObjectsForward(0); + + if (chatPartnerNum != -1 && chatPartnerNum < 5) + restoreChatPartnerAnimFrame(chatPartnerNum); + + endCharacterChat(charNum, convoInitialized); +} + +void KyraEngine::drawSentenceCommand(char *sentence, int color) { + debug(9, "KyraEngine::drawSentenceCommand('%s', %i)", sentence, color); + _screen->hideMouse(); + _screen->fillRect(8, 143, 311, 152, 12); + + if (_startSentencePalIndex != color || _fadeText != false) { + _currSentenceColor[0] = _screen->_currentPalette[765] = _screen->_currentPalette[color*3]; + _currSentenceColor[1] = _screen->_currentPalette[766] = _screen->_currentPalette[color*3+1]; + _currSentenceColor[2] = _screen->_currentPalette[767] = _screen->_currentPalette[color*3+2]; + + _screen->setScreenPalette(_screen->_currentPalette); + _startSentencePalIndex = 0; + } + + _text->printText(sentence, 8, 143, 0xFF, 12, 0); + _screen->showMouse(); + setTextFadeTimerCountdown(15); + _fadeText = false; +} + +void KyraEngine::updateSentenceCommand(char *str1, char *str2, int color) { + debug(9, "KyraEngine::updateSentenceCommand('%s', '%s', %i)", str1, str2, color); + char sentenceCommand[500]; + strncpy(sentenceCommand, str1, 500); + if (str2) + strncat(sentenceCommand, str2, 500 - strlen(sentenceCommand)); + + drawSentenceCommand(sentenceCommand, color); + _screen->updateScreen(); +} + +void KyraEngine::updateTextFade() { + debug(9, "KyraEngine::updateTextFade()"); + if (!_fadeText) + return; + + bool finished = false; + for (int i = 0; i < 3; i++) + if (_currSentenceColor[i] > 4) + _currSentenceColor[i] -= 4; + else + if (_currSentenceColor[i]) { + _currSentenceColor[i] = 0; + finished = true; + } + + _screen->_currentPalette[765] = _currSentenceColor[0]; + _screen->_currentPalette[766] = _currSentenceColor[1]; + _screen->_currentPalette[767] = _currSentenceColor[2]; + _screen->setScreenPalette(_screen->_currentPalette); + + if (finished) { + _fadeText = false; + _startSentencePalIndex = -1; + } +} + TextDisplayer::TextDisplayer(Screen *screen) { _screen = screen; |