From bf5bb9280b1dc4a02b4c0ec9506a0723ed80b55e Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 29 Jul 2007 16:28:25 +0000 Subject: - Restructure Kyrandia sourcecode (part 1, breaks compiling) svn-id: r28294 --- engines/kyra/animator.cpp | 692 ------------------ engines/kyra/animator.h | 132 ---- engines/kyra/animator_v1.cpp | 692 ++++++++++++++++++ engines/kyra/animator_v1.h | 132 ++++ engines/kyra/gui.cpp | 1640 ------------------------------------------ engines/kyra/gui_v1.cpp | 1640 ++++++++++++++++++++++++++++++++++++++++++ engines/kyra/items.cpp | 944 ------------------------ engines/kyra/items_v1.cpp | 944 ++++++++++++++++++++++++ engines/kyra/saveload.cpp | 366 ---------- engines/kyra/saveload_v1.cpp | 366 ++++++++++ engines/kyra/scene.cpp | 1624 ----------------------------------------- engines/kyra/scene_v1.cpp | 1624 +++++++++++++++++++++++++++++++++++++++++ engines/kyra/timer.cpp | 292 -------- engines/kyra/timer_v1.cpp | 292 ++++++++ 14 files changed, 5690 insertions(+), 5690 deletions(-) delete mode 100644 engines/kyra/animator.cpp delete mode 100644 engines/kyra/animator.h create mode 100644 engines/kyra/animator_v1.cpp create mode 100644 engines/kyra/animator_v1.h delete mode 100644 engines/kyra/gui.cpp create mode 100644 engines/kyra/gui_v1.cpp delete mode 100644 engines/kyra/items.cpp create mode 100644 engines/kyra/items_v1.cpp delete mode 100644 engines/kyra/saveload.cpp create mode 100644 engines/kyra/saveload_v1.cpp delete mode 100644 engines/kyra/scene.cpp create mode 100644 engines/kyra/scene_v1.cpp delete mode 100644 engines/kyra/timer.cpp create mode 100644 engines/kyra/timer_v1.cpp (limited to 'engines/kyra') diff --git a/engines/kyra/animator.cpp b/engines/kyra/animator.cpp deleted file mode 100644 index 7683bb6417..0000000000 --- a/engines/kyra/animator.cpp +++ /dev/null @@ -1,692 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "common/endian.h" - -#include "kyra/kyra.h" -#include "kyra/screen.h" -#include "kyra/animator.h" -#include "kyra/sprites.h" - -#include "common/system.h" - -namespace Kyra { -ScreenAnimator::ScreenAnimator(KyraEngine *vm, OSystem *system) { - _vm = vm; - _screen = vm->screen(); - _initOk = false; - _updateScreen = false; - _system = system; - _screenObjects = _actors = _items = _sprites = _objectQueue = 0; - _noDrawShapesFlag = 0; - - _actorBkgBackUp[0] = new uint8[_screen->getRectSize(8, 69)]; - memset(_actorBkgBackUp[0], 0, _screen->getRectSize(8, 69)); - _actorBkgBackUp[1] = new uint8[_screen->getRectSize(8, 69)]; - memset(_actorBkgBackUp[1], 0, _screen->getRectSize(8, 69)); -} - -ScreenAnimator::~ScreenAnimator() { - close(); - delete [] _actorBkgBackUp[0]; - delete [] _actorBkgBackUp[1]; -} - -void ScreenAnimator::init(int actors_, int items_, int sprites_) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::init(%d, %d, %d)", actors_, items_, sprites_); - _screenObjects = new AnimObject[actors_ + items_ + sprites_]; - assert(_screenObjects); - memset(_screenObjects, 0, sizeof(AnimObject) * (actors_ + items_ + sprites_)); - _actors = _screenObjects; - _sprites = &_screenObjects[actors_]; - _items = &_screenObjects[actors_ + items_]; - _brandonDrawFrame = 113; - - _initOk = true; -} - -void ScreenAnimator::close() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::close()"); - if (_initOk) { - _initOk = false; - delete [] _screenObjects; - _screenObjects = _actors = _items = _sprites = _objectQueue = 0; - } -} - -void ScreenAnimator::initAnimStateList() { - AnimObject *animStates = _screenObjects; - animStates[0].index = 0; - animStates[0].active = 1; - animStates[0].flags = 0x800; - animStates[0].background = _actorBkgBackUp[0]; - 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 = _actorBkgBackUp[1]; - 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[345+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() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::preserveAllBackgrounds()"); - uint8 curPage = _screen->_curPage; - _screen->_curPage = 2; - - AnimObject *curObject = _objectQueue; - while (curObject) { - if (curObject->active && !curObject->disable) { - preserveOrRestoreBackground(curObject, false); - curObject->bkgdChangeFlag = 0; - } - curObject = curObject->nextAnimObject; - } - _screen->_curPage = curPage; -} - -void ScreenAnimator::flagAllObjectsForBkgdChange() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::flagAllObjectsForBkgdChange()"); - AnimObject *curObject = _objectQueue; - while (curObject) { - curObject->bkgdChangeFlag = 1; - curObject = curObject->nextAnimObject; - } -} - -void ScreenAnimator::flagAllObjectsForRefresh() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::flagAllObjectsForRefresh()"); - AnimObject *curObject = _objectQueue; - while (curObject) { - curObject->refreshFlag = 1; - curObject = curObject->nextAnimObject; - } -} - -void ScreenAnimator::restoreAllObjectBackgrounds() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::restoreAllObjectBackground()"); - AnimObject *curObject = _objectQueue; - _screen->_curPage = 2; - - while (curObject) { - if (curObject->active && !curObject->disable) { - preserveOrRestoreBackground(curObject, true); - curObject->x2 = curObject->x1; - curObject->y2 = curObject->y1; - } - curObject = curObject->nextAnimObject; - } - - _screen->_curPage = 0; -} - -void ScreenAnimator::preserveAnyChangedBackgrounds() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::preserveAnyChangedBackgrounds()"); - AnimObject *curObject = _objectQueue; - _screen->_curPage = 2; - - while (curObject) { - if (curObject->active && !curObject->disable && curObject->bkgdChangeFlag) { - preserveOrRestoreBackground(curObject, false); - curObject->bkgdChangeFlag = 0; - } - curObject = curObject->nextAnimObject; - } - - _screen->_curPage = 0; -} - -void ScreenAnimator::preserveOrRestoreBackground(AnimObject *obj, bool restore) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::preserveOrRestoreBackground(%p, %d)", (const void *)obj, restore); - int x = 0, y = 0, width = obj->width, height = obj->height; - - if (restore) { - x = obj->x2 >> 3; - y = obj->y2; - } else { - x = obj->x1 >> 3; - y = obj->y1; - } - - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - int temp; - - temp = x + width; - if (temp >= 39) - x = 39 - width; - temp = y + height; - if (temp >= 136) - y = 136 - height; - - if (restore) - _screen->copyBlockToPage(_screen->_curPage, x << 3, y, width << 3, height, obj->background); - else - _screen->copyRegionToBuffer(_screen->_curPage, x << 3, y, width << 3, height, obj->background); -} - -void ScreenAnimator::prepDrawAllObjects() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::prepDrawAllObjects()"); - AnimObject *curObject = _objectQueue; - int drawPage = 2; - int flagUnk1 = 0, flagUnk2 = 0, flagUnk3 = 0; - if (_noDrawShapesFlag) - return; - if (_vm->_brandonStatusBit & 0x20) - flagUnk1 = 0x200; - if (_vm->_brandonStatusBit & 0x40) - flagUnk2 = 0x4000; - - while (curObject) { - if (curObject->active) { - int xpos = curObject->x1; - int ypos = curObject->y1; - - int drawLayer = 0; - if (!(curObject->flags & 0x800)) - drawLayer = 7; - else if (curObject->disable) - drawLayer = 0; - else - drawLayer = _vm->_sprites->getDrawLayer(curObject->drawY); - - // talking head functionallity - if (_vm->_talkingCharNum != -1 && (_vm->_currentCharacter->currentAnimFrame != 88 || curObject->index != 0)) { - const int16 baseAnimFrameTable1[] = { 0x11, 0x35, 0x59, 0x00, 0x00, 0x00 }; - const int16 baseAnimFrameTable2[] = { 0x15, 0x39, 0x5D, 0x00, 0x00, 0x00 }; - const int8 xOffsetTable1[] = { 2, 4, 0, 5, 2, 0, 0, 0 }; - const int8 xOffsetTable2[] = { 6, 4, 8, 3, 6, 0, 0, 0 }; - const int8 yOffsetTable1[] = { 0, 8, 1, 1, 0, 0, 0, 0 }; - const int8 yOffsetTable2[] = { 0, 8, 1, 1, 0, 0, 0, 0 }; - if (curObject->index == 0 || curObject->index <= 4) { - int shapesIndex = 0; - if (curObject->index == _vm->_charSayUnk3) { - shapesIndex = _vm->_currHeadShape + baseAnimFrameTable1[curObject->index]; - } else { - shapesIndex = baseAnimFrameTable2[curObject->index]; - int temp2 = 0; - if (curObject->index == 2) { - if (_vm->_characterList[2].sceneId == 77 || _vm->_characterList[2].sceneId == 86) - temp2 = 1; - else - temp2 = 0; - } else { - temp2 = 1; - } - - if (!temp2) - shapesIndex = -1; - } - - xpos = curObject->x1; - ypos = curObject->y1; - - int tempX = 0, tempY = 0; - if (curObject->flags & 0x1) { - tempX = (xOffsetTable1[curObject->index] * _brandonScaleX) >> 8; - tempY = yOffsetTable1[curObject->index]; - } else { - tempX = (xOffsetTable2[curObject->index] * _brandonScaleX) >> 8; - tempY = yOffsetTable2[curObject->index]; - } - tempY = (tempY * _brandonScaleY) >> 8; - xpos += tempX; - ypos += tempY; - - if (_vm->_scaleMode && _brandonScaleX != 256) - ++xpos; - - if (curObject->index == 0 && shapesIndex != -1) { - if (!(_vm->_brandonStatusBit & 2)) { - flagUnk3 = 0x100; - if ((flagUnk1 & 0x200) || (flagUnk2 & 0x4000)) - flagUnk3 = 0; - - int tempFlags = 0; - if (flagUnk3 & 0x100) { - tempFlags = curObject->flags & 1; - tempFlags |= 0x800 | flagUnk1 | 0x100; - } - - if (!(flagUnk3 & 0x100) && (flagUnk2 & 0x4000)) { - tempFlags = curObject->flags & 1; - tempFlags |= 0x900 | flagUnk1 | 0x4000; - _screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | 4, _vm->_brandonPoisonFlagsGFX, int(1), int(_vm->_brandonInvFlag), drawLayer, _brandonScaleX, _brandonScaleY); - } else { - if (!(flagUnk2 & 0x4000)) { - tempFlags = curObject->flags & 1; - tempFlags |= 0x900 | flagUnk1; - } - - _screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | 4, _vm->_brandonPoisonFlagsGFX, int(1), drawLayer, _brandonScaleX, _brandonScaleY); - } - } - } else { - if (shapesIndex != -1) { - int tempFlags = 0; - if (curObject->flags & 1) - tempFlags = 1; - _screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | 0x800, drawLayer); - } - } - } - } - - xpos = curObject->x1; - ypos = curObject->y1; - - curObject->flags |= 0x800; - if (curObject->index == 0) { - flagUnk3 = 0x100; - - if (flagUnk1 & 0x200 || flagUnk2 & 0x4000) - flagUnk3 = 0; - - if (_vm->_brandonStatusBit & 2) - curObject->flags &= 0xFFFFFFFE; - - if (!_vm->_scaleMode) { - if (flagUnk3 & 0x100) - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x100, (uint8*)_vm->_brandonPoisonFlagsGFX, int(1), drawLayer); - else if (flagUnk2 & 0x4000) - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x4000, int(_vm->_brandonInvFlag), drawLayer); - else - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1, drawLayer); - } else { - if (flagUnk3 & 0x100) - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x104, (uint8*)_vm->_brandonPoisonFlagsGFX, int(1), drawLayer, _brandonScaleX, _brandonScaleY); - else if (flagUnk2 & 0x4000) - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x4004, int(_vm->_brandonInvFlag), drawLayer, _brandonScaleX, _brandonScaleY); - else - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x4, drawLayer, _brandonScaleX, _brandonScaleY); - } - } else { - if (curObject->index >= 16 && curObject->index <= 27) - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | 4, drawLayer, (int)_vm->_scaleTable[curObject->drawY], (int)_vm->_scaleTable[curObject->drawY]); - else - _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags, drawLayer); - } - } - curObject = curObject->nextAnimObject; - } -} - -void ScreenAnimator::copyChangedObjectsForward(int refreshFlag) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::copyChangedObjectsForward(%d)", refreshFlag); - - for (AnimObject *curObject = _objectQueue; curObject; curObject = curObject->nextAnimObject) { - if (curObject->active) { - if (curObject->refreshFlag || refreshFlag) { - int xpos = 0, ypos = 0, width = 0, height = 0; - xpos = (curObject->x1>>3) - (curObject->width2>>3) - 1; - ypos = curObject->y1 - curObject->height2; - width = curObject->width + (curObject->width2>>3) + 2; - height = curObject->height + curObject->height2*2; - - if (xpos < 1) - xpos = 1; - else if (xpos > 39) - continue; - - if (xpos + width > 39) - width = 39 - xpos; - - if (ypos < 8) - ypos = 8; - else if (ypos > 136) - continue; - - if (ypos + height > 136) - height = 136 - ypos; - - _screen->copyRegion(xpos << 3, ypos, xpos << 3, ypos, width << 3, height, 2, 0, Screen::CR_CLIPPED); - curObject->refreshFlag = 0; - _updateScreen = true; - } - } - } - - if (_updateScreen) { - _screen->updateScreen(); - _updateScreen = false; - } -} - -void ScreenAnimator::updateAllObjectShapes() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::updateAllObjectShapes()"); - restoreAllObjectBackgrounds(); - preserveAnyChangedBackgrounds(); - prepDrawAllObjects(); - copyChangedObjectsForward(0); -} - -void ScreenAnimator::animRemoveGameItem(int index) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::animRemoveGameItem(%d)", index); - restoreAllObjectBackgrounds(); - - AnimObject *animObj = &_items[index]; - animObj->sceneAnimPtr = 0; - animObj->animFrameNumber = -1; - animObj->refreshFlag = 1; - animObj->bkgdChangeFlag = 1; - updateAllObjectShapes(); - animObj->active = 0; - - objectRemoveQueue(_objectQueue, animObj); -} - -void ScreenAnimator::animAddGameItem(int index, uint16 sceneId) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::animRemoveGameItem(%d, %d)", index, sceneId); - restoreAllObjectBackgrounds(); - assert(sceneId < _vm->_roomTableSize); - Room *currentRoom = &_vm->_roomTable[sceneId]; - AnimObject *animObj = &_items[index]; - animObj->active = 1; - animObj->refreshFlag = 1; - animObj->bkgdChangeFlag = 1; - animObj->drawY = currentRoom->itemsYPos[index]; - animObj->sceneAnimPtr = _vm->_shapes[216+currentRoom->itemsTable[index]]; - animObj->animFrameNumber = -1; - animObj->x1 = currentRoom->itemsXPos[index]; - animObj->y1 = currentRoom->itemsYPos[index]; - animObj->x1 -= fetchAnimWidth(animObj->sceneAnimPtr, _vm->_scaleTable[animObj->drawY]) >> 1; - animObj->y1 -= fetchAnimHeight(animObj->sceneAnimPtr, _vm->_scaleTable[animObj->drawY]); - animObj->x2 = animObj->x1; - animObj->y2 = animObj->y1; - animObj->width2 = 0; - animObj->height2 = 0; - _objectQueue = objectQueue(_objectQueue, animObj); - preserveAnyChangedBackgrounds(); - animObj->refreshFlag = 1; - animObj->bkgdChangeFlag = 1; -} - -void ScreenAnimator::animAddNPC(int character) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::animAddNPC(%d)", character); - restoreAllObjectBackgrounds(); - AnimObject *animObj = &_actors[character]; - const Character *ch = &_vm->_characterList[character]; - - animObj->active = 1; - animObj->refreshFlag = 1; - animObj->bkgdChangeFlag = 1; - animObj->drawY = ch->y1; - animObj->sceneAnimPtr = _vm->_shapes[ch->currentAnimFrame]; - animObj->x1 = animObj->x2 = ch->x1 + _vm->_defaultShapeTable[ch->currentAnimFrame-7].xOffset; - animObj->y1 = animObj->y2 = ch->y1 + _vm->_defaultShapeTable[ch->currentAnimFrame-7].yOffset; - - if (ch->facing >= 1 && ch->facing <= 3) - animObj->flags |= 1; - else if (ch->facing >= 5 && ch->facing <= 7) - animObj->flags &= 0xFFFFFFFE; - - _objectQueue = objectQueue(_objectQueue, animObj); - preserveAnyChangedBackgrounds(); - animObj->refreshFlag = 1; - animObj->bkgdChangeFlag = 1; -} - -AnimObject *ScreenAnimator::objectRemoveQueue(AnimObject *queue, AnimObject *rem) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::objectRemoveQueue(%p, %p)", (const void *)queue, (const void *)rem); - AnimObject *cur = queue; - AnimObject *prev = queue; - - while (cur != rem && cur) { - AnimObject *temp = cur->nextAnimObject; - if (!temp) - break; - prev = cur; - cur = temp; - } - - if (cur == queue) { - if (!cur) - return 0; - return cur->nextAnimObject; - } - - if (!cur->nextAnimObject) { - if (cur == rem) { - if (!prev) - return 0; - else - prev->nextAnimObject = 0; - } - } else { - if (cur == rem) - prev->nextAnimObject = rem->nextAnimObject; - } - - return queue; -} - -AnimObject *ScreenAnimator::objectAddHead(AnimObject *queue, AnimObject *head) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::objectAddHead(%p, %p)", (const void *)queue, (const void *)head); - head->nextAnimObject = queue; - return head; -} - -AnimObject *ScreenAnimator::objectQueue(AnimObject *queue, AnimObject *add) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::objectQueue(%p, %p)", (const void *)queue, (const void *)add); - if (add->drawY <= queue->drawY || !queue) { - add->nextAnimObject = queue; - return add; - } - AnimObject *cur = queue; - AnimObject *prev = queue; - while (add->drawY > cur->drawY) { - AnimObject *temp = cur->nextAnimObject; - if (!temp) - break; - prev = cur; - cur = temp; - } - - if (add->drawY <= cur->drawY) { - prev->nextAnimObject = add; - add->nextAnimObject = cur; - } else { - cur->nextAnimObject = add; - add->nextAnimObject = 0; - } - return queue; -} - -void ScreenAnimator::addObjectToQueue(AnimObject *object) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::addObjectToQueue(%p)", (const void *)object); - if (!_objectQueue) - _objectQueue = objectAddHead(0, object); - else - _objectQueue = objectQueue(_objectQueue, object); -} - -void ScreenAnimator::refreshObject(AnimObject *object) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::refreshObject(%p)", (const void *)object); - _objectQueue = objectRemoveQueue(_objectQueue, object); - if (_objectQueue) - _objectQueue = objectQueue(_objectQueue, object); - else - _objectQueue = objectAddHead(0, object); -} - -void ScreenAnimator::makeBrandonFaceMouse() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::makeBrandonFaceMouse()"); - Common::Point mouse = _vm->getMousePos(); - if (mouse.x >= _vm->_currentCharacter->x1) - _vm->_currentCharacter->facing = 3; - else - _vm->_currentCharacter->facing = 5; - animRefreshNPC(0); - updateAllObjectShapes(); -} - -int16 ScreenAnimator::fetchAnimWidth(const uint8 *shape, int16 mult) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::fetchAnimWidth(%p, %d)", (const void *)shape, mult); - if (_vm->gameFlags().useAltShapeHeader) - shape += 2; - return (((int16)READ_LE_UINT16((shape+3))) * mult) >> 8; -} - -int16 ScreenAnimator::fetchAnimHeight(const uint8 *shape, int16 mult) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::fetchAnimHeight(%p, %d)", (const void *)shape, mult); - if (_vm->gameFlags().useAltShapeHeader) - shape += 2; - return (int16)(((int8)*(shape+2)) * mult) >> 8; -} - -void ScreenAnimator::setBrandonAnimSeqSize(int width, int height) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::setBrandonAnimSeqSize(%d, %d)", width, height); - restoreAllObjectBackgrounds(); - _brandonAnimSeqSizeWidth = _actors[0].width; - _brandonAnimSeqSizeHeight = _actors[0].height; - _actors[0].width = width + 1; - _actors[0].height = height; - preserveAllBackgrounds(); -} - -void ScreenAnimator::resetBrandonAnimSeqSize() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::resetBrandonAnimSeqSize()"); - restoreAllObjectBackgrounds(); - _actors[0].width = _brandonAnimSeqSizeWidth; - _actors[0].height = _brandonAnimSeqSizeHeight; - preserveAllBackgrounds(); -} - -void ScreenAnimator::animRefreshNPC(int character) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::animRefreshNPC(%d)", character); - AnimObject *animObj = &_actors[character]; - Character *ch = &_vm->characterList()[character]; - - animObj->refreshFlag = 1; - animObj->bkgdChangeFlag = 1; - int facing = ch->facing; - if (facing >= 1 && facing <= 3) - animObj->flags |= 1; - else if (facing >= 5 && facing <= 7) - animObj->flags &= 0xFFFFFFFE; - - animObj->drawY = ch->y1; - animObj->sceneAnimPtr = _vm->shapes()[ch->currentAnimFrame]; - animObj->animFrameNumber = ch->currentAnimFrame; - if (character == 0) { - if (_vm->brandonStatus() & 10) { - animObj->animFrameNumber = 88; - ch->currentAnimFrame = 88; - } - if (_vm->brandonStatus() & 2) { - animObj->animFrameNumber = _brandonDrawFrame; - ch->currentAnimFrame = _brandonDrawFrame; - animObj->sceneAnimPtr = _vm->shapes()[_brandonDrawFrame]; - if (_vm->_brandonStatusBit0x02Flag) { - ++_brandonDrawFrame; - // TODO: check this - if (_brandonDrawFrame >= 122) { - _brandonDrawFrame = 113; - _vm->_brandonStatusBit0x02Flag = 0; - } - } - } - } - - int xOffset = _vm->_defaultShapeTable[ch->currentAnimFrame-7].xOffset; - int yOffset = _vm->_defaultShapeTable[ch->currentAnimFrame-7].yOffset; - - if (_vm->_scaleMode) { - animObj->x1 = ch->x1; - animObj->y1 = ch->y1; - - int newScale = _vm->_scaleTable[ch->y1]; - _brandonScaleX = newScale; - _brandonScaleY = newScale; - - animObj->x1 += (_brandonScaleX * xOffset) >> 8; - animObj->y1 += (_brandonScaleY * yOffset) >> 8; - } else { - animObj->x1 = ch->x1 + xOffset; - animObj->y1 = ch->y1 + yOffset; - } - animObj->width2 = 4; - animObj->height2 = 3; - - refreshObject(animObj); -} - -void ScreenAnimator::setCharacterDefaultFrame(int character) { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::setCharacterDefaultFrame()"); - static uint16 initFrameTable[] = { - 7, 41, 77, 0, 0 - }; - assert(character < ARRAYSIZE(initFrameTable)); - Character *edit = &_vm->characterList()[character]; - edit->sceneId = 0xFFFF; - edit->facing = 0; - edit->currentAnimFrame = initFrameTable[character]; - // edit->unk6 = 1; -} - -void ScreenAnimator::setCharactersHeight() { - debugC(9, kDebugLevelAnimator, "ScreenAnimator::setCharactersHeight()"); - static int8 initHeightTable[] = { - 48, 40, 48, 47, 56, - 44, 42, 47, 38, 35, - 40 - }; - for (int i = 0; i < 11; ++i) - _vm->characterList()[i].height = initHeightTable[i]; -} - -} // end of namespace Kyra - diff --git a/engines/kyra/animator.h b/engines/kyra/animator.h deleted file mode 100644 index e817be86d5..0000000000 --- a/engines/kyra/animator.h +++ /dev/null @@ -1,132 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef KYRA_ANIMATOR_H -#define KYRA_ANIMATOR_H - -namespace Kyra { -class KyraEngine; -class Screen; - -struct AnimObject { - uint8 index; - uint32 active; - uint32 refreshFlag; - uint32 bkgdChangeFlag; - bool disable; - uint32 flags; - int16 drawY; - uint8 *sceneAnimPtr; - int16 animFrameNumber; - uint8 *background; - uint16 rectSize; - int16 x1, y1; - int16 x2, y2; - uint16 width; - uint16 height; - uint16 width2; - uint16 height2; - AnimObject *nextAnimObject; -}; - -class ScreenAnimator { -public: - ScreenAnimator(KyraEngine *vm, OSystem *system); - virtual ~ScreenAnimator(); - - operator bool() const { return _initOk; } - - void init(int actors, int items, int sprites); - void close(); - - AnimObject *objects() { return _screenObjects; } - AnimObject *actors() { return _actors; } - AnimObject *items() { return _items; } - AnimObject *sprites() { return _sprites; } - - void initAnimStateList(); - void preserveAllBackgrounds(); - void flagAllObjectsForBkgdChange(); - void flagAllObjectsForRefresh(); - void restoreAllObjectBackgrounds(); - void preserveAnyChangedBackgrounds(); - virtual void prepDrawAllObjects(); - void copyChangedObjectsForward(int refreshFlag); - - void updateAllObjectShapes(); - void animRemoveGameItem(int index); - void animAddGameItem(int index, uint16 sceneId); - void animAddNPC(int character); - void animRefreshNPC(int character); - - void clearQueue() { _objectQueue = 0; } - void addObjectToQueue(AnimObject *object); - void refreshObject(AnimObject *object); - - void makeBrandonFaceMouse(); - void setBrandonAnimSeqSize(int width, int height); - void resetBrandonAnimSeqSize(); - void setCharacterDefaultFrame(int character); - void setCharactersHeight(); - - int16 fetchAnimWidth(const uint8 *shape, int16 mult); - int16 fetchAnimHeight(const uint8 *shape, int16 mult); - - int _noDrawShapesFlag; - bool _updateScreen; - uint16 _brandonDrawFrame; - int _brandonScaleX; - int _brandonScaleY; - -protected: - KyraEngine *_vm; - Screen *_screen; - OSystem *_system; - bool _initOk; - - AnimObject *_screenObjects; - - AnimObject *_actors; - AnimObject *_items; - AnimObject *_sprites; - - uint8 *_actorBkgBackUp[2]; - - AnimObject *objectRemoveQueue(AnimObject *queue, AnimObject *rem); - AnimObject *objectAddHead(AnimObject *queue, AnimObject *head); - AnimObject *objectQueue(AnimObject *queue, AnimObject *add); - - void preserveOrRestoreBackground(AnimObject *obj, bool restore); - - AnimObject *_objectQueue; - - int _brandonAnimSeqSizeWidth; - int _brandonAnimSeqSizeHeight; - -}; -} // end of namespace Kyra - -#endif - diff --git a/engines/kyra/animator_v1.cpp b/engines/kyra/animator_v1.cpp new file mode 100644 index 0000000000..7683bb6417 --- /dev/null +++ b/engines/kyra/animator_v1.cpp @@ -0,0 +1,692 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/endian.h" + +#include "kyra/kyra.h" +#include "kyra/screen.h" +#include "kyra/animator.h" +#include "kyra/sprites.h" + +#include "common/system.h" + +namespace Kyra { +ScreenAnimator::ScreenAnimator(KyraEngine *vm, OSystem *system) { + _vm = vm; + _screen = vm->screen(); + _initOk = false; + _updateScreen = false; + _system = system; + _screenObjects = _actors = _items = _sprites = _objectQueue = 0; + _noDrawShapesFlag = 0; + + _actorBkgBackUp[0] = new uint8[_screen->getRectSize(8, 69)]; + memset(_actorBkgBackUp[0], 0, _screen->getRectSize(8, 69)); + _actorBkgBackUp[1] = new uint8[_screen->getRectSize(8, 69)]; + memset(_actorBkgBackUp[1], 0, _screen->getRectSize(8, 69)); +} + +ScreenAnimator::~ScreenAnimator() { + close(); + delete [] _actorBkgBackUp[0]; + delete [] _actorBkgBackUp[1]; +} + +void ScreenAnimator::init(int actors_, int items_, int sprites_) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::init(%d, %d, %d)", actors_, items_, sprites_); + _screenObjects = new AnimObject[actors_ + items_ + sprites_]; + assert(_screenObjects); + memset(_screenObjects, 0, sizeof(AnimObject) * (actors_ + items_ + sprites_)); + _actors = _screenObjects; + _sprites = &_screenObjects[actors_]; + _items = &_screenObjects[actors_ + items_]; + _brandonDrawFrame = 113; + + _initOk = true; +} + +void ScreenAnimator::close() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::close()"); + if (_initOk) { + _initOk = false; + delete [] _screenObjects; + _screenObjects = _actors = _items = _sprites = _objectQueue = 0; + } +} + +void ScreenAnimator::initAnimStateList() { + AnimObject *animStates = _screenObjects; + animStates[0].index = 0; + animStates[0].active = 1; + animStates[0].flags = 0x800; + animStates[0].background = _actorBkgBackUp[0]; + 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 = _actorBkgBackUp[1]; + 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[345+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() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::preserveAllBackgrounds()"); + uint8 curPage = _screen->_curPage; + _screen->_curPage = 2; + + AnimObject *curObject = _objectQueue; + while (curObject) { + if (curObject->active && !curObject->disable) { + preserveOrRestoreBackground(curObject, false); + curObject->bkgdChangeFlag = 0; + } + curObject = curObject->nextAnimObject; + } + _screen->_curPage = curPage; +} + +void ScreenAnimator::flagAllObjectsForBkgdChange() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::flagAllObjectsForBkgdChange()"); + AnimObject *curObject = _objectQueue; + while (curObject) { + curObject->bkgdChangeFlag = 1; + curObject = curObject->nextAnimObject; + } +} + +void ScreenAnimator::flagAllObjectsForRefresh() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::flagAllObjectsForRefresh()"); + AnimObject *curObject = _objectQueue; + while (curObject) { + curObject->refreshFlag = 1; + curObject = curObject->nextAnimObject; + } +} + +void ScreenAnimator::restoreAllObjectBackgrounds() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::restoreAllObjectBackground()"); + AnimObject *curObject = _objectQueue; + _screen->_curPage = 2; + + while (curObject) { + if (curObject->active && !curObject->disable) { + preserveOrRestoreBackground(curObject, true); + curObject->x2 = curObject->x1; + curObject->y2 = curObject->y1; + } + curObject = curObject->nextAnimObject; + } + + _screen->_curPage = 0; +} + +void ScreenAnimator::preserveAnyChangedBackgrounds() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::preserveAnyChangedBackgrounds()"); + AnimObject *curObject = _objectQueue; + _screen->_curPage = 2; + + while (curObject) { + if (curObject->active && !curObject->disable && curObject->bkgdChangeFlag) { + preserveOrRestoreBackground(curObject, false); + curObject->bkgdChangeFlag = 0; + } + curObject = curObject->nextAnimObject; + } + + _screen->_curPage = 0; +} + +void ScreenAnimator::preserveOrRestoreBackground(AnimObject *obj, bool restore) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::preserveOrRestoreBackground(%p, %d)", (const void *)obj, restore); + int x = 0, y = 0, width = obj->width, height = obj->height; + + if (restore) { + x = obj->x2 >> 3; + y = obj->y2; + } else { + x = obj->x1 >> 3; + y = obj->y1; + } + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + int temp; + + temp = x + width; + if (temp >= 39) + x = 39 - width; + temp = y + height; + if (temp >= 136) + y = 136 - height; + + if (restore) + _screen->copyBlockToPage(_screen->_curPage, x << 3, y, width << 3, height, obj->background); + else + _screen->copyRegionToBuffer(_screen->_curPage, x << 3, y, width << 3, height, obj->background); +} + +void ScreenAnimator::prepDrawAllObjects() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::prepDrawAllObjects()"); + AnimObject *curObject = _objectQueue; + int drawPage = 2; + int flagUnk1 = 0, flagUnk2 = 0, flagUnk3 = 0; + if (_noDrawShapesFlag) + return; + if (_vm->_brandonStatusBit & 0x20) + flagUnk1 = 0x200; + if (_vm->_brandonStatusBit & 0x40) + flagUnk2 = 0x4000; + + while (curObject) { + if (curObject->active) { + int xpos = curObject->x1; + int ypos = curObject->y1; + + int drawLayer = 0; + if (!(curObject->flags & 0x800)) + drawLayer = 7; + else if (curObject->disable) + drawLayer = 0; + else + drawLayer = _vm->_sprites->getDrawLayer(curObject->drawY); + + // talking head functionallity + if (_vm->_talkingCharNum != -1 && (_vm->_currentCharacter->currentAnimFrame != 88 || curObject->index != 0)) { + const int16 baseAnimFrameTable1[] = { 0x11, 0x35, 0x59, 0x00, 0x00, 0x00 }; + const int16 baseAnimFrameTable2[] = { 0x15, 0x39, 0x5D, 0x00, 0x00, 0x00 }; + const int8 xOffsetTable1[] = { 2, 4, 0, 5, 2, 0, 0, 0 }; + const int8 xOffsetTable2[] = { 6, 4, 8, 3, 6, 0, 0, 0 }; + const int8 yOffsetTable1[] = { 0, 8, 1, 1, 0, 0, 0, 0 }; + const int8 yOffsetTable2[] = { 0, 8, 1, 1, 0, 0, 0, 0 }; + if (curObject->index == 0 || curObject->index <= 4) { + int shapesIndex = 0; + if (curObject->index == _vm->_charSayUnk3) { + shapesIndex = _vm->_currHeadShape + baseAnimFrameTable1[curObject->index]; + } else { + shapesIndex = baseAnimFrameTable2[curObject->index]; + int temp2 = 0; + if (curObject->index == 2) { + if (_vm->_characterList[2].sceneId == 77 || _vm->_characterList[2].sceneId == 86) + temp2 = 1; + else + temp2 = 0; + } else { + temp2 = 1; + } + + if (!temp2) + shapesIndex = -1; + } + + xpos = curObject->x1; + ypos = curObject->y1; + + int tempX = 0, tempY = 0; + if (curObject->flags & 0x1) { + tempX = (xOffsetTable1[curObject->index] * _brandonScaleX) >> 8; + tempY = yOffsetTable1[curObject->index]; + } else { + tempX = (xOffsetTable2[curObject->index] * _brandonScaleX) >> 8; + tempY = yOffsetTable2[curObject->index]; + } + tempY = (tempY * _brandonScaleY) >> 8; + xpos += tempX; + ypos += tempY; + + if (_vm->_scaleMode && _brandonScaleX != 256) + ++xpos; + + if (curObject->index == 0 && shapesIndex != -1) { + if (!(_vm->_brandonStatusBit & 2)) { + flagUnk3 = 0x100; + if ((flagUnk1 & 0x200) || (flagUnk2 & 0x4000)) + flagUnk3 = 0; + + int tempFlags = 0; + if (flagUnk3 & 0x100) { + tempFlags = curObject->flags & 1; + tempFlags |= 0x800 | flagUnk1 | 0x100; + } + + if (!(flagUnk3 & 0x100) && (flagUnk2 & 0x4000)) { + tempFlags = curObject->flags & 1; + tempFlags |= 0x900 | flagUnk1 | 0x4000; + _screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | 4, _vm->_brandonPoisonFlagsGFX, int(1), int(_vm->_brandonInvFlag), drawLayer, _brandonScaleX, _brandonScaleY); + } else { + if (!(flagUnk2 & 0x4000)) { + tempFlags = curObject->flags & 1; + tempFlags |= 0x900 | flagUnk1; + } + + _screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | 4, _vm->_brandonPoisonFlagsGFX, int(1), drawLayer, _brandonScaleX, _brandonScaleY); + } + } + } else { + if (shapesIndex != -1) { + int tempFlags = 0; + if (curObject->flags & 1) + tempFlags = 1; + _screen->drawShape(drawPage, _vm->_shapes[shapesIndex], xpos, ypos, 2, tempFlags | 0x800, drawLayer); + } + } + } + } + + xpos = curObject->x1; + ypos = curObject->y1; + + curObject->flags |= 0x800; + if (curObject->index == 0) { + flagUnk3 = 0x100; + + if (flagUnk1 & 0x200 || flagUnk2 & 0x4000) + flagUnk3 = 0; + + if (_vm->_brandonStatusBit & 2) + curObject->flags &= 0xFFFFFFFE; + + if (!_vm->_scaleMode) { + if (flagUnk3 & 0x100) + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x100, (uint8*)_vm->_brandonPoisonFlagsGFX, int(1), drawLayer); + else if (flagUnk2 & 0x4000) + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x4000, int(_vm->_brandonInvFlag), drawLayer); + else + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1, drawLayer); + } else { + if (flagUnk3 & 0x100) + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x104, (uint8*)_vm->_brandonPoisonFlagsGFX, int(1), drawLayer, _brandonScaleX, _brandonScaleY); + else if (flagUnk2 & 0x4000) + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x4004, int(_vm->_brandonInvFlag), drawLayer, _brandonScaleX, _brandonScaleY); + else + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | flagUnk1 | 0x4, drawLayer, _brandonScaleX, _brandonScaleY); + } + } else { + if (curObject->index >= 16 && curObject->index <= 27) + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags | 4, drawLayer, (int)_vm->_scaleTable[curObject->drawY], (int)_vm->_scaleTable[curObject->drawY]); + else + _screen->drawShape(drawPage, curObject->sceneAnimPtr, xpos, ypos, 2, curObject->flags, drawLayer); + } + } + curObject = curObject->nextAnimObject; + } +} + +void ScreenAnimator::copyChangedObjectsForward(int refreshFlag) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::copyChangedObjectsForward(%d)", refreshFlag); + + for (AnimObject *curObject = _objectQueue; curObject; curObject = curObject->nextAnimObject) { + if (curObject->active) { + if (curObject->refreshFlag || refreshFlag) { + int xpos = 0, ypos = 0, width = 0, height = 0; + xpos = (curObject->x1>>3) - (curObject->width2>>3) - 1; + ypos = curObject->y1 - curObject->height2; + width = curObject->width + (curObject->width2>>3) + 2; + height = curObject->height + curObject->height2*2; + + if (xpos < 1) + xpos = 1; + else if (xpos > 39) + continue; + + if (xpos + width > 39) + width = 39 - xpos; + + if (ypos < 8) + ypos = 8; + else if (ypos > 136) + continue; + + if (ypos + height > 136) + height = 136 - ypos; + + _screen->copyRegion(xpos << 3, ypos, xpos << 3, ypos, width << 3, height, 2, 0, Screen::CR_CLIPPED); + curObject->refreshFlag = 0; + _updateScreen = true; + } + } + } + + if (_updateScreen) { + _screen->updateScreen(); + _updateScreen = false; + } +} + +void ScreenAnimator::updateAllObjectShapes() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::updateAllObjectShapes()"); + restoreAllObjectBackgrounds(); + preserveAnyChangedBackgrounds(); + prepDrawAllObjects(); + copyChangedObjectsForward(0); +} + +void ScreenAnimator::animRemoveGameItem(int index) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::animRemoveGameItem(%d)", index); + restoreAllObjectBackgrounds(); + + AnimObject *animObj = &_items[index]; + animObj->sceneAnimPtr = 0; + animObj->animFrameNumber = -1; + animObj->refreshFlag = 1; + animObj->bkgdChangeFlag = 1; + updateAllObjectShapes(); + animObj->active = 0; + + objectRemoveQueue(_objectQueue, animObj); +} + +void ScreenAnimator::animAddGameItem(int index, uint16 sceneId) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::animRemoveGameItem(%d, %d)", index, sceneId); + restoreAllObjectBackgrounds(); + assert(sceneId < _vm->_roomTableSize); + Room *currentRoom = &_vm->_roomTable[sceneId]; + AnimObject *animObj = &_items[index]; + animObj->active = 1; + animObj->refreshFlag = 1; + animObj->bkgdChangeFlag = 1; + animObj->drawY = currentRoom->itemsYPos[index]; + animObj->sceneAnimPtr = _vm->_shapes[216+currentRoom->itemsTable[index]]; + animObj->animFrameNumber = -1; + animObj->x1 = currentRoom->itemsXPos[index]; + animObj->y1 = currentRoom->itemsYPos[index]; + animObj->x1 -= fetchAnimWidth(animObj->sceneAnimPtr, _vm->_scaleTable[animObj->drawY]) >> 1; + animObj->y1 -= fetchAnimHeight(animObj->sceneAnimPtr, _vm->_scaleTable[animObj->drawY]); + animObj->x2 = animObj->x1; + animObj->y2 = animObj->y1; + animObj->width2 = 0; + animObj->height2 = 0; + _objectQueue = objectQueue(_objectQueue, animObj); + preserveAnyChangedBackgrounds(); + animObj->refreshFlag = 1; + animObj->bkgdChangeFlag = 1; +} + +void ScreenAnimator::animAddNPC(int character) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::animAddNPC(%d)", character); + restoreAllObjectBackgrounds(); + AnimObject *animObj = &_actors[character]; + const Character *ch = &_vm->_characterList[character]; + + animObj->active = 1; + animObj->refreshFlag = 1; + animObj->bkgdChangeFlag = 1; + animObj->drawY = ch->y1; + animObj->sceneAnimPtr = _vm->_shapes[ch->currentAnimFrame]; + animObj->x1 = animObj->x2 = ch->x1 + _vm->_defaultShapeTable[ch->currentAnimFrame-7].xOffset; + animObj->y1 = animObj->y2 = ch->y1 + _vm->_defaultShapeTable[ch->currentAnimFrame-7].yOffset; + + if (ch->facing >= 1 && ch->facing <= 3) + animObj->flags |= 1; + else if (ch->facing >= 5 && ch->facing <= 7) + animObj->flags &= 0xFFFFFFFE; + + _objectQueue = objectQueue(_objectQueue, animObj); + preserveAnyChangedBackgrounds(); + animObj->refreshFlag = 1; + animObj->bkgdChangeFlag = 1; +} + +AnimObject *ScreenAnimator::objectRemoveQueue(AnimObject *queue, AnimObject *rem) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::objectRemoveQueue(%p, %p)", (const void *)queue, (const void *)rem); + AnimObject *cur = queue; + AnimObject *prev = queue; + + while (cur != rem && cur) { + AnimObject *temp = cur->nextAnimObject; + if (!temp) + break; + prev = cur; + cur = temp; + } + + if (cur == queue) { + if (!cur) + return 0; + return cur->nextAnimObject; + } + + if (!cur->nextAnimObject) { + if (cur == rem) { + if (!prev) + return 0; + else + prev->nextAnimObject = 0; + } + } else { + if (cur == rem) + prev->nextAnimObject = rem->nextAnimObject; + } + + return queue; +} + +AnimObject *ScreenAnimator::objectAddHead(AnimObject *queue, AnimObject *head) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::objectAddHead(%p, %p)", (const void *)queue, (const void *)head); + head->nextAnimObject = queue; + return head; +} + +AnimObject *ScreenAnimator::objectQueue(AnimObject *queue, AnimObject *add) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::objectQueue(%p, %p)", (const void *)queue, (const void *)add); + if (add->drawY <= queue->drawY || !queue) { + add->nextAnimObject = queue; + return add; + } + AnimObject *cur = queue; + AnimObject *prev = queue; + while (add->drawY > cur->drawY) { + AnimObject *temp = cur->nextAnimObject; + if (!temp) + break; + prev = cur; + cur = temp; + } + + if (add->drawY <= cur->drawY) { + prev->nextAnimObject = add; + add->nextAnimObject = cur; + } else { + cur->nextAnimObject = add; + add->nextAnimObject = 0; + } + return queue; +} + +void ScreenAnimator::addObjectToQueue(AnimObject *object) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::addObjectToQueue(%p)", (const void *)object); + if (!_objectQueue) + _objectQueue = objectAddHead(0, object); + else + _objectQueue = objectQueue(_objectQueue, object); +} + +void ScreenAnimator::refreshObject(AnimObject *object) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::refreshObject(%p)", (const void *)object); + _objectQueue = objectRemoveQueue(_objectQueue, object); + if (_objectQueue) + _objectQueue = objectQueue(_objectQueue, object); + else + _objectQueue = objectAddHead(0, object); +} + +void ScreenAnimator::makeBrandonFaceMouse() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::makeBrandonFaceMouse()"); + Common::Point mouse = _vm->getMousePos(); + if (mouse.x >= _vm->_currentCharacter->x1) + _vm->_currentCharacter->facing = 3; + else + _vm->_currentCharacter->facing = 5; + animRefreshNPC(0); + updateAllObjectShapes(); +} + +int16 ScreenAnimator::fetchAnimWidth(const uint8 *shape, int16 mult) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::fetchAnimWidth(%p, %d)", (const void *)shape, mult); + if (_vm->gameFlags().useAltShapeHeader) + shape += 2; + return (((int16)READ_LE_UINT16((shape+3))) * mult) >> 8; +} + +int16 ScreenAnimator::fetchAnimHeight(const uint8 *shape, int16 mult) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::fetchAnimHeight(%p, %d)", (const void *)shape, mult); + if (_vm->gameFlags().useAltShapeHeader) + shape += 2; + return (int16)(((int8)*(shape+2)) * mult) >> 8; +} + +void ScreenAnimator::setBrandonAnimSeqSize(int width, int height) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::setBrandonAnimSeqSize(%d, %d)", width, height); + restoreAllObjectBackgrounds(); + _brandonAnimSeqSizeWidth = _actors[0].width; + _brandonAnimSeqSizeHeight = _actors[0].height; + _actors[0].width = width + 1; + _actors[0].height = height; + preserveAllBackgrounds(); +} + +void ScreenAnimator::resetBrandonAnimSeqSize() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::resetBrandonAnimSeqSize()"); + restoreAllObjectBackgrounds(); + _actors[0].width = _brandonAnimSeqSizeWidth; + _actors[0].height = _brandonAnimSeqSizeHeight; + preserveAllBackgrounds(); +} + +void ScreenAnimator::animRefreshNPC(int character) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::animRefreshNPC(%d)", character); + AnimObject *animObj = &_actors[character]; + Character *ch = &_vm->characterList()[character]; + + animObj->refreshFlag = 1; + animObj->bkgdChangeFlag = 1; + int facing = ch->facing; + if (facing >= 1 && facing <= 3) + animObj->flags |= 1; + else if (facing >= 5 && facing <= 7) + animObj->flags &= 0xFFFFFFFE; + + animObj->drawY = ch->y1; + animObj->sceneAnimPtr = _vm->shapes()[ch->currentAnimFrame]; + animObj->animFrameNumber = ch->currentAnimFrame; + if (character == 0) { + if (_vm->brandonStatus() & 10) { + animObj->animFrameNumber = 88; + ch->currentAnimFrame = 88; + } + if (_vm->brandonStatus() & 2) { + animObj->animFrameNumber = _brandonDrawFrame; + ch->currentAnimFrame = _brandonDrawFrame; + animObj->sceneAnimPtr = _vm->shapes()[_brandonDrawFrame]; + if (_vm->_brandonStatusBit0x02Flag) { + ++_brandonDrawFrame; + // TODO: check this + if (_brandonDrawFrame >= 122) { + _brandonDrawFrame = 113; + _vm->_brandonStatusBit0x02Flag = 0; + } + } + } + } + + int xOffset = _vm->_defaultShapeTable[ch->currentAnimFrame-7].xOffset; + int yOffset = _vm->_defaultShapeTable[ch->currentAnimFrame-7].yOffset; + + if (_vm->_scaleMode) { + animObj->x1 = ch->x1; + animObj->y1 = ch->y1; + + int newScale = _vm->_scaleTable[ch->y1]; + _brandonScaleX = newScale; + _brandonScaleY = newScale; + + animObj->x1 += (_brandonScaleX * xOffset) >> 8; + animObj->y1 += (_brandonScaleY * yOffset) >> 8; + } else { + animObj->x1 = ch->x1 + xOffset; + animObj->y1 = ch->y1 + yOffset; + } + animObj->width2 = 4; + animObj->height2 = 3; + + refreshObject(animObj); +} + +void ScreenAnimator::setCharacterDefaultFrame(int character) { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::setCharacterDefaultFrame()"); + static uint16 initFrameTable[] = { + 7, 41, 77, 0, 0 + }; + assert(character < ARRAYSIZE(initFrameTable)); + Character *edit = &_vm->characterList()[character]; + edit->sceneId = 0xFFFF; + edit->facing = 0; + edit->currentAnimFrame = initFrameTable[character]; + // edit->unk6 = 1; +} + +void ScreenAnimator::setCharactersHeight() { + debugC(9, kDebugLevelAnimator, "ScreenAnimator::setCharactersHeight()"); + static int8 initHeightTable[] = { + 48, 40, 48, 47, 56, + 44, 42, 47, 38, 35, + 40 + }; + for (int i = 0; i < 11; ++i) + _vm->characterList()[i].height = initHeightTable[i]; +} + +} // end of namespace Kyra + diff --git a/engines/kyra/animator_v1.h b/engines/kyra/animator_v1.h new file mode 100644 index 0000000000..e817be86d5 --- /dev/null +++ b/engines/kyra/animator_v1.h @@ -0,0 +1,132 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef KYRA_ANIMATOR_H +#define KYRA_ANIMATOR_H + +namespace Kyra { +class KyraEngine; +class Screen; + +struct AnimObject { + uint8 index; + uint32 active; + uint32 refreshFlag; + uint32 bkgdChangeFlag; + bool disable; + uint32 flags; + int16 drawY; + uint8 *sceneAnimPtr; + int16 animFrameNumber; + uint8 *background; + uint16 rectSize; + int16 x1, y1; + int16 x2, y2; + uint16 width; + uint16 height; + uint16 width2; + uint16 height2; + AnimObject *nextAnimObject; +}; + +class ScreenAnimator { +public: + ScreenAnimator(KyraEngine *vm, OSystem *system); + virtual ~ScreenAnimator(); + + operator bool() const { return _initOk; } + + void init(int actors, int items, int sprites); + void close(); + + AnimObject *objects() { return _screenObjects; } + AnimObject *actors() { return _actors; } + AnimObject *items() { return _items; } + AnimObject *sprites() { return _sprites; } + + void initAnimStateList(); + void preserveAllBackgrounds(); + void flagAllObjectsForBkgdChange(); + void flagAllObjectsForRefresh(); + void restoreAllObjectBackgrounds(); + void preserveAnyChangedBackgrounds(); + virtual void prepDrawAllObjects(); + void copyChangedObjectsForward(int refreshFlag); + + void updateAllObjectShapes(); + void animRemoveGameItem(int index); + void animAddGameItem(int index, uint16 sceneId); + void animAddNPC(int character); + void animRefreshNPC(int character); + + void clearQueue() { _objectQueue = 0; } + void addObjectToQueue(AnimObject *object); + void refreshObject(AnimObject *object); + + void makeBrandonFaceMouse(); + void setBrandonAnimSeqSize(int width, int height); + void resetBrandonAnimSeqSize(); + void setCharacterDefaultFrame(int character); + void setCharactersHeight(); + + int16 fetchAnimWidth(const uint8 *shape, int16 mult); + int16 fetchAnimHeight(const uint8 *shape, int16 mult); + + int _noDrawShapesFlag; + bool _updateScreen; + uint16 _brandonDrawFrame; + int _brandonScaleX; + int _brandonScaleY; + +protected: + KyraEngine *_vm; + Screen *_screen; + OSystem *_system; + bool _initOk; + + AnimObject *_screenObjects; + + AnimObject *_actors; + AnimObject *_items; + AnimObject *_sprites; + + uint8 *_actorBkgBackUp[2]; + + AnimObject *objectRemoveQueue(AnimObject *queue, AnimObject *rem); + AnimObject *objectAddHead(AnimObject *queue, AnimObject *head); + AnimObject *objectQueue(AnimObject *queue, AnimObject *add); + + void preserveOrRestoreBackground(AnimObject *obj, bool restore); + + AnimObject *_objectQueue; + + int _brandonAnimSeqSizeWidth; + int _brandonAnimSeqSizeHeight; + +}; +} // end of namespace Kyra + +#endif + diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp deleted file mode 100644 index fe051dd75c..0000000000 --- a/engines/kyra/gui.cpp +++ /dev/null @@ -1,1640 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "kyra/kyra.h" -#include "kyra/screen.h" -#include "kyra/script.h" -#include "kyra/text.h" -#include "kyra/animator.h" -#include "kyra/sound.h" - -#include "common/config-manager.h" -#include "common/savefile.h" -#include "common/events.h" -#include "common/system.h" - -namespace Kyra { - -void KyraEngine::registerDefaultSettings() { - // Most settings already have sensible defaults. This one, however, is - // specific to the Kyra engine. - ConfMan.registerDefault("walkspeed", 2); - ConfMan.registerDefault("cdaudio", _flags.platform == Common::kPlatformFMTowns); -} - -void KyraEngine::readSettings() { - int talkspeed = ConfMan.getInt("talkspeed"); - - // The default talk speed is 60. This should be mapped to "Normal". - - if (talkspeed == 0) - _configTextspeed = 3; // Clickable - if (talkspeed <= 50) - _configTextspeed = 0; // Slow - else if (talkspeed <= 150) - _configTextspeed = 1; // Normal - else - _configTextspeed = 2; // Fast - - _configWalkspeed = ConfMan.getInt("walkspeed"); - _configMusic = ConfMan.getBool("music_mute") ? 0 : ((ConfMan.getBool("cdaudio") && _flags.platform == Common::kPlatformFMTowns) ? 2 : 1); - _configSounds = ConfMan.getBool("sfx_mute") ? 0 : 1; - - _sound->enableMusic(_configMusic); - _sound->enableSFX(_configSounds); - - bool speechMute = ConfMan.getBool("speech_mute"); - bool subtitles = ConfMan.getBool("subtitles"); - - if (!speechMute && subtitles) - _configVoice = 2; // Voice & Text - else if (!speechMute && !subtitles) - _configVoice = 1; // Voice only - else - _configVoice = 0; // Text only - - setWalkspeed(_configWalkspeed); -} - -void KyraEngine::writeSettings() { - bool speechMute, subtitles; - int talkspeed; - - switch (_configTextspeed) { - case 0: // Slow - talkspeed = 1; - break; - case 1: // Normal - talkspeed = 60; - break; - case 2: // Fast - talkspeed = 255; - break; - default: // Clickable - talkspeed = 0; - break; - } - - ConfMan.setInt("talkspeed", talkspeed); - ConfMan.setInt("walkspeed", _configWalkspeed); - ConfMan.setBool("music_mute", _configMusic == 0); - ConfMan.setBool("cdaudio", _configMusic == 2); - ConfMan.setBool("sfx_mute", _configSounds == 0); - - switch (_configVoice) { - case 0: // Text only - speechMute = true; - subtitles = true; - break; - case 1: // Voice only - speechMute = false; - subtitles = false; - break; - default: // Voice & Text - speechMute = false; - subtitles = true; - break; - } - - if (!_configMusic) - _sound->beginFadeOut(); - - _sound->enableMusic(_configMusic); - _sound->enableSFX(_configSounds); - - ConfMan.setBool("speech_mute", speechMute); - ConfMan.setBool("subtitles", subtitles); - - ConfMan.flushToDisk(); -} - -void KyraEngine::initMainButtonList() { - _haveScrollButtons = false; - _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; - if (!list) - return newButton; - Button *cur = list; - - while (true) { - if (!cur->nextButton) - break; - cur = cur->nextButton; - } - - cur->nextButton = newButton; - return list; -} - -int KyraEngine::buttonInventoryCallback(Button *caller) { - int itemOffset = caller->specialValue - 2; - uint8 inventoryItem = _currentCharacter->inventoryItems[itemOffset]; - if (_itemInHand == -1) { - if (inventoryItem == 0xFF) { - snd_playSoundEffect(0x36); - return 0; - } else { - _screen->hideMouse(); - _screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, 12); - snd_playSoundEffect(0x35); - setMouseItem(inventoryItem); - updateSentenceCommand(_itemList[inventoryItem], _takenList[0], 179); - _itemInHand = inventoryItem; - _screen->showMouse(); - _currentCharacter->inventoryItems[itemOffset] = 0xFF; - } - } else { - if (inventoryItem != 0xFF) { - snd_playSoundEffect(0x35); - _screen->hideMouse(); - _screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, 12); - _screen->drawShape(0, _shapes[216+_itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0); - setMouseItem(inventoryItem); - updateSentenceCommand(_itemList[inventoryItem], _takenList[1], 179); - _screen->showMouse(); - _currentCharacter->inventoryItems[itemOffset] = _itemInHand; - _itemInHand = inventoryItem; - } else { - snd_playSoundEffect(0x32); - _screen->hideMouse(); - _screen->drawShape(0, _shapes[216+_itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0); - _screen->setMouseCursor(1, 1, _shapes[0]); - updateSentenceCommand(_itemList[_itemInHand], _placedList[0], 179); - _screen->showMouse(); - _currentCharacter->inventoryItems[itemOffset] = _itemInHand; - _itemInHand = -1; - } - } - _screen->updateScreen(); - // XXX clearKyrandiaButtonIO - return 0; -} - -int KyraEngine::buttonAmuletCallback(Button *caller) { - if (!(_deathHandler & 8)) - return 1; - int jewel = caller->specialValue - 0x14; - if (_currentCharacter->sceneId == 210) { - if (_beadStateVar == 4 || _beadStateVar == 6) - return 1; - } - if (!queryGameFlag(0x2D)) - return 1; - if (_itemInHand != -1) { - assert(_putDownFirst); - characterSays(2000, _putDownFirst[0], 0, -2); - return 1; - } - if (queryGameFlag(0xF1)) { - assert(_waitForAmulet); - characterSays(2001, _waitForAmulet[0], 0, -2); - return 1; - } - if (!queryGameFlag(0x55+jewel)) { - assert(_blackJewel); - _animator->makeBrandonFaceMouse(); - drawJewelPress(jewel, 1); - characterSays(2002, _blackJewel[0], 0, -2); - return 1; - } - drawJewelPress(jewel, 0); - drawJewelsFadeOutStart(); - drawJewelsFadeOutEnd(jewel); - - _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - _scriptClick->regs[3] = 0; - _scriptClick->regs[6] = jewel; - _scriptInterpreter->startScript(_scriptClick, 4); - - while (_scriptInterpreter->validScript(_scriptClick)) - _scriptInterpreter->runScript(_scriptClick); - - if (_scriptClick->regs[3]) - return 1; - - _unkAmuletVar = 1; - switch (jewel-1) { - case 0: - if (_brandonStatusBit & 1) { - seq_brandonHealing2(); - } else if (_brandonStatusBit == 0) { - seq_brandonHealing(); - assert(_healingTip); - characterSays(2003, _healingTip[0], 0, -2); - } - break; - - case 1: - seq_makeBrandonInv(); - break; - - case 2: - if (_brandonStatusBit & 1) { - assert(_wispJewelStrings); - characterSays(2004, _wispJewelStrings[0], 0, -2); - } else { - if (_brandonStatusBit & 2) { - // XXX - seq_makeBrandonNormal2(); - // XXX - } else { - // do not check for item in hand again as in the original since some strings are missing - // in the cd version - if (_currentCharacter->sceneId >= 109 && _currentCharacter->sceneId <= 198) { - snd_playWanderScoreViaMap(1, 0); - seq_makeBrandonWisp(); - snd_playWanderScoreViaMap(17, 0); - } else { - seq_makeBrandonWisp(); - } - setGameFlag(0x9E); - } - } - break; - - case 3: - seq_dispelMagicAnimation(); - assert(_magicJewelString); - characterSays(2007, _magicJewelString[0], 0, -2); - break; - - default: - break; - } - _unkAmuletVar = 0; - // XXX clearKyrandiaButtonIO (!used before every return in this function!) - return 1; -} - -void KyraEngine::processButtonList(Button *list) { - if (_haveScrollButtons) { - if (_mouseWheel < 0) - gui_scrollUp(&_scrollUpButton); - else if (_mouseWheel > 0) - gui_scrollDown(&_scrollDownButton); - } - while (list) { - if (list->flags & 8) { - list = list->nextButton; - continue; - } - - int x = list->x; - int y = list->y; - assert(list->dimTableIndex < _screen->_screenDimTableCount); - if (x < 0) { - x += _screen->_screenDimTable[list->dimTableIndex].w << 3; - } - x += _screen->_screenDimTable[list->dimTableIndex].sx << 3; - - if (y < 0) { - y += _screen->_screenDimTable[list->dimTableIndex].h; - } - y += _screen->_screenDimTable[list->dimTableIndex].sy; - - Common::Point mouse = getMousePos(); - if (mouse.x >= x && mouse.y >= y && x + list->width >= mouse.x && y + list->height >= mouse.y) { - int processMouseClick = 0; - if (list->flags & 0x400) { - if (_mousePressFlag) { - if (!(list->flags2 & 1)) { - list->flags2 |= 1; - list->flags2 |= 4; - processButton(list); - _screen->updateScreen(); - } - } else { - if (list->flags2 & 1) { - list->flags2 &= 0xFFFE; - processButton(list); - processMouseClick = 1; - } - } - } else if (_mousePressFlag) { - processMouseClick = 1; - } - - if (processMouseClick) { - if (list->buttonCallback) { - if ((this->*(list->buttonCallback))(list)) { - break; - } - } - } - } else { - if (list->flags2 & 1) { - list->flags2 &= 0xFFFE; - processButton(list); - } - if (list->flags2 & 4) { - list->flags2 &= 0xFFFB; - processButton(list); - _screen->updateScreen(); - } - list = list->nextButton; - continue; - } - - list = list->nextButton; - } -} - -void KyraEngine::processButton(Button *button) { - if (!button) - return; - - int processType = 0; - uint8 *shape = 0; - Button::ButtonCallback callback = 0; - - int flags = (button->flags2 & 5); - if (flags == 1) { - processType = button->process2; - if (processType == 1) - shape = button->process2PtrShape; - else if (processType == 4) - callback = button->process2PtrCallback; - } else if (flags == 4 || flags == 5) { - processType = button->process1; - if (processType == 1) - shape = button->process1PtrShape; - else if (processType == 4) - callback = button->process1PtrCallback; - } else { - processType = button->process0; - if (processType == 1) - shape = button->process0PtrShape; - else if (processType == 4) - callback = button->process0PtrCallback; - } - - int x = button->x; - int y = button->y; - assert(button->dimTableIndex < _screen->_screenDimTableCount); - if (x < 0) - x += _screen->_screenDimTable[button->dimTableIndex].w << 3; - - if (y < 0) - y += _screen->_screenDimTable[button->dimTableIndex].h; - - if (processType == 1 && shape) - _screen->drawShape(_screen->_curPage, shape, x, y, button->dimTableIndex, 0x10); - else if (processType == 4 && callback) - (this->*callback)(button); -} - -void KyraEngine::processAllMenuButtons() { - if (!_menuButtonList) - return; - - Button *cur = _menuButtonList; - while (true) { - if (!cur->nextButton) - break; - processMenuButton(cur); - cur = cur->nextButton; - } - return; -} - -void KyraEngine::processMenuButton(Button *button) { - if (!_displayMenu) - return; - - if (!button || (button->flags & 8)) - return; - - if (button->flags2 & 1) - button->flags2 &= 0xf7; - else - button->flags2 |= 8; - - button->flags2 &= 0xfc; - - if (button->flags2 & 4) - button->flags2 |= 0x10; - else - button->flags2 &= 0xef; - - button->flags2 &= 0xfb; - - processButton(button); -} - -int KyraEngine::drawBoxCallback(Button *button) { - if (!_displayMenu) - return 0; - - _screen->hideMouse(); - _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xf8); - _screen->showMouse(); - - return 0; -} - -int KyraEngine::drawShadedBoxCallback(Button *button) { - if (!_displayMenu) - return 0; - - _screen->hideMouse(); - _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xf9, 0xfa); - _screen->showMouse(); - - return 0; -} - -void KyraEngine::setGUILabels() { - int offset = 0; - int offsetOptions = 0; - int offsetMainMenu = 0; - int offsetOn = 0; - - int walkspeedGarbageOffset = 36; - int menuLabelGarbageOffset = 0; - - if (_flags.isTalkie) { - if (_flags.lang == Common::EN_ANY) - offset = 52; - else if (_flags.lang == Common::DE_DEU) - offset = 30; - else if (_flags.lang == Common::FR_FRA || _flags.lang == Common::IT_ITA) - offset = 6; - offsetOn = offsetMainMenu = offsetOptions = offset; - walkspeedGarbageOffset = 48; - } else if (_flags.lang == Common::ES_ESP) { - offsetOn = offsetMainMenu = offsetOptions = offset = -4; - menuLabelGarbageOffset = 72; - } else if (_flags.lang == Common::DE_DEU) { - offset = offsetMainMenu = offsetOn = offsetOptions = 24; - } else if (_flags.platform == Common::kPlatformFMTowns) { - offset = 1; - offsetOptions = 10; - offsetOn = 0; - walkspeedGarbageOffset = 0; - } - - assert(offset + 27 < _guiStringsSize); - - // The Legend of Kyrandia - _menu[0].menuName = _guiStrings[0]; - // Load a Game - _menu[0].item[0].itemString = _guiStrings[1]; - // Save a Game - _menu[0].item[1].itemString = _guiStrings[2]; - // Game controls - _menu[0].item[2].itemString = _guiStrings[3]; - // Quit playing - _menu[0].item[3].itemString = _guiStrings[4]; - // Resume game - _menu[0].item[4].itemString = _guiStrings[5]; - - // Cancel - _menu[2].item[5].itemString = _guiStrings[10]; - - // Enter a description of your saved game: - _menu[3].menuName = _guiStrings[11]; - // Save - _menu[3].item[0].itemString = _guiStrings[12]; - // Cancel - _menu[3].item[1].itemString = _guiStrings[10]; - - // Rest in peace, Brandon - _menu[4].menuName = _guiStrings[13]; - // Load a game - _menu[4].item[0].itemString = _guiStrings[1]; - // Quit playing - _menu[4].item[1].itemString = _guiStrings[4]; - - // Game Controls - _menu[5].menuName = _guiStrings[6]; - // Yes - _menu[1].item[0].itemString = _guiStrings[22 + offset]; - // No - _menu[1].item[1].itemString = _guiStrings[23 + offset]; - - // Music is - _menu[5].item[0].labelString = _guiStrings[26 + offsetOptions]; - // Sounds are - _menu[5].item[1].labelString = _guiStrings[27 + offsetOptions]; - // Walk speed - _menu[5].item[2].labelString = &_guiStrings[24 + offsetOptions][walkspeedGarbageOffset]; - // Text speed - _menu[5].item[4].labelString = _guiStrings[25 + offsetOptions]; - // Main Menu - _menu[5].item[5].itemString = &_guiStrings[19 + offsetMainMenu][menuLabelGarbageOffset]; - - if (_flags.isTalkie) - // Text & Voice - _voiceTextString = _guiStrings[28 + offset]; - - _textSpeedString = _guiStrings[25 + offsetOptions]; - _onString = _guiStrings[20 + offsetOn]; - _offString = _guiStrings[21 + offset]; - _onCDString = _guiStrings[21]; -} - -int KyraEngine::buttonMenuCallback(Button *caller) { - _displayMenu = true; - - assert(_guiStrings); - assert(_configStrings); - - /* - for (int i = 0; i < _guiStringsSize; i++) - debug("GUI string %i: %s", i, _guiStrings[i]); - - for (int i = 0; i < _configStringsSize; i++) - debug("Config string %i: %s", i, _configStrings[i]); - */ - - setGUILabels(); - if (_currentCharacter->sceneId == 210 && _deathHandler == 0xFF) { - snd_playSoundEffect(0x36); - return 0; - } - // XXX - _screen->setPaletteIndex(0xFE, 60, 60, 0); - for (int i = 0; i < 6; i++) { - _menuButtonData[i].process0 = _menuButtonData[i].process1 = _menuButtonData[i].process2 = 4; - _menuButtonData[i].process0PtrCallback = &KyraEngine::drawShadedBoxCallback; - _menuButtonData[i].process1PtrCallback = &KyraEngine::drawBoxCallback; - _menuButtonData[i].process2PtrCallback = &KyraEngine::drawShadedBoxCallback; - } - - _screen->savePageToDisk("SEENPAGE.TMP", 0); - gui_fadePalette(); - - for (int i = 0; i < 5; i++) - calcCoords(_menu[i]); - - _menuRestoreScreen = true; - _keyPressed.reset(); - _mousePressFlag = false; - - _toplevelMenu = 0; - if (_menuDirectlyToLoad) { - gui_loadGameMenu(0); - } else { - if (!caller) - _toplevelMenu = 4; - - initMenu(_menu[_toplevelMenu]); - processAllMenuButtons(); - } - - while (_displayMenu && !_quitFlag) { - gui_processHighlights(_menu[_toplevelMenu]); - processButtonList(_menuButtonList); - gui_getInput(); - } - - if (_menuRestoreScreen) { - gui_restorePalette(); - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _animator->_updateScreen = true; - } else { - _screen->deletePageFromDisk(0); - } - - return 0; -} - -void KyraEngine::initMenu(Menu &menu) { - _menuButtonList = 0; - - _screen->hideMouse(); - - int textX; - int textY; - - int menu_x2 = menu.width + menu.x - 1; - int menu_y2 = menu.height + menu.y - 1; - - _screen->fillRect(menu.x + 2, menu.y + 2, menu_x2 - 2, menu_y2 - 2, menu.bgcolor); - _screen->drawShadedBox(menu.x, menu.y, menu_x2, menu_y2, menu.color1, menu.color2); - - if (menu.field_10 != -1) - textX = menu.x; - else - textX = _text->getCenterStringX(menu.menuName, menu.x, menu_x2); - - textY = menu.y + menu.field_12; - - _text->printText(menu.menuName, textX - 1, textY + 1, 12, 248, 0); - _text->printText(menu.menuName, textX, textY, menu.textColor, 0, 0); - - int x1, y1, x2, y2; - for (int i = 0; i < menu.nrOfItems; i++) { - if (!menu.item[i].enabled) - continue; - - x1 = menu.x + menu.item[i].x; - y1 = menu.y + menu.item[i].y; - - x2 = x1 + menu.item[i].width - 1; - y2 = y1 + menu.item[i].height - 1; - - if (i < 6) { - _menuButtonData[i].nextButton = 0; - _menuButtonData[i].x = x1; - _menuButtonData[i].y = y1; - _menuButtonData[i].width = menu.item[i].width - 1; - _menuButtonData[i].height = menu.item[i].height - 1; - _menuButtonData[i].buttonCallback = menu.item[i].callback; - _menuButtonData[i].specialValue = menu.item[i].field_1b; - //_menuButtonData[i].field_6 = menu.item[i].field_25; - //_menuButtonData[i].field_8 = 0; - - if (!_menuButtonList) - _menuButtonList = &_menuButtonData[i]; - else - _menuButtonList = initButton(_menuButtonList, &_menuButtonData[i]); - } - _screen->fillRect(x1, y1, x2, y2, menu.item[i].bgcolor); - _screen->drawShadedBox(x1, y1, x2, y2, menu.item[i].color1, menu.item[i].color2); - - if (menu.item[i].itemString) { - if (menu.item[i].field_12 != -1 && _flags.lang == Common::EN_ANY) - textX = x1 + menu.item[i].field_12 + 3; - else - textX = _text->getCenterStringX(menu.item[i].itemString, x1, x2); - - textY = y1 + 2; - _text->printText(menu.item[i].itemString, textX - 1, textY + 1, 12, 0, 0); - - if (i == menu.highlightedItem) - _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].highlightColor, 0, 0); - else - _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].textColor, 0, 0); - - if (menu.item[i].labelString) { - _text->printText(menu.item[i].labelString, menu.x + menu.item[i].labelX - 1, menu.y + menu.item[i].labelY + 1, 12, 0, 0); - _text->printText(menu.item[i].labelString, menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, 253, 0, 0); - } - } - } - - if (menu.scrollUpBtnX != -1) { - _haveScrollButtons = true; - - _scrollUpButton.x = menu.scrollUpBtnX + menu.x; - _scrollUpButton.y = menu.scrollUpBtnY + menu.y; - _scrollUpButton.buttonCallback = &KyraEngine::gui_scrollUp; - _scrollUpButton.nextButton = 0; - _menuButtonList = initButton(_menuButtonList, &_scrollUpButton); - processMenuButton(&_scrollUpButton); - - _scrollDownButton.x = menu.scrollDownBtnX + menu.x; - _scrollDownButton.y = menu.scrollDownBtnY + menu.y; - _scrollDownButton.buttonCallback = &KyraEngine::gui_scrollDown; - _scrollDownButton.nextButton = 0; - _menuButtonList = initButton(_menuButtonList, &_scrollDownButton); - processMenuButton(&_scrollDownButton); - } else { - _haveScrollButtons = false; - } - - _screen->showMouse(); - _screen->updateScreen(); -} - -void KyraEngine::calcCoords(Menu &menu) { - assert(menu.nrOfItems < 7); - - int widthBackup = _screen->_charWidth; - _screen->_charWidth = -2; - - menu.x = (320 - menu.width)/2; - - int menu_x2 = menu.width + menu.x - 1; - int maxOffset = 0; - int x1, x2, y1, y2; - - for (int i = 0; i < menu.nrOfItems; i++) { - if (menu.item[i].x == -1) - menu.item[i].x = (menu.width - menu.item[i].width)/2; - - if (menu.item[i].labelString) { - x1 = menu.x + menu.item[i].x + 25; - y1 = (200 - menu.height)/2 + menu.item[i].y; - - x2 = x1 + menu.item[i].width; - y2 = y1 + menu.item[i].height; - - int textWidth = _screen->getTextWidth(menu.item[i].labelString) + 25; - int textX = menu.item[i].labelX + menu.x; - - if (textWidth + textX > x1) { - int offset = ((textWidth + textX) - x1); - if (maxOffset < offset) - maxOffset = offset; - } - } - - if (menu.item[i].itemString) { - int textWidth = _screen->getTextWidth(menu.item[i].itemString) + 15; - - if (menu.item[i].width < textWidth) { - menu.item[i].width = textWidth; - - if ( menu.x + menu.item[i].x + menu.item[i].width > menu_x2) - menu.item[i].x -= (menu.x + menu.item[i].x + menu.item[i].width) - menu_x2 + 10; - } - } - - } - - if (maxOffset > 0) { - maxOffset = maxOffset/2; - for (int i = 0; i < menu.nrOfItems; i++) { - menu.item[i].x += maxOffset + 10; - menu.item[i].labelX -= maxOffset; - } - menu.width += maxOffset; - } - - if (menu.menuName != 0) { - int menuNameLength = _screen->getTextWidth(menu.menuName); - if (menuNameLength > menu.width) - menu.width = menuNameLength; - } - - if (menu.width > 310) - menu.width = 310; - - menu.x = (320 - menu.width)/2; - - if (menu.y == -1) - menu.y = (200 - menu.height)/2; - - _screen->_charWidth = widthBackup; -} - -void KyraEngine::gui_getInput() { - Common::Event event; - static uint32 lastScreenUpdate = 0; - uint32 now = _system->getMillis(); - - _mouseWheel = 0; - while (_eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_QUIT: - quitGame(); - break; - case Common::EVENT_LBUTTONDOWN: - _mousePressFlag = true; - break; - case Common::EVENT_LBUTTONUP: - _mousePressFlag = false; - break; - case Common::EVENT_MOUSEMOVE: - _system->updateScreen(); - lastScreenUpdate = now; - break; - case Common::EVENT_WHEELUP: - _mouseWheel = -1; - break; - case Common::EVENT_WHEELDOWN: - _mouseWheel = 1; - break; - case Common::EVENT_KEYDOWN: - _keyPressed = event.kbd; - break; - default: - break; - } - } - - if (now - lastScreenUpdate > 50) { - _system->updateScreen(); - lastScreenUpdate = now; - } - - _system->delayMillis(3); -} - -int KyraEngine::gui_resumeGame(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_resumeGame()"); - processMenuButton(button); - _displayMenu = false; - - return 0; -} - -const char *KyraEngine::getSavegameFilename(int num) { - static char saveLoadSlot[12]; - - sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), num); - return saveLoadSlot; -} - -int KyraEngine::getNextSavegameSlot() { - Common::InSaveFile *in; - - for (int i = 1; i < 1000; i++) { - if ((in = _saveFileMan->openForLoading(getSavegameFilename(i)))) - delete in; - else - return i; - } - warning("Didn't save: Ran out of savegame filenames"); - return 0; -} - -void KyraEngine::setupSavegames(Menu &menu, int num) { - Common::InSaveFile *in; - static char savenames[5][31]; - uint8 startSlot; - assert(num <= 5); - - if (_savegameOffset == 0) { - menu.item[0].itemString = _specialSavegameString; - menu.item[0].enabled = 1; - menu.item[0].field_1b = 0; - startSlot = 1; - } else { - startSlot = 0; - } - - for (int i = startSlot; i < num; i++) { - if ((in = _saveFileMan->openForLoading(getSavegameFilename(i + _savegameOffset)))) { - in->skip(8); - in->read(savenames[i], 31); - menu.item[i].itemString = savenames[i]; - menu.item[i].enabled = 1; - menu.item[i].field_1b = i + _savegameOffset; - delete in; - } else { - menu.item[i].enabled = 0; - //menu.item[i].itemString = ""; - //menu.item[i].field_1b = -1; - } - } -} - -int KyraEngine::gui_saveGameMenu(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_saveGameMenu()"); - processMenuButton(button); - _menu[2].item[5].enabled = true; - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - _menu[2].menuName = _guiStrings[8]; // Select a position to save to: - _specialSavegameString = _guiStrings[9]; // [ EMPTY SLOT ] - for (int i = 0; i < 5; i++) - _menu[2].item[i].callback = &KyraEngine::gui_saveGame; - - _savegameOffset = 0; - setupSavegames(_menu[2], 5); - - initMenu(_menu[2]); - processAllMenuButtons(); - - _displaySubMenu = true; - _cancelSubMenu = false; - - while (_displaySubMenu && !_quitFlag) { - gui_getInput(); - gui_processHighlights(_menu[2]); - processButtonList(_menuButtonList); - } - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - if (_cancelSubMenu) { - initMenu(_menu[0]); - processAllMenuButtons(); - } else { - _displayMenu = false; - } - return 0; -} - -int KyraEngine::gui_loadGameMenu(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_loadGameMenu()"); - if (_menuDirectlyToLoad) { - _menu[2].item[5].enabled = false; - } else { - processMenuButton(button); - _menu[2].item[5].enabled = true; - } - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - _specialSavegameString = _newGameString[0]; //[ START A NEW GAME ] - _menu[2].menuName = _guiStrings[7]; // Which game would you like to reload? - for (int i = 0; i < 5; i++) - _menu[2].item[i].callback = &KyraEngine::gui_loadGame; - - _savegameOffset = 0; - setupSavegames(_menu[2], 5); - - initMenu(_menu[2]); - processAllMenuButtons(); - - _displaySubMenu = true; - _cancelSubMenu = false; - - while (_displaySubMenu && !_quitFlag) { - gui_getInput(); - gui_processHighlights(_menu[2]); - processButtonList(_menuButtonList); - } - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - if (_cancelSubMenu) { - initMenu(_menu[_toplevelMenu]); - processAllMenuButtons(); - } else { - gui_restorePalette(); - loadGame(getSavegameFilename(_gameToLoad)); - _displayMenu = false; - _menuRestoreScreen = false; - } - return 0; -} - -void KyraEngine::gui_redrawTextfield() { - _screen->fillRect(38, 91, 287, 102, 250); - _text->printText(_savegameName, 38, 92, 253, 0, 0); - - _screen->_charWidth = -2; - int width = _screen->getTextWidth(_savegameName); - _screen->fillRect(39 + width, 93, 45 + width, 100, 254); - _screen->_charWidth = 0; - - _screen->updateScreen(); -} - -void KyraEngine::gui_updateSavegameString() { - int length; - - if (_keyPressed.keycode) { - length = strlen(_savegameName); - - if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127) { - if (length < 31) { - _savegameName[length] = _keyPressed.ascii; - _savegameName[length+1] = 0; - gui_redrawTextfield(); - } - } else if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE || - _keyPressed.keycode == Common::KEYCODE_DELETE) { - if (length > 0) { - _savegameName[length-1] = 0; - gui_redrawTextfield(); - } - } else if (_keyPressed.keycode == Common::KEYCODE_RETURN || - _keyPressed.keycode == Common::KEYCODE_KP_ENTER) { - _displaySubMenu = false; - } - } - - _keyPressed.reset(); -} - -int KyraEngine::gui_saveGame(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_saveGame()"); - processMenuButton(button); - _gameToLoad = button->specialValue; - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - initMenu(_menu[3]); - processAllMenuButtons(); - - _displaySubMenu = true; - _cancelSubMenu = false; - - if (_savegameOffset == 0 && _gameToLoad == 0) { - _savegameName[0] = 0; - } else { - for (int i = 0; i < 5; i++) { - if (_menu[2].item[i].field_1b == _gameToLoad) { - strncpy(_savegameName, _menu[2].item[i].itemString, 31); - break; - } - } - } - gui_redrawTextfield(); - - while (_displaySubMenu && !_quitFlag) { - gui_getInput(); - gui_updateSavegameString(); - gui_processHighlights(_menu[3]); - processButtonList(_menuButtonList); - } - - if (_cancelSubMenu) { - _displaySubMenu = true; - _cancelSubMenu = false; - initMenu(_menu[2]); - processAllMenuButtons(); - } else { - if (_savegameOffset == 0 && _gameToLoad == 0) - _gameToLoad = getNextSavegameSlot(); - if (_gameToLoad > 0) - saveGame(getSavegameFilename(_gameToLoad), _savegameName); - } - - return 0; -} - -int KyraEngine::gui_savegameConfirm(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_savegameConfirm()"); - processMenuButton(button); - _displaySubMenu = false; - - return 0; -} - -int KyraEngine::gui_loadGame(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_loadGame()"); - processMenuButton(button); - _displaySubMenu = false; - _gameToLoad = button->specialValue; - - return 0; -} - -int KyraEngine::gui_cancelSubMenu(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_cancelLoadGameMenu()"); - processMenuButton(button); - _displaySubMenu = false; - _cancelSubMenu = true; - - return 0; -} - -int KyraEngine::gui_quitPlaying(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitPlaying()"); - processMenuButton(button); - - if (gui_quitConfirm(_guiStrings[14])) { // Are you sure you want to quit playing? - quitGame(); - } else { - initMenu(_menu[_toplevelMenu]); - processAllMenuButtons(); - } - - return 0; -} - -bool KyraEngine::gui_quitConfirm(const char *str) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitConfirm()"); - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - _menu[1].menuName = str; - calcCoords(_menu[1]); - initMenu(_menu[1]); - - _displaySubMenu = true; - _cancelSubMenu = true; - - while (_displaySubMenu && !_quitFlag) { - gui_getInput(); - gui_processHighlights(_menu[1]); - processButtonList(_menuButtonList); - } - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - return !_cancelSubMenu; -} - -int KyraEngine::gui_quitConfirmYes(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitConfirmYes()"); - processMenuButton(button); - _displaySubMenu = false; - _cancelSubMenu = false; - - return 0; -} - -int KyraEngine::gui_quitConfirmNo(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitConfirmNo()"); - processMenuButton(button); - _displaySubMenu = false; - _cancelSubMenu = true; - - return 0; -} - -int KyraEngine::gui_gameControlsMenu(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_gameControlsMenu()"); - - readSettings(); - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - if (_flags.isTalkie) { - //_menu[5].width = 230; - - for (int i = 0; i < 5; i++) { - //_menu[5].item[i].labelX = 24; - //_menu[5].item[i].x = 115; - //_menu[5].item[i].width = 94; - } - - _menu[5].item[3].labelString = _voiceTextString; //"Voice / Text " - _menu[5].item[3].callback = &KyraEngine::gui_controlsChangeVoice; - - } else { - //_menu[5].height = 136; - //_menu[5].item[5].y = 110; - _menu[5].item[4].enabled = 0; - _menu[5].item[3].labelString = _textSpeedString; // "Text speed " - _menu[5].item[3].callback = &KyraEngine::gui_controlsChangeText; - } - - gui_setupControls(_menu[5]); - - processAllMenuButtons(); - - _displaySubMenu = true; - _cancelSubMenu = false; - - while (_displaySubMenu && !_quitFlag) { - gui_getInput(); - gui_processHighlights(_menu[5]); - processButtonList(_menuButtonList); - } - - _screen->loadPageFromDisk("SEENPAGE.TMP", 0); - _screen->savePageToDisk("SEENPAGE.TMP", 0); - - if (_cancelSubMenu) { - initMenu(_menu[_toplevelMenu]); - processAllMenuButtons(); - } - return 0; -} - -void KyraEngine::gui_setupControls(Menu &menu) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_setupControls()"); - - switch (_configMusic) { - case 0: - menu.item[0].itemString = _offString; //"Off" - break; - case 1: - menu.item[0].itemString = _onString; //"On" - break; - case 2: - menu.item[0].itemString = _onCDString; //"On + CD" - break; - } - - if (_configSounds) - menu.item[1].itemString = _onString; //"On" - else - menu.item[1].itemString = _offString; //"Off" - - - switch (_configWalkspeed) { - case 0: - menu.item[2].itemString = _configStrings[0]; //"Slowest" - break; - case 1: - menu.item[2].itemString = _configStrings[1]; //"Slow" - break; - case 2: - menu.item[2].itemString = _configStrings[2]; //"Normal" - break; - case 3: - menu.item[2].itemString = _configStrings[3]; //"Fast" - break; - case 4: - menu.item[2].itemString = _configStrings[4]; //"Fastest" - break; - default: - menu.item[2].itemString = "ERROR"; - break; - } - - int textControl = 3; - int clickableOffset = 8; - if (_flags.isTalkie) { - textControl = 4; - clickableOffset = 11; - - if (_configVoice == 0) - _menu[5].item[4].enabled = 1; - else - _menu[5].item[4].enabled = 0; - - switch (_configVoice) { - case 0: - menu.item[3].itemString = _configStrings[5]; //"Text only" - break; - case 1: - menu.item[3].itemString = _configStrings[6]; //"Voice only" - break; - case 2: - menu.item[3].itemString = _configStrings[7]; //"Voice & Text" - break; - default: - menu.item[3].itemString = "ERROR"; - break; - } - } - - switch (_configTextspeed) { - case 0: - menu.item[textControl].itemString = _configStrings[1]; //"Slow" - break; - case 1: - menu.item[textControl].itemString = _configStrings[2]; //"Normal" - break; - case 2: - menu.item[textControl].itemString = _configStrings[3]; //"Fast" - break; - case 3: - menu.item[textControl].itemString = _configStrings[clickableOffset]; //"Clickable" - break; - default: - menu.item[textControl].itemString = "ERROR"; - break; - } - - calcCoords(menu); - initMenu(menu); -} - -int KyraEngine::gui_controlsChangeMusic(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeMusic()"); - processMenuButton(button); - - _configMusic = ++_configMusic % (_flags.platform == Common::kPlatformFMTowns ? 3 : 2); - gui_setupControls(_menu[5]); - return 0; -} - -int KyraEngine::gui_controlsChangeSounds(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeSounds()"); - processMenuButton(button); - - _configSounds = !_configSounds; - gui_setupControls(_menu[5]); - return 0; -} - -int KyraEngine::gui_controlsChangeWalk(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeWalk()"); - processMenuButton(button); - - _configWalkspeed = ++_configWalkspeed % 5; - setWalkspeed(_configWalkspeed); - gui_setupControls(_menu[5]); - return 0; -} - -int KyraEngine::gui_controlsChangeText(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeText()"); - processMenuButton(button); - - _configTextspeed = ++_configTextspeed % 4; - gui_setupControls(_menu[5]); - return 0; -} - -int KyraEngine::gui_controlsChangeVoice(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeVoice()"); - processMenuButton(button); - - _configVoice = ++_configVoice % 3; - gui_setupControls(_menu[5]); - return 0; -} - -int KyraEngine::gui_controlsApply(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsApply()"); - writeSettings(); - return gui_cancelSubMenu(button); -} - -int KyraEngine::gui_scrollUp(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_scrollUp()"); - processMenuButton(button); - - if (_savegameOffset > 0) { - _savegameOffset--; - setupSavegames(_menu[2], 5); - initMenu(_menu[2]); - } - return 0; -} - -int KyraEngine::gui_scrollDown(Button *button) { - debugC(9, kDebugLevelGUI, "KyraEngine::gui_scrollDown()"); - processMenuButton(button); - - _savegameOffset++; - setupSavegames(_menu[2], 5); - initMenu(_menu[2]); - - return 0; -} - -void KyraEngine::gui_processHighlights(Menu &menu) { - int x1, y1, x2, y2; - - Common::Point mouse = getMousePos(); - for (int i = 0; i < menu.nrOfItems; i++) { - if (!menu.item[i].enabled) - continue; - - x1 = menu.x + menu.item[i].x; - y1 = menu.y + menu.item[i].y; - - x2 = x1 + menu.item[i].width; - y2 = y1 + menu.item[i].height; - - if (mouse.x > x1 && mouse.x < x2 && - mouse.y > y1 && mouse.y < y2) { - - if (menu.highlightedItem != i) { - if (menu.item[menu.highlightedItem].enabled ) - gui_redrawText(menu); - - menu.highlightedItem = i; - gui_redrawHighlight(menu); - _screen->updateScreen(); - } - } - } -} - -void KyraEngine::gui_redrawText(Menu menu) { - int textX; - int i = menu.highlightedItem; - - int x1 = menu.x + menu.item[i].x; - int y1 = menu.y + menu.item[i].y; - - int x2 = x1 + menu.item[i].width - 1; - - if (menu.item[i].field_12 != -1 &&_flags.lang == Common::EN_ANY) - textX = x1 + menu.item[i].field_12 + 3; - else - textX = _text->getCenterStringX(menu.item[i].itemString, x1, x2); - - int textY = y1 + 2; - _text->printText(menu.item[i].itemString, textX - 1, textY + 1, 12, 0, 0); - _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].textColor, 0, 0); -} - -void KyraEngine::gui_redrawHighlight(Menu menu) { - int textX; - int i = menu.highlightedItem; - - int x1 = menu.x + menu.item[i].x; - int y1 = menu.y + menu.item[i].y; - - int x2 = x1 + menu.item[i].width - 1; - - if (menu.item[i].field_12 != -1 &&_flags.lang == Common::EN_ANY) - textX = x1 + menu.item[i].field_12 + 3; - else - textX = _text->getCenterStringX(menu.item[i].itemString, x1, x2); - - int textY = y1 + 2; - _text->printText(menu.item[i].itemString, textX - 1, textY + 1, 12, 0, 0); - _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].highlightColor, 0, 0); -} - -void KyraEngine::gui_fadePalette() { - if (_flags.platform == Common::kPlatformAmiga) - return; - - static int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; - int index = 0; - - memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); - - for (int i = 0; i < 768; i++) - _screen->_currentPalette[i] >>= 1; - - while (menuPalIndexes[index] != -1) { - memcpy(&_screen->_currentPalette[menuPalIndexes[index]*3], &_screen->getPalette(2)[menuPalIndexes[index]*3], 3); - index++; - } - - _screen->fadePalette(_screen->_currentPalette, 2); -} - -void KyraEngine::gui_restorePalette() { - if (_flags.platform == Common::kPlatformAmiga) - return; - - memcpy(_screen->_currentPalette, _screen->getPalette(2), 768); - _screen->fadePalette(_screen->_currentPalette, 2); -} - -#pragma mark - - -// Kyra 2 and 3 main menu - -void KyraEngine::gui_updateMainMenuAnimation() { - _screen->updateScreen(); -} - -bool KyraEngine::gui_mainMenuGetInput() { - Common::Event event; - - while (_eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_QUIT: - quitGame(); - break; - case Common::EVENT_LBUTTONUP: - return true; - default: - break; - } - } - return false; -} - -int KyraEngine::gui_handleMainMenu() { - debugC(9, kDebugLevelMain, "KyraEngine::gui_handleMainMenu()"); - int command = -1; - - uint8 colorMap[16]; - memset(colorMap, 0, sizeof(colorMap)); - _screen->setTextColorMap(colorMap); - - const char * const *strings = &_mainMenuStrings[_lang << 2]; - Screen::FontId oldFont = _screen->setFont(Screen::FID_8_FNT); - int charWidthBackUp = _screen->_charWidth; - - _screen->_charWidth = -2; - _screen->setScreenDim(3); - int backUpX = _screen->_curDim->sx; - int backUpY = _screen->_curDim->sy; - int backUpWidth = _screen->_curDim->w; - int backUpHeight = _screen->_curDim->h; - _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 0, 3); - - int x = _screen->_curDim->sx << 3; - int y = _screen->_curDim->sy; - int width = _screen->_curDim->w << 3; - int height = _screen->_curDim->h; - - gui_drawMainBox(x, y, width, height, 1); - gui_drawMainBox(x + 1, y + 1, width - 2, height - 2, 0); - - int selected = 0; - - gui_drawMainMenu(strings, selected); - - _screen->showMouse(); - - int fh = _screen->getFontHeight(); - int textPos = ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3; - - Common::Rect menuRect(x + 16, y + 4, x + width - 16, y + 4 + fh * 4); - - while (!_quitFlag) { - gui_updateMainMenuAnimation(); - bool mousePressed = gui_mainMenuGetInput(); - - Common::Point mouse = getMousePos(); - if (menuRect.contains(mouse)) { - int item = (mouse.y - menuRect.top) / fh; - - if (item != selected) { - gui_printString(strings[selected], textPos, menuRect.top + selected * fh, 0x80, 0, 5); - gui_printString(strings[item], textPos, menuRect.top + item * fh, 0xFF, 0, 5); - - selected = item; - } - - if (mousePressed) { - // TODO: Flash the text - command = item; - break; - } - } - _system->delayMillis(10); - } - - if (_quitFlag) - command = -1; - - _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 3, 0); - _screen->_charWidth = charWidthBackUp; - _screen->setFont(oldFont); - - return command; -} - -void KyraEngine::gui_drawMainMenu(const char * const *strings, int select) { - debugC(9, kDebugLevelMain, "KyraEngine::gui_drawMainMenu(%p)", (const void*)strings); - static const uint16 menuTable[] = { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x80, 0xFF, 0x00, 0x01, 0x02, 0x03 }; - - int top = _screen->_curDim->sy; - top += menuTable[1]; - - for (int i = 0; i < menuTable[3]; ++i) { - int curY = top + i * _screen->getFontHeight(); - int color = (i == select) ? menuTable[6] : menuTable[5]; - gui_printString(strings[i], ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5); - } -} - -void KyraEngine::gui_drawMainBox(int x, int y, int w, int h, int fill) { - debugC(9, kDebugLevelMain, "KyraEngine::gui_drawMainBox(%d, %d, %d, %d, %d)", x, y, w, h, fill); - static const uint8 kyra3ColorTable[] = { 0x16, 0x19, 0x1A, 0x16 }; - static const uint8 kyra2ColorTable[] = { 0x0, 0x19, 0x28, 0xc8 }; - - const uint8 *colorTable; - if (_flags.gameID == GI_KYRA3) - colorTable = kyra3ColorTable; - else - colorTable = kyra2ColorTable; - - --w; --h; - - if (fill) - _screen->fillRect(x, y, x+w, y+h, colorTable[0]); - - _screen->drawClippedLine(x, y+h, x+w, y+h, colorTable[1]); - _screen->drawClippedLine(x+w, y, x+w, y+h, colorTable[1]); - _screen->drawClippedLine(x, y, x+w, y, colorTable[2]); - _screen->drawClippedLine(x, y, x, y+h, colorTable[2]); - - _screen->setPagePixel(_screen->_curPage, x, y+h, colorTable[3]); - _screen->setPagePixel(_screen->_curPage, x+w, y, colorTable[3]); -} - -void KyraEngine::gui_printString(const char *format, int x, int y, int col1, int col2, int flags, ...) { - debugC(9, kDebugLevelMain, "KyraEngine::gui_printString('%s', %d, %d, %d, %d, %d, ...)", format, x, y, col1, col2, flags); - if (!format) - return; - - char string[512]; - va_list vaList; - va_start(vaList, flags); - vsprintf(string, format, vaList); - va_end(vaList); - - if (flags & 1) - x -= _screen->getTextWidth(string) >> 1; - - if (flags & 2) - x -= _screen->getTextWidth(string); - - if (flags & 4) { - _screen->printText(string, x - 1, y, 240, col2); - _screen->printText(string, x, y + 1, 240, col2); - } - - if (flags & 8) { - _screen->printText(string, x - 1, y, 227, col2); - _screen->printText(string, x, y + 1, 227, col2); - } - - _screen->printText(string, x, y, col1, col2); -} - -} // end of namespace Kyra - diff --git a/engines/kyra/gui_v1.cpp b/engines/kyra/gui_v1.cpp new file mode 100644 index 0000000000..fe051dd75c --- /dev/null +++ b/engines/kyra/gui_v1.cpp @@ -0,0 +1,1640 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "kyra/kyra.h" +#include "kyra/screen.h" +#include "kyra/script.h" +#include "kyra/text.h" +#include "kyra/animator.h" +#include "kyra/sound.h" + +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/events.h" +#include "common/system.h" + +namespace Kyra { + +void KyraEngine::registerDefaultSettings() { + // Most settings already have sensible defaults. This one, however, is + // specific to the Kyra engine. + ConfMan.registerDefault("walkspeed", 2); + ConfMan.registerDefault("cdaudio", _flags.platform == Common::kPlatformFMTowns); +} + +void KyraEngine::readSettings() { + int talkspeed = ConfMan.getInt("talkspeed"); + + // The default talk speed is 60. This should be mapped to "Normal". + + if (talkspeed == 0) + _configTextspeed = 3; // Clickable + if (talkspeed <= 50) + _configTextspeed = 0; // Slow + else if (talkspeed <= 150) + _configTextspeed = 1; // Normal + else + _configTextspeed = 2; // Fast + + _configWalkspeed = ConfMan.getInt("walkspeed"); + _configMusic = ConfMan.getBool("music_mute") ? 0 : ((ConfMan.getBool("cdaudio") && _flags.platform == Common::kPlatformFMTowns) ? 2 : 1); + _configSounds = ConfMan.getBool("sfx_mute") ? 0 : 1; + + _sound->enableMusic(_configMusic); + _sound->enableSFX(_configSounds); + + bool speechMute = ConfMan.getBool("speech_mute"); + bool subtitles = ConfMan.getBool("subtitles"); + + if (!speechMute && subtitles) + _configVoice = 2; // Voice & Text + else if (!speechMute && !subtitles) + _configVoice = 1; // Voice only + else + _configVoice = 0; // Text only + + setWalkspeed(_configWalkspeed); +} + +void KyraEngine::writeSettings() { + bool speechMute, subtitles; + int talkspeed; + + switch (_configTextspeed) { + case 0: // Slow + talkspeed = 1; + break; + case 1: // Normal + talkspeed = 60; + break; + case 2: // Fast + talkspeed = 255; + break; + default: // Clickable + talkspeed = 0; + break; + } + + ConfMan.setInt("talkspeed", talkspeed); + ConfMan.setInt("walkspeed", _configWalkspeed); + ConfMan.setBool("music_mute", _configMusic == 0); + ConfMan.setBool("cdaudio", _configMusic == 2); + ConfMan.setBool("sfx_mute", _configSounds == 0); + + switch (_configVoice) { + case 0: // Text only + speechMute = true; + subtitles = true; + break; + case 1: // Voice only + speechMute = false; + subtitles = false; + break; + default: // Voice & Text + speechMute = false; + subtitles = true; + break; + } + + if (!_configMusic) + _sound->beginFadeOut(); + + _sound->enableMusic(_configMusic); + _sound->enableSFX(_configSounds); + + ConfMan.setBool("speech_mute", speechMute); + ConfMan.setBool("subtitles", subtitles); + + ConfMan.flushToDisk(); +} + +void KyraEngine::initMainButtonList() { + _haveScrollButtons = false; + _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; + if (!list) + return newButton; + Button *cur = list; + + while (true) { + if (!cur->nextButton) + break; + cur = cur->nextButton; + } + + cur->nextButton = newButton; + return list; +} + +int KyraEngine::buttonInventoryCallback(Button *caller) { + int itemOffset = caller->specialValue - 2; + uint8 inventoryItem = _currentCharacter->inventoryItems[itemOffset]; + if (_itemInHand == -1) { + if (inventoryItem == 0xFF) { + snd_playSoundEffect(0x36); + return 0; + } else { + _screen->hideMouse(); + _screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, 12); + snd_playSoundEffect(0x35); + setMouseItem(inventoryItem); + updateSentenceCommand(_itemList[inventoryItem], _takenList[0], 179); + _itemInHand = inventoryItem; + _screen->showMouse(); + _currentCharacter->inventoryItems[itemOffset] = 0xFF; + } + } else { + if (inventoryItem != 0xFF) { + snd_playSoundEffect(0x35); + _screen->hideMouse(); + _screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, 12); + _screen->drawShape(0, _shapes[216+_itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0); + setMouseItem(inventoryItem); + updateSentenceCommand(_itemList[inventoryItem], _takenList[1], 179); + _screen->showMouse(); + _currentCharacter->inventoryItems[itemOffset] = _itemInHand; + _itemInHand = inventoryItem; + } else { + snd_playSoundEffect(0x32); + _screen->hideMouse(); + _screen->drawShape(0, _shapes[216+_itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0); + _screen->setMouseCursor(1, 1, _shapes[0]); + updateSentenceCommand(_itemList[_itemInHand], _placedList[0], 179); + _screen->showMouse(); + _currentCharacter->inventoryItems[itemOffset] = _itemInHand; + _itemInHand = -1; + } + } + _screen->updateScreen(); + // XXX clearKyrandiaButtonIO + return 0; +} + +int KyraEngine::buttonAmuletCallback(Button *caller) { + if (!(_deathHandler & 8)) + return 1; + int jewel = caller->specialValue - 0x14; + if (_currentCharacter->sceneId == 210) { + if (_beadStateVar == 4 || _beadStateVar == 6) + return 1; + } + if (!queryGameFlag(0x2D)) + return 1; + if (_itemInHand != -1) { + assert(_putDownFirst); + characterSays(2000, _putDownFirst[0], 0, -2); + return 1; + } + if (queryGameFlag(0xF1)) { + assert(_waitForAmulet); + characterSays(2001, _waitForAmulet[0], 0, -2); + return 1; + } + if (!queryGameFlag(0x55+jewel)) { + assert(_blackJewel); + _animator->makeBrandonFaceMouse(); + drawJewelPress(jewel, 1); + characterSays(2002, _blackJewel[0], 0, -2); + return 1; + } + drawJewelPress(jewel, 0); + drawJewelsFadeOutStart(); + drawJewelsFadeOutEnd(jewel); + + _scriptInterpreter->initScript(_scriptClick, _scriptClickData); + _scriptClick->regs[3] = 0; + _scriptClick->regs[6] = jewel; + _scriptInterpreter->startScript(_scriptClick, 4); + + while (_scriptInterpreter->validScript(_scriptClick)) + _scriptInterpreter->runScript(_scriptClick); + + if (_scriptClick->regs[3]) + return 1; + + _unkAmuletVar = 1; + switch (jewel-1) { + case 0: + if (_brandonStatusBit & 1) { + seq_brandonHealing2(); + } else if (_brandonStatusBit == 0) { + seq_brandonHealing(); + assert(_healingTip); + characterSays(2003, _healingTip[0], 0, -2); + } + break; + + case 1: + seq_makeBrandonInv(); + break; + + case 2: + if (_brandonStatusBit & 1) { + assert(_wispJewelStrings); + characterSays(2004, _wispJewelStrings[0], 0, -2); + } else { + if (_brandonStatusBit & 2) { + // XXX + seq_makeBrandonNormal2(); + // XXX + } else { + // do not check for item in hand again as in the original since some strings are missing + // in the cd version + if (_currentCharacter->sceneId >= 109 && _currentCharacter->sceneId <= 198) { + snd_playWanderScoreViaMap(1, 0); + seq_makeBrandonWisp(); + snd_playWanderScoreViaMap(17, 0); + } else { + seq_makeBrandonWisp(); + } + setGameFlag(0x9E); + } + } + break; + + case 3: + seq_dispelMagicAnimation(); + assert(_magicJewelString); + characterSays(2007, _magicJewelString[0], 0, -2); + break; + + default: + break; + } + _unkAmuletVar = 0; + // XXX clearKyrandiaButtonIO (!used before every return in this function!) + return 1; +} + +void KyraEngine::processButtonList(Button *list) { + if (_haveScrollButtons) { + if (_mouseWheel < 0) + gui_scrollUp(&_scrollUpButton); + else if (_mouseWheel > 0) + gui_scrollDown(&_scrollDownButton); + } + while (list) { + if (list->flags & 8) { + list = list->nextButton; + continue; + } + + int x = list->x; + int y = list->y; + assert(list->dimTableIndex < _screen->_screenDimTableCount); + if (x < 0) { + x += _screen->_screenDimTable[list->dimTableIndex].w << 3; + } + x += _screen->_screenDimTable[list->dimTableIndex].sx << 3; + + if (y < 0) { + y += _screen->_screenDimTable[list->dimTableIndex].h; + } + y += _screen->_screenDimTable[list->dimTableIndex].sy; + + Common::Point mouse = getMousePos(); + if (mouse.x >= x && mouse.y >= y && x + list->width >= mouse.x && y + list->height >= mouse.y) { + int processMouseClick = 0; + if (list->flags & 0x400) { + if (_mousePressFlag) { + if (!(list->flags2 & 1)) { + list->flags2 |= 1; + list->flags2 |= 4; + processButton(list); + _screen->updateScreen(); + } + } else { + if (list->flags2 & 1) { + list->flags2 &= 0xFFFE; + processButton(list); + processMouseClick = 1; + } + } + } else if (_mousePressFlag) { + processMouseClick = 1; + } + + if (processMouseClick) { + if (list->buttonCallback) { + if ((this->*(list->buttonCallback))(list)) { + break; + } + } + } + } else { + if (list->flags2 & 1) { + list->flags2 &= 0xFFFE; + processButton(list); + } + if (list->flags2 & 4) { + list->flags2 &= 0xFFFB; + processButton(list); + _screen->updateScreen(); + } + list = list->nextButton; + continue; + } + + list = list->nextButton; + } +} + +void KyraEngine::processButton(Button *button) { + if (!button) + return; + + int processType = 0; + uint8 *shape = 0; + Button::ButtonCallback callback = 0; + + int flags = (button->flags2 & 5); + if (flags == 1) { + processType = button->process2; + if (processType == 1) + shape = button->process2PtrShape; + else if (processType == 4) + callback = button->process2PtrCallback; + } else if (flags == 4 || flags == 5) { + processType = button->process1; + if (processType == 1) + shape = button->process1PtrShape; + else if (processType == 4) + callback = button->process1PtrCallback; + } else { + processType = button->process0; + if (processType == 1) + shape = button->process0PtrShape; + else if (processType == 4) + callback = button->process0PtrCallback; + } + + int x = button->x; + int y = button->y; + assert(button->dimTableIndex < _screen->_screenDimTableCount); + if (x < 0) + x += _screen->_screenDimTable[button->dimTableIndex].w << 3; + + if (y < 0) + y += _screen->_screenDimTable[button->dimTableIndex].h; + + if (processType == 1 && shape) + _screen->drawShape(_screen->_curPage, shape, x, y, button->dimTableIndex, 0x10); + else if (processType == 4 && callback) + (this->*callback)(button); +} + +void KyraEngine::processAllMenuButtons() { + if (!_menuButtonList) + return; + + Button *cur = _menuButtonList; + while (true) { + if (!cur->nextButton) + break; + processMenuButton(cur); + cur = cur->nextButton; + } + return; +} + +void KyraEngine::processMenuButton(Button *button) { + if (!_displayMenu) + return; + + if (!button || (button->flags & 8)) + return; + + if (button->flags2 & 1) + button->flags2 &= 0xf7; + else + button->flags2 |= 8; + + button->flags2 &= 0xfc; + + if (button->flags2 & 4) + button->flags2 |= 0x10; + else + button->flags2 &= 0xef; + + button->flags2 &= 0xfb; + + processButton(button); +} + +int KyraEngine::drawBoxCallback(Button *button) { + if (!_displayMenu) + return 0; + + _screen->hideMouse(); + _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xf8); + _screen->showMouse(); + + return 0; +} + +int KyraEngine::drawShadedBoxCallback(Button *button) { + if (!_displayMenu) + return 0; + + _screen->hideMouse(); + _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xf9, 0xfa); + _screen->showMouse(); + + return 0; +} + +void KyraEngine::setGUILabels() { + int offset = 0; + int offsetOptions = 0; + int offsetMainMenu = 0; + int offsetOn = 0; + + int walkspeedGarbageOffset = 36; + int menuLabelGarbageOffset = 0; + + if (_flags.isTalkie) { + if (_flags.lang == Common::EN_ANY) + offset = 52; + else if (_flags.lang == Common::DE_DEU) + offset = 30; + else if (_flags.lang == Common::FR_FRA || _flags.lang == Common::IT_ITA) + offset = 6; + offsetOn = offsetMainMenu = offsetOptions = offset; + walkspeedGarbageOffset = 48; + } else if (_flags.lang == Common::ES_ESP) { + offsetOn = offsetMainMenu = offsetOptions = offset = -4; + menuLabelGarbageOffset = 72; + } else if (_flags.lang == Common::DE_DEU) { + offset = offsetMainMenu = offsetOn = offsetOptions = 24; + } else if (_flags.platform == Common::kPlatformFMTowns) { + offset = 1; + offsetOptions = 10; + offsetOn = 0; + walkspeedGarbageOffset = 0; + } + + assert(offset + 27 < _guiStringsSize); + + // The Legend of Kyrandia + _menu[0].menuName = _guiStrings[0]; + // Load a Game + _menu[0].item[0].itemString = _guiStrings[1]; + // Save a Game + _menu[0].item[1].itemString = _guiStrings[2]; + // Game controls + _menu[0].item[2].itemString = _guiStrings[3]; + // Quit playing + _menu[0].item[3].itemString = _guiStrings[4]; + // Resume game + _menu[0].item[4].itemString = _guiStrings[5]; + + // Cancel + _menu[2].item[5].itemString = _guiStrings[10]; + + // Enter a description of your saved game: + _menu[3].menuName = _guiStrings[11]; + // Save + _menu[3].item[0].itemString = _guiStrings[12]; + // Cancel + _menu[3].item[1].itemString = _guiStrings[10]; + + // Rest in peace, Brandon + _menu[4].menuName = _guiStrings[13]; + // Load a game + _menu[4].item[0].itemString = _guiStrings[1]; + // Quit playing + _menu[4].item[1].itemString = _guiStrings[4]; + + // Game Controls + _menu[5].menuName = _guiStrings[6]; + // Yes + _menu[1].item[0].itemString = _guiStrings[22 + offset]; + // No + _menu[1].item[1].itemString = _guiStrings[23 + offset]; + + // Music is + _menu[5].item[0].labelString = _guiStrings[26 + offsetOptions]; + // Sounds are + _menu[5].item[1].labelString = _guiStrings[27 + offsetOptions]; + // Walk speed + _menu[5].item[2].labelString = &_guiStrings[24 + offsetOptions][walkspeedGarbageOffset]; + // Text speed + _menu[5].item[4].labelString = _guiStrings[25 + offsetOptions]; + // Main Menu + _menu[5].item[5].itemString = &_guiStrings[19 + offsetMainMenu][menuLabelGarbageOffset]; + + if (_flags.isTalkie) + // Text & Voice + _voiceTextString = _guiStrings[28 + offset]; + + _textSpeedString = _guiStrings[25 + offsetOptions]; + _onString = _guiStrings[20 + offsetOn]; + _offString = _guiStrings[21 + offset]; + _onCDString = _guiStrings[21]; +} + +int KyraEngine::buttonMenuCallback(Button *caller) { + _displayMenu = true; + + assert(_guiStrings); + assert(_configStrings); + + /* + for (int i = 0; i < _guiStringsSize; i++) + debug("GUI string %i: %s", i, _guiStrings[i]); + + for (int i = 0; i < _configStringsSize; i++) + debug("Config string %i: %s", i, _configStrings[i]); + */ + + setGUILabels(); + if (_currentCharacter->sceneId == 210 && _deathHandler == 0xFF) { + snd_playSoundEffect(0x36); + return 0; + } + // XXX + _screen->setPaletteIndex(0xFE, 60, 60, 0); + for (int i = 0; i < 6; i++) { + _menuButtonData[i].process0 = _menuButtonData[i].process1 = _menuButtonData[i].process2 = 4; + _menuButtonData[i].process0PtrCallback = &KyraEngine::drawShadedBoxCallback; + _menuButtonData[i].process1PtrCallback = &KyraEngine::drawBoxCallback; + _menuButtonData[i].process2PtrCallback = &KyraEngine::drawShadedBoxCallback; + } + + _screen->savePageToDisk("SEENPAGE.TMP", 0); + gui_fadePalette(); + + for (int i = 0; i < 5; i++) + calcCoords(_menu[i]); + + _menuRestoreScreen = true; + _keyPressed.reset(); + _mousePressFlag = false; + + _toplevelMenu = 0; + if (_menuDirectlyToLoad) { + gui_loadGameMenu(0); + } else { + if (!caller) + _toplevelMenu = 4; + + initMenu(_menu[_toplevelMenu]); + processAllMenuButtons(); + } + + while (_displayMenu && !_quitFlag) { + gui_processHighlights(_menu[_toplevelMenu]); + processButtonList(_menuButtonList); + gui_getInput(); + } + + if (_menuRestoreScreen) { + gui_restorePalette(); + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _animator->_updateScreen = true; + } else { + _screen->deletePageFromDisk(0); + } + + return 0; +} + +void KyraEngine::initMenu(Menu &menu) { + _menuButtonList = 0; + + _screen->hideMouse(); + + int textX; + int textY; + + int menu_x2 = menu.width + menu.x - 1; + int menu_y2 = menu.height + menu.y - 1; + + _screen->fillRect(menu.x + 2, menu.y + 2, menu_x2 - 2, menu_y2 - 2, menu.bgcolor); + _screen->drawShadedBox(menu.x, menu.y, menu_x2, menu_y2, menu.color1, menu.color2); + + if (menu.field_10 != -1) + textX = menu.x; + else + textX = _text->getCenterStringX(menu.menuName, menu.x, menu_x2); + + textY = menu.y + menu.field_12; + + _text->printText(menu.menuName, textX - 1, textY + 1, 12, 248, 0); + _text->printText(menu.menuName, textX, textY, menu.textColor, 0, 0); + + int x1, y1, x2, y2; + for (int i = 0; i < menu.nrOfItems; i++) { + if (!menu.item[i].enabled) + continue; + + x1 = menu.x + menu.item[i].x; + y1 = menu.y + menu.item[i].y; + + x2 = x1 + menu.item[i].width - 1; + y2 = y1 + menu.item[i].height - 1; + + if (i < 6) { + _menuButtonData[i].nextButton = 0; + _menuButtonData[i].x = x1; + _menuButtonData[i].y = y1; + _menuButtonData[i].width = menu.item[i].width - 1; + _menuButtonData[i].height = menu.item[i].height - 1; + _menuButtonData[i].buttonCallback = menu.item[i].callback; + _menuButtonData[i].specialValue = menu.item[i].field_1b; + //_menuButtonData[i].field_6 = menu.item[i].field_25; + //_menuButtonData[i].field_8 = 0; + + if (!_menuButtonList) + _menuButtonList = &_menuButtonData[i]; + else + _menuButtonList = initButton(_menuButtonList, &_menuButtonData[i]); + } + _screen->fillRect(x1, y1, x2, y2, menu.item[i].bgcolor); + _screen->drawShadedBox(x1, y1, x2, y2, menu.item[i].color1, menu.item[i].color2); + + if (menu.item[i].itemString) { + if (menu.item[i].field_12 != -1 && _flags.lang == Common::EN_ANY) + textX = x1 + menu.item[i].field_12 + 3; + else + textX = _text->getCenterStringX(menu.item[i].itemString, x1, x2); + + textY = y1 + 2; + _text->printText(menu.item[i].itemString, textX - 1, textY + 1, 12, 0, 0); + + if (i == menu.highlightedItem) + _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].highlightColor, 0, 0); + else + _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].textColor, 0, 0); + + if (menu.item[i].labelString) { + _text->printText(menu.item[i].labelString, menu.x + menu.item[i].labelX - 1, menu.y + menu.item[i].labelY + 1, 12, 0, 0); + _text->printText(menu.item[i].labelString, menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, 253, 0, 0); + } + } + } + + if (menu.scrollUpBtnX != -1) { + _haveScrollButtons = true; + + _scrollUpButton.x = menu.scrollUpBtnX + menu.x; + _scrollUpButton.y = menu.scrollUpBtnY + menu.y; + _scrollUpButton.buttonCallback = &KyraEngine::gui_scrollUp; + _scrollUpButton.nextButton = 0; + _menuButtonList = initButton(_menuButtonList, &_scrollUpButton); + processMenuButton(&_scrollUpButton); + + _scrollDownButton.x = menu.scrollDownBtnX + menu.x; + _scrollDownButton.y = menu.scrollDownBtnY + menu.y; + _scrollDownButton.buttonCallback = &KyraEngine::gui_scrollDown; + _scrollDownButton.nextButton = 0; + _menuButtonList = initButton(_menuButtonList, &_scrollDownButton); + processMenuButton(&_scrollDownButton); + } else { + _haveScrollButtons = false; + } + + _screen->showMouse(); + _screen->updateScreen(); +} + +void KyraEngine::calcCoords(Menu &menu) { + assert(menu.nrOfItems < 7); + + int widthBackup = _screen->_charWidth; + _screen->_charWidth = -2; + + menu.x = (320 - menu.width)/2; + + int menu_x2 = menu.width + menu.x - 1; + int maxOffset = 0; + int x1, x2, y1, y2; + + for (int i = 0; i < menu.nrOfItems; i++) { + if (menu.item[i].x == -1) + menu.item[i].x = (menu.width - menu.item[i].width)/2; + + if (menu.item[i].labelString) { + x1 = menu.x + menu.item[i].x + 25; + y1 = (200 - menu.height)/2 + menu.item[i].y; + + x2 = x1 + menu.item[i].width; + y2 = y1 + menu.item[i].height; + + int textWidth = _screen->getTextWidth(menu.item[i].labelString) + 25; + int textX = menu.item[i].labelX + menu.x; + + if (textWidth + textX > x1) { + int offset = ((textWidth + textX) - x1); + if (maxOffset < offset) + maxOffset = offset; + } + } + + if (menu.item[i].itemString) { + int textWidth = _screen->getTextWidth(menu.item[i].itemString) + 15; + + if (menu.item[i].width < textWidth) { + menu.item[i].width = textWidth; + + if ( menu.x + menu.item[i].x + menu.item[i].width > menu_x2) + menu.item[i].x -= (menu.x + menu.item[i].x + menu.item[i].width) - menu_x2 + 10; + } + } + + } + + if (maxOffset > 0) { + maxOffset = maxOffset/2; + for (int i = 0; i < menu.nrOfItems; i++) { + menu.item[i].x += maxOffset + 10; + menu.item[i].labelX -= maxOffset; + } + menu.width += maxOffset; + } + + if (menu.menuName != 0) { + int menuNameLength = _screen->getTextWidth(menu.menuName); + if (menuNameLength > menu.width) + menu.width = menuNameLength; + } + + if (menu.width > 310) + menu.width = 310; + + menu.x = (320 - menu.width)/2; + + if (menu.y == -1) + menu.y = (200 - menu.height)/2; + + _screen->_charWidth = widthBackup; +} + +void KyraEngine::gui_getInput() { + Common::Event event; + static uint32 lastScreenUpdate = 0; + uint32 now = _system->getMillis(); + + _mouseWheel = 0; + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + quitGame(); + break; + case Common::EVENT_LBUTTONDOWN: + _mousePressFlag = true; + break; + case Common::EVENT_LBUTTONUP: + _mousePressFlag = false; + break; + case Common::EVENT_MOUSEMOVE: + _system->updateScreen(); + lastScreenUpdate = now; + break; + case Common::EVENT_WHEELUP: + _mouseWheel = -1; + break; + case Common::EVENT_WHEELDOWN: + _mouseWheel = 1; + break; + case Common::EVENT_KEYDOWN: + _keyPressed = event.kbd; + break; + default: + break; + } + } + + if (now - lastScreenUpdate > 50) { + _system->updateScreen(); + lastScreenUpdate = now; + } + + _system->delayMillis(3); +} + +int KyraEngine::gui_resumeGame(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_resumeGame()"); + processMenuButton(button); + _displayMenu = false; + + return 0; +} + +const char *KyraEngine::getSavegameFilename(int num) { + static char saveLoadSlot[12]; + + sprintf(saveLoadSlot, "%s.%.3d", _targetName.c_str(), num); + return saveLoadSlot; +} + +int KyraEngine::getNextSavegameSlot() { + Common::InSaveFile *in; + + for (int i = 1; i < 1000; i++) { + if ((in = _saveFileMan->openForLoading(getSavegameFilename(i)))) + delete in; + else + return i; + } + warning("Didn't save: Ran out of savegame filenames"); + return 0; +} + +void KyraEngine::setupSavegames(Menu &menu, int num) { + Common::InSaveFile *in; + static char savenames[5][31]; + uint8 startSlot; + assert(num <= 5); + + if (_savegameOffset == 0) { + menu.item[0].itemString = _specialSavegameString; + menu.item[0].enabled = 1; + menu.item[0].field_1b = 0; + startSlot = 1; + } else { + startSlot = 0; + } + + for (int i = startSlot; i < num; i++) { + if ((in = _saveFileMan->openForLoading(getSavegameFilename(i + _savegameOffset)))) { + in->skip(8); + in->read(savenames[i], 31); + menu.item[i].itemString = savenames[i]; + menu.item[i].enabled = 1; + menu.item[i].field_1b = i + _savegameOffset; + delete in; + } else { + menu.item[i].enabled = 0; + //menu.item[i].itemString = ""; + //menu.item[i].field_1b = -1; + } + } +} + +int KyraEngine::gui_saveGameMenu(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_saveGameMenu()"); + processMenuButton(button); + _menu[2].item[5].enabled = true; + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + _menu[2].menuName = _guiStrings[8]; // Select a position to save to: + _specialSavegameString = _guiStrings[9]; // [ EMPTY SLOT ] + for (int i = 0; i < 5; i++) + _menu[2].item[i].callback = &KyraEngine::gui_saveGame; + + _savegameOffset = 0; + setupSavegames(_menu[2], 5); + + initMenu(_menu[2]); + processAllMenuButtons(); + + _displaySubMenu = true; + _cancelSubMenu = false; + + while (_displaySubMenu && !_quitFlag) { + gui_getInput(); + gui_processHighlights(_menu[2]); + processButtonList(_menuButtonList); + } + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + if (_cancelSubMenu) { + initMenu(_menu[0]); + processAllMenuButtons(); + } else { + _displayMenu = false; + } + return 0; +} + +int KyraEngine::gui_loadGameMenu(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_loadGameMenu()"); + if (_menuDirectlyToLoad) { + _menu[2].item[5].enabled = false; + } else { + processMenuButton(button); + _menu[2].item[5].enabled = true; + } + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + _specialSavegameString = _newGameString[0]; //[ START A NEW GAME ] + _menu[2].menuName = _guiStrings[7]; // Which game would you like to reload? + for (int i = 0; i < 5; i++) + _menu[2].item[i].callback = &KyraEngine::gui_loadGame; + + _savegameOffset = 0; + setupSavegames(_menu[2], 5); + + initMenu(_menu[2]); + processAllMenuButtons(); + + _displaySubMenu = true; + _cancelSubMenu = false; + + while (_displaySubMenu && !_quitFlag) { + gui_getInput(); + gui_processHighlights(_menu[2]); + processButtonList(_menuButtonList); + } + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + if (_cancelSubMenu) { + initMenu(_menu[_toplevelMenu]); + processAllMenuButtons(); + } else { + gui_restorePalette(); + loadGame(getSavegameFilename(_gameToLoad)); + _displayMenu = false; + _menuRestoreScreen = false; + } + return 0; +} + +void KyraEngine::gui_redrawTextfield() { + _screen->fillRect(38, 91, 287, 102, 250); + _text->printText(_savegameName, 38, 92, 253, 0, 0); + + _screen->_charWidth = -2; + int width = _screen->getTextWidth(_savegameName); + _screen->fillRect(39 + width, 93, 45 + width, 100, 254); + _screen->_charWidth = 0; + + _screen->updateScreen(); +} + +void KyraEngine::gui_updateSavegameString() { + int length; + + if (_keyPressed.keycode) { + length = strlen(_savegameName); + + if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127) { + if (length < 31) { + _savegameName[length] = _keyPressed.ascii; + _savegameName[length+1] = 0; + gui_redrawTextfield(); + } + } else if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE || + _keyPressed.keycode == Common::KEYCODE_DELETE) { + if (length > 0) { + _savegameName[length-1] = 0; + gui_redrawTextfield(); + } + } else if (_keyPressed.keycode == Common::KEYCODE_RETURN || + _keyPressed.keycode == Common::KEYCODE_KP_ENTER) { + _displaySubMenu = false; + } + } + + _keyPressed.reset(); +} + +int KyraEngine::gui_saveGame(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_saveGame()"); + processMenuButton(button); + _gameToLoad = button->specialValue; + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + initMenu(_menu[3]); + processAllMenuButtons(); + + _displaySubMenu = true; + _cancelSubMenu = false; + + if (_savegameOffset == 0 && _gameToLoad == 0) { + _savegameName[0] = 0; + } else { + for (int i = 0; i < 5; i++) { + if (_menu[2].item[i].field_1b == _gameToLoad) { + strncpy(_savegameName, _menu[2].item[i].itemString, 31); + break; + } + } + } + gui_redrawTextfield(); + + while (_displaySubMenu && !_quitFlag) { + gui_getInput(); + gui_updateSavegameString(); + gui_processHighlights(_menu[3]); + processButtonList(_menuButtonList); + } + + if (_cancelSubMenu) { + _displaySubMenu = true; + _cancelSubMenu = false; + initMenu(_menu[2]); + processAllMenuButtons(); + } else { + if (_savegameOffset == 0 && _gameToLoad == 0) + _gameToLoad = getNextSavegameSlot(); + if (_gameToLoad > 0) + saveGame(getSavegameFilename(_gameToLoad), _savegameName); + } + + return 0; +} + +int KyraEngine::gui_savegameConfirm(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_savegameConfirm()"); + processMenuButton(button); + _displaySubMenu = false; + + return 0; +} + +int KyraEngine::gui_loadGame(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_loadGame()"); + processMenuButton(button); + _displaySubMenu = false; + _gameToLoad = button->specialValue; + + return 0; +} + +int KyraEngine::gui_cancelSubMenu(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_cancelLoadGameMenu()"); + processMenuButton(button); + _displaySubMenu = false; + _cancelSubMenu = true; + + return 0; +} + +int KyraEngine::gui_quitPlaying(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitPlaying()"); + processMenuButton(button); + + if (gui_quitConfirm(_guiStrings[14])) { // Are you sure you want to quit playing? + quitGame(); + } else { + initMenu(_menu[_toplevelMenu]); + processAllMenuButtons(); + } + + return 0; +} + +bool KyraEngine::gui_quitConfirm(const char *str) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitConfirm()"); + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + _menu[1].menuName = str; + calcCoords(_menu[1]); + initMenu(_menu[1]); + + _displaySubMenu = true; + _cancelSubMenu = true; + + while (_displaySubMenu && !_quitFlag) { + gui_getInput(); + gui_processHighlights(_menu[1]); + processButtonList(_menuButtonList); + } + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + return !_cancelSubMenu; +} + +int KyraEngine::gui_quitConfirmYes(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitConfirmYes()"); + processMenuButton(button); + _displaySubMenu = false; + _cancelSubMenu = false; + + return 0; +} + +int KyraEngine::gui_quitConfirmNo(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_quitConfirmNo()"); + processMenuButton(button); + _displaySubMenu = false; + _cancelSubMenu = true; + + return 0; +} + +int KyraEngine::gui_gameControlsMenu(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_gameControlsMenu()"); + + readSettings(); + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + if (_flags.isTalkie) { + //_menu[5].width = 230; + + for (int i = 0; i < 5; i++) { + //_menu[5].item[i].labelX = 24; + //_menu[5].item[i].x = 115; + //_menu[5].item[i].width = 94; + } + + _menu[5].item[3].labelString = _voiceTextString; //"Voice / Text " + _menu[5].item[3].callback = &KyraEngine::gui_controlsChangeVoice; + + } else { + //_menu[5].height = 136; + //_menu[5].item[5].y = 110; + _menu[5].item[4].enabled = 0; + _menu[5].item[3].labelString = _textSpeedString; // "Text speed " + _menu[5].item[3].callback = &KyraEngine::gui_controlsChangeText; + } + + gui_setupControls(_menu[5]); + + processAllMenuButtons(); + + _displaySubMenu = true; + _cancelSubMenu = false; + + while (_displaySubMenu && !_quitFlag) { + gui_getInput(); + gui_processHighlights(_menu[5]); + processButtonList(_menuButtonList); + } + + _screen->loadPageFromDisk("SEENPAGE.TMP", 0); + _screen->savePageToDisk("SEENPAGE.TMP", 0); + + if (_cancelSubMenu) { + initMenu(_menu[_toplevelMenu]); + processAllMenuButtons(); + } + return 0; +} + +void KyraEngine::gui_setupControls(Menu &menu) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_setupControls()"); + + switch (_configMusic) { + case 0: + menu.item[0].itemString = _offString; //"Off" + break; + case 1: + menu.item[0].itemString = _onString; //"On" + break; + case 2: + menu.item[0].itemString = _onCDString; //"On + CD" + break; + } + + if (_configSounds) + menu.item[1].itemString = _onString; //"On" + else + menu.item[1].itemString = _offString; //"Off" + + + switch (_configWalkspeed) { + case 0: + menu.item[2].itemString = _configStrings[0]; //"Slowest" + break; + case 1: + menu.item[2].itemString = _configStrings[1]; //"Slow" + break; + case 2: + menu.item[2].itemString = _configStrings[2]; //"Normal" + break; + case 3: + menu.item[2].itemString = _configStrings[3]; //"Fast" + break; + case 4: + menu.item[2].itemString = _configStrings[4]; //"Fastest" + break; + default: + menu.item[2].itemString = "ERROR"; + break; + } + + int textControl = 3; + int clickableOffset = 8; + if (_flags.isTalkie) { + textControl = 4; + clickableOffset = 11; + + if (_configVoice == 0) + _menu[5].item[4].enabled = 1; + else + _menu[5].item[4].enabled = 0; + + switch (_configVoice) { + case 0: + menu.item[3].itemString = _configStrings[5]; //"Text only" + break; + case 1: + menu.item[3].itemString = _configStrings[6]; //"Voice only" + break; + case 2: + menu.item[3].itemString = _configStrings[7]; //"Voice & Text" + break; + default: + menu.item[3].itemString = "ERROR"; + break; + } + } + + switch (_configTextspeed) { + case 0: + menu.item[textControl].itemString = _configStrings[1]; //"Slow" + break; + case 1: + menu.item[textControl].itemString = _configStrings[2]; //"Normal" + break; + case 2: + menu.item[textControl].itemString = _configStrings[3]; //"Fast" + break; + case 3: + menu.item[textControl].itemString = _configStrings[clickableOffset]; //"Clickable" + break; + default: + menu.item[textControl].itemString = "ERROR"; + break; + } + + calcCoords(menu); + initMenu(menu); +} + +int KyraEngine::gui_controlsChangeMusic(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeMusic()"); + processMenuButton(button); + + _configMusic = ++_configMusic % (_flags.platform == Common::kPlatformFMTowns ? 3 : 2); + gui_setupControls(_menu[5]); + return 0; +} + +int KyraEngine::gui_controlsChangeSounds(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeSounds()"); + processMenuButton(button); + + _configSounds = !_configSounds; + gui_setupControls(_menu[5]); + return 0; +} + +int KyraEngine::gui_controlsChangeWalk(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeWalk()"); + processMenuButton(button); + + _configWalkspeed = ++_configWalkspeed % 5; + setWalkspeed(_configWalkspeed); + gui_setupControls(_menu[5]); + return 0; +} + +int KyraEngine::gui_controlsChangeText(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeText()"); + processMenuButton(button); + + _configTextspeed = ++_configTextspeed % 4; + gui_setupControls(_menu[5]); + return 0; +} + +int KyraEngine::gui_controlsChangeVoice(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsChangeVoice()"); + processMenuButton(button); + + _configVoice = ++_configVoice % 3; + gui_setupControls(_menu[5]); + return 0; +} + +int KyraEngine::gui_controlsApply(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_controlsApply()"); + writeSettings(); + return gui_cancelSubMenu(button); +} + +int KyraEngine::gui_scrollUp(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_scrollUp()"); + processMenuButton(button); + + if (_savegameOffset > 0) { + _savegameOffset--; + setupSavegames(_menu[2], 5); + initMenu(_menu[2]); + } + return 0; +} + +int KyraEngine::gui_scrollDown(Button *button) { + debugC(9, kDebugLevelGUI, "KyraEngine::gui_scrollDown()"); + processMenuButton(button); + + _savegameOffset++; + setupSavegames(_menu[2], 5); + initMenu(_menu[2]); + + return 0; +} + +void KyraEngine::gui_processHighlights(Menu &menu) { + int x1, y1, x2, y2; + + Common::Point mouse = getMousePos(); + for (int i = 0; i < menu.nrOfItems; i++) { + if (!menu.item[i].enabled) + continue; + + x1 = menu.x + menu.item[i].x; + y1 = menu.y + menu.item[i].y; + + x2 = x1 + menu.item[i].width; + y2 = y1 + menu.item[i].height; + + if (mouse.x > x1 && mouse.x < x2 && + mouse.y > y1 && mouse.y < y2) { + + if (menu.highlightedItem != i) { + if (menu.item[menu.highlightedItem].enabled ) + gui_redrawText(menu); + + menu.highlightedItem = i; + gui_redrawHighlight(menu); + _screen->updateScreen(); + } + } + } +} + +void KyraEngine::gui_redrawText(Menu menu) { + int textX; + int i = menu.highlightedItem; + + int x1 = menu.x + menu.item[i].x; + int y1 = menu.y + menu.item[i].y; + + int x2 = x1 + menu.item[i].width - 1; + + if (menu.item[i].field_12 != -1 &&_flags.lang == Common::EN_ANY) + textX = x1 + menu.item[i].field_12 + 3; + else + textX = _text->getCenterStringX(menu.item[i].itemString, x1, x2); + + int textY = y1 + 2; + _text->printText(menu.item[i].itemString, textX - 1, textY + 1, 12, 0, 0); + _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].textColor, 0, 0); +} + +void KyraEngine::gui_redrawHighlight(Menu menu) { + int textX; + int i = menu.highlightedItem; + + int x1 = menu.x + menu.item[i].x; + int y1 = menu.y + menu.item[i].y; + + int x2 = x1 + menu.item[i].width - 1; + + if (menu.item[i].field_12 != -1 &&_flags.lang == Common::EN_ANY) + textX = x1 + menu.item[i].field_12 + 3; + else + textX = _text->getCenterStringX(menu.item[i].itemString, x1, x2); + + int textY = y1 + 2; + _text->printText(menu.item[i].itemString, textX - 1, textY + 1, 12, 0, 0); + _text->printText(menu.item[i].itemString, textX, textY, menu.item[i].highlightColor, 0, 0); +} + +void KyraEngine::gui_fadePalette() { + if (_flags.platform == Common::kPlatformAmiga) + return; + + static int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; + int index = 0; + + memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); + + for (int i = 0; i < 768; i++) + _screen->_currentPalette[i] >>= 1; + + while (menuPalIndexes[index] != -1) { + memcpy(&_screen->_currentPalette[menuPalIndexes[index]*3], &_screen->getPalette(2)[menuPalIndexes[index]*3], 3); + index++; + } + + _screen->fadePalette(_screen->_currentPalette, 2); +} + +void KyraEngine::gui_restorePalette() { + if (_flags.platform == Common::kPlatformAmiga) + return; + + memcpy(_screen->_currentPalette, _screen->getPalette(2), 768); + _screen->fadePalette(_screen->_currentPalette, 2); +} + +#pragma mark - + +// Kyra 2 and 3 main menu + +void KyraEngine::gui_updateMainMenuAnimation() { + _screen->updateScreen(); +} + +bool KyraEngine::gui_mainMenuGetInput() { + Common::Event event; + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_QUIT: + quitGame(); + break; + case Common::EVENT_LBUTTONUP: + return true; + default: + break; + } + } + return false; +} + +int KyraEngine::gui_handleMainMenu() { + debugC(9, kDebugLevelMain, "KyraEngine::gui_handleMainMenu()"); + int command = -1; + + uint8 colorMap[16]; + memset(colorMap, 0, sizeof(colorMap)); + _screen->setTextColorMap(colorMap); + + const char * const *strings = &_mainMenuStrings[_lang << 2]; + Screen::FontId oldFont = _screen->setFont(Screen::FID_8_FNT); + int charWidthBackUp = _screen->_charWidth; + + _screen->_charWidth = -2; + _screen->setScreenDim(3); + int backUpX = _screen->_curDim->sx; + int backUpY = _screen->_curDim->sy; + int backUpWidth = _screen->_curDim->w; + int backUpHeight = _screen->_curDim->h; + _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 0, 3); + + int x = _screen->_curDim->sx << 3; + int y = _screen->_curDim->sy; + int width = _screen->_curDim->w << 3; + int height = _screen->_curDim->h; + + gui_drawMainBox(x, y, width, height, 1); + gui_drawMainBox(x + 1, y + 1, width - 2, height - 2, 0); + + int selected = 0; + + gui_drawMainMenu(strings, selected); + + _screen->showMouse(); + + int fh = _screen->getFontHeight(); + int textPos = ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3; + + Common::Rect menuRect(x + 16, y + 4, x + width - 16, y + 4 + fh * 4); + + while (!_quitFlag) { + gui_updateMainMenuAnimation(); + bool mousePressed = gui_mainMenuGetInput(); + + Common::Point mouse = getMousePos(); + if (menuRect.contains(mouse)) { + int item = (mouse.y - menuRect.top) / fh; + + if (item != selected) { + gui_printString(strings[selected], textPos, menuRect.top + selected * fh, 0x80, 0, 5); + gui_printString(strings[item], textPos, menuRect.top + item * fh, 0xFF, 0, 5); + + selected = item; + } + + if (mousePressed) { + // TODO: Flash the text + command = item; + break; + } + } + _system->delayMillis(10); + } + + if (_quitFlag) + command = -1; + + _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 3, 0); + _screen->_charWidth = charWidthBackUp; + _screen->setFont(oldFont); + + return command; +} + +void KyraEngine::gui_drawMainMenu(const char * const *strings, int select) { + debugC(9, kDebugLevelMain, "KyraEngine::gui_drawMainMenu(%p)", (const void*)strings); + static const uint16 menuTable[] = { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x80, 0xFF, 0x00, 0x01, 0x02, 0x03 }; + + int top = _screen->_curDim->sy; + top += menuTable[1]; + + for (int i = 0; i < menuTable[3]; ++i) { + int curY = top + i * _screen->getFontHeight(); + int color = (i == select) ? menuTable[6] : menuTable[5]; + gui_printString(strings[i], ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5); + } +} + +void KyraEngine::gui_drawMainBox(int x, int y, int w, int h, int fill) { + debugC(9, kDebugLevelMain, "KyraEngine::gui_drawMainBox(%d, %d, %d, %d, %d)", x, y, w, h, fill); + static const uint8 kyra3ColorTable[] = { 0x16, 0x19, 0x1A, 0x16 }; + static const uint8 kyra2ColorTable[] = { 0x0, 0x19, 0x28, 0xc8 }; + + const uint8 *colorTable; + if (_flags.gameID == GI_KYRA3) + colorTable = kyra3ColorTable; + else + colorTable = kyra2ColorTable; + + --w; --h; + + if (fill) + _screen->fillRect(x, y, x+w, y+h, colorTable[0]); + + _screen->drawClippedLine(x, y+h, x+w, y+h, colorTable[1]); + _screen->drawClippedLine(x+w, y, x+w, y+h, colorTable[1]); + _screen->drawClippedLine(x, y, x+w, y, colorTable[2]); + _screen->drawClippedLine(x, y, x, y+h, colorTable[2]); + + _screen->setPagePixel(_screen->_curPage, x, y+h, colorTable[3]); + _screen->setPagePixel(_screen->_curPage, x+w, y, colorTable[3]); +} + +void KyraEngine::gui_printString(const char *format, int x, int y, int col1, int col2, int flags, ...) { + debugC(9, kDebugLevelMain, "KyraEngine::gui_printString('%s', %d, %d, %d, %d, %d, ...)", format, x, y, col1, col2, flags); + if (!format) + return; + + char string[512]; + va_list vaList; + va_start(vaList, flags); + vsprintf(string, format, vaList); + va_end(vaList); + + if (flags & 1) + x -= _screen->getTextWidth(string) >> 1; + + if (flags & 2) + x -= _screen->getTextWidth(string); + + if (flags & 4) { + _screen->printText(string, x - 1, y, 240, col2); + _screen->printText(string, x, y + 1, 240, col2); + } + + if (flags & 8) { + _screen->printText(string, x - 1, y, 227, col2); + _screen->printText(string, x, y + 1, 227, col2); + } + + _screen->printText(string, x, y, col1, col2); +} + +} // end of namespace Kyra + diff --git a/engines/kyra/items.cpp b/engines/kyra/items.cpp deleted file mode 100644 index 2a1a08b7de..0000000000 --- a/engines/kyra/items.cpp +++ /dev/null @@ -1,944 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#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) { - debugC(9, kDebugLevelMain, "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() { - debugC(9, kDebugLevelMain, "KyraEngine::clearNoDropRects()"); - memset(_noDropRects, -1, sizeof(_noDropRects)); -} - -byte KyraEngine::findFreeItemInScene(int scene) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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: - 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) { - debugC(9, kDebugLevelMain, "KyraEngine::createMouseItem(%d)", item); - _screen->hideMouse(); - setMouseItem(item); - _itemInHand = item; - _screen->showMouse(); -} - -void KyraEngine::destroyMouseItem() { - debugC(9, kDebugLevelMain, "KyraEngine::destroyMouseItem()"); - _screen->hideMouse(); - _screen->setMouseCursor(1, 1, _shapes[0]); - _itemInHand = -1; - _screen->showMouse(); -} - -void KyraEngine::setMouseItem(int item) { - debugC(9, kDebugLevelMain, "KyraEngine::setMouseItem(%d)", item); - if (item == -1) - _screen->setMouseCursor(1, 1, _shapes[6]); - else - _screen->setMouseCursor(8, 15, _shapes[216+item]); -} - -void KyraEngine::wipeDownMouseItem(int xpos, int ypos) { - debugC(9, kDebugLevelMain, "KyraEngine::wipeDownMouseItem(%d, %d)", xpos, ypos); - if (_itemInHand == -1) - return; - xpos -= 8; - ypos -= 15; - _screen->hideMouse(); - backUpItemRect1(xpos, ypos); - int y = ypos; - int height = 16; - - while (height >= 0) { - restoreItemRect1(xpos, ypos); - _screen->setNewShapeHeight(_shapes[216+_itemInHand], height); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, _shapes[216+_itemInHand], xpos, y, 0, 0); - _screen->updateScreen(); - y += 2; - height -= 2; - delayUntil(nextTime); - } - restoreItemRect1(xpos, ypos); - _screen->resetShapeHeight(_shapes[216+_itemInHand]); - destroyMouseItem(); - _screen->showMouse(); -} - -void KyraEngine::setupSceneItems() { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "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; - - backUpItemRect0(drawX, y - 16); - - while (tempY < destY) { - restoreItemRect0(drawX, tempY - 16); - tempY += addY; - if (tempY > destY) - tempY = destY; - ++addY; - drawY = tempY - 16; - backUpItemRect0(drawX, drawY); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, _shapes[216+item], drawX, drawY, 0, 0); - _screen->updateScreen(); - delayUntil(nextTime); - } - - 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; - restoreItemRect0(drawX, drawY); - tempY += addY; - unkX += xDiff; - if (tempY > destY) - tempY = destY; - ++addY; - drawX = (unkX >> 4) - 8; - drawY = tempY - 16; - backUpItemRect0(drawX, drawY); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, _shapes[216+item], drawX, drawY, 0, 0); - _screen->updateScreen(); - delayUntil(nextTime); - } - restoreItemRect0(drawX, drawY); - } else { - restoreItemRect0(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) { - debugC(9, kDebugLevelMain, "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); - assert(_noDropList); - if (12 == countItemsInScene(_currentCharacter->sceneId)) - drawSentenceCommand(_noDropList[0], 6); - else - drawSentenceCommand(_noDropList[1], 6); -} - -void KyraEngine::itemSpecialFX(int x, int y, int item) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "KyraEngine::itemSpecialFX1(%d, %d, %d)", x, y, item); - uint8 *shape = _shapes[216+item]; - x -= 8; - int startY = y; - y -= 15; - _screen->hideMouse(); - backUpItemRect0(x, y); - for (int i = 1; i <= 16; ++i) { - _screen->setNewShapeHeight(shape, i); - --startY; - restoreItemRect0(x, y); - uint32 nextTime = _system->getMillis() + 1 * _tickLength; - _screen->drawShape(0, shape, x, startY, 0, 0); - _screen->updateScreen(); - delayUntil(nextTime); - } - restoreItemRect0(x, y); - _screen->showMouse(); -} - -void KyraEngine::itemSpecialFX2(int x, int y, int item) { - debugC(9, kDebugLevelMain, "KyraEngine::itemSpecialFX2(%d, %d, %d)", x, y, item); - x -= 8; - y -= 15; - int yAdd = (int8)(((16 - _itemTable[item].height) >> 1) & 0xFF); - backUpItemRect0(x, y); - if (item >= 80 && item <= 89) - snd_playSoundEffect(55); - - for (int i = 201; i <= 205; ++i) { - restoreItemRect0(x, y); - uint32 nextTime = _system->getMillis() + 3 * _tickLength; - _screen->drawShape(0, _shapes[i], x, y + yAdd, 0, 0); - _screen->updateScreen(); - delayUntil(nextTime); - } - - for (int i = 204; i >= 201; --i) { - restoreItemRect0(x, y); - uint32 nextTime = _system->getMillis() + 3 * _tickLength; - _screen->drawShape(0, _shapes[216+item], x, y, 0, 0); - _screen->drawShape(0, _shapes[i], x, y + yAdd, 0, 0); - _screen->updateScreen(); - delayUntil(nextTime); - } - restoreItemRect0(x, y); -} - -void KyraEngine::magicOutMouseItem(int animIndex, int itemPos) { - debugC(9, kDebugLevelMain, "KyraEngine::magicOutMouseItem(%d, %d)", animIndex, itemPos); - int videoPageBackUp = _screen->_curPage; - _screen->_curPage = 0; - int x = 0, y = 0; - if (itemPos == -1) { - Common::Point mouse = getMousePos(); - x = mouse.x - 12; - y = mouse.y - 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(); - backUpItemRect1(x, y); - - for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { - restoreItemRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - _screen->drawShape(0, _shapes[216+_itemInHand], x + 4, y + 3, 0, 0); - if (tableIndex == -1) - _screen->drawShape(0, _shapes[shape], x, y, 0, 0); - else - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - _screen->updateScreen(); - delayUntil(nextTime); - } - - if (itemPos != -1) { - restoreItemRect1(x, y); - _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, 12, 0); - backUpItemRect1(x, y); - } - - for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { - restoreItemRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - _screen->drawShape(0, _shapes[216+_itemInHand], x + 4, y + 3, 0, 0); - if (tableIndex == -1) - _screen->drawShape(0, _shapes[shape], x, y, 0, 0); - else - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - _screen->updateScreen(); - delayUntil(nextTime); - } - restoreItemRect1(x, y); - if (itemPos == -1) { - _screen->setMouseCursor(1, 1, _shapes[0]); - _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) { - debugC(9, kDebugLevelMain, "KyraEngine::magicInMouseItem(%d, %d, %d)", animIndex, item, itemPos); - int videoPageBackUp = _screen->_curPage; - _screen->_curPage = 0; - int x = 0, y = 0; - if (itemPos == -1) { - Common::Point mouse = getMousePos(); - x = mouse.x - 12; - y = mouse.y - 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(); - backUpItemRect1(x, y); - if (animIndex == 2) - snd_playSoundEffect(0x5E); - else - snd_playSoundEffect(0x37); - - for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { - restoreItemRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - if (tableIndex == -1) - _screen->drawShape(0, _shapes[shape], x, y, 0, 0); - else - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - _screen->updateScreen(); - delayUntil(nextTime); - } - - for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { - restoreItemRect1(x, y); - uint32 nextTime = _system->getMillis() + 4 * _tickLength; - if (tableIndex == -1) - _screen->drawShape(0, _shapes[shape], x, y, 0, 0); - else - specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); - _screen->updateScreen(); - delayUntil(nextTime); - } - restoreItemRect1(x, y); - if (itemPos == -1) { - _screen->setMouseCursor(8, 15, _shapes[216+item]); - _itemInHand = item; - } else { - _characterList[0].inventoryItems[itemPos] = item; - _screen->hideMouse(); - _screen->drawShape(0, _shapes[216+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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "KyraEngine::processSpecialMouseItemFX(%d, %d, %d, %d, %d, %d)", shape, x, y, tableValue, loopStart, maxLoops); - uint8 shapeColorTable[16]; - uint8 *shapePtr = _shapes[shape] + 10; - if (_flags.useAltShapeHeader) - 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[shape], x, y, 0, 0x8000, shapeColorTable); -} - -void KyraEngine::updatePlayerItemsForScene() { - debugC(9, kDebugLevelMain, "KyraEngine::updatePlayerItemsForScene()"); - if (_itemInHand >= 29 && _itemInHand < 33) { - ++_itemInHand; - if (_itemInHand > 33) - _itemInHand = 33; - _screen->hideMouse(); - _screen->setMouseCursor(8, 15, _shapes[216+_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[216+item], _itemPosX[i], _itemPosY[i], 0, 0); - } - } - _screen->showMouse(); - _screen->_curPage = videoPageBackUp; - _screen->updateScreen(); -} - -void KyraEngine::backUpItemRect0(int xpos, int ypos) { - debugC(9, kDebugLevelMain, "KyraEngine::backUpItemRect0(%d, %d)", xpos, ypos); - _screen->rectClip(xpos, ypos, 3<<3, 24); - _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 3<<3, 24, _itemBkgBackUp[0]); -} - -void KyraEngine::restoreItemRect0(int xpos, int ypos) { - debugC(9, kDebugLevelMain, "KyraEngine::restoreItemRect0(%d, %d)", xpos, ypos); - _screen->rectClip(xpos, ypos, 3<<3, 24); - _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 3<<3, 24, _itemBkgBackUp[0]); -} - -void KyraEngine::backUpItemRect1(int xpos, int ypos) { - debugC(9, kDebugLevelMain, "KyraEngine::backUpItemRect1(%d, %d)", xpos, ypos); - _screen->rectClip(xpos, ypos, 4<<3, 32); - _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]); -} - -void KyraEngine::restoreItemRect1(int xpos, int ypos) { - debugC(9, kDebugLevelMain, "KyraEngine::restoreItemRect1(%d, %d)", xpos, ypos); - _screen->rectClip(xpos, ypos, 4<<3, 32); - _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]); -} - -} // end of namespace Kyra - diff --git a/engines/kyra/items_v1.cpp b/engines/kyra/items_v1.cpp new file mode 100644 index 0000000000..2a1a08b7de --- /dev/null +++ b/engines/kyra/items_v1.cpp @@ -0,0 +1,944 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#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) { + debugC(9, kDebugLevelMain, "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() { + debugC(9, kDebugLevelMain, "KyraEngine::clearNoDropRects()"); + memset(_noDropRects, -1, sizeof(_noDropRects)); +} + +byte KyraEngine::findFreeItemInScene(int scene) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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: + 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) { + debugC(9, kDebugLevelMain, "KyraEngine::createMouseItem(%d)", item); + _screen->hideMouse(); + setMouseItem(item); + _itemInHand = item; + _screen->showMouse(); +} + +void KyraEngine::destroyMouseItem() { + debugC(9, kDebugLevelMain, "KyraEngine::destroyMouseItem()"); + _screen->hideMouse(); + _screen->setMouseCursor(1, 1, _shapes[0]); + _itemInHand = -1; + _screen->showMouse(); +} + +void KyraEngine::setMouseItem(int item) { + debugC(9, kDebugLevelMain, "KyraEngine::setMouseItem(%d)", item); + if (item == -1) + _screen->setMouseCursor(1, 1, _shapes[6]); + else + _screen->setMouseCursor(8, 15, _shapes[216+item]); +} + +void KyraEngine::wipeDownMouseItem(int xpos, int ypos) { + debugC(9, kDebugLevelMain, "KyraEngine::wipeDownMouseItem(%d, %d)", xpos, ypos); + if (_itemInHand == -1) + return; + xpos -= 8; + ypos -= 15; + _screen->hideMouse(); + backUpItemRect1(xpos, ypos); + int y = ypos; + int height = 16; + + while (height >= 0) { + restoreItemRect1(xpos, ypos); + _screen->setNewShapeHeight(_shapes[216+_itemInHand], height); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, _shapes[216+_itemInHand], xpos, y, 0, 0); + _screen->updateScreen(); + y += 2; + height -= 2; + delayUntil(nextTime); + } + restoreItemRect1(xpos, ypos); + _screen->resetShapeHeight(_shapes[216+_itemInHand]); + destroyMouseItem(); + _screen->showMouse(); +} + +void KyraEngine::setupSceneItems() { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "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; + + backUpItemRect0(drawX, y - 16); + + while (tempY < destY) { + restoreItemRect0(drawX, tempY - 16); + tempY += addY; + if (tempY > destY) + tempY = destY; + ++addY; + drawY = tempY - 16; + backUpItemRect0(drawX, drawY); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, _shapes[216+item], drawX, drawY, 0, 0); + _screen->updateScreen(); + delayUntil(nextTime); + } + + 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; + restoreItemRect0(drawX, drawY); + tempY += addY; + unkX += xDiff; + if (tempY > destY) + tempY = destY; + ++addY; + drawX = (unkX >> 4) - 8; + drawY = tempY - 16; + backUpItemRect0(drawX, drawY); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, _shapes[216+item], drawX, drawY, 0, 0); + _screen->updateScreen(); + delayUntil(nextTime); + } + restoreItemRect0(drawX, drawY); + } else { + restoreItemRect0(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) { + debugC(9, kDebugLevelMain, "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); + assert(_noDropList); + if (12 == countItemsInScene(_currentCharacter->sceneId)) + drawSentenceCommand(_noDropList[0], 6); + else + drawSentenceCommand(_noDropList[1], 6); +} + +void KyraEngine::itemSpecialFX(int x, int y, int item) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "KyraEngine::itemSpecialFX1(%d, %d, %d)", x, y, item); + uint8 *shape = _shapes[216+item]; + x -= 8; + int startY = y; + y -= 15; + _screen->hideMouse(); + backUpItemRect0(x, y); + for (int i = 1; i <= 16; ++i) { + _screen->setNewShapeHeight(shape, i); + --startY; + restoreItemRect0(x, y); + uint32 nextTime = _system->getMillis() + 1 * _tickLength; + _screen->drawShape(0, shape, x, startY, 0, 0); + _screen->updateScreen(); + delayUntil(nextTime); + } + restoreItemRect0(x, y); + _screen->showMouse(); +} + +void KyraEngine::itemSpecialFX2(int x, int y, int item) { + debugC(9, kDebugLevelMain, "KyraEngine::itemSpecialFX2(%d, %d, %d)", x, y, item); + x -= 8; + y -= 15; + int yAdd = (int8)(((16 - _itemTable[item].height) >> 1) & 0xFF); + backUpItemRect0(x, y); + if (item >= 80 && item <= 89) + snd_playSoundEffect(55); + + for (int i = 201; i <= 205; ++i) { + restoreItemRect0(x, y); + uint32 nextTime = _system->getMillis() + 3 * _tickLength; + _screen->drawShape(0, _shapes[i], x, y + yAdd, 0, 0); + _screen->updateScreen(); + delayUntil(nextTime); + } + + for (int i = 204; i >= 201; --i) { + restoreItemRect0(x, y); + uint32 nextTime = _system->getMillis() + 3 * _tickLength; + _screen->drawShape(0, _shapes[216+item], x, y, 0, 0); + _screen->drawShape(0, _shapes[i], x, y + yAdd, 0, 0); + _screen->updateScreen(); + delayUntil(nextTime); + } + restoreItemRect0(x, y); +} + +void KyraEngine::magicOutMouseItem(int animIndex, int itemPos) { + debugC(9, kDebugLevelMain, "KyraEngine::magicOutMouseItem(%d, %d)", animIndex, itemPos); + int videoPageBackUp = _screen->_curPage; + _screen->_curPage = 0; + int x = 0, y = 0; + if (itemPos == -1) { + Common::Point mouse = getMousePos(); + x = mouse.x - 12; + y = mouse.y - 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(); + backUpItemRect1(x, y); + + for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { + restoreItemRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + _screen->drawShape(0, _shapes[216+_itemInHand], x + 4, y + 3, 0, 0); + if (tableIndex == -1) + _screen->drawShape(0, _shapes[shape], x, y, 0, 0); + else + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + _screen->updateScreen(); + delayUntil(nextTime); + } + + if (itemPos != -1) { + restoreItemRect1(x, y); + _screen->fillRect(_itemPosX[itemPos], _itemPosY[itemPos], _itemPosX[itemPos] + 15, _itemPosY[itemPos] + 15, 12, 0); + backUpItemRect1(x, y); + } + + for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { + restoreItemRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + _screen->drawShape(0, _shapes[216+_itemInHand], x + 4, y + 3, 0, 0); + if (tableIndex == -1) + _screen->drawShape(0, _shapes[shape], x, y, 0, 0); + else + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + _screen->updateScreen(); + delayUntil(nextTime); + } + restoreItemRect1(x, y); + if (itemPos == -1) { + _screen->setMouseCursor(1, 1, _shapes[0]); + _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) { + debugC(9, kDebugLevelMain, "KyraEngine::magicInMouseItem(%d, %d, %d)", animIndex, item, itemPos); + int videoPageBackUp = _screen->_curPage; + _screen->_curPage = 0; + int x = 0, y = 0; + if (itemPos == -1) { + Common::Point mouse = getMousePos(); + x = mouse.x - 12; + y = mouse.y - 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(); + backUpItemRect1(x, y); + if (animIndex == 2) + snd_playSoundEffect(0x5E); + else + snd_playSoundEffect(0x37); + + for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) { + restoreItemRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + if (tableIndex == -1) + _screen->drawShape(0, _shapes[shape], x, y, 0, 0); + else + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + _screen->updateScreen(); + delayUntil(nextTime); + } + + for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) { + restoreItemRect1(x, y); + uint32 nextTime = _system->getMillis() + 4 * _tickLength; + if (tableIndex == -1) + _screen->drawShape(0, _shapes[shape], x, y, 0, 0); + else + specialMouseItemFX(shape, x, y, animIndex, tableIndex, loopStart, maxLoops); + _screen->updateScreen(); + delayUntil(nextTime); + } + restoreItemRect1(x, y); + if (itemPos == -1) { + _screen->setMouseCursor(8, 15, _shapes[216+item]); + _itemInHand = item; + } else { + _characterList[0].inventoryItems[itemPos] = item; + _screen->hideMouse(); + _screen->drawShape(0, _shapes[216+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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "KyraEngine::processSpecialMouseItemFX(%d, %d, %d, %d, %d, %d)", shape, x, y, tableValue, loopStart, maxLoops); + uint8 shapeColorTable[16]; + uint8 *shapePtr = _shapes[shape] + 10; + if (_flags.useAltShapeHeader) + 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[shape], x, y, 0, 0x8000, shapeColorTable); +} + +void KyraEngine::updatePlayerItemsForScene() { + debugC(9, kDebugLevelMain, "KyraEngine::updatePlayerItemsForScene()"); + if (_itemInHand >= 29 && _itemInHand < 33) { + ++_itemInHand; + if (_itemInHand > 33) + _itemInHand = 33; + _screen->hideMouse(); + _screen->setMouseCursor(8, 15, _shapes[216+_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[216+item], _itemPosX[i], _itemPosY[i], 0, 0); + } + } + _screen->showMouse(); + _screen->_curPage = videoPageBackUp; + _screen->updateScreen(); +} + +void KyraEngine::backUpItemRect0(int xpos, int ypos) { + debugC(9, kDebugLevelMain, "KyraEngine::backUpItemRect0(%d, %d)", xpos, ypos); + _screen->rectClip(xpos, ypos, 3<<3, 24); + _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 3<<3, 24, _itemBkgBackUp[0]); +} + +void KyraEngine::restoreItemRect0(int xpos, int ypos) { + debugC(9, kDebugLevelMain, "KyraEngine::restoreItemRect0(%d, %d)", xpos, ypos); + _screen->rectClip(xpos, ypos, 3<<3, 24); + _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 3<<3, 24, _itemBkgBackUp[0]); +} + +void KyraEngine::backUpItemRect1(int xpos, int ypos) { + debugC(9, kDebugLevelMain, "KyraEngine::backUpItemRect1(%d, %d)", xpos, ypos); + _screen->rectClip(xpos, ypos, 4<<3, 32); + _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]); +} + +void KyraEngine::restoreItemRect1(int xpos, int ypos) { + debugC(9, kDebugLevelMain, "KyraEngine::restoreItemRect1(%d, %d)", xpos, ypos); + _screen->rectClip(xpos, ypos, 4<<3, 32); + _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]); +} + +} // end of namespace Kyra + diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp deleted file mode 100644 index 95693684a1..0000000000 --- a/engines/kyra/saveload.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "common/endian.h" -#include "common/savefile.h" -#include "common/system.h" - -#include "kyra/kyra.h" -#include "kyra/animator.h" -#include "kyra/screen.h" -#include "kyra/resource.h" -#include "kyra/sound.h" - -#define CURRENT_VERSION 7 - -// TODO: our current savefiles still use the old -// flag system to check the version, we should -// change that some day, but for now it works -#define GF_FLOPPY (1 << 0) -#define GF_TALKIE (1 << 1) -#define GF_FMTOWNS (1 << 2) - -namespace Kyra { -void KyraEngine::loadGame(const char *fileName) { - debugC(9, kDebugLevelMain, "loadGame('%s')", fileName); - Common::InSaveFile *in; - - if (!(in = _saveFileMan->openForLoading(fileName))) { - warning("Can't open file '%s', game not loaded", fileName); - return; - } - - uint32 type = in->readUint32BE(); - - // FIXME: The kyra savegame code used to be endian unsafe. Uncomment the - // following line to graciously handle old savegames from LE machines. - // if (type != MKID_BE('KYRA') && type != MKID_BE('ARYK')) { - if (type != MKID_BE('KYRA')) { - warning("No Kyrandia 1 savefile header"); - delete in; - return; - } - uint32 version = in->readUint32BE(); - if (version > CURRENT_VERSION) { - warning("Savegame is not the right version (%d)", version); - delete in; - return; - } - - char saveName[31]; - in->read(saveName, 31); - - if (version >= 2) { - uint32 flags = in->readUint32BE(); - if ((flags & GF_FLOPPY) && _flags.isTalkie) { - warning("Can not load floppy savefile for this (non floppy) gameversion"); - delete in; - return; - } else if ((flags & GF_TALKIE) && !(_flags.isTalkie)) { - warning("Can not load cdrom savefile for this (non cdrom) gameversion"); - delete in; - return; - } else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns)) { - warning("can not load FM-Towns savefile for this (non FM-Towns) gameversion"); - delete in; - return; - } - } else { - warning("Make sure your savefile was from this version! (too old savefile version to detect that)"); - } - - snd_playSoundEffect(0x0A); - snd_playWanderScoreViaMap(0, 1); - - // unload the current voice file should fix some problems with voices - if (_currentRoom != 0xFFFF && _flags.isTalkie) { - char file[32]; - assert(_currentRoom < _roomTableSize); - int tableId = _roomTable[_currentRoom].nameIndex; - assert(tableId < _roomFilenameTableSize); - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".VRM"); - _res->unloadPakFile(file); - } - - int brandonX = 0, brandonY = 0; - for (int i = 0; i < 11; i++) { - _characterList[i].sceneId = in->readUint16BE(); - _characterList[i].height = in->readByte(); - _characterList[i].facing = in->readByte(); - _characterList[i].currentAnimFrame = in->readUint16BE(); - //_characterList[i].unk6 = in->readUint32BE(); - in->read(_characterList[i].inventoryItems, 10); - _characterList[i].x1 = in->readSint16BE(); - _characterList[i].y1 = in->readSint16BE(); - _characterList[i].x2 = in->readSint16BE(); - _characterList[i].y2 = in->readSint16BE(); - if (i == 0) { - brandonX = _characterList[i].x1; - brandonY = _characterList[i].y1; - } - //_characterList[i].field_20 = in->readUint16BE(); - //_characterList[i].field_23 = in->readUint16BE(); - } - - _marbleVaseItem = in->readSint16BE(); - _itemInHand = in->readByte(); - - for (int i = 0; i < 4; ++i) - _birthstoneGemTable[i] = in->readByte(); - for (int i = 0; i < 3; ++i) - _idolGemsTable[i] = in->readByte(); - for (int i = 0; i < 3; ++i) - _foyerItemTable[i] = in->readByte(); - _cauldronState = in->readByte(); - for (int i = 0; i < 2; ++i) - _crystalState[i] = in->readByte(); - - _brandonStatusBit = in->readUint16BE(); - _brandonStatusBit0x02Flag = in->readByte(); - _brandonStatusBit0x20Flag = in->readByte(); - in->read(_brandonPoisonFlagsGFX, 256); - _brandonInvFlag = in->readSint16BE(); - _poisonDeathCounter = in->readByte(); - _animator->_brandonDrawFrame = in->readUint16BE(); - - for (int i = 0; i < 32; i++) { - _timers[i].active = in->readByte(); - _timers[i].countdown = in->readSint32BE(); - _timers[i].nextRun = in->readUint32BE(); - if (_timers[i].nextRun != 0) - _timers[i].nextRun += _system->getMillis(); - } - _timerNextRun = 0; - - memset(_flagsTable, 0, sizeof(_flagsTable)); - uint32 flagsSize = in->readUint32BE(); - assert(flagsSize <= sizeof(_flagsTable)); - in->read(_flagsTable, flagsSize); - - for (int i = 0; i < _roomTableSize; ++i) { - for (int item = 0; item < 12; ++item) { - _roomTable[i].itemsTable[item] = 0xFF; - _roomTable[i].itemsXPos[item] = 0xFFFF; - _roomTable[i].itemsYPos[item] = 0xFF; - _roomTable[i].needInit[item] = 0; - } - } - - uint16 sceneId = 0; - - while (true) { - sceneId = in->readUint16BE(); - if (sceneId == 0xFFFF) - break; - assert(sceneId < _roomTableSize); - _roomTable[sceneId].nameIndex = in->readByte(); - - for (int i = 0; i < 12; i++) { - _roomTable[sceneId].itemsTable[i] = in->readByte(); - _roomTable[sceneId].itemsXPos[i] = in->readUint16BE(); - _roomTable[sceneId].itemsYPos[i] = in->readUint16BE(); - _roomTable[sceneId].needInit[i] = in->readByte(); - } - } - if (version >= 3) { - _lastMusicCommand = in->readSint16BE(); - if (_lastMusicCommand != -1) - snd_playWanderScoreViaMap(_lastMusicCommand, 1); - } - - // Version 4 stored settings in the savegame. As of version 5, they are - // handled by the config manager. - - if (version == 4) { - in->readByte(); // Text speed - in->readByte(); // Walk speed - in->readByte(); // Music - in->readByte(); // Sound - in->readByte(); // Voice - } - - if (version >= 7) { - _curSfxFile = in->readByte(); - - // In the first version there this entry was introduced, - // it wasn't made sure that _curSfxFile was initialized - // so if it's out of bounds we just set it to 0. - if (_curSfxFile >= _soundFilesTownsCount || _curSfxFile < 0) - _curSfxFile = 0; - - if (_flags.platform == Common::kPlatformFMTowns) - _sound->loadSoundFile(_curSfxFile); - } - - _screen->_disableScreen = true; - loadMainScreen(8); - - if (queryGameFlag(0x2D)) { - _screen->loadBitmap("AMULET3.CPS", 10, 10, 0); - if (!queryGameFlag(0xF1)) { - for (int i = 0x55; i <= 0x5A; ++i) { - if (queryGameFlag(i)) - seq_createAmuletJewel(i-0x55, 10, 1, 1); - } - } - _screen->copyRegion(0, 0, 0, 0, 320, 200, 10, 8); - _screen->copyRegion(0, 0, 0, 0, 320, 200, 8, 0); - } - - createMouseItem(_itemInHand); - _animator->setBrandonAnimSeqSize(3, 48); - redrawInventory(0); - _animator->_noDrawShapesFlag = 1; - enterNewScene(_currentCharacter->sceneId, _currentCharacter->facing, 0, 0, 1); - _animator->_noDrawShapesFlag = 0; - - _currentCharacter->x1 = brandonX; - _currentCharacter->y1 = brandonY; - _animator->animRefreshNPC(0); - _animator->restoreAllObjectBackgrounds(); - _animator->preserveAnyChangedBackgrounds(); - _animator->prepDrawAllObjects(); - _animator->copyChangedObjectsForward(0); - _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); - _screen->_disableScreen = false; - _screen->updateScreen(); - - _abortWalkFlag = true; - _abortWalkFlag2 = false; - _mousePressFlag = false; - _system->warpMouse(brandonX, brandonY); - - if (in->ioFailed()) - error("Load failed."); - else - debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", saveName); - - // We didn't explicitly set the walk speed, but it's saved as part of - // the _timers array, so we need to re-sync it with _configWalkspeed. - setWalkspeed(_configWalkspeed); - - delete in; -} - -void KyraEngine::saveGame(const char *fileName, const char *saveName) { - debugC(9, kDebugLevelMain, "saveGame('%s', '%s')", fileName, saveName); - Common::OutSaveFile *out; - if (_quitFlag) return; - - if (!(out = _saveFileMan->openForSaving(fileName))) { - warning("Can't create file '%s', game not saved", fileName); - return; - } - - // Savegame version - out->writeUint32BE(MKID_BE('KYRA')); - out->writeUint32BE(CURRENT_VERSION); - out->write(saveName, 31); - if (_flags.isTalkie) - out->writeUint32BE(GF_TALKIE); - else if (_flags.platform == Common::kPlatformFMTowns) - out->writeUint32BE(GF_FMTOWNS); - else - out->writeUint32BE(GF_FLOPPY); - - for (int i = 0; i < 11; i++) { - out->writeUint16BE(_characterList[i].sceneId); - out->writeByte(_characterList[i].height); - out->writeByte(_characterList[i].facing); - out->writeUint16BE(_characterList[i].currentAnimFrame); - //out->writeUint32BE(_characterList[i].unk6); - out->write(_characterList[i].inventoryItems, 10); - out->writeSint16BE(_characterList[i].x1); - out->writeSint16BE(_characterList[i].y1); - out->writeSint16BE(_characterList[i].x2); - out->writeSint16BE(_characterList[i].y2); - //out->writeUint16BE(_characterList[i].field_20); - //out->writeUint16BE(_characterList[i].field_23); - } - - out->writeSint16BE(_marbleVaseItem); - out->writeByte(_itemInHand); - - for (int i = 0; i < 4; ++i) - out->writeByte(_birthstoneGemTable[i]); - for (int i = 0; i < 3; ++i) - out->writeByte(_idolGemsTable[i]); - for (int i = 0; i < 3; ++i) - out->writeByte(_foyerItemTable[i]); - out->writeByte(_cauldronState); - for (int i = 0; i < 2; ++i) - out->writeByte(_crystalState[i]); - - out->writeUint16BE(_brandonStatusBit); - out->writeByte(_brandonStatusBit0x02Flag); - out->writeByte(_brandonStatusBit0x20Flag); - out->write(_brandonPoisonFlagsGFX, 256); - out->writeSint16BE(_brandonInvFlag); - out->writeByte(_poisonDeathCounter); - out->writeUint16BE(_animator->_brandonDrawFrame); - - for (int i = 0; i < 32; i++) { - out->writeByte(_timers[i].active); - out->writeSint32BE(_timers[i].countdown); - if (_system->getMillis() >= _timers[i].nextRun) - out->writeUint32BE(0); - else - out->writeUint32BE(_timers[i].nextRun - _system->getMillis()); - } - - out->writeUint32BE(sizeof(_flagsTable)); - out->write(_flagsTable, sizeof(_flagsTable)); - - for (uint16 i = 0; i < _roomTableSize; i++) { - out->writeUint16BE(i); - out->writeByte(_roomTable[i].nameIndex); - for (int a = 0; a < 12; a++) { - out->writeByte(_roomTable[i].itemsTable[a]); - out->writeUint16BE(_roomTable[i].itemsXPos[a]); - out->writeUint16BE(_roomTable[i].itemsYPos[a]); - out->writeByte(_roomTable[i].needInit[a]); - } - } - // room table terminator - out->writeUint16BE(0xFFFF); - - out->writeSint16BE(_lastMusicCommand); - - out->writeByte(_curSfxFile); - - out->finalize(); - - // check for errors - if (out->ioFailed()) - warning("Can't write file '%s'. (Disk full?)", fileName); - else - debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); - - delete out; -} -} // end of namespace Kyra - diff --git a/engines/kyra/saveload_v1.cpp b/engines/kyra/saveload_v1.cpp new file mode 100644 index 0000000000..95693684a1 --- /dev/null +++ b/engines/kyra/saveload_v1.cpp @@ -0,0 +1,366 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/endian.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "kyra/kyra.h" +#include "kyra/animator.h" +#include "kyra/screen.h" +#include "kyra/resource.h" +#include "kyra/sound.h" + +#define CURRENT_VERSION 7 + +// TODO: our current savefiles still use the old +// flag system to check the version, we should +// change that some day, but for now it works +#define GF_FLOPPY (1 << 0) +#define GF_TALKIE (1 << 1) +#define GF_FMTOWNS (1 << 2) + +namespace Kyra { +void KyraEngine::loadGame(const char *fileName) { + debugC(9, kDebugLevelMain, "loadGame('%s')", fileName); + Common::InSaveFile *in; + + if (!(in = _saveFileMan->openForLoading(fileName))) { + warning("Can't open file '%s', game not loaded", fileName); + return; + } + + uint32 type = in->readUint32BE(); + + // FIXME: The kyra savegame code used to be endian unsafe. Uncomment the + // following line to graciously handle old savegames from LE machines. + // if (type != MKID_BE('KYRA') && type != MKID_BE('ARYK')) { + if (type != MKID_BE('KYRA')) { + warning("No Kyrandia 1 savefile header"); + delete in; + return; + } + uint32 version = in->readUint32BE(); + if (version > CURRENT_VERSION) { + warning("Savegame is not the right version (%d)", version); + delete in; + return; + } + + char saveName[31]; + in->read(saveName, 31); + + if (version >= 2) { + uint32 flags = in->readUint32BE(); + if ((flags & GF_FLOPPY) && _flags.isTalkie) { + warning("Can not load floppy savefile for this (non floppy) gameversion"); + delete in; + return; + } else if ((flags & GF_TALKIE) && !(_flags.isTalkie)) { + warning("Can not load cdrom savefile for this (non cdrom) gameversion"); + delete in; + return; + } else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns)) { + warning("can not load FM-Towns savefile for this (non FM-Towns) gameversion"); + delete in; + return; + } + } else { + warning("Make sure your savefile was from this version! (too old savefile version to detect that)"); + } + + snd_playSoundEffect(0x0A); + snd_playWanderScoreViaMap(0, 1); + + // unload the current voice file should fix some problems with voices + if (_currentRoom != 0xFFFF && _flags.isTalkie) { + char file[32]; + assert(_currentRoom < _roomTableSize); + int tableId = _roomTable[_currentRoom].nameIndex; + assert(tableId < _roomFilenameTableSize); + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".VRM"); + _res->unloadPakFile(file); + } + + int brandonX = 0, brandonY = 0; + for (int i = 0; i < 11; i++) { + _characterList[i].sceneId = in->readUint16BE(); + _characterList[i].height = in->readByte(); + _characterList[i].facing = in->readByte(); + _characterList[i].currentAnimFrame = in->readUint16BE(); + //_characterList[i].unk6 = in->readUint32BE(); + in->read(_characterList[i].inventoryItems, 10); + _characterList[i].x1 = in->readSint16BE(); + _characterList[i].y1 = in->readSint16BE(); + _characterList[i].x2 = in->readSint16BE(); + _characterList[i].y2 = in->readSint16BE(); + if (i == 0) { + brandonX = _characterList[i].x1; + brandonY = _characterList[i].y1; + } + //_characterList[i].field_20 = in->readUint16BE(); + //_characterList[i].field_23 = in->readUint16BE(); + } + + _marbleVaseItem = in->readSint16BE(); + _itemInHand = in->readByte(); + + for (int i = 0; i < 4; ++i) + _birthstoneGemTable[i] = in->readByte(); + for (int i = 0; i < 3; ++i) + _idolGemsTable[i] = in->readByte(); + for (int i = 0; i < 3; ++i) + _foyerItemTable[i] = in->readByte(); + _cauldronState = in->readByte(); + for (int i = 0; i < 2; ++i) + _crystalState[i] = in->readByte(); + + _brandonStatusBit = in->readUint16BE(); + _brandonStatusBit0x02Flag = in->readByte(); + _brandonStatusBit0x20Flag = in->readByte(); + in->read(_brandonPoisonFlagsGFX, 256); + _brandonInvFlag = in->readSint16BE(); + _poisonDeathCounter = in->readByte(); + _animator->_brandonDrawFrame = in->readUint16BE(); + + for (int i = 0; i < 32; i++) { + _timers[i].active = in->readByte(); + _timers[i].countdown = in->readSint32BE(); + _timers[i].nextRun = in->readUint32BE(); + if (_timers[i].nextRun != 0) + _timers[i].nextRun += _system->getMillis(); + } + _timerNextRun = 0; + + memset(_flagsTable, 0, sizeof(_flagsTable)); + uint32 flagsSize = in->readUint32BE(); + assert(flagsSize <= sizeof(_flagsTable)); + in->read(_flagsTable, flagsSize); + + for (int i = 0; i < _roomTableSize; ++i) { + for (int item = 0; item < 12; ++item) { + _roomTable[i].itemsTable[item] = 0xFF; + _roomTable[i].itemsXPos[item] = 0xFFFF; + _roomTable[i].itemsYPos[item] = 0xFF; + _roomTable[i].needInit[item] = 0; + } + } + + uint16 sceneId = 0; + + while (true) { + sceneId = in->readUint16BE(); + if (sceneId == 0xFFFF) + break; + assert(sceneId < _roomTableSize); + _roomTable[sceneId].nameIndex = in->readByte(); + + for (int i = 0; i < 12; i++) { + _roomTable[sceneId].itemsTable[i] = in->readByte(); + _roomTable[sceneId].itemsXPos[i] = in->readUint16BE(); + _roomTable[sceneId].itemsYPos[i] = in->readUint16BE(); + _roomTable[sceneId].needInit[i] = in->readByte(); + } + } + if (version >= 3) { + _lastMusicCommand = in->readSint16BE(); + if (_lastMusicCommand != -1) + snd_playWanderScoreViaMap(_lastMusicCommand, 1); + } + + // Version 4 stored settings in the savegame. As of version 5, they are + // handled by the config manager. + + if (version == 4) { + in->readByte(); // Text speed + in->readByte(); // Walk speed + in->readByte(); // Music + in->readByte(); // Sound + in->readByte(); // Voice + } + + if (version >= 7) { + _curSfxFile = in->readByte(); + + // In the first version there this entry was introduced, + // it wasn't made sure that _curSfxFile was initialized + // so if it's out of bounds we just set it to 0. + if (_curSfxFile >= _soundFilesTownsCount || _curSfxFile < 0) + _curSfxFile = 0; + + if (_flags.platform == Common::kPlatformFMTowns) + _sound->loadSoundFile(_curSfxFile); + } + + _screen->_disableScreen = true; + loadMainScreen(8); + + if (queryGameFlag(0x2D)) { + _screen->loadBitmap("AMULET3.CPS", 10, 10, 0); + if (!queryGameFlag(0xF1)) { + for (int i = 0x55; i <= 0x5A; ++i) { + if (queryGameFlag(i)) + seq_createAmuletJewel(i-0x55, 10, 1, 1); + } + } + _screen->copyRegion(0, 0, 0, 0, 320, 200, 10, 8); + _screen->copyRegion(0, 0, 0, 0, 320, 200, 8, 0); + } + + createMouseItem(_itemInHand); + _animator->setBrandonAnimSeqSize(3, 48); + redrawInventory(0); + _animator->_noDrawShapesFlag = 1; + enterNewScene(_currentCharacter->sceneId, _currentCharacter->facing, 0, 0, 1); + _animator->_noDrawShapesFlag = 0; + + _currentCharacter->x1 = brandonX; + _currentCharacter->y1 = brandonY; + _animator->animRefreshNPC(0); + _animator->restoreAllObjectBackgrounds(); + _animator->preserveAnyChangedBackgrounds(); + _animator->prepDrawAllObjects(); + _animator->copyChangedObjectsForward(0); + _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); + _screen->_disableScreen = false; + _screen->updateScreen(); + + _abortWalkFlag = true; + _abortWalkFlag2 = false; + _mousePressFlag = false; + _system->warpMouse(brandonX, brandonY); + + if (in->ioFailed()) + error("Load failed."); + else + debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", saveName); + + // We didn't explicitly set the walk speed, but it's saved as part of + // the _timers array, so we need to re-sync it with _configWalkspeed. + setWalkspeed(_configWalkspeed); + + delete in; +} + +void KyraEngine::saveGame(const char *fileName, const char *saveName) { + debugC(9, kDebugLevelMain, "saveGame('%s', '%s')", fileName, saveName); + Common::OutSaveFile *out; + if (_quitFlag) return; + + if (!(out = _saveFileMan->openForSaving(fileName))) { + warning("Can't create file '%s', game not saved", fileName); + return; + } + + // Savegame version + out->writeUint32BE(MKID_BE('KYRA')); + out->writeUint32BE(CURRENT_VERSION); + out->write(saveName, 31); + if (_flags.isTalkie) + out->writeUint32BE(GF_TALKIE); + else if (_flags.platform == Common::kPlatformFMTowns) + out->writeUint32BE(GF_FMTOWNS); + else + out->writeUint32BE(GF_FLOPPY); + + for (int i = 0; i < 11; i++) { + out->writeUint16BE(_characterList[i].sceneId); + out->writeByte(_characterList[i].height); + out->writeByte(_characterList[i].facing); + out->writeUint16BE(_characterList[i].currentAnimFrame); + //out->writeUint32BE(_characterList[i].unk6); + out->write(_characterList[i].inventoryItems, 10); + out->writeSint16BE(_characterList[i].x1); + out->writeSint16BE(_characterList[i].y1); + out->writeSint16BE(_characterList[i].x2); + out->writeSint16BE(_characterList[i].y2); + //out->writeUint16BE(_characterList[i].field_20); + //out->writeUint16BE(_characterList[i].field_23); + } + + out->writeSint16BE(_marbleVaseItem); + out->writeByte(_itemInHand); + + for (int i = 0; i < 4; ++i) + out->writeByte(_birthstoneGemTable[i]); + for (int i = 0; i < 3; ++i) + out->writeByte(_idolGemsTable[i]); + for (int i = 0; i < 3; ++i) + out->writeByte(_foyerItemTable[i]); + out->writeByte(_cauldronState); + for (int i = 0; i < 2; ++i) + out->writeByte(_crystalState[i]); + + out->writeUint16BE(_brandonStatusBit); + out->writeByte(_brandonStatusBit0x02Flag); + out->writeByte(_brandonStatusBit0x20Flag); + out->write(_brandonPoisonFlagsGFX, 256); + out->writeSint16BE(_brandonInvFlag); + out->writeByte(_poisonDeathCounter); + out->writeUint16BE(_animator->_brandonDrawFrame); + + for (int i = 0; i < 32; i++) { + out->writeByte(_timers[i].active); + out->writeSint32BE(_timers[i].countdown); + if (_system->getMillis() >= _timers[i].nextRun) + out->writeUint32BE(0); + else + out->writeUint32BE(_timers[i].nextRun - _system->getMillis()); + } + + out->writeUint32BE(sizeof(_flagsTable)); + out->write(_flagsTable, sizeof(_flagsTable)); + + for (uint16 i = 0; i < _roomTableSize; i++) { + out->writeUint16BE(i); + out->writeByte(_roomTable[i].nameIndex); + for (int a = 0; a < 12; a++) { + out->writeByte(_roomTable[i].itemsTable[a]); + out->writeUint16BE(_roomTable[i].itemsXPos[a]); + out->writeUint16BE(_roomTable[i].itemsYPos[a]); + out->writeByte(_roomTable[i].needInit[a]); + } + } + // room table terminator + out->writeUint16BE(0xFFFF); + + out->writeSint16BE(_lastMusicCommand); + + out->writeByte(_curSfxFile); + + out->finalize(); + + // check for errors + if (out->ioFailed()) + warning("Can't write file '%s'. (Disk full?)", fileName); + else + debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); + + delete out; +} +} // end of namespace Kyra + diff --git a/engines/kyra/scene.cpp b/engines/kyra/scene.cpp deleted file mode 100644 index a92fd9ce7c..0000000000 --- a/engines/kyra/scene.cpp +++ /dev/null @@ -1,1624 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#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) { - debugC(9, kDebugLevelMain, "KyraEngine::enterNewScene(%d, %d, %d, %d, %d)", sceneId, facing, unk1, unk2, brandonAlive); - int unkVar1 = 1; - _screen->hideMouse(); - _handleInput = false; - _abortWalkFlag = false; - _abortWalkFlag2 = false; - - if (_flags.platform == Common::kPlatformFMTowns) { - int newSfxFile = -1; - if (_currentCharacter->sceneId == 7 && sceneId == 24) - newSfxFile = 2; - else if (_currentCharacter->sceneId == 25 && sceneId == 109) - newSfxFile = 3; - else if (_currentCharacter->sceneId == 120 && sceneId == 37) - newSfxFile = 4; - else if (_currentCharacter->sceneId == 52 && sceneId == 199) - newSfxFile = 5; - else if (_currentCharacter->sceneId == 37 && sceneId == 120) - newSfxFile = 3; - else if (_currentCharacter->sceneId == 109 && sceneId == 25) - newSfxFile = 2; - else if (_currentCharacter->sceneId == 24 && sceneId == 7) - newSfxFile = 1; - - if (newSfxFile != -1) { - _curSfxFile = newSfxFile; - _sound->loadSoundFile(_curSfxFile); - } - } - - switch (_currentCharacter->sceneId) { - case 1: - if (sceneId == 0) { - moveCharacterToPos(0, 0, _currentCharacter->x1, 84); - unkVar1 = 0; - } - break; - - case 3: - if (sceneId == 2) { - moveCharacterToPos(0, 6, 155, _currentCharacter->y1); - unkVar1 = 0; - } - break; - - case 26: - if (sceneId == 27) { - moveCharacterToPos(0, 6, 155, _currentCharacter->y1); - unkVar1 = 0; - } - break; - - case 44: - if (sceneId == 45) { - moveCharacterToPos(0, 2, 192, _currentCharacter->y1); - unkVar1 = 0; - } - break; - - default: - break; - } - - if (unkVar1 && unk1) { - int xpos = _currentCharacter->x1; - int ypos = _currentCharacter->y1; - switch (facing) { - case 0: - ypos = _currentCharacter->y1 - 6; - break; - - case 2: - xpos = 336; - break; - - case 4: - ypos = 143; - break; - - case 6: - xpos = -16; - break; - - default: - break; - } - - moveCharacterToPos(0, facing, xpos, ypos); - } - - for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i) - _movieObjects[i]->close(); - - if (!brandonAlive) { - _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]; - - setupSceneResource(sceneId); - - _currentRoom = sceneId; - - int tableId = _roomTable[sceneId].nameIndex; - char fileNameBuffer[32]; - strcpy(fileNameBuffer, _roomFilenameTable[tableId]); - strcat(fileNameBuffer, ".DAT"); - _sprites->loadDat(fileNameBuffer, _sceneExits); - _sprites->setupSceneAnims(); - _scriptInterpreter->unloadScript(_scriptClickData); - loadSceneMsc(); - - _walkBlockNorth = currentRoom->northExit; - _walkBlockEast = currentRoom->eastExit; - _walkBlockSouth = currentRoom->southExit; - _walkBlockWest = currentRoom->westExit; - - if (_walkBlockNorth == 0xFFFF) - _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF)+3); - if (_walkBlockEast == 0xFFFF) - _screen->blockOutRegion(312, 0, 8, 139); - if (_walkBlockSouth == 0xFFFF) - _screen->blockOutRegion(0, 135, 320, 8); - if (_walkBlockWest == 0xFFFF) - _screen->blockOutRegion(0, 0, 8, 139); - - if (!brandonAlive) - updatePlayerItemsForScene(); - - startSceneScript(brandonAlive); - setupSceneItems(); - - initSceneData(facing, unk2, brandonAlive); - - _loopFlag2 = 0; - _screen->showMouse(); - if (!brandonAlive) - seq_poisonDeathNow(0); - updateMousePointer(true); - _changedScene = true; -} - -void KyraEngine::transcendScenes(int roomIndex, int roomName) { - debugC(9, kDebugLevelMain, "KyraEngine::transcendScenes(%d, %d)", roomIndex, roomName); - assert(roomIndex < _roomTableSize); - - if (_flags.isTalkie) { - char file[32]; - assert(roomIndex < _roomTableSize); - int tableId = _roomTable[roomIndex].nameIndex; - assert(tableId < _roomFilenameTableSize); - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".VRM"); - _res->unloadPakFile(file); - } - - _roomTable[roomIndex].nameIndex = roomName; - _unkScreenVar2 = 1; - _unkScreenVar3 = 1; - _unkScreenVar1 = 0; - _brandonPosX = _currentCharacter->x1; - _brandonPosY = _currentCharacter->y1; - enterNewScene(roomIndex, _currentCharacter->facing, 0, 0, 0); - _unkScreenVar1 = 1; - _unkScreenVar2 = 0; - _unkScreenVar3 = 0; -} - -void KyraEngine::setSceneFile(int roomIndex, int roomName) { - debugC(9, kDebugLevelMain, "KyraEngine::setSceneFile(%d, %d)", roomIndex, roomName); - assert(roomIndex < _roomTableSize); - _roomTable[roomIndex].nameIndex = roomName; -} - -void KyraEngine::moveCharacterToPos(int character, int facing, int xpos, int ypos) { - debugC(9, kDebugLevelMain, "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); - delayUntil(nextFrame, true); - } - break; - - case 2: - while (ch->x1 < xpos) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - delayUntil(nextFrame, true); - } - break; - - case 4: - while (ypos > ch->y1) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - delayUntil(nextFrame, true); - } - break; - - case 6: - while (ch->x1 > xpos) { - nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); - setCharacterPositionWithUpdate(character); - delayUntil(nextFrame, true); - } - break; - - default: - break; - } - - enableTimer(19); - enableTimer(14); - enableTimer(18); - _screen->showMouse(); -} - -void KyraEngine::setCharacterPositionWithUpdate(int character) { - debugC(9, kDebugLevelMain, "KyraEngine::setCharacterPositionWithUpdate(%d)", character); - setCharacterPosition(character, 0); - _sprites->updateSceneAnims(); - updateGameTimers(); - _animator->updateAllObjectShapes(); - updateTextFade(); - - if (_currentCharacter->sceneId == 210) - updateKyragemFading(); -} - -int KyraEngine::setCharacterPosition(int character, int *facingTable) { - debugC(9, kDebugLevelMain, "KyraEngine::setCharacterPosition(%d, %p)", character, (const void *)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) { - debugC(9, kDebugLevelMain, "KyraEngine::setCharacterPositionHelper(%d, %p)", character, (const void *)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 && (_brandonStatusBit & 0x10)) - ch->currentAnimFrame = 88; - - _animator->animRefreshNPC(character); -} - -int KyraEngine::getOppositeFacingDirection(int dir) { - debugC(9, kDebugLevelMain, "KyraEngine::getOppositeFacingDirection(%d)", dir); - switch (dir) { - case 0: - return 2; - case 1: - return 1; - case 3: - return 7; - case 4: - return 6; - case 5: - return 5; - case 6: - return 4; - case 7: - return 3; - 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); - _screen->loadBitmap(fileNameBuffer, 3, 5, 0); -} - -void KyraEngine::startSceneScript(int brandonAlive) { - debugC(9, kDebugLevelMain, "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"); - _screen->clearPage(3); - // FIXME: check this hack for amiga version - _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? _screen->getPalette(0) : 0)); - _sprites->loadSceneShapes(); - _exitListPtr = 0; - - _scaleMode = 1; - for (int i = 0; i < 145; ++i) - _scaleTable[i] = 256; - - clearNoDropRects(); - _scriptInterpreter->initScript(_scriptClick, _scriptClickData); - strcpy(fileNameBuffer, _roomFilenameTable[tableId]); - strcat(fileNameBuffer, ".EMC"); - _scriptInterpreter->unloadScript(_scriptClickData); - _scriptInterpreter->loadScript(fileNameBuffer, _scriptClickData, &_opcodes); - _scriptInterpreter->startScript(_scriptClick, 0); - _scriptClick->regs[0] = _currentCharacter->sceneId; - _scriptClick->regs[7] = brandonAlive; - - while (_scriptInterpreter->validScript(_scriptClick)) - _scriptInterpreter->runScript(_scriptClick); -} - -void KyraEngine::initSceneData(int facing, int unk1, int brandonAlive) { - debugC(9, kDebugLevelMain, "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->regs[4] = _itemInHand; - _scriptClick->regs[7] = brandonAlive; - _scriptInterpreter->startScript(_scriptClick, 3); - while (_scriptInterpreter->validScript(_scriptClick)) - _scriptInterpreter->runScript(_scriptClick); -} - -void KyraEngine::initSceneObjectList(int brandonAlive) { - debugC(9, kDebugLevelMain, "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[_currentCharacter->currentAnimFrame]; - curAnimState->animFrameNumber = _currentCharacter->currentAnimFrame; - startAnimFrame = _currentCharacter->currentAnimFrame-7; - int xOffset = _defaultShapeTable[startAnimFrame].xOffset; - int yOffset = _defaultShapeTable[startAnimFrame].yOffset; - - if (_scaleMode) { - curAnimState->x1 = _currentCharacter->x1; - curAnimState->y1 = _currentCharacter->y1; - - _animator->_brandonScaleX = _scaleTable[_currentCharacter->y1]; - _animator->_brandonScaleY = _scaleTable[_currentCharacter->y1]; - - curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8; - curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8; - } else { - curAnimState->x1 = _currentCharacter->x1 + xOffset; - curAnimState->y1 = _currentCharacter->y1 + yOffset; - } - - curAnimState->x2 = curAnimState->x1; - curAnimState->y2 = curAnimState->y1; - curAnimState->refreshFlag = 1; - curAnimState->bkgdChangeFlag = 1; - _animator->clearQueue(); - _animator->addObjectToQueue(curAnimState); - - int listAdded = 0; - int addedObjects = 1; - - for (int i = 1; i < 5; ++i) { - Character *ch = &_characterList[i]; - curAnimState = &_animator->actors()[addedObjects]; - if (ch->sceneId != _currentCharacter->sceneId) { - curAnimState->active = 0; - curAnimState->refreshFlag = 0; - curAnimState->bkgdChangeFlag = 0; - ++addedObjects; - continue; - } - - curAnimState->drawY = ch->y1; - curAnimState->sceneAnimPtr = _shapes[ch->currentAnimFrame]; - curAnimState->animFrameNumber = ch->currentAnimFrame; - startAnimFrame = ch->currentAnimFrame-7; - xOffset = _defaultShapeTable[startAnimFrame].xOffset; - yOffset = _defaultShapeTable[startAnimFrame].yOffset; - if (_scaleMode) { - curAnimState->x1 = ch->x1; - curAnimState->y1 = ch->y1; - - _animator->_brandonScaleX = _scaleTable[ch->y1]; - _animator->_brandonScaleY = _scaleTable[ch->y1]; - - curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8; - curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8; - } else { - curAnimState->x1 = ch->x1 + xOffset; - curAnimState->y1 = ch->y1 + yOffset; - } - curAnimState->x2 = curAnimState->x1; - curAnimState->y2 = curAnimState->y1; - curAnimState->active = 1; - curAnimState->refreshFlag = 1; - curAnimState->bkgdChangeFlag = 1; - - if (ch->facing >= 1 && ch->facing <= 3) - curAnimState->flags |= 1; - else if (ch->facing >= 5 && ch->facing <= 7) - curAnimState->flags &= 0xFFFFFFFE; - - _animator->addObjectToQueue(curAnimState); - - ++addedObjects; - ++listAdded; - if (listAdded < 2) - i = 5; - } - - for (int i = 0; i < 11; ++i) { - curAnimState = &_animator->sprites()[i]; - - if (_sprites->_anims[i].play) { - curAnimState->active = 1; - curAnimState->refreshFlag = 1; - curAnimState->bkgdChangeFlag = 1; - } else { - curAnimState->active = 0; - curAnimState->refreshFlag = 0; - curAnimState->bkgdChangeFlag = 0; - } - curAnimState->height = _sprites->_anims[i].height; - curAnimState->height2 = _sprites->_anims[i].height2; - curAnimState->width = _sprites->_anims[i].width + 1; - curAnimState->width2 = _sprites->_anims[i].width2; - curAnimState->drawY = _sprites->_anims[i].drawY; - curAnimState->x1 = curAnimState->x2 = _sprites->_anims[i].x; - curAnimState->y1 = curAnimState->y2 = _sprites->_anims[i].y; - curAnimState->background = _sprites->_anims[i].background; - curAnimState->sceneAnimPtr = _sprites->_sceneShapes[_sprites->_anims[i].sprite]; - - curAnimState->disable = _sprites->_anims[i].disable; - - if (_sprites->_anims[i].unk2) - curAnimState->flags = 0x800; - else - curAnimState->flags = 0; - - if (_sprites->_anims[i].flipX) - curAnimState->flags |= 0x1; - - _animator->addObjectToQueue(curAnimState); - } - - for (int i = 0; i < 12; ++i) { - curAnimState = &_animator->items()[i]; - Room *curRoom = &_roomTable[_currentCharacter->sceneId]; - byte curItem = curRoom->itemsTable[i]; - if (curItem != 0xFF) { - curAnimState->drawY = curRoom->itemsYPos[i]; - curAnimState->sceneAnimPtr = _shapes[216+curItem]; - curAnimState->animFrameNumber = (int16)0xFFFF; - curAnimState->y1 = curRoom->itemsYPos[i]; - curAnimState->x1 = curRoom->itemsXPos[i]; - - curAnimState->x1 -= (_animator->fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1; - curAnimState->y1 -= _animator->fetchAnimHeight(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY]); - - curAnimState->x2 = curAnimState->x1; - curAnimState->y2 = curAnimState->y1; - - curAnimState->active = 1; - curAnimState->refreshFlag = 1; - curAnimState->bkgdChangeFlag = 1; - - _animator->addObjectToQueue(curAnimState); - } else { - curAnimState->active = 0; - curAnimState->refreshFlag = 0; - curAnimState->bkgdChangeFlag = 0; - } - } - - _animator->preserveAnyChangedBackgrounds(); - curAnimState = _animator->actors(); - curAnimState->bkgdChangeFlag = 1; - curAnimState->refreshFlag = 1; - for (int i = 1; i < 28; ++i) { - curAnimState = &_animator->objects()[i]; - if (curAnimState->active) { - curAnimState->bkgdChangeFlag = 1; - curAnimState->refreshFlag = 1; - } - } - _animator->restoreAllObjectBackgrounds(); - _animator->preserveAnyChangedBackgrounds(); - _animator->prepDrawAllObjects(); - initSceneScreen(brandonAlive); - _animator->copyChangedObjectsForward(0); -} - -void KyraEngine::initSceneScreen(int brandonAlive) { - if (_flags.platform == Common::kPlatformAmiga) { - if (_unkScreenVar1 && !queryGameFlag(0xF0)) { - memset(_screen->getPalette(2), 0, 32*3); - if (_currentCharacter->sceneId != 117 || !queryGameFlag(0xB3)) - _screen->setScreenPalette(_screen->getPalette(2)); - } - - if (_unkScreenVar2 == 1) - _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false); - else - _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); - - if (_unkScreenVar1 && !queryGameFlag(0xA0)) { - if (_currentCharacter->sceneId == 45 && _paletteChanged) - memcpy(_screen->getPalette(0) + 12*3, _screen->getPalette(4) + 12*3, 2); - - if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245 && (_brandonStatusBit & 1)) - memcpy(_screen->getPalette(0), _screen->getPalette(0) + 320*3, 64); - - _screen->setScreenPalette(_screen->getPalette(0)); - } - } else { - if (_unkScreenVar1 && !queryGameFlag(0xA0)) { - for (int i = 0; i < 60; ++i) { - uint16 col = _screen->getPalette(0)[684+i]; - col += _screen->getPalette(1)[684+i] << 1; - col >>= 2; - _screen->getPalette(0)[684+i] = col; - } - _screen->setScreenPalette(_screen->getPalette(0)); - } - - if (_unkScreenVar2 == 1) - _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false); - else - _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); - - if (_unkScreenVar1 && _paletteChanged) { - if (!queryGameFlag(0xA0)) { - memcpy(_screen->getPalette(0) + 684, _screen->getPalette(1) + 684, 60); - _screen->setScreenPalette(_screen->getPalette(0)); - } else { - memset(_screen->getPalette(0), 0, 768); - } - } - } - - // really call this here? - _screen->updateScreen(); - - if (!_scriptInterpreter->startScript(_scriptClick, 2)) - error("Could not start script function 2 of scene script"); - - _scriptClick->regs[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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "KyraEngine::processSceneChange(%p, %d, %d)", (const void *)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; - _animator->animRefreshNPC(0); - _animator->updateAllObjectShapes(); - processInput(); - 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) { - updateGameTimers(); - - if (_currentCharacter->sceneId == 210) { - updateKyragemFading(); - if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) { - *table = 8; - running = false; - break; - } - } - - if ((nextFrame - _system->getMillis()) >= 10) - delay(10, true); - } - } - - if (frameReset && !(_brandonStatusBit & 2)) - _currentCharacter->currentAnimFrame = 7; - - _animator->animRefreshNPC(0); - _animator->updateAllObjectShapes(); - return returnValue; -} - -int KyraEngine::changeScene(int facing) { - debugC(9, kDebugLevelMain, "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 one time, seems to be some hack in the original - while (true) { - if (*ptr == -1) - break; - - if (*ptr > _currentCharacter->x1 || _currentCharacter->y1 < ptr[1] || _currentCharacter->x1 > ptr[2] || _currentCharacter->y1 > ptr[3]) { - ptr += 10; - break; - } - - _brandonPosX = ptr[6]; - _brandonPosY = ptr[7]; - uint16 sceneId = ptr[5]; - facing = ptr[4]; - int unk1 = ptr[8]; - int unk2 = ptr[9]; - - if (sceneId == 0xFFFF) { - switch (facing) { - case 0: - sceneId = _roomTable[_currentCharacter->sceneId].northExit; - break; - - case 2: - sceneId = _roomTable[_currentCharacter->sceneId].eastExit; - break; - - case 4: - sceneId = _roomTable[_currentCharacter->sceneId].southExit; - break; - - case 6: - sceneId = _roomTable[_currentCharacter->sceneId].westExit; - break; - - default: - break; - } - } - - _currentCharacter->facing = facing; - _animator->animRefreshNPC(0); - _animator->updateAllObjectShapes(); - enterNewScene(sceneId, facing, unk1, unk2, 0); - resetGameFlag(0xEE); - return 1; - } - } - - int returnValue = 0; - facing = 0; - - if ((_northExitHeight & 0xFF) + 2 >= ypos || (_northExitHeight & 0xFF) + 2 >= _currentCharacter->y1) { - facing = 0; - returnValue = 1; - } - - if (xpos >= 308 || (_currentCharacter->x1 + 4) >= 308) { - facing = 2; - returnValue = 1; - } - - if (((_northExitHeight >> 8) & 0xFF) - 2 < ypos || ((_northExitHeight >> 8) & 0xFF) - 2 < _currentCharacter->y1) { - facing = 4; - returnValue = 1; - } - - if (xpos <= 12 || _currentCharacter->y1 <= 12) { - facing = 6; - returnValue = 1; - } - - if (!returnValue) - return 0; - - uint16 sceneId = 0xFFFF; - switch (facing) { - case 0: - sceneId = _roomTable[_currentCharacter->sceneId].northExit; - break; - - case 2: - sceneId = _roomTable[_currentCharacter->sceneId].eastExit; - break; - - case 4: - sceneId = _roomTable[_currentCharacter->sceneId].southExit; - break; - - default: - sceneId = _roomTable[_currentCharacter->sceneId].westExit; - 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) { - debugC(9, kDebugLevelMain, "KyraEngine::findWay(%d, %d, %d, %d, %p, %d)", x, y, toX, toY, (const void *)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) { - debugC(9, kDebugLevelMain, "KyraEngine::findSubPath(%d, %d, %d, %d, %p, %d, %d)", x, y, toX, toY, (const void *)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) { - debugC(9, kDebugLevelMain, "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) { - debugC(9, kDebugLevelMain, "KyraEngine::changePosTowardsFacing(%d, %d, %d)", x, y, facing); - x += _addXPosTable[facing]; - y += _addYPosTable[facing]; -} - -bool KyraEngine::lineIsPassable(int x, int y) { - debugC(9, kDebugLevelMain, "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; - - if (y < 0) - y = 0; - - int ypos = 8; - if (_scaleMode) { - ypos = (_scaleTable[y] >> 5) + 1; - if (8 < ypos) - ypos = 8; - } - - x -= (ypos >> 1); - - int xpos = x; - int xtemp = xpos + ypos - 1; - if (x < 0) - xpos = 0; - - if (xtemp > 319) - xtemp = 319; - - for (; xpos < xtemp; ++xpos) { - if (!_screen->getShapeFlag1(xpos, y)) - return false; - } - return true; -} - -int KyraEngine::getMoveTableSize(int *moveTable) { - debugC(9, kDebugLevelMain, "KyraEngine::getMoveTableSize(%p)", (const void *)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; -} - -void KyraEngine::setupSceneResource(int sceneId) { - debugC(9, kDebugLevelMain, "KyraEngine::setupSceneResource(%d)", sceneId); - if (!_flags.isTalkie) - return; - - if (_currentRoom != 0xFFFF) { - assert(_currentRoom < _roomTableSize); - int tableId = _roomTable[_currentRoom].nameIndex; - assert(tableId < _roomFilenameTableSize); - - // unload our old room - char file[64]; - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".VRM"); - _res->unloadPakFile(file); - - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".PAK"); - _res->unloadPakFile(file); - - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".APK"); - _res->unloadPakFile(file); - } - - assert(sceneId < _roomTableSize); - int tableId = _roomTable[sceneId].nameIndex; - assert(tableId < _roomFilenameTableSize); - - // load our new room - char file[64]; - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".VRM"); - if (Common::File::exists(file)) - _res->loadPakFile(file); - - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".PAK"); - if (Common::File::exists(file)) - _res->loadPakFile(file); - - strcpy(file, _roomFilenameTable[tableId]); - strcat(file, ".APK"); - if (Common::File::exists(file)) - _res->loadPakFile(file); -} - -} // end of namespace Kyra - diff --git a/engines/kyra/scene_v1.cpp b/engines/kyra/scene_v1.cpp new file mode 100644 index 0000000000..a92fd9ce7c --- /dev/null +++ b/engines/kyra/scene_v1.cpp @@ -0,0 +1,1624 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#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) { + debugC(9, kDebugLevelMain, "KyraEngine::enterNewScene(%d, %d, %d, %d, %d)", sceneId, facing, unk1, unk2, brandonAlive); + int unkVar1 = 1; + _screen->hideMouse(); + _handleInput = false; + _abortWalkFlag = false; + _abortWalkFlag2 = false; + + if (_flags.platform == Common::kPlatformFMTowns) { + int newSfxFile = -1; + if (_currentCharacter->sceneId == 7 && sceneId == 24) + newSfxFile = 2; + else if (_currentCharacter->sceneId == 25 && sceneId == 109) + newSfxFile = 3; + else if (_currentCharacter->sceneId == 120 && sceneId == 37) + newSfxFile = 4; + else if (_currentCharacter->sceneId == 52 && sceneId == 199) + newSfxFile = 5; + else if (_currentCharacter->sceneId == 37 && sceneId == 120) + newSfxFile = 3; + else if (_currentCharacter->sceneId == 109 && sceneId == 25) + newSfxFile = 2; + else if (_currentCharacter->sceneId == 24 && sceneId == 7) + newSfxFile = 1; + + if (newSfxFile != -1) { + _curSfxFile = newSfxFile; + _sound->loadSoundFile(_curSfxFile); + } + } + + switch (_currentCharacter->sceneId) { + case 1: + if (sceneId == 0) { + moveCharacterToPos(0, 0, _currentCharacter->x1, 84); + unkVar1 = 0; + } + break; + + case 3: + if (sceneId == 2) { + moveCharacterToPos(0, 6, 155, _currentCharacter->y1); + unkVar1 = 0; + } + break; + + case 26: + if (sceneId == 27) { + moveCharacterToPos(0, 6, 155, _currentCharacter->y1); + unkVar1 = 0; + } + break; + + case 44: + if (sceneId == 45) { + moveCharacterToPos(0, 2, 192, _currentCharacter->y1); + unkVar1 = 0; + } + break; + + default: + break; + } + + if (unkVar1 && unk1) { + int xpos = _currentCharacter->x1; + int ypos = _currentCharacter->y1; + switch (facing) { + case 0: + ypos = _currentCharacter->y1 - 6; + break; + + case 2: + xpos = 336; + break; + + case 4: + ypos = 143; + break; + + case 6: + xpos = -16; + break; + + default: + break; + } + + moveCharacterToPos(0, facing, xpos, ypos); + } + + for (int i = 0; i < ARRAYSIZE(_movieObjects); ++i) + _movieObjects[i]->close(); + + if (!brandonAlive) { + _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]; + + setupSceneResource(sceneId); + + _currentRoom = sceneId; + + int tableId = _roomTable[sceneId].nameIndex; + char fileNameBuffer[32]; + strcpy(fileNameBuffer, _roomFilenameTable[tableId]); + strcat(fileNameBuffer, ".DAT"); + _sprites->loadDat(fileNameBuffer, _sceneExits); + _sprites->setupSceneAnims(); + _scriptInterpreter->unloadScript(_scriptClickData); + loadSceneMsc(); + + _walkBlockNorth = currentRoom->northExit; + _walkBlockEast = currentRoom->eastExit; + _walkBlockSouth = currentRoom->southExit; + _walkBlockWest = currentRoom->westExit; + + if (_walkBlockNorth == 0xFFFF) + _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF)+3); + if (_walkBlockEast == 0xFFFF) + _screen->blockOutRegion(312, 0, 8, 139); + if (_walkBlockSouth == 0xFFFF) + _screen->blockOutRegion(0, 135, 320, 8); + if (_walkBlockWest == 0xFFFF) + _screen->blockOutRegion(0, 0, 8, 139); + + if (!brandonAlive) + updatePlayerItemsForScene(); + + startSceneScript(brandonAlive); + setupSceneItems(); + + initSceneData(facing, unk2, brandonAlive); + + _loopFlag2 = 0; + _screen->showMouse(); + if (!brandonAlive) + seq_poisonDeathNow(0); + updateMousePointer(true); + _changedScene = true; +} + +void KyraEngine::transcendScenes(int roomIndex, int roomName) { + debugC(9, kDebugLevelMain, "KyraEngine::transcendScenes(%d, %d)", roomIndex, roomName); + assert(roomIndex < _roomTableSize); + + if (_flags.isTalkie) { + char file[32]; + assert(roomIndex < _roomTableSize); + int tableId = _roomTable[roomIndex].nameIndex; + assert(tableId < _roomFilenameTableSize); + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".VRM"); + _res->unloadPakFile(file); + } + + _roomTable[roomIndex].nameIndex = roomName; + _unkScreenVar2 = 1; + _unkScreenVar3 = 1; + _unkScreenVar1 = 0; + _brandonPosX = _currentCharacter->x1; + _brandonPosY = _currentCharacter->y1; + enterNewScene(roomIndex, _currentCharacter->facing, 0, 0, 0); + _unkScreenVar1 = 1; + _unkScreenVar2 = 0; + _unkScreenVar3 = 0; +} + +void KyraEngine::setSceneFile(int roomIndex, int roomName) { + debugC(9, kDebugLevelMain, "KyraEngine::setSceneFile(%d, %d)", roomIndex, roomName); + assert(roomIndex < _roomTableSize); + _roomTable[roomIndex].nameIndex = roomName; +} + +void KyraEngine::moveCharacterToPos(int character, int facing, int xpos, int ypos) { + debugC(9, kDebugLevelMain, "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); + delayUntil(nextFrame, true); + } + break; + + case 2: + while (ch->x1 < xpos) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + delayUntil(nextFrame, true); + } + break; + + case 4: + while (ypos > ch->y1) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + delayUntil(nextFrame, true); + } + break; + + case 6: + while (ch->x1 > xpos) { + nextFrame = getTimerDelay(5 + character) * _tickLength + _system->getMillis(); + setCharacterPositionWithUpdate(character); + delayUntil(nextFrame, true); + } + break; + + default: + break; + } + + enableTimer(19); + enableTimer(14); + enableTimer(18); + _screen->showMouse(); +} + +void KyraEngine::setCharacterPositionWithUpdate(int character) { + debugC(9, kDebugLevelMain, "KyraEngine::setCharacterPositionWithUpdate(%d)", character); + setCharacterPosition(character, 0); + _sprites->updateSceneAnims(); + updateGameTimers(); + _animator->updateAllObjectShapes(); + updateTextFade(); + + if (_currentCharacter->sceneId == 210) + updateKyragemFading(); +} + +int KyraEngine::setCharacterPosition(int character, int *facingTable) { + debugC(9, kDebugLevelMain, "KyraEngine::setCharacterPosition(%d, %p)", character, (const void *)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) { + debugC(9, kDebugLevelMain, "KyraEngine::setCharacterPositionHelper(%d, %p)", character, (const void *)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 && (_brandonStatusBit & 0x10)) + ch->currentAnimFrame = 88; + + _animator->animRefreshNPC(character); +} + +int KyraEngine::getOppositeFacingDirection(int dir) { + debugC(9, kDebugLevelMain, "KyraEngine::getOppositeFacingDirection(%d)", dir); + switch (dir) { + case 0: + return 2; + case 1: + return 1; + case 3: + return 7; + case 4: + return 6; + case 5: + return 5; + case 6: + return 4; + case 7: + return 3; + 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); + _screen->loadBitmap(fileNameBuffer, 3, 5, 0); +} + +void KyraEngine::startSceneScript(int brandonAlive) { + debugC(9, kDebugLevelMain, "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"); + _screen->clearPage(3); + // FIXME: check this hack for amiga version + _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? _screen->getPalette(0) : 0)); + _sprites->loadSceneShapes(); + _exitListPtr = 0; + + _scaleMode = 1; + for (int i = 0; i < 145; ++i) + _scaleTable[i] = 256; + + clearNoDropRects(); + _scriptInterpreter->initScript(_scriptClick, _scriptClickData); + strcpy(fileNameBuffer, _roomFilenameTable[tableId]); + strcat(fileNameBuffer, ".EMC"); + _scriptInterpreter->unloadScript(_scriptClickData); + _scriptInterpreter->loadScript(fileNameBuffer, _scriptClickData, &_opcodes); + _scriptInterpreter->startScript(_scriptClick, 0); + _scriptClick->regs[0] = _currentCharacter->sceneId; + _scriptClick->regs[7] = brandonAlive; + + while (_scriptInterpreter->validScript(_scriptClick)) + _scriptInterpreter->runScript(_scriptClick); +} + +void KyraEngine::initSceneData(int facing, int unk1, int brandonAlive) { + debugC(9, kDebugLevelMain, "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->regs[4] = _itemInHand; + _scriptClick->regs[7] = brandonAlive; + _scriptInterpreter->startScript(_scriptClick, 3); + while (_scriptInterpreter->validScript(_scriptClick)) + _scriptInterpreter->runScript(_scriptClick); +} + +void KyraEngine::initSceneObjectList(int brandonAlive) { + debugC(9, kDebugLevelMain, "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[_currentCharacter->currentAnimFrame]; + curAnimState->animFrameNumber = _currentCharacter->currentAnimFrame; + startAnimFrame = _currentCharacter->currentAnimFrame-7; + int xOffset = _defaultShapeTable[startAnimFrame].xOffset; + int yOffset = _defaultShapeTable[startAnimFrame].yOffset; + + if (_scaleMode) { + curAnimState->x1 = _currentCharacter->x1; + curAnimState->y1 = _currentCharacter->y1; + + _animator->_brandonScaleX = _scaleTable[_currentCharacter->y1]; + _animator->_brandonScaleY = _scaleTable[_currentCharacter->y1]; + + curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8; + curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8; + } else { + curAnimState->x1 = _currentCharacter->x1 + xOffset; + curAnimState->y1 = _currentCharacter->y1 + yOffset; + } + + curAnimState->x2 = curAnimState->x1; + curAnimState->y2 = curAnimState->y1; + curAnimState->refreshFlag = 1; + curAnimState->bkgdChangeFlag = 1; + _animator->clearQueue(); + _animator->addObjectToQueue(curAnimState); + + int listAdded = 0; + int addedObjects = 1; + + for (int i = 1; i < 5; ++i) { + Character *ch = &_characterList[i]; + curAnimState = &_animator->actors()[addedObjects]; + if (ch->sceneId != _currentCharacter->sceneId) { + curAnimState->active = 0; + curAnimState->refreshFlag = 0; + curAnimState->bkgdChangeFlag = 0; + ++addedObjects; + continue; + } + + curAnimState->drawY = ch->y1; + curAnimState->sceneAnimPtr = _shapes[ch->currentAnimFrame]; + curAnimState->animFrameNumber = ch->currentAnimFrame; + startAnimFrame = ch->currentAnimFrame-7; + xOffset = _defaultShapeTable[startAnimFrame].xOffset; + yOffset = _defaultShapeTable[startAnimFrame].yOffset; + if (_scaleMode) { + curAnimState->x1 = ch->x1; + curAnimState->y1 = ch->y1; + + _animator->_brandonScaleX = _scaleTable[ch->y1]; + _animator->_brandonScaleY = _scaleTable[ch->y1]; + + curAnimState->x1 += (_animator->_brandonScaleX * xOffset) >> 8; + curAnimState->y1 += (_animator->_brandonScaleY * yOffset) >> 8; + } else { + curAnimState->x1 = ch->x1 + xOffset; + curAnimState->y1 = ch->y1 + yOffset; + } + curAnimState->x2 = curAnimState->x1; + curAnimState->y2 = curAnimState->y1; + curAnimState->active = 1; + curAnimState->refreshFlag = 1; + curAnimState->bkgdChangeFlag = 1; + + if (ch->facing >= 1 && ch->facing <= 3) + curAnimState->flags |= 1; + else if (ch->facing >= 5 && ch->facing <= 7) + curAnimState->flags &= 0xFFFFFFFE; + + _animator->addObjectToQueue(curAnimState); + + ++addedObjects; + ++listAdded; + if (listAdded < 2) + i = 5; + } + + for (int i = 0; i < 11; ++i) { + curAnimState = &_animator->sprites()[i]; + + if (_sprites->_anims[i].play) { + curAnimState->active = 1; + curAnimState->refreshFlag = 1; + curAnimState->bkgdChangeFlag = 1; + } else { + curAnimState->active = 0; + curAnimState->refreshFlag = 0; + curAnimState->bkgdChangeFlag = 0; + } + curAnimState->height = _sprites->_anims[i].height; + curAnimState->height2 = _sprites->_anims[i].height2; + curAnimState->width = _sprites->_anims[i].width + 1; + curAnimState->width2 = _sprites->_anims[i].width2; + curAnimState->drawY = _sprites->_anims[i].drawY; + curAnimState->x1 = curAnimState->x2 = _sprites->_anims[i].x; + curAnimState->y1 = curAnimState->y2 = _sprites->_anims[i].y; + curAnimState->background = _sprites->_anims[i].background; + curAnimState->sceneAnimPtr = _sprites->_sceneShapes[_sprites->_anims[i].sprite]; + + curAnimState->disable = _sprites->_anims[i].disable; + + if (_sprites->_anims[i].unk2) + curAnimState->flags = 0x800; + else + curAnimState->flags = 0; + + if (_sprites->_anims[i].flipX) + curAnimState->flags |= 0x1; + + _animator->addObjectToQueue(curAnimState); + } + + for (int i = 0; i < 12; ++i) { + curAnimState = &_animator->items()[i]; + Room *curRoom = &_roomTable[_currentCharacter->sceneId]; + byte curItem = curRoom->itemsTable[i]; + if (curItem != 0xFF) { + curAnimState->drawY = curRoom->itemsYPos[i]; + curAnimState->sceneAnimPtr = _shapes[216+curItem]; + curAnimState->animFrameNumber = (int16)0xFFFF; + curAnimState->y1 = curRoom->itemsYPos[i]; + curAnimState->x1 = curRoom->itemsXPos[i]; + + curAnimState->x1 -= (_animator->fetchAnimWidth(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY])) >> 1; + curAnimState->y1 -= _animator->fetchAnimHeight(curAnimState->sceneAnimPtr, _scaleTable[curAnimState->drawY]); + + curAnimState->x2 = curAnimState->x1; + curAnimState->y2 = curAnimState->y1; + + curAnimState->active = 1; + curAnimState->refreshFlag = 1; + curAnimState->bkgdChangeFlag = 1; + + _animator->addObjectToQueue(curAnimState); + } else { + curAnimState->active = 0; + curAnimState->refreshFlag = 0; + curAnimState->bkgdChangeFlag = 0; + } + } + + _animator->preserveAnyChangedBackgrounds(); + curAnimState = _animator->actors(); + curAnimState->bkgdChangeFlag = 1; + curAnimState->refreshFlag = 1; + for (int i = 1; i < 28; ++i) { + curAnimState = &_animator->objects()[i]; + if (curAnimState->active) { + curAnimState->bkgdChangeFlag = 1; + curAnimState->refreshFlag = 1; + } + } + _animator->restoreAllObjectBackgrounds(); + _animator->preserveAnyChangedBackgrounds(); + _animator->prepDrawAllObjects(); + initSceneScreen(brandonAlive); + _animator->copyChangedObjectsForward(0); +} + +void KyraEngine::initSceneScreen(int brandonAlive) { + if (_flags.platform == Common::kPlatformAmiga) { + if (_unkScreenVar1 && !queryGameFlag(0xF0)) { + memset(_screen->getPalette(2), 0, 32*3); + if (_currentCharacter->sceneId != 117 || !queryGameFlag(0xB3)) + _screen->setScreenPalette(_screen->getPalette(2)); + } + + if (_unkScreenVar2 == 1) + _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false); + else + _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); + + if (_unkScreenVar1 && !queryGameFlag(0xA0)) { + if (_currentCharacter->sceneId == 45 && _paletteChanged) + memcpy(_screen->getPalette(0) + 12*3, _screen->getPalette(4) + 12*3, 2); + + if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245 && (_brandonStatusBit & 1)) + memcpy(_screen->getPalette(0), _screen->getPalette(0) + 320*3, 64); + + _screen->setScreenPalette(_screen->getPalette(0)); + } + } else { + if (_unkScreenVar1 && !queryGameFlag(0xA0)) { + for (int i = 0; i < 60; ++i) { + uint16 col = _screen->getPalette(0)[684+i]; + col += _screen->getPalette(1)[684+i] << 1; + col >>= 2; + _screen->getPalette(0)[684+i] = col; + } + _screen->setScreenPalette(_screen->getPalette(0)); + } + + if (_unkScreenVar2 == 1) + _screen->shuffleScreen(8, 8, 304, 128, 2, 0, _unkScreenVar3, false); + else + _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); + + if (_unkScreenVar1 && _paletteChanged) { + if (!queryGameFlag(0xA0)) { + memcpy(_screen->getPalette(0) + 684, _screen->getPalette(1) + 684, 60); + _screen->setScreenPalette(_screen->getPalette(0)); + } else { + memset(_screen->getPalette(0), 0, 768); + } + } + } + + // really call this here? + _screen->updateScreen(); + + if (!_scriptInterpreter->startScript(_scriptClick, 2)) + error("Could not start script function 2 of scene script"); + + _scriptClick->regs[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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "KyraEngine::processSceneChange(%p, %d, %d)", (const void *)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; + _animator->animRefreshNPC(0); + _animator->updateAllObjectShapes(); + processInput(); + 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) { + updateGameTimers(); + + if (_currentCharacter->sceneId == 210) { + updateKyragemFading(); + if (seq_playEnd() || _beadStateVar == 4 || _beadStateVar == 5) { + *table = 8; + running = false; + break; + } + } + + if ((nextFrame - _system->getMillis()) >= 10) + delay(10, true); + } + } + + if (frameReset && !(_brandonStatusBit & 2)) + _currentCharacter->currentAnimFrame = 7; + + _animator->animRefreshNPC(0); + _animator->updateAllObjectShapes(); + return returnValue; +} + +int KyraEngine::changeScene(int facing) { + debugC(9, kDebugLevelMain, "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 one time, seems to be some hack in the original + while (true) { + if (*ptr == -1) + break; + + if (*ptr > _currentCharacter->x1 || _currentCharacter->y1 < ptr[1] || _currentCharacter->x1 > ptr[2] || _currentCharacter->y1 > ptr[3]) { + ptr += 10; + break; + } + + _brandonPosX = ptr[6]; + _brandonPosY = ptr[7]; + uint16 sceneId = ptr[5]; + facing = ptr[4]; + int unk1 = ptr[8]; + int unk2 = ptr[9]; + + if (sceneId == 0xFFFF) { + switch (facing) { + case 0: + sceneId = _roomTable[_currentCharacter->sceneId].northExit; + break; + + case 2: + sceneId = _roomTable[_currentCharacter->sceneId].eastExit; + break; + + case 4: + sceneId = _roomTable[_currentCharacter->sceneId].southExit; + break; + + case 6: + sceneId = _roomTable[_currentCharacter->sceneId].westExit; + break; + + default: + break; + } + } + + _currentCharacter->facing = facing; + _animator->animRefreshNPC(0); + _animator->updateAllObjectShapes(); + enterNewScene(sceneId, facing, unk1, unk2, 0); + resetGameFlag(0xEE); + return 1; + } + } + + int returnValue = 0; + facing = 0; + + if ((_northExitHeight & 0xFF) + 2 >= ypos || (_northExitHeight & 0xFF) + 2 >= _currentCharacter->y1) { + facing = 0; + returnValue = 1; + } + + if (xpos >= 308 || (_currentCharacter->x1 + 4) >= 308) { + facing = 2; + returnValue = 1; + } + + if (((_northExitHeight >> 8) & 0xFF) - 2 < ypos || ((_northExitHeight >> 8) & 0xFF) - 2 < _currentCharacter->y1) { + facing = 4; + returnValue = 1; + } + + if (xpos <= 12 || _currentCharacter->y1 <= 12) { + facing = 6; + returnValue = 1; + } + + if (!returnValue) + return 0; + + uint16 sceneId = 0xFFFF; + switch (facing) { + case 0: + sceneId = _roomTable[_currentCharacter->sceneId].northExit; + break; + + case 2: + sceneId = _roomTable[_currentCharacter->sceneId].eastExit; + break; + + case 4: + sceneId = _roomTable[_currentCharacter->sceneId].southExit; + break; + + default: + sceneId = _roomTable[_currentCharacter->sceneId].westExit; + 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) { + debugC(9, kDebugLevelMain, "KyraEngine::findWay(%d, %d, %d, %d, %p, %d)", x, y, toX, toY, (const void *)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) { + debugC(9, kDebugLevelMain, "KyraEngine::findSubPath(%d, %d, %d, %d, %p, %d, %d)", x, y, toX, toY, (const void *)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) { + debugC(9, kDebugLevelMain, "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) { + debugC(9, kDebugLevelMain, "KyraEngine::changePosTowardsFacing(%d, %d, %d)", x, y, facing); + x += _addXPosTable[facing]; + y += _addYPosTable[facing]; +} + +bool KyraEngine::lineIsPassable(int x, int y) { + debugC(9, kDebugLevelMain, "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; + + if (y < 0) + y = 0; + + int ypos = 8; + if (_scaleMode) { + ypos = (_scaleTable[y] >> 5) + 1; + if (8 < ypos) + ypos = 8; + } + + x -= (ypos >> 1); + + int xpos = x; + int xtemp = xpos + ypos - 1; + if (x < 0) + xpos = 0; + + if (xtemp > 319) + xtemp = 319; + + for (; xpos < xtemp; ++xpos) { + if (!_screen->getShapeFlag1(xpos, y)) + return false; + } + return true; +} + +int KyraEngine::getMoveTableSize(int *moveTable) { + debugC(9, kDebugLevelMain, "KyraEngine::getMoveTableSize(%p)", (const void *)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; +} + +void KyraEngine::setupSceneResource(int sceneId) { + debugC(9, kDebugLevelMain, "KyraEngine::setupSceneResource(%d)", sceneId); + if (!_flags.isTalkie) + return; + + if (_currentRoom != 0xFFFF) { + assert(_currentRoom < _roomTableSize); + int tableId = _roomTable[_currentRoom].nameIndex; + assert(tableId < _roomFilenameTableSize); + + // unload our old room + char file[64]; + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".VRM"); + _res->unloadPakFile(file); + + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".PAK"); + _res->unloadPakFile(file); + + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".APK"); + _res->unloadPakFile(file); + } + + assert(sceneId < _roomTableSize); + int tableId = _roomTable[sceneId].nameIndex; + assert(tableId < _roomFilenameTableSize); + + // load our new room + char file[64]; + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".VRM"); + if (Common::File::exists(file)) + _res->loadPakFile(file); + + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".PAK"); + if (Common::File::exists(file)) + _res->loadPakFile(file); + + strcpy(file, _roomFilenameTable[tableId]); + strcat(file, ".APK"); + if (Common::File::exists(file)) + _res->loadPakFile(file); +} + +} // end of namespace Kyra + diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp deleted file mode 100644 index a35b701697..0000000000 --- a/engines/kyra/timer.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "kyra/kyra.h" -#include "kyra/screen.h" -#include "kyra/animator.h" - -#include "common/system.h" - -namespace Kyra { -void KyraEngine::setupTimers() { - debugC(9, kDebugLevelMain, "KyraEngine::setupTimers()"); - memset(_timers, 0, sizeof(_timers)); - - for (int i = 0; i < 34; i++) - _timers[i].active = 1; - - _timers[0].func = _timers[1].func = _timers[2].func = _timers[3].func = _timers[4].func = 0; //Unused. - _timers[5].func = _timers[6].func = _timers[7].func = _timers[8].func = _timers[9].func = 0; //_nullsub51; - _timers[10].func = _timers[11].func = _timers[12].func = _timers[13].func = 0; //_nullsub50; - _timers[14].func = &KyraEngine::timerCheckAnimFlag2; //_nullsub52; - _timers[15].func = &KyraEngine::timerUpdateHeadAnims; //_nullsub48; - _timers[16].func = &KyraEngine::timerSetFlags1; //_nullsub47; - _timers[17].func = 0; //sub_15120; - _timers[18].func = &KyraEngine::timerCheckAnimFlag1; //_nullsub53; - _timers[19].func = &KyraEngine::timerRedrawAmulet; //_nullsub54; - _timers[20].func = 0; //offset _timerDummy1 - _timers[21].func = 0; //sub_1517C; - _timers[22].func = 0; //offset _timerDummy2 - _timers[23].func = 0; //offset _timerDummy3, - _timers[24].func = 0; //_nullsub45; - _timers[25].func = 0; //offset _timerDummy4 - _timers[26].func = 0; //_nullsub46; - _timers[27].func = 0; //offset _timerDummy5, - _timers[28].func = 0; //offset _timerDummy6 - _timers[29].func = 0; //offset _timerDummy7, - _timers[30].func = 0; //offset _timerDummy8, - _timers[31].func = &KyraEngine::timerFadeText; //sub_151F8; - _timers[32].func = &KyraEngine::updateAnimFlag1; //_nullsub61; - _timers[33].func = &KyraEngine::updateAnimFlag2; //_nullsub62; - - _timers[0].countdown = _timers[1].countdown = _timers[2].countdown = _timers[3].countdown = _timers[4].countdown = -1; - _timers[5].countdown = 5; - _timers[6].countdown = 7; - _timers[7].countdown = 8; - _timers[8].countdown = 9; - _timers[9].countdown = 7; - _timers[10].countdown = _timers[11].countdown = _timers[12].countdown = _timers[13].countdown = 420; - _timers[14].countdown = 600; - _timers[15].countdown = 11; - _timers[16].countdown = _timers[17].countdown = 7200; - _timers[18].countdown = _timers[19].countdown = 600; - _timers[20].countdown = 7200; - _timers[21].countdown = 18000; - _timers[22].countdown = 7200; - _timers[23].countdown = _timers[24].countdown = _timers[25].countdown = _timers[26].countdown = _timers[27].countdown = 10800; - _timers[28].countdown = 21600; - _timers[29].countdown = 7200; - _timers[30].countdown = 10800; - _timers[31].countdown = -1; - _timers[32].countdown = 9; - _timers[33].countdown = 3; -} - -void KyraEngine::updateGameTimers() { - debugC(9, kDebugLevelMain, "KyraEngine::updateGameTimers()"); - - if (_system->getMillis() < _timerNextRun) - return; - - _timerNextRun += 99999; - - for (int i = 0; i < 34; i++) { - if (_timers[i].active && _timers[i].countdown > -1) { - if (_timers[i].nextRun <=_system->getMillis()) { - if (i > 4 && _timers[i].func) - (*this.*_timers[i].func)(i); - - _timers[i].nextRun = _system->getMillis() + _timers[i].countdown * _tickLength; - } - } - if (_timers[i].nextRun < _timerNextRun) - _timerNextRun = _timers[i].nextRun; - } -} - -void KyraEngine::clearNextEventTickCount() { - debugC(9, kDebugLevelMain, "KyraEngine::clearNextEventTickCount()"); - _timerNextRun = 0; -} - -void KyraEngine::setTimerDelay(uint8 timer, int32 countdown) { - debugC(9, kDebugLevelMain, "KyraEngine::setTimerDelay(%i, %d)", timer, countdown); - _timers[timer].countdown = countdown; -} - -int16 KyraEngine::getTimerDelay(uint8 timer) { - debugC(9, kDebugLevelMain, "KyraEngine::getTimerDelay(%i)", timer); - return _timers[timer].countdown; -} - -void KyraEngine::setTimerCountdown(uint8 timer, int32 countdown) { - debugC(9, kDebugLevelMain, "KyraEngine::setTimerCountdown(%i, %i)", timer, countdown); - _timers[timer].countdown = countdown; - _timers[timer].nextRun = _system->getMillis() + countdown * _tickLength; - - uint32 nextRun = _system->getMillis() + countdown * _tickLength; - if (nextRun < _timerNextRun) - _timerNextRun = nextRun; -} - -void KyraEngine::enableTimer(uint8 timer) { - debugC(9, kDebugLevelMain, "KyraEngine::enableTimer(%i)", timer); - _timers[timer].active = 1; -} - -void KyraEngine::disableTimer(uint8 timer) { - debugC(9, kDebugLevelMain, "KyraEngine::disableTimer(%i)", timer); - _timers[timer].active = 0; -} - -void KyraEngine::timerUpdateHeadAnims(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerUpdateHeadAnims(%i)", timerNum); - static int8 currentFrame = 0; - static const int8 frameTable[] = {4, 5, 4, 5, 4, 5, 0, 1, 4, 5, - 4, 4, 6, 4, 8, 1, 9, 4, -1}; - - if (_talkingCharNum < 0) - return; - - _currHeadShape = frameTable[currentFrame]; - currentFrame++; - - if (frameTable[currentFrame] == -1) - currentFrame = 0; - - _animator->animRefreshNPC(0); - _animator->animRefreshNPC(_talkingCharNum); -} - -void KyraEngine::timerSetFlags1(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerSetFlags(%i)", timerNum); - if (_currentCharacter->sceneId == 0x1C) - return; - - int rndNr = _rnd.getRandomNumberRng(0, 3); - - for (int i = 0; i < 4; i++) { - if (!queryGameFlag(rndNr + 17)) { - setGameFlag(rndNr + 17); - break; - } else { - rndNr++; - if (rndNr > 3) - rndNr = 0; - } - } -} - -void KyraEngine::timerFadeText(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerFadeText(%i)", timerNum); - _fadeText = true; -} - -void KyraEngine::updateAnimFlag1(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::updateAnimFlag1(%d)", timerNum); - if (_brandonStatusBit & 2) { - _brandonStatusBit0x02Flag = 1; - } -} - -void KyraEngine::updateAnimFlag2(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::updateAnimFlag2(%d)", timerNum); - if (_brandonStatusBit & 0x20) { - _brandonStatusBit0x20Flag = 1; - } -} - -void KyraEngine::setTextFadeTimerCountdown(int16 countdown) { - debugC(9, kDebugLevelMain, "KyraEngine::setTextFadeTimerCountdown(%i)", countdown); - //if (countdown == -1) - //countdown = 32000; - - setTimerCountdown(31, countdown*60); -} - -void KyraEngine::timerSetFlags2(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerSetFlags2(%i)", timerNum); - if (!((uint32*)(_flagsTable+0x2D))[timerNum]) - ((uint32*)(_flagsTable+0x2D))[timerNum] = 1; -} - -void KyraEngine::timerCheckAnimFlag1(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerCheckAnimFlag1(%i)", timerNum); - if (_brandonStatusBit & 0x20) { - checkAmuletAnimFlags(); - setTimerCountdown(18, -1); - } -} - -void KyraEngine::timerCheckAnimFlag2(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerCheckAnimFlag1(%i)", timerNum); - if (_brandonStatusBit & 0x2) { - checkAmuletAnimFlags(); - setTimerCountdown(14, -1); - } -} - -void KyraEngine::checkAmuletAnimFlags() { - debugC(9, kDebugLevelMain, "KyraEngine::checkSpecialAnimFlags()"); - if (_brandonStatusBit & 2) { - seq_makeBrandonNormal2(); - setTimerCountdown(19, 300); - } - - if (_brandonStatusBit & 0x20) { - seq_makeBrandonNormal(); - setTimerCountdown(19, 300); - } -} - -void KyraEngine::timerRedrawAmulet(int timerNum) { - debugC(9, kDebugLevelMain, "KyraEngine::timerRedrawAmulet(%i)", timerNum); - if (queryGameFlag(0xF1)) { - drawAmulet(); - setTimerCountdown(19, -1); - } -} - -void KyraEngine::drawAmulet() { - debugC(9, kDebugLevelMain, "KyraEngine::drawAmulet()"); - static const int16 amuletTable1[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x150, 0x155, 0x15A, 0x15F, 0x164, 0x145, -1}; - static const int16 amuletTable3[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x14F, 0x154, 0x159, 0x15E, 0x163, 0x144, -1}; - static const int16 amuletTable2[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x152, 0x157, 0x15C, 0x161, 0x166, 0x147, -1}; - static const int16 amuletTable4[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x151, 0x156, 0x15B, 0x160, 0x165, 0x146, -1}; - - resetGameFlag(0xF1); - _screen->hideMouse(); - - int i = 0; - while (amuletTable1[i] != -1) { - if (queryGameFlag(87)) - _screen->drawShape(0, _shapes[amuletTable1[i]], _amuletX[0], _amuletY[0], 0, 0); - - if (queryGameFlag(89)) - _screen->drawShape(0, _shapes[amuletTable2[i]], _amuletX[1], _amuletY[1], 0, 0); - - if (queryGameFlag(86)) - _screen->drawShape(0, _shapes[amuletTable3[i]], _amuletX[2], _amuletY[2], 0, 0); - - if (queryGameFlag(88)) - _screen->drawShape(0, _shapes[amuletTable4[i]], _amuletX[3], _amuletY[3], 0, 0); - - _screen->updateScreen(); - delayWithTicks(3); - i++; - } - _screen->showMouse(); -} - -void KyraEngine::setWalkspeed(uint8 newSpeed) { - debugC(9, kDebugLevelMain, "KyraEngine::setWalkspeed(%i)", newSpeed); - static const uint8 speeds[] = {11, 9, 6, 5, 3}; - - assert(newSpeed < ARRAYSIZE(speeds)); - setTimerDelay(5, speeds[newSpeed]); -} - -} // end of namespace Kyra - diff --git a/engines/kyra/timer_v1.cpp b/engines/kyra/timer_v1.cpp new file mode 100644 index 0000000000..a35b701697 --- /dev/null +++ b/engines/kyra/timer_v1.cpp @@ -0,0 +1,292 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "kyra/kyra.h" +#include "kyra/screen.h" +#include "kyra/animator.h" + +#include "common/system.h" + +namespace Kyra { +void KyraEngine::setupTimers() { + debugC(9, kDebugLevelMain, "KyraEngine::setupTimers()"); + memset(_timers, 0, sizeof(_timers)); + + for (int i = 0; i < 34; i++) + _timers[i].active = 1; + + _timers[0].func = _timers[1].func = _timers[2].func = _timers[3].func = _timers[4].func = 0; //Unused. + _timers[5].func = _timers[6].func = _timers[7].func = _timers[8].func = _timers[9].func = 0; //_nullsub51; + _timers[10].func = _timers[11].func = _timers[12].func = _timers[13].func = 0; //_nullsub50; + _timers[14].func = &KyraEngine::timerCheckAnimFlag2; //_nullsub52; + _timers[15].func = &KyraEngine::timerUpdateHeadAnims; //_nullsub48; + _timers[16].func = &KyraEngine::timerSetFlags1; //_nullsub47; + _timers[17].func = 0; //sub_15120; + _timers[18].func = &KyraEngine::timerCheckAnimFlag1; //_nullsub53; + _timers[19].func = &KyraEngine::timerRedrawAmulet; //_nullsub54; + _timers[20].func = 0; //offset _timerDummy1 + _timers[21].func = 0; //sub_1517C; + _timers[22].func = 0; //offset _timerDummy2 + _timers[23].func = 0; //offset _timerDummy3, + _timers[24].func = 0; //_nullsub45; + _timers[25].func = 0; //offset _timerDummy4 + _timers[26].func = 0; //_nullsub46; + _timers[27].func = 0; //offset _timerDummy5, + _timers[28].func = 0; //offset _timerDummy6 + _timers[29].func = 0; //offset _timerDummy7, + _timers[30].func = 0; //offset _timerDummy8, + _timers[31].func = &KyraEngine::timerFadeText; //sub_151F8; + _timers[32].func = &KyraEngine::updateAnimFlag1; //_nullsub61; + _timers[33].func = &KyraEngine::updateAnimFlag2; //_nullsub62; + + _timers[0].countdown = _timers[1].countdown = _timers[2].countdown = _timers[3].countdown = _timers[4].countdown = -1; + _timers[5].countdown = 5; + _timers[6].countdown = 7; + _timers[7].countdown = 8; + _timers[8].countdown = 9; + _timers[9].countdown = 7; + _timers[10].countdown = _timers[11].countdown = _timers[12].countdown = _timers[13].countdown = 420; + _timers[14].countdown = 600; + _timers[15].countdown = 11; + _timers[16].countdown = _timers[17].countdown = 7200; + _timers[18].countdown = _timers[19].countdown = 600; + _timers[20].countdown = 7200; + _timers[21].countdown = 18000; + _timers[22].countdown = 7200; + _timers[23].countdown = _timers[24].countdown = _timers[25].countdown = _timers[26].countdown = _timers[27].countdown = 10800; + _timers[28].countdown = 21600; + _timers[29].countdown = 7200; + _timers[30].countdown = 10800; + _timers[31].countdown = -1; + _timers[32].countdown = 9; + _timers[33].countdown = 3; +} + +void KyraEngine::updateGameTimers() { + debugC(9, kDebugLevelMain, "KyraEngine::updateGameTimers()"); + + if (_system->getMillis() < _timerNextRun) + return; + + _timerNextRun += 99999; + + for (int i = 0; i < 34; i++) { + if (_timers[i].active && _timers[i].countdown > -1) { + if (_timers[i].nextRun <=_system->getMillis()) { + if (i > 4 && _timers[i].func) + (*this.*_timers[i].func)(i); + + _timers[i].nextRun = _system->getMillis() + _timers[i].countdown * _tickLength; + } + } + if (_timers[i].nextRun < _timerNextRun) + _timerNextRun = _timers[i].nextRun; + } +} + +void KyraEngine::clearNextEventTickCount() { + debugC(9, kDebugLevelMain, "KyraEngine::clearNextEventTickCount()"); + _timerNextRun = 0; +} + +void KyraEngine::setTimerDelay(uint8 timer, int32 countdown) { + debugC(9, kDebugLevelMain, "KyraEngine::setTimerDelay(%i, %d)", timer, countdown); + _timers[timer].countdown = countdown; +} + +int16 KyraEngine::getTimerDelay(uint8 timer) { + debugC(9, kDebugLevelMain, "KyraEngine::getTimerDelay(%i)", timer); + return _timers[timer].countdown; +} + +void KyraEngine::setTimerCountdown(uint8 timer, int32 countdown) { + debugC(9, kDebugLevelMain, "KyraEngine::setTimerCountdown(%i, %i)", timer, countdown); + _timers[timer].countdown = countdown; + _timers[timer].nextRun = _system->getMillis() + countdown * _tickLength; + + uint32 nextRun = _system->getMillis() + countdown * _tickLength; + if (nextRun < _timerNextRun) + _timerNextRun = nextRun; +} + +void KyraEngine::enableTimer(uint8 timer) { + debugC(9, kDebugLevelMain, "KyraEngine::enableTimer(%i)", timer); + _timers[timer].active = 1; +} + +void KyraEngine::disableTimer(uint8 timer) { + debugC(9, kDebugLevelMain, "KyraEngine::disableTimer(%i)", timer); + _timers[timer].active = 0; +} + +void KyraEngine::timerUpdateHeadAnims(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerUpdateHeadAnims(%i)", timerNum); + static int8 currentFrame = 0; + static const int8 frameTable[] = {4, 5, 4, 5, 4, 5, 0, 1, 4, 5, + 4, 4, 6, 4, 8, 1, 9, 4, -1}; + + if (_talkingCharNum < 0) + return; + + _currHeadShape = frameTable[currentFrame]; + currentFrame++; + + if (frameTable[currentFrame] == -1) + currentFrame = 0; + + _animator->animRefreshNPC(0); + _animator->animRefreshNPC(_talkingCharNum); +} + +void KyraEngine::timerSetFlags1(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerSetFlags(%i)", timerNum); + if (_currentCharacter->sceneId == 0x1C) + return; + + int rndNr = _rnd.getRandomNumberRng(0, 3); + + for (int i = 0; i < 4; i++) { + if (!queryGameFlag(rndNr + 17)) { + setGameFlag(rndNr + 17); + break; + } else { + rndNr++; + if (rndNr > 3) + rndNr = 0; + } + } +} + +void KyraEngine::timerFadeText(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerFadeText(%i)", timerNum); + _fadeText = true; +} + +void KyraEngine::updateAnimFlag1(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::updateAnimFlag1(%d)", timerNum); + if (_brandonStatusBit & 2) { + _brandonStatusBit0x02Flag = 1; + } +} + +void KyraEngine::updateAnimFlag2(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::updateAnimFlag2(%d)", timerNum); + if (_brandonStatusBit & 0x20) { + _brandonStatusBit0x20Flag = 1; + } +} + +void KyraEngine::setTextFadeTimerCountdown(int16 countdown) { + debugC(9, kDebugLevelMain, "KyraEngine::setTextFadeTimerCountdown(%i)", countdown); + //if (countdown == -1) + //countdown = 32000; + + setTimerCountdown(31, countdown*60); +} + +void KyraEngine::timerSetFlags2(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerSetFlags2(%i)", timerNum); + if (!((uint32*)(_flagsTable+0x2D))[timerNum]) + ((uint32*)(_flagsTable+0x2D))[timerNum] = 1; +} + +void KyraEngine::timerCheckAnimFlag1(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerCheckAnimFlag1(%i)", timerNum); + if (_brandonStatusBit & 0x20) { + checkAmuletAnimFlags(); + setTimerCountdown(18, -1); + } +} + +void KyraEngine::timerCheckAnimFlag2(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerCheckAnimFlag1(%i)", timerNum); + if (_brandonStatusBit & 0x2) { + checkAmuletAnimFlags(); + setTimerCountdown(14, -1); + } +} + +void KyraEngine::checkAmuletAnimFlags() { + debugC(9, kDebugLevelMain, "KyraEngine::checkSpecialAnimFlags()"); + if (_brandonStatusBit & 2) { + seq_makeBrandonNormal2(); + setTimerCountdown(19, 300); + } + + if (_brandonStatusBit & 0x20) { + seq_makeBrandonNormal(); + setTimerCountdown(19, 300); + } +} + +void KyraEngine::timerRedrawAmulet(int timerNum) { + debugC(9, kDebugLevelMain, "KyraEngine::timerRedrawAmulet(%i)", timerNum); + if (queryGameFlag(0xF1)) { + drawAmulet(); + setTimerCountdown(19, -1); + } +} + +void KyraEngine::drawAmulet() { + debugC(9, kDebugLevelMain, "KyraEngine::drawAmulet()"); + static const int16 amuletTable1[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x150, 0x155, 0x15A, 0x15F, 0x164, 0x145, -1}; + static const int16 amuletTable3[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x14F, 0x154, 0x159, 0x15E, 0x163, 0x144, -1}; + static const int16 amuletTable2[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x152, 0x157, 0x15C, 0x161, 0x166, 0x147, -1}; + static const int16 amuletTable4[] = {0x167, 0x162, 0x15D, 0x158, 0x153, 0x151, 0x156, 0x15B, 0x160, 0x165, 0x146, -1}; + + resetGameFlag(0xF1); + _screen->hideMouse(); + + int i = 0; + while (amuletTable1[i] != -1) { + if (queryGameFlag(87)) + _screen->drawShape(0, _shapes[amuletTable1[i]], _amuletX[0], _amuletY[0], 0, 0); + + if (queryGameFlag(89)) + _screen->drawShape(0, _shapes[amuletTable2[i]], _amuletX[1], _amuletY[1], 0, 0); + + if (queryGameFlag(86)) + _screen->drawShape(0, _shapes[amuletTable3[i]], _amuletX[2], _amuletY[2], 0, 0); + + if (queryGameFlag(88)) + _screen->drawShape(0, _shapes[amuletTable4[i]], _amuletX[3], _amuletY[3], 0, 0); + + _screen->updateScreen(); + delayWithTicks(3); + i++; + } + _screen->showMouse(); +} + +void KyraEngine::setWalkspeed(uint8 newSpeed) { + debugC(9, kDebugLevelMain, "KyraEngine::setWalkspeed(%i)", newSpeed); + static const uint8 speeds[] = {11, 9, 6, 5, 3}; + + assert(newSpeed < ARRAYSIZE(speeds)); + setTimerDelay(5, speeds[newSpeed]); +} + +} // end of namespace Kyra + -- cgit v1.2.3