Initial commit
This commit is contained in:
426
engines/kyra/engine/items_hof.cpp
Normal file
426
engines/kyra/engine/items_hof.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kyra/engine/kyra_hof.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Kyra {
|
||||
|
||||
int KyraEngine_HoF::checkItemCollision(int x, int y) {
|
||||
int itemPos = -1, yPos = -1;
|
||||
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
const ItemDefinition &curItem = _itemList[i];
|
||||
|
||||
if (curItem.id == kItemNone || 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() {
|
||||
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, Item item, int x, int y, int unk2) {
|
||||
if (_mouseState <= -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, Item 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 == kItemNone) {
|
||||
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;
|
||||
|
||||
// Comment out dead code (verified in disasm that it is really like that in the
|
||||
// original code: unk1 == 3 will automatically lead to freeItemSlot == -1, thus
|
||||
// returning from this function early, never to arrive here.
|
||||
/*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, Item 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, true), 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();
|
||||
|
||||
delayUntil(endDelay, false, true);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
delayUntil(endDelay, false, true);
|
||||
}
|
||||
|
||||
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, true), 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) {
|
||||
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);
|
||||
|
||||
runSceneScript6();
|
||||
}
|
||||
|
||||
bool KyraEngine_HoF::pickUpItem(int x, int y) {
|
||||
int itemPos = checkItemCollision(x, y);
|
||||
|
||||
if (itemPos <= -1)
|
||||
return false;
|
||||
|
||||
if (_itemInHand >= 0) {
|
||||
exchangeMouseItem(itemPos);
|
||||
} else {
|
||||
deleteItemAnimEntry(itemPos);
|
||||
int itemId = _itemList[itemPos].id;
|
||||
_itemList[itemPos].id = kItemNone;
|
||||
snd_playSoundEffect(0x0B);
|
||||
setMouseCursor(itemId);
|
||||
int str2 = 7;
|
||||
|
||||
if (_lang == 1)
|
||||
str2 = getItemCommandStringPickUp(itemId);
|
||||
|
||||
updateCommandLineEx(itemId + 54, str2, 0xD6);
|
||||
_itemInHand = itemId;
|
||||
|
||||
runSceneScript6();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KyraEngine_HoF::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_HoF::getItemCommandStringDrop(Item item) {
|
||||
assert(item >= 0 && 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(Item item) {
|
||||
assert(item >= 0 && 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(Item item) {
|
||||
assert(item >= 0 && 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(Item item) {
|
||||
for (int i = 0; _flaskTable[i] != kItemNone; ++i) {
|
||||
if (_flaskTable[i] == item)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void KyraEngine_HoF::setMouseCursor(Item item) {
|
||||
int shape = 0;
|
||||
int hotX = 1;
|
||||
int hotY = 1;
|
||||
|
||||
if (item != kItemNone) {
|
||||
hotX = 8;
|
||||
hotY = 15;
|
||||
shape = item+64;
|
||||
}
|
||||
|
||||
_screen->setMouseCursor(hotX, hotY, getShapePtr(shape));
|
||||
}
|
||||
|
||||
} // End of namespace Kyra
|
||||
Reference in New Issue
Block a user