- added support for dropping items into scenes
- added const to some static data
- implemented opcode 0x55 o2_setLayerFlag
- fixed a bug in Screen_v2::drawShape

svn-id: r29175
This commit is contained in:
Johannes Schickel 2007-10-09 04:47:41 +00:00
parent 8db35c8a62
commit cf3fd283bb
9 changed files with 366 additions and 53 deletions

View file

@ -191,6 +191,17 @@ void KyraEngine_v2::refreshAnimObjectsIfNeed() {
}
}
void KyraEngine_v2::updateCharFacing() {
if (_mainCharacter.x1 > _mouseX)
_mainCharacter.facing = 5;
else
_mainCharacter.facing = 3;
_mainCharacter.animFrame = _characterFrameTable[_mainCharacter.animFrame];
updateCharacterAnim(0);
refreshAnimObjectsIfNeed();
}
void KyraEngine_v2::updateCharacterAnim(int) {
Character *c = &_mainCharacter;
AnimObj *animState = _animObjects;
@ -331,7 +342,7 @@ void KyraEngine_v2::addItemToAnimList(int item) {
scaleY = scaleX = getScale(animObj->xPos1, animObj->yPos1);
uint8 *shapePtr = getShapePtr(64+itemId);
animObj->xPos3 = (animObj->xPos2 -= _screen->getShapeScaledWidth(shapePtr, scaleX) >> 1);
animObj->xPos3 = (animObj->xPos2 -= (_screen->getShapeScaledWidth(shapePtr, scaleX) >> 1));
animObj->yPos3 = (animObj->yPos2 -= _screen->getShapeScaledHeight(shapePtr, scaleY));
animObj->width2 = animObj->height2 = 0;

View file

@ -117,8 +117,203 @@ bool KyraEngine_v2::processItemDrop(uint16 sceneId, uint16 item, int x, int y, i
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_playSfx(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_playSfx(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_playSfx(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_playSfx(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_playSfx(0x0c);
addItemToAnimList(itemSlot);
_screen->showMouse();
}
}
}
void KyraEngine_v2::exchangeMouseItem(int itemPos) {
@ -136,7 +331,7 @@ void KyraEngine_v2::exchangeMouseItem(int itemPos) {
int str2 = 7;
if (_lang == 1)
str2 = getItemCommandString(itemId);
str2 = getItemCommandStringPickUp(itemId);
updateCommandLineEx(itemId + 54, str2, 0xD6);
_screen->showMouse();
@ -162,7 +357,7 @@ bool KyraEngine_v2::pickUpItem(int x, int y) {
int str2 = 7;
if (_lang == 1)
str2 = getItemCommandString(itemId);
str2 = getItemCommandStringPickUp(itemId);
updateCommandLineEx(itemId + 54, str2, 0xD6);
_itemInHand = itemId;
@ -174,42 +369,43 @@ bool KyraEngine_v2::pickUpItem(int x, int y) {
return true;
}
int KyraEngine_v2::getItemCommandString(uint16 item) {
// This is just needed for French version
static const uint8 index[] = {
2, 2, 0, 0, 2, 2, 2, 0,
2, 2, 0, 0, 0, 2, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0,
0, 1, 0, 2, 2, 2, 2, 0,
3, 0, 3, 2, 2, 2, 3, 2,
2, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 2, 0, 0,
2, 0, 0, 0, 0, 0, 0, 2,
2, 0, 0, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0,
2, 2, 2, 0, 0, 1, 3, 2,
2, 2, 2, 2, 2, 0, 0, 0,
0, 2, 2, 1, 0, 1, 2, 0,
0, 0, 0, 0, 0, 2, 2, 2,
2, 2, 2, 2, 0, 2, 2, 2,
2, 3, 2, 0, 0, 0, 0, 1,
2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 0, 0, 0, 0, 0, 2,
0, 2, 0, 0, 0, 0, 0, 0
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));
assert(item < ARRAYSIZE(index));
return dropStringIds[stringId];
}
static const int stringId[] = {
0x02B, 0x102, 0x007, 0x105, 0x02D, 0x103,
0x003, 0x106, 0x02C, 0x104, 0x008, 0x107
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));
assert(index[item] < ARRAYSIZE(index));
return stringId[index[item]];
return pickUpStringIds[stringId];
}
void KyraEngine_v2::setMouseCursor(uint16 item) {
@ -226,4 +422,12 @@ void KyraEngine_v2::setMouseCursor(uint16 item) {
_screen->setMouseCursor(hotX, hotY, getShapePtr(shape));
}
void KyraEngine_v2::removeHandItem() {
_screen->hideMouse();
_screen->setMouseCursor(0, 0, _defaultShapeTable[0]);
_itemInHand = -1;
_handItemSet = -1;
_screen->showMouse();
}
} // end of namespace Kyra

View file

@ -242,6 +242,7 @@ void KyraEngine_v2::startup() {
_gfxBackUpRect = new uint8[_screen->getRectSize(32, 32)];
_itemList = new Item[30];
memset(_itemList, 0, sizeof(Item)*30);
resetItemList();
//loadButtonShapes();
_loadedZTable = 1;
@ -381,12 +382,12 @@ void KyraEngine_v2::handleInput(int x, int y) {
return;
}
/*if (_itemInHand >= 0) {
if (_itemInHand >= 0) {
if (y > 136)
return;
dropItem(0, _itemInHand, x, y, 1);
} else {*/
} else {
if (_unk3 == -2 || y > 135)
return;
@ -396,7 +397,7 @@ void KyraEngine_v2::handleInput(int x, int y) {
}
_unk5 = 0;
//}
}
}
}
@ -1176,6 +1177,16 @@ int KyraEngine_v2::checkCharCollision(int x, int y) {
#pragma mark -
void KyraEngine_v2::backUpGfxRect24x24(int x, int y) {
_screen->copyRegionToBuffer(_screen->_curPage, x, y, 24, 24, _gfxBackUpRect);
}
void KyraEngine_v2::restoreGfxRect24x24(int x, int y) {
_screen->copyBlockToPage(_screen->_curPage, x, y, 24, 24, _gfxBackUpRect);
}
#pragma mark -
typedef Functor1Mem<ScriptState*, int, KyraEngine_v2> OpcodeV2;
#define Opcode(x) OpcodeV2(this, &KyraEngine_v2::x)
#define OpcodeUnImpl() OpcodeV2(this, 0)
@ -1288,7 +1299,7 @@ void KyraEngine_v2::setupOpcodeTable() {
OpcodeUnImpl(),
// 0x54
OpcodeUnImpl(),
OpcodeUnImpl(),
Opcode(o2_setLayerFlag),
OpcodeUnImpl(),
OpcodeUnImpl(),
// 0x58

View file

@ -186,6 +186,9 @@ protected:
uint8 *_maskPage;
uint8 *_gfxBackUpRect;
void backUpGfxRect24x24(int x, int y);
void restoreGfxRect24x24(int x, int y);
uint8 *getShapePtr(int index) { return _defaultShapeTable[index]; }
uint8 *_defaultShapeTable[250];
uint8 *_sceneShapeTable[50];
@ -239,6 +242,8 @@ protected:
int getDrawLayer(int x, int y);
int _drawLayerTable[15];
int _layerFlagTable[16]; // seems to indicate layers where items get destroyed when dropped to (TODO: check this!)
// animator
struct AnimObj {
uint16 index;
@ -282,6 +287,7 @@ protected:
void refreshAnimObjects(int force);
void refreshAnimObjectsIfNeed();
void updateCharFacing();
void updateCharacterAnim(int);
void updateSceneAnim(int anim, int newFrame);
@ -352,7 +358,7 @@ protected:
uint16 id;
uint16 sceneId;
int16 x;
int8 y;
uint8 y;
uint16 unk7;
};
Item *_itemList;
@ -368,16 +374,25 @@ protected:
bool dropItem(int unk1, uint16 item, int x, int y, int unk2);
bool processItemDrop(uint16 sceneId, uint16 item, int x, int y, int unk1, int unk2);
void itemDropDown(int startX, int startY, int dstX, int dstY, int itemSlot, uint16 item);
void exchangeMouseItem(int itemPos);
bool pickUpItem(int x, int y);
int getItemCommandString(uint16 item);
bool isDropable(int x, int y);
static const byte _itemStringMap[];
static const int _itemStringMapSize;
// Just used in French version
int getItemCommandStringDrop(uint16 item);
int getItemCommandStringPickUp(uint16 item);
void setMouseCursor(uint16 item);
void removeHandItem();
// inventroy
static int _inventoryX[];
static int _inventoryY[];
static const int _inventoryX[];
static const int _inventoryY[];
// localization
void loadCCodeBuffer(const char *file);
@ -433,7 +448,7 @@ protected:
int _mainCharX, _mainCharY;
int _charScaleX, _charScaleY;
static int _characterFrameTable[];
static const int _characterFrameTable[];
// text
void showMessageFromCCode(int id, int16 palIndex, int);
@ -480,6 +495,7 @@ protected:
int o2_setDrawLayerTableItem(ScriptState *script);
int o2_drawSceneShapeOnPage(ScriptState *script);
int o2_restoreBackBuffer(ScriptState *script);
int o2_setLayerFlag(ScriptState *script);
int o2_getRand(ScriptState *script);
int o2_encodeShape(ScriptState *script);
int o2_defineRoomEntrance(ScriptState *script);

View file

@ -392,7 +392,7 @@ void KyraEngine_v2::startSceneScript(int unk1) {
resetScaleTable();
_useCharPal = false;
memset(_charPalTable, 0, sizeof(_charPalTable));
//XXX _unkTable33
memset(_layerFlagTable, 0, sizeof(_layerFlagTable));
memset(_specialSceneScriptState, 0, sizeof(_specialSceneScriptState));
_sceneEnterX1 = 160;

View file

@ -573,10 +573,28 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag
void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *dest) {
debugC(9, kDebugLevelScreen, "Screen::copyRegionToBuffer(%d, %d, %d, %d, %d)", pageNum, x, y, w, h);
assert(x >= 0 && x < Screen::SCREEN_W && y >= 0 && y < Screen::SCREEN_H && dest);
if (y < 0) {
dest += (-y) * w;
h += y;
y = 0;
} else if (y + h > SCREEN_H) {
h = SCREEN_H - y;
}
if (x < 0) {
dest += -x;
w += x;
x = 0;
} else if (x + w > SCREEN_W) {
w = SCREEN_W - x;
}
if (w < 0 || h < 0)
return;
uint8 *pagePtr = getPagePtr(pageNum);
for (int i = y; i < y + h; i++)
for (int i = y; i < y + h; ++i)
memcpy(dest + (i - y) * w, pagePtr + i * SCREEN_W + x, w);
}
@ -593,7 +611,25 @@ void Screen::copyPage(uint8 srcPage, uint8 dstPage) {
void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint8 *src) {
debugC(9, kDebugLevelScreen, "Screen::copyBlockToPage(%d, %d, %d, %d, %d, %p)", pageNum, x, y, w, h, (const void *)src);
assert(x >= 0 && x < Screen::SCREEN_W && y >= 0 && y < Screen::SCREEN_H);
if (y < 0) {
src += (-y) * w;
h += y;
y = 0;
} else if (y + h > SCREEN_H) {
h = SCREEN_H - y;
}
if (x < 0) {
src += -x;
w += x;
x = 0;
} else if (x + w > SCREEN_W) {
w = SCREEN_W - x;
}
if (w < 0 || h < 0)
return;
uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W + x;
if (pageNum == 0 || pageNum == 1)

View file

@ -500,7 +500,7 @@ void Screen_v2::drawShape(uint8 page, const uint8 *shape, int x, int y, int sd,
case 8: {
int layer = _shapePages[0][dst - dstStart] & 7;
if (drawLayer > layer)
if (drawLayer < layer)
color = _shapePages[1][dst - dstStart];
*dst = color;
} break;

View file

@ -294,6 +294,14 @@ int KyraEngine_v2::o2_restoreBackBuffer(ScriptState *script) {
return 0;
}
int KyraEngine_v2::o2_setLayerFlag(ScriptState *script) {
debugC(3, kDebugLevelScriptFuncs, "o2_setLayerFlag(%p) (%d)", (const void *)script, stackPos(0));
int layer = stackPos(0);
if (layer >= 1 && layer <= 16)
_layerFlagTable[layer] = 1;
return 0;
}
int KyraEngine_v2::o2_getRand(ScriptState *script) {
debugC(3, kDebugLevelScriptFuncs, "o2_getRand(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
assert(stackPos(0) < stackPos(1));

View file

@ -1229,18 +1229,45 @@ const char *KyraEngine_v2::_scriptLangExt[] = {
"SMC"*/
};
int KyraEngine_v2::_characterFrameTable[] = {
const int KyraEngine_v2::_characterFrameTable[] = {
0x19, 0x09, 0x09, 0x12, 0x12, 0x12, 0x09, 0x09
};
int KyraEngine_v2::_inventoryX[] = {
const int KyraEngine_v2::_inventoryX[] = {
0x4F, 0x63, 0x77, 0x8B, 0x9F, 0x4F, 0x63, 0x77, 0x8B, 0x9F
};
int KyraEngine_v2::_inventoryY[] = {
const int KyraEngine_v2::_inventoryY[] = {
0x95, 0x95, 0x95, 0x95, 0x95, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
};
const byte KyraEngine_v2::_itemStringMap[] = {
2, 2, 0, 0, 2, 2, 2, 0,
2, 2, 0, 0, 0, 2, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0,
0, 1, 0, 2, 2, 2, 2, 0,
3, 0, 3, 2, 2, 2, 3, 2,
2, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 2, 0, 0,
2, 0, 0, 0, 0, 0, 0, 2,
2, 0, 0, 0, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 0,
2, 2, 2, 0, 0, 1, 3, 2,
2, 2, 2, 2, 2, 0, 0, 0,
0, 2, 2, 1, 0, 1, 2, 0,
0, 0, 0, 0, 0, 2, 2, 2,
2, 2, 2, 2, 0, 2, 2, 2,
2, 3, 2, 0, 0, 0, 0, 1,
2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 0, 0, 0, 0, 0, 2,
0, 2, 0, 0, 0, 0, 0, 0
};
const int KyraEngine_v2::_itemStringMapSize = ARRAYSIZE(KyraEngine_v2::_itemStringMap);
// kyra 3 static res
const char *KyraEngine_v3::_soundList[] = {