diff options
Diffstat (limited to 'engines/kyra/engine/items_mr.cpp')
-rw-r--r-- | engines/kyra/engine/items_mr.cpp | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/engines/kyra/engine/items_mr.cpp b/engines/kyra/engine/items_mr.cpp new file mode 100644 index 0000000000..3963934ffb --- /dev/null +++ b/engines/kyra/engine/items_mr.cpp @@ -0,0 +1,536 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "kyra/engine/kyra_mr.h" +#include "kyra/engine/timer.h" + +#include "common/system.h" + +namespace Kyra { + +void KyraEngine_MR::removeTrashItems() { + for (int i = 0; _trashItemList[i] != kItemNone; ++i) { + for (int item = findItem(_trashItemList[i]); item != -1; item = findItem(_trashItemList[i])) { + if (_itemList[item].sceneId != _mainCharacter.sceneId) + resetItem(item); + else + break; + } + } +} + +int KyraEngine_MR::findFreeInventorySlot() { + for (int i = 0; i < 10; ++i) { + if (_mainCharacter.inventory[i] == kItemNone) + return i; + } + return -1; +} + +int KyraEngine_MR::checkItemCollision(int x, int y) { + int itemIndex = -1; + int maxItemY = -1; + + for (int i = 0; i < 50; ++i) { + if (_itemList[i].id == kItemNone || _itemList[i].sceneId != _mainCharacter.sceneId) + continue; + + const int x1 = _itemList[i].x - 11; + const int x2 = _itemList[i].x + 10; + + if (x < x1 || x > x2) + continue; + + const int y1 = _itemList[i].y - _itemBuffer1[_itemList[i].id] - 3; + const int y2 = _itemList[i].y + 3; + + if (y < y1 || y > y2) + continue; + + if (_itemList[i].y >= maxItemY) { + itemIndex = i; + maxItemY = _itemList[i].y; + } + } + + return itemIndex; +} + +void KyraEngine_MR::setMouseCursor(Item item) { + int shape = 0; + int hotX = 1; + int hotY = 1; + + if (item != kItemNone) { + hotX = 12; + hotY = 19; + shape = item+248; + } + + _mouseState = item; + if ((int16)item >= 0) + _screen->setMouseCursor(hotX, hotY, getShapePtr(shape)); +} + +void KyraEngine_MR::setItemMouseCursor() { + _mouseState = _itemInHand; + if (_itemInHand == kItemNone) + _screen->setMouseCursor(0, 0, _gameShapes[0]); + else + _screen->setMouseCursor(12, 19, _gameShapes[_itemInHand+248]); +} + +bool KyraEngine_MR::dropItem(int unk1, Item item, int x, int y, int unk2) { + if (_mouseState <= -1) + return false; + + if (processItemDrop(_mainCharacter.sceneId, item, x, y, unk1, unk2)) + return true; + + snd_playSoundEffect(13, 200); + + if (countAllItems() >= 50) { + removeTrashItems(); + if (processItemDrop(_mainCharacter.sceneId, item, x, y, unk1, unk2)) + return true; + + if (countAllItems() >= 50) + showMessageFromCCode(14, 0xB3, 0); + } + + if (!_chatText) + snd_playSoundEffect(13, 200); + return false; +} + +bool KyraEngine_MR::processItemDrop(uint16 sceneId, Item item, int x, int y, int unk1, int unk2) { + int itemPos = checkItemCollision(x, y); + + if (unk1) + itemPos = -1; + + if (itemPos >= 0) { + exchangeMouseItem(itemPos, 1); + return true; + } + + int freeItemSlot = -1; + + if (unk2 != 3) { + for (int i = 0; i < 50; ++i) { + if (_itemList[i].id == kItemNone) { + freeItemSlot = i; + break; + } + } + } + + if (freeItemSlot < 0) + return false; + + if (_mainCharacter.sceneId != sceneId) { + _itemList[freeItemSlot].x = x; + _itemList[freeItemSlot].y = y; + _itemList[freeItemSlot].id = item; + _itemList[freeItemSlot].sceneId = sceneId; + return true; + } + + int itemHeight = _itemBuffer1[item]; + + // no idea why it's '&&' here and not single checks for x and y + if (x == -1 && y == -1) { + x = _rnd.getRandomNumberRng(0x18, 0x128); + y = _rnd.getRandomNumberRng(0x14, 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 == 187) { + int posX2 = posX, posX3 = posX; + bool repositioning = true; + + while (repositioning) { + if (isDropable(posX3, posY) && _screen->getDrawLayer2(posX3, posY, itemHeight) < 7 && checkItemCollision(posX3, posY) == -1) { + itemX = posX3; + itemY = posY; + needRepositioning = false; + repositioning = false; + } + + if (isDropable(posX2, posY) && _screen->getDrawLayer2(posX2, posY, itemHeight) < 7 && checkItemCollision(posX2, posY) == -1) { + itemX = posX2; + itemY = posY; + needRepositioning = false; + repositioning = false; + } + + if (repositioning) { + posX3 = MAX(posX3 - 2, 24); + posX2 = MIN(posX2 + 2, 296); + + if (posX3 <= 24 && posX2 >= 296) + repositioning = false; + } + } + } + + if (posY == 187) + needRepositioning = false; + else + posY = MIN(posY + 2, 187); + } + + 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, 0); + } + + itemDropDown(x, y, itemX, itemY, freeItemSlot, item, (unk1 == 0) ? 1 : 0); + + if (!unk1 && unk2) { + int itemStr = 1; + if (_lang == 1) + itemStr = getItemCommandStringDrop(item); + updateItemCommand(item, itemStr, 0xFF); + } + + return true; +} + +void KyraEngine_MR::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, Item item, int remove) { + if (startX == dstX && startY == dstY) { + _itemList[itemSlot].x = dstX; + _itemList[itemSlot].y = dstY; + _itemList[itemSlot].id = item; + _itemList[itemSlot].sceneId = _mainCharacter.sceneId; + snd_playSoundEffect(0x0C, 0xC8); + addItemToAnimList(itemSlot); + } else { + uint8 *itemShape = getShapePtr(item + 248); + _screen->hideMouse(); + + if (startY <= dstY) { + int speed = 2; + int curY = startY; + int curX = startX - 12; + + backUpGfxRect32x32(curX, curY-16); + while (curY < dstY) { + restoreGfxRect32x32(curX, curY-16); + + curY = MIN(curY + speed, dstY); + ++speed; + + backUpGfxRect32x32(curX, curY-16); + uint32 endDelay = _system->getMillis() + _tickLength; + + _screen->drawShape(0, itemShape, curX, curY-16, 0, 0); + _screen->updateScreen(); + + delayUntil(endDelay); + } + restoreGfxRect32x32(curX, curY-16); + + if (dstX != dstY || (dstY - startY > 16)) { + snd_playSoundEffect(0x11, 0xC8); + 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) { + curY = MIN(curY + speed, dstY); + curX += speedX; + ++speed; + + x = (curX >> 4) - 8; + y = curY - 16; + backUpGfxRect32x32(x, y); + + uint16 endDelay = _system->getMillis() + _tickLength; + _screen->drawShape(0, itemShape, x, y, 0, 0); + _screen->updateScreen(); + + restoreGfxRect32x32(x, y); + + delayUntil(endDelay); + } + + restoreGfxRect32x32(x, y); + } + } + + _itemList[itemSlot].x = dstX; + _itemList[itemSlot].y = dstY; + _itemList[itemSlot].id = item; + _itemList[itemSlot].sceneId = _mainCharacter.sceneId; + snd_playSoundEffect(0x0C, 0xC8); + addItemToAnimList(itemSlot); + _screen->showMouse(); + } + + if (remove) + removeHandItem(); +} + +void KyraEngine_MR::exchangeMouseItem(int itemPos, int runScript) { + if (itemListMagic(_itemInHand, itemPos)) + return; + + if (_itemInHand == 43) { + removeHandItem(); + return; + } + + deleteItemAnimEntry(itemPos); + + Item itemId = _itemList[itemPos].id; + _itemList[itemPos].id = _itemInHand; + _itemInHand = itemId; + + addItemToAnimList(itemPos); + snd_playSoundEffect(0x0B, 0xC8); + setMouseCursor(_itemInHand); + int str2 = 0; + + if (_lang == 1) + str2 = getItemCommandStringPickUp(itemId); + + updateItemCommand(itemId, str2, 0xFF); + + if (runScript) + runSceneScript6(); +} + +bool KyraEngine_MR::pickUpItem(int x, int y, int runScript) { + int itemPos = checkItemCollision(x, y); + + if (itemPos <= -1) + return false; + + if (_itemInHand >= 0) { + exchangeMouseItem(itemPos, runScript); + } else { + deleteItemAnimEntry(itemPos); + Item itemId = _itemList[itemPos].id; + _itemList[itemPos].id = kItemNone; + snd_playSoundEffect(0x0B, 0xC8); + setMouseCursor(itemId); + int itemString = 0; + + if (_lang == 1) + itemString = getItemCommandStringPickUp(itemId); + + updateItemCommand(itemId, itemString, 0xFF); + _itemInHand = itemId; + + if (runScript) + runSceneScript6(); + } + + return true; +} + +bool KyraEngine_MR::isDropable(int x, int y) { + if (y < 14 || y > 187) + return false; + + x -= 12; + + for (int xpos = x; xpos < x + 24; ++xpos) { + if (_screen->getShapeFlag1(xpos, y) == 0) + return false; + } + + return true; +} + +bool KyraEngine_MR::itemListMagic(Item handItem, int itemSlot) { + Item item = _itemList[itemSlot].id; + + if (_currentChapter == 1 && handItem == 3 && item == 3 && queryGameFlag(0x76)) { + eelScript(); + return true; + } else if ((handItem == 6 || handItem == 7) && item == 2) { + int animObjIndex = -1; + for (int i = 17; i <= 66; ++i) { + if (_animObjects[i].shapeIndex2 == 250) + animObjIndex = i; + } + + assert(animObjIndex != -1); + + snd_playSoundEffect(0x93, 0xC8); + for (int i = 109; i <= 141; ++i) { + _animObjects[animObjIndex].shapeIndex1 = i+248; + _animObjects[animObjIndex].needRefresh = true; + delay(1*_tickLength, true); + } + + deleteItemAnimEntry(itemSlot); + _itemList[itemSlot].id = kItemNone; + return true; + } + + if (_mainCharacter.sceneId == 51 && queryGameFlag(0x19B) && !queryGameFlag(0x19C) + && ((item == 63 && handItem == 56) || (item == 56 && handItem == 63))) { + + if (queryGameFlag(0x1AC)) { + setGameFlag(0x19C); + setGameFlag(0x1AD); + } else { + setGameFlag(0x1AE); + } + + _timer->setCountdown(12, 1); + _timer->enable(12); + } + + for (int i = 0; _itemMagicTable[i] != 0xFF; i += 4) { + if (_itemMagicTable[i+0] != handItem || (int8)_itemMagicTable[i+1] != item) + continue; + + uint8 resItem = _itemMagicTable[i+2]; + uint8 newItem = _itemMagicTable[i+3]; + + snd_playSoundEffect(0x0F, 0xC8); + + _itemList[itemSlot].id = (int8)resItem; + + deleteItemAnimEntry(itemSlot); + addItemToAnimList(itemSlot); + + if (newItem == 0xFE) + removeHandItem(); + else if (newItem != 0xFF) + setHandItem(newItem); + + if (_lang != 1) + updateItemCommand(resItem, 3, 0xFF); + + // Unlike the original we give points for when combining with scene items + if (resItem == 7) { + updateScore(35, 100); + delay(60*_tickLength, true); + } + + return true; + } + + return false; +} + +bool KyraEngine_MR::itemInventoryMagic(Item handItem, int invSlot) { + Item item = _mainCharacter.inventory[invSlot]; + + if (_currentChapter == 1 && handItem == 3 && item == 3 && queryGameFlag(0x76)) { + eelScript(); + return true; + } else if ((handItem == 6 || handItem == 7) && item == 2) { + _screen->hideMouse(); + snd_playSoundEffect(0x93, 0xC8); + for (int i = 109; i <= 141; ++i) { + _mainCharacter.inventory[invSlot] = i; + _screen->drawShape(2, getShapePtr(invSlot+422), 0, 144, 0, 0); + _screen->drawShape(2, getShapePtr(i+248), 0, 144, 0, 0); + _screen->copyRegion(0, 144, _inventoryX[invSlot], _inventoryY[invSlot], 24, 20, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + delay(1*_tickLength, true); + } + + _mainCharacter.inventory[invSlot] = kItemNone; + clearInventorySlot(invSlot, 0); + _screen->showMouse(); + return true; + } + + for (int i = 0; _itemMagicTable[i] != 0xFF; i += 4) { + if (_itemMagicTable[i+0] != handItem || _itemMagicTable[i+1] != item) + continue; + + uint8 resItem = _itemMagicTable[i+2]; + uint8 newItem = _itemMagicTable[i+3]; + + snd_playSoundEffect(0x0F, 0xC8); + + _mainCharacter.inventory[invSlot] = (int8)resItem; + + clearInventorySlot(invSlot, 0); + drawInventorySlot(0, resItem, invSlot); + + if (newItem == 0xFE) + removeHandItem(); + else if (newItem != 0xFF) + setHandItem(newItem); + + if (_lang != 1) + updateItemCommand(resItem, 3, 0xFF); + + // Unlike the original we give points for every language + if (resItem == 7) { + updateScore(35, 100); + delay(60*_tickLength, true); + } + + return true; + } + + return false; +} + +int KyraEngine_MR::getItemCommandStringDrop(uint16 item) { + assert(item < _itemStringMapSize); + int stringId = _itemStringMap[item]; + return _itemStringDrop[stringId]; +} + +int KyraEngine_MR::getItemCommandStringPickUp(uint16 item) { + assert(item < _itemStringMapSize); + int stringId = _itemStringMap[item]; + return _itemStringPickUp[stringId]; +} + +int KyraEngine_MR::getItemCommandStringInv(uint16 item) { + assert(item < _itemStringMapSize); + int stringId = _itemStringMap[item]; + return _itemStringInv[stringId]; +} + +} // End of namespace Kyra |