scummvm/engines/kyra/items_v2.cpp
Johannes Schickel 28a57c434a Cleanup(/formatting).
svn-id: r29983
2007-12-24 22:27:30 +00:00

448 lines
10 KiB
C++

/* 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_v2.h"
namespace Kyra {
int KyraEngine_v2::findFreeItem() {
for (int i = 0; i < 30; ++i) {
if (_itemList[i].id == 0xFFFF)
return i;
}
return -1;
}
int KyraEngine_v2::countAllItems() {
int num = 0;
for (int i = 0; i < 30; ++i) {
if (_itemList[i].id != 0xFFFF)
++num;
}
return num;
}
int KyraEngine_v2::findItem(uint16 sceneId, uint16 id) {
for (int i = 0; i < 30; ++i) {
if (_itemList[i].id == id && _itemList[i].sceneId == sceneId)
return i;
}
return -1;
}
int KyraEngine_v2::checkItemCollision(int x, int 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_v2::resetItemList() {
for (int i = 0; i < 30; ++i) {
_itemList[i].id = 0xFFFF;
_itemList[i].sceneId = 0xFFFF;
_itemList[i].x = 0;
_itemList[i].y = 0;
_itemList[i].unk7 = 0;
}
}
bool KyraEngine_v2::dropItem(int unk1, uint16 item, int x, int y, int 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_v2::processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int 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) {
//addToItemList(sceneId, item, freeItemSlot, x, y);
//return true;
//XXX
return false;
}
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_v2::itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item) {
uint8 *itemShape = getShapePtr(item + 64);
if (startX == dstX && startY == dstY) {
if (_layerFlagTable[_screen->getLayer(dstX, dstY)] && item != 13) {
updateCharFacing();
snd_playSoundEffect(0x2d);
removeHandItem();
//XXX sub_277FA(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();
//XXX sub_277FA(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_v2::exchangeMouseItem(int 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_v2::pickUpItem(int x, int 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_v2::isDropable(int x, int 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_v2::getItemCommandStringDrop(uint16 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_v2::getItemCommandStringPickUp(uint16 item) {
assert(item < _itemStringMapSize);
int stringId = _itemStringMap[item];
static const int pickUpStringIds[] = {
0x02B, 0x102, 0x007, 0x105
};
assert(stringId < ARRAYSIZE(pickUpStringIds));
return pickUpStringIds[stringId];
}
void KyraEngine_v2::setMouseCursor(uint16 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));
}
void KyraEngine_v2::setHandItem(uint16 item) {
_screen->hideMouse();
if (item == 0xFFFF) {
removeHandItem();
} else {
setMouseCursor(item);
_itemInHand = item;
}
_screen->showMouse();
}
void KyraEngine_v2::removeHandItem() {
_screen->hideMouse();
_screen->setMouseCursor(0, 0, _defaultShapeTable[0]);
_itemInHand = -1;
_handItemSet = -1;
_screen->showMouse();
}
} // end of namespace Kyra