diff options
Diffstat (limited to 'engines/kyra/items_hof.cpp')
-rw-r--r-- | engines/kyra/items_hof.cpp | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/engines/kyra/items_hof.cpp b/engines/kyra/items_hof.cpp new file mode 100644 index 0000000000..da3062fe2c --- /dev/null +++ b/engines/kyra/items_hof.cpp @@ -0,0 +1,448 @@ +/* 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_hof.h" + +namespace Kyra { + +int KyraEngine_HoF::checkItemCollision(int x, int y) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::checkItemCollision(%d, %d)", x, y); + int itemPos = -1, yPos = -1; + + for (int i = 0; i < 30; ++i) { + const Item &curItem = _itemList[i]; + + if (curItem.id == 0xFFFF || curItem.sceneId != _mainCharacter.sceneId) + continue; + + int itemX1 = curItem.x - 8 - 3; + int itemX2 = curItem.x + 7 + 3; + + if (x < itemX1 || x > itemX2) + continue; + + int itemY1 = curItem.y - _itemHtDat[curItem.id] - 3; + int itemY2 = curItem.y + 3; + + if (y < itemY1 || y > itemY2) + continue; + + if (curItem.y >= yPos) { + itemPos = i; + yPos = curItem.y; + } + } + + return itemPos; +} + +void KyraEngine_HoF::updateWaterFlasks() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::updateWaterFlasks()"); + for (int i = 22; i < 24; i++) { + if (_itemInHand == i) + setHandItem(i - 1); + + for (int ii = 0; ii < 20; ii++) { + if (_mainCharacter.inventory[ii] == i) { + _mainCharacter.inventory[ii]--; + if (ii < 10) { + clearInventorySlot(ii, 0); + _screen->drawShape(0, getShapePtr(i + 63), _inventoryX[ii], _inventoryY[ii], 0, 0); + } + } + } + + for (int ii = 0; ii < 30; ii++) { + if (_itemList[ii].id == i) + _itemList[ii].id--; + } + } +} + +bool KyraEngine_HoF::dropItem(int unk1, uint16 item, int x, int y, int unk2) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::dropItem(%d, %u, %d, %d, %d)", unk1, item, x, y, unk2); + if (_handItemSet <= -1) + return false; + + bool success = processItemDrop(_mainCharacter.sceneId, item, x, y, unk1, unk2); + if (!success) { + snd_playSoundEffect(0x0d); + if (countAllItems() >= 30) + showMessageFromCCode(5, 0x84, 0); + } + + return success; +} + +bool KyraEngine_HoF::processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int unk2) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::processItemDrop(%u, %u, %d, %d, %d, %d)", sceneId, item, x, y, unk1, unk2); + int itemPos = checkItemCollision(x, y); + + if (unk1) + itemPos = -1; + + if (itemPos >= 0) { + exchangeMouseItem(itemPos); + return false; + } + + int freeItemSlot = -1; + + if (unk1 != 3) { + for (int i = 0; i < 30; ++i) { + if (_itemList[i].id == 0xFFFF) { + freeItemSlot = i; + break; + } + } + } + + if (freeItemSlot == -1) + return false; + + if (sceneId != _mainCharacter.sceneId) { + _itemList[freeItemSlot].x = x; + _itemList[freeItemSlot].y = y; + _itemList[freeItemSlot].id = item; + _itemList[freeItemSlot].sceneId = sceneId; + return true; + } + + int itemHeight = _itemHtDat[item]; + + // no idea why it's '&&' here and not single checks for x and y + if (x == -1 && y == -1) { + x = _rnd.getRandomNumberRng(0x10, 0x130); + y = _rnd.getRandomNumberRng(0x10, 0x87); + } + + int posX = x, posY = y; + int itemX = -1, itemY = -1; + bool needRepositioning = true; + + while (needRepositioning) { + if ((_screen->getDrawLayer(posX, posY) <= 1 && _screen->getDrawLayer2(posX, posY, itemHeight) <= 1 && isDropable(posX, posY)) || posY == 136) { + int posX2 = posX, posX3 = posX; + bool repositioning = true; + + while (repositioning) { + if (isDropable(posX3, posY) && _screen->getDrawLayer(posX3, posY) < 7 && checkItemCollision(posX3, posY) == -1) { + itemX = posX3; + itemY = posY; + needRepositioning = false; + repositioning = false; + } + + if (isDropable(posX2, posY) && _screen->getDrawLayer(posX2, posY) < 7 && checkItemCollision(posX2, posY) == -1) { + itemX = posX2; + itemY = posY; + needRepositioning = false; + repositioning = false; + } + + if (repositioning) { + posX3 = MAX(posX3 - 2, 16); + posX2 = MIN(posX2 + 2, 304); + + if (posX3 <= 16 && posX2 >= 304) + repositioning = false; + } + } + } + + if (posY == 136) + needRepositioning = false; + else + posY = MIN(posY + 2, 136); + } + + if (itemX == -1 || itemY == -1) + return false; + + if (unk1 == 3) { + _itemList[freeItemSlot].x = itemX; + _itemList[freeItemSlot].y = itemY; + return true; + } else if (unk1 == 2) { + itemDropDown(x, y, itemX, itemY, freeItemSlot, item); + } + + if (!unk1) + removeHandItem(); + + itemDropDown(x, y, itemX, itemY, freeItemSlot, item); + + if (!unk1 && unk2) { + int itemStr = 3; + if (_lang == 1) + itemStr = getItemCommandStringDrop(item); + updateCommandLineEx(item+54, itemStr, 0xD6); + } + + return true; +} + +void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::itemDropDown(%d, %d, %d, %d, %d, %u)", startX, startY, dstX, dstY, itemSlot, item); + uint8 *itemShape = getShapePtr(item + 64); + + if (startX == dstX && startY == dstY) { + if (_layerFlagTable[_screen->getLayer(dstX, dstY)] && item != 13) { + updateCharFacing(); + snd_playSoundEffect(0x2d); + removeHandItem(); + objectChat(getTableString(0xFF, _cCodeBuffer, 1), 0, 0x83, 0xFF); + } else { + _itemList[itemSlot].x = dstX; + _itemList[itemSlot].y = dstY; + _itemList[itemSlot].id = item; + _itemList[itemSlot].sceneId = _mainCharacter.sceneId; + snd_playSoundEffect(0x0c); + addItemToAnimList(itemSlot); + } + } else { + _screen->hideMouse(); + + if (startY <= dstY) { + int speed = 2; + int curY = startY; + int curX = startX - 8; + + backUpGfxRect24x24(curX, curY-16); + while (curY < dstY) { + restoreGfxRect24x24(curX, curY-16); + + curY = MIN(curY + speed, dstY); + ++speed; + + backUpGfxRect24x24(curX, curY-16); + uint32 endDelay = _system->getMillis() + _tickLength; + + _screen->drawShape(0, itemShape, curX, curY-16, 0, 0); + _screen->updateScreen(); + + // XXX: original doesn't update game state while delaying + // our implementation *could* do it, so maybe check this again + delayUntil(endDelay); + } + + if (dstX != dstY || (dstY - startY > 16)) { + snd_playSoundEffect(0x69); + speed = MAX(speed, 6); + int speedX = ((dstX - startX) << 4) / speed; + int origSpeed = speed; + speed >>= 1; + + if (dstY - startY <= 8) + speed >>= 1; + + speed = -speed; + + curX = startX << 4; + + int x = 0, y = 0; + while (--origSpeed) { + x = (curX >> 4) - 8; + y = curY - 16; + + restoreGfxRect24x24(x, y); + curY = MIN(curY + speed, dstY); + curX += speedX; + ++speed; + + x = (curX >> 4) - 8; + y = curY - 16; + backUpGfxRect24x24(x, y); + + uint16 endDelay = _system->getMillis() + _tickLength; + _screen->drawShape(0, itemShape, x, y, 0, 0); + _screen->updateScreen(); + + // XXX: original doesn't update game state while delaying + // our implementation *could* do it, so maybe check this again + delayUntil(endDelay); + } + + restoreGfxRect24x24(x, y); + } else { + restoreGfxRect24x24(curX, curY-16); + } + } + + if (_layerFlagTable[_screen->getLayer(dstX, dstY)] && item != 13) { + updateCharFacing(); + snd_playSoundEffect(0x2d); + removeHandItem(); + _screen->showMouse(); + objectChat(getTableString(0xFF, _cCodeBuffer, 1), 0, 0x83, 0xFF); + } else { + _itemList[itemSlot].x = dstX; + _itemList[itemSlot].y = dstY; + _itemList[itemSlot].id = item; + _itemList[itemSlot].sceneId = _mainCharacter.sceneId; + snd_playSoundEffect(0x0c); + addItemToAnimList(itemSlot); + _screen->showMouse(); + } + } +} + +void KyraEngine_HoF::exchangeMouseItem(int itemPos) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::exchangeMouseItem(%d)", itemPos); + _screen->hideMouse(); + + deleteItemAnimEntry(itemPos); + + int itemId = _itemList[itemPos].id; + _itemList[itemPos].id = _itemInHand; + _itemInHand = itemId; + + addItemToAnimList(itemPos); + snd_playSoundEffect(0x0b); + setMouseCursor(_itemInHand); + int str2 = 7; + + if (_lang == 1) + str2 = getItemCommandStringPickUp(itemId); + + updateCommandLineEx(itemId + 54, str2, 0xD6); + _screen->showMouse(); + + runSceneScript6(); +} + +bool KyraEngine_HoF::pickUpItem(int x, int y) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::pickUpItem(%d, %d)", x, y); + int itemPos = checkItemCollision(x, y); + + if (itemPos <= -1) + return false; + + if (_itemInHand >= 0) { + exchangeMouseItem(itemPos); + } else { + _screen->hideMouse(); + deleteItemAnimEntry(itemPos); + int itemId = _itemList[itemPos].id; + _itemList[itemPos].id = 0xFFFF; + snd_playSoundEffect(0x0b); + setMouseCursor(itemId); + int str2 = 7; + + if (_lang == 1) + str2 = getItemCommandStringPickUp(itemId); + + updateCommandLineEx(itemId + 54, str2, 0xD6); + _itemInHand = itemId; + _screen->showMouse(); + + runSceneScript6(); + } + + return true; +} + +bool KyraEngine_HoF::isDropable(int x, int y) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::isDropable(%d, %d)", x, y); + if (x < 14 || x > 304 || y < 14 || y > 136) + return false; + + x -= 8; + y -= 1; + + for (int xpos = x; xpos < x + 16; ++xpos) { + if (_screen->getShapeFlag1(xpos, y) == 0) + return false; + } + + return true; +} + +int KyraEngine_HoF::getItemCommandStringDrop(uint16 item) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::getItemCommandStringDrop(%u)", item); + assert(item < _itemStringMapSize); + int stringId = _itemStringMap[item]; + + static const int dropStringIds[] = { + 0x2D, 0x103, 0x003, 0x106 + }; + assert(stringId < ARRAYSIZE(dropStringIds)); + + return dropStringIds[stringId]; +} + +int KyraEngine_HoF::getItemCommandStringPickUp(uint16 item) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::getItemCommandStringPickUp(%u)", item); + assert(item < _itemStringMapSize); + int stringId = _itemStringMap[item]; + + static const int pickUpStringIds[] = { + 0x02B, 0x102, 0x007, 0x105 + }; + assert(stringId < ARRAYSIZE(pickUpStringIds)); + + return pickUpStringIds[stringId]; +} + +int KyraEngine_HoF::getItemCommandStringInv(uint16 item) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::getItemCommandStringInv(%u)", item); + assert(item < _itemStringMapSize); + int stringId = _itemStringMap[item]; + + static const int pickUpStringIds[] = { + 0x02C, 0x104, 0x008, 0x107 + }; + assert(stringId < ARRAYSIZE(pickUpStringIds)); + + return pickUpStringIds[stringId]; +} + +bool KyraEngine_HoF::itemIsFlask(int item) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::itemIsFlask(%d)", item); + for (int i = 0; _flaskTable[i] != -1; ++i) { + if (_flaskTable[i] == item) + return true; + } + + return false; +} + +void KyraEngine_HoF::setMouseCursor(uint16 item) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::setMouseCursor(%u)", item); + int shape = 0; + int hotX = 1; + int hotY = 1; + + if (item != 0xFFFF) { + hotX = 8; + hotY = 15; + shape = item+64; + } + + _screen->setMouseCursor(hotX, hotY, getShapePtr(shape)); +} + +} // end of namespace Kyra + |