diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp index 95294130c57..f996c573438 100644 --- a/kyra/kyra.cpp +++ b/kyra/kyra.cpp @@ -323,9 +323,11 @@ int KyraEngine::init(GameDetector &detector) { memset(_itemTable, 0, sizeof(_itemTable)); memset(_exitList, 0xFFFF, sizeof(_exitList)); _exitListPtr = 0; + _pathfinderFlag = 0; _movFacingTable = new int[150]; assert(_movFacingTable); + _movFacingTable[0] = 8; return 0; } @@ -1010,7 +1012,7 @@ void KyraEngine::loadMouseShapes() { _shapes[364] = _screen->encodeShape(0x28, 0, 0x10, 13, 0); _screen->setMouseCursor(1, 1, 0); _screen->setMouseCursor(1, 1, _shapes[4]); - _screen->setShapePages(3, 5); + _screen->setShapePages(5, 3); } void KyraEngine::loadCharacterShapes() { @@ -1165,7 +1167,7 @@ void KyraEngine::setCharactersInDefaultScene() { void KyraEngine::setCharacterDefaultFrame(int character) { static uint16 initFrameTable[] = { - 0x07, 0x29, 0x4D, 0x00, 0x00 + 7, 41, 77, 0, 0 }; assert(character < ARRAYSIZE(initFrameTable)); Character *edit = &_characterList[character]; @@ -1176,12 +1178,11 @@ void KyraEngine::setCharacterDefaultFrame(int character) { } void KyraEngine::setCharactersPositions(int character) { - static int16 initXPosTable[] = { + static uint16 initXPosTable[] = { 0x3200, 0x0024, 0x2230, 0x2F00, 0x0020, 0x002B, - 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042, 0x6767, - 0x5A60 + 0x00CA, 0x00F0, 0x0082, 0x00A2, 0x0042 }; - static int8 initYPosTable[] = { + static uint8 initYPosTable[] = { 0x00, 0xA2, 0x00, 0x42, 0x00, 0x67, 0x67, 0x60, 0x5A, 0x71, 0x76 @@ -1194,9 +1195,9 @@ void KyraEngine::setCharactersPositions(int character) { void KyraEngine::setCharactersHeight() { static int8 initHeightTable[] = { - 0x30, 0x28, 0x30, 0x2F, 0x38, - 0x2C, 0x2A, 0x2F, 0x26, 0x23, - 0x28 + 48, 40, 48, 47, 56, + 44, 42, 47, 38, 35, + 40 }; for (int i = 0; i < 11; ++i) { _characterList[i].height = initHeightTable[i]; @@ -1218,6 +1219,7 @@ int KyraEngine::resetGameFlag(int flag) { } void KyraEngine::enterNewScene(int sceneId, int facing, int unk1, int unk2, int brandonAlive) { + debug(9, "enterNewScene(%d, %d, %d, %d, %d)", sceneId, facing, unk1, unk2, brandonAlive); int unkVar1 = 1; _screen->hideMouse(); if (_currentCharacter->sceneId == 7 && sceneId == 24) { @@ -1413,18 +1415,14 @@ void KyraEngine::setCharacterPositionWithUpdate(int character) { int KyraEngine::setCharacterPosition(int character, uint8 *unk1) { debug(9, "setCharacterPosition(%d)", character); - static bool firstRun = true; if (character == 0) { - if (firstRun) { - firstRun = false; - _currentCharacter->x1 += _charXPosTable[character]; - _currentCharacter->y1 += _charYPosTable[character]; - setCharacterPositionHelper(0, unk1); - return 1; - } + _currentCharacter->x1 += _charXPosTable[_currentCharacter->facing]; + _currentCharacter->y1 += _charYPosTable[_currentCharacter->facing]; + setCharacterPositionHelper(0, unk1); + return 1; } else { - _characterList[character].x1 += _charXPosTable[character]; - _characterList[character].y1 += _charYPosTable[character]; + _characterList[character].x1 += _charXPosTable[_currentCharacter->facing]; + _characterList[character].y1 += _charYPosTable[_currentCharacter->facing]; if (_characterList[character].sceneId == _currentCharacter->sceneId) { setCharacterPositionHelper(character, 0); } @@ -1433,14 +1431,17 @@ int KyraEngine::setCharacterPosition(int character, uint8 *unk1) { } void KyraEngine::setCharacterPositionHelper(int character, uint8 *unk1) { + debug(9, "setCharacterPositionHelper(%d, 0x%X)", character, unk1); Character *ch = &_characterList[character]; + ++ch->currentAnimFrame; int facing = ch->facing; if (unk1) { + warning("unk1 handling is NOT implemented"); // XXX } - static uint8 facingIsZero[8]; - static uint8 facingIsFour[8]; + static uint8 facingIsZero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static uint8 facingIsFour[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; if (facing == 0) { ++facingIsZero[character]; @@ -2117,6 +2118,7 @@ void KyraEngine::placeItemInGenericMapScene(int item, int index) { #pragma mark - void KyraEngine::restoreAllObjectBackgrounds() { + debug(9, "restoreAllObjectBackground()"); AnimObject *curObject = _objectQueue; _screen->_curPage = 2; @@ -2134,6 +2136,7 @@ void KyraEngine::restoreAllObjectBackgrounds() { } void KyraEngine::preserveAnyChangedBackgrounds() { + debug(9, "preserveAnyChangedBackgrounds()"); AnimObject *curObject = _objectQueue; _screen->_curPage = 2; @@ -2150,6 +2153,7 @@ void KyraEngine::preserveAnyChangedBackgrounds() { } void KyraEngine::preserveOrRestoreBackground(AnimObject *obj, bool restore) { + debug(9, "preserveOrRestoreBackground(0x%X, restore)", obj, restore); int x, y, width = obj->width, height = obj->height; if (restore) { @@ -2184,6 +2188,7 @@ void KyraEngine::preserveOrRestoreBackground(AnimObject *obj, bool restore) { } void KyraEngine::prepDrawAllObjects() { + debug(9, "prepDrawAllObjects()"); AnimObject *curObject = _objectQueue; int drawPage = 2; int flagUnk1 = 0, flagUnk2 = 0, flagUnk3 = 0; @@ -2259,6 +2264,7 @@ void KyraEngine::prepDrawAllObjects() { } void KyraEngine::copyChangedObjectsForward(int refreshFlag) { + debug(9, "copyChangedObjectsForward(%d)", refreshFlag); AnimObject *curObject = _objectQueue; while (curObject) { if (curObject->active) { @@ -2269,7 +2275,7 @@ void KyraEngine::copyChangedObjectsForward(int refreshFlag) { width = curObject->width; height = curObject->height; - _screen->copyRegion(xpos, ypos, xpos, ypos, width, height, 2, 0); + _screen->copyRegion(xpos, ypos, xpos, ypos, width, height, 2, 0, Screen::CR_CLIPPED); curObject->refreshFlag = 0; } } @@ -2278,6 +2284,7 @@ void KyraEngine::copyChangedObjectsForward(int refreshFlag) { } void KyraEngine::updateAllObjectShapes() { + debug(9, "updateAllObjectShapes()"); restoreAllObjectBackgrounds(); preserveAnyChangedBackgrounds(); prepDrawAllObjects(); @@ -2287,6 +2294,7 @@ void KyraEngine::updateAllObjectShapes() { } void KyraEngine::animRefreshNPC(int character) { + debug(9, "animRefreshNPC(%d)", character); AnimObject *animObj = &_charactersAnimState[character]; Character *ch = &_characterList[character]; @@ -2424,4 +2432,365 @@ int8 KyraEngine::fetchAnimHeight(const uint8 *shape, int8 mult) { shape += 2; return ((int8)*(shape+2)) * mult; } + +#pragma mark - +#pragma mark - Pathfinder +#pragma mark - + +int KyraEngine::findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize) { + debug(9, "findWay(%d, %d, %d, %d, 0x%X, %d)", x, y, toX, toY, moveTable, moveTableSize); + x &= 0xFFFC; toX &= 0xFFFC; + y &= 0xFFFE; toY &= 0xFFFE; + + if (x == toY && y == toY) { + moveTable[0] = 8; + return 0; + } + + int curX = x; + int curY = y; + int lastUsedEntry = 0; + int tempValue = 0; + int *pathTable1 = new int[0x7D0]; + int *pathTable2 = new int[0x7D0]; + + while (true) { + int newFacing = getFacingFromPointToPoint(x, y, toX, toY); + changePosTowardsFacing(curX, curY, newFacing); + + if (curX == toX && curY == toY) { + if (!lineIsPassable(curX, curY)) + break; + moveTable[lastUsedEntry++] = newFacing; + x = curX; + y = curY; + break; + } + + if (lineIsPassable(curX, curY)) { + if (lastUsedEntry == moveTableSize) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + moveTable[lastUsedEntry++] = newFacing; + x = curX; + y = curY; + continue; + } + + int temp = 0; + while (true) { + newFacing = getFacingFromPointToPoint(curX, curY, toX, toY); + changePosTowardsFacing(curX, curY, newFacing); + + if (!lineIsPassable(curX, curY)) { + if (curX != toX || curY != toY) + continue; + } + + if (curX == toX && curY == toY) { + if (!lineIsPassable(curX, curY)) { + tempValue = 0; + temp = 0; + break; + } + } + + assert(pathTable1 && pathTable1); + temp = findSubPath(x, y, curX, curY, pathTable1, 1, 0x7D0); + tempValue = findSubPath(x, y, curX, curY, pathTable2, 0, 0x7D0); + if (curX == toX && curY == toY) { + if (temp == 0x7D00 && tempValue == 0x7D00) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + } + + if (temp != 0x7D00 || tempValue != 0x7D00) + break; + } + + if (temp < tempValue) { + if (lastUsedEntry + temp > moveTableSize) { + delete [] pathTable1; + delete [] pathTable2; + return 0x7D00; + } + memcpy(&moveTable[lastUsedEntry], pathTable1, temp); + lastUsedEntry += temp; + } else { + if (lastUsedEntry + tempValue > moveTableSize) { + delete [] pathTable1; + delete [] pathTable2; + debug("[2] oh no"); + return 0x7D00; + } + memcpy(&moveTable[lastUsedEntry], pathTable2, temp); + debug("[2] temp: %d", temp); + lastUsedEntry += temp; + } + x = curX; + y = curY; + if (curX == toX && curY == toY) { + break; + } + } + delete [] pathTable1; + delete [] pathTable2; + moveTable[lastUsedEntry] = 8; + return getMoveTableSize(moveTable); +} + +int KyraEngine::findSubPath(int x, int y, int toX, int toY, int *moveTable, int start, int end) { + debug(9, "findSubPath(%d, %d, %d, %d, 0x%X, %d, %d)", x, y, toX, toY, moveTable, start, end); + static uint16 unkTable[] = { 8, 5 }; + static const int8 facingTable1[] = { 7, 0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 0 }; + static const int8 facingTable2[] = { -1, 0, -1, 2, -1, 4, -1, 6, -1, 2, -1, 4, -1, 6, -1, 0 }; + static const int8 facingTable3[] = { 2, 4, 4, 6, 6, 0, 0, 2, 6, 6, 0, 0, 2, 2, 4, 4 }; + static const int8 addPosTable1[] = { -1, 0, -1, 4, -1, 0, -1, -4, -1, -4, -1, 0, -1, 4, -1, 0 }; + static const int8 addPosTable2[] = { -1, 2, -1, 0, -1, -2, -1, 0, -1, 0, -1, 2, -1, 0, -1, -2 }; + ++unkTable[start]; + + while (_screen->getPalette(0)[unkTable[start]] != 0x0F) { + ++unkTable[start]; + } + + int xpos1 = x, xpos2 = x; + int ypos1 = y, ypos2 = y; + int newFacing = getFacingFromPointToPoint(x, y, toX, toY); + int position = 0; + + while (position != end) { + changePosTowardsFacing(xpos1, ypos1, facingTable1[start<<3 + newFacing]); + while (true) { + if (!lineIsPassable(xpos1, ypos1)) { + if (facingTable1[start<<3 + newFacing] == newFacing) { + return 0x7D00; + } + newFacing = facingTable1[start<<3 + newFacing]; + xpos1 = x; + ypos1 = x; + continue; + } + break; + } + if (newFacing & 1) { + int temp = xpos1 + addPosTable1[newFacing + start * 8]; + if (toX == temp) { + temp = ypos1 + addPosTable2[newFacing + start * 8]; + if (toY == temp) { + moveTable[position++] = facingTable2[newFacing + start * 8]; + return position; + } + } + } + moveTable[position++] = newFacing; + x = xpos1; + y = ypos1; + if (x == toX && y == toY) { + return position; + } + + if (xpos1 == xpos2 && ypos1 == ypos2) { + break; + } + + newFacing = facingTable3[start<<3 + newFacing]; + } + return 0x7D00; +} + +int KyraEngine::getFacingFromPointToPoint(int x, int y, int toX, int toY) { + debug(9, "getFacingFromPointToPoint(%d, %d, %d, %d)", x, y, toX, toY); + static const int facingTable[] = { + 1, 0, 1, 2, 3, 4, 3, 2, 7, 0, 7, 6, 5, 4, 5, 6 + }; + + int facingEntry = 0; + int ydiff = y - toY; + if (ydiff < 0) { + ++facingEntry; + ydiff = -ydiff; + } + facingEntry <<= 1; + + int xdiff = toX - x; + if (xdiff < 0) { + ++facingEntry; + xdiff = -xdiff; + } + + if (xdiff >= ydiff) { + int temp = xdiff; + ydiff = xdiff; + xdiff = temp; + + facingEntry <<= 1; + } else { + facingEntry <<= 1; + facingEntry += 1; + } + int temp = (ydiff + 1) >> 1; + + if (xdiff < temp) { + facingEntry <<= 1; + facingEntry += 1; + } else { + facingEntry <<= 1; + } + assert(facingEntry < ARRAYSIZE(facingTable)); + return facingTable[facingEntry]; +} + +void KyraEngine::changePosTowardsFacing(int &x, int &y, int facing) { + debug(9, "changePosTowardsFacing(%d, %d, %d)", x, y, facing); + x += _addXPosTable[facing]; + y += _addYPosTable[facing]; +} + +bool KyraEngine::lineIsPassable(int x, int y) { + debug(9, "lineIsPassable(%d, %d)", x, y); + if (queryGameFlag(0xEF)) { + if (_currentCharacter->sceneId == 5) + return true; + } + + if (_pathfinderFlag & 2) { + if (x >= 312) + return false; + } + + if (_pathfinderFlag & 4) { + if (y >= 136) + return false; + } + + if (_pathfinderFlag & 8) { + if (x < 8) + return false; + } + + if (_pathfinderFlag2) { + if (x <= 8 || x >= 312) + return true; + if (y < _northExitHeight || y >= 135) + return true; + } + + if (y > 137) { + return false; + } + + int ypos = 8; + if (_scaleMode) { + int scaling = (_scaleTable[y] >> 5) + 1; + if (8 < scaling) + ypos = scaling; + } + + x -= (ypos >> 1); + if (y < 0) + y = 0; + + int xpos = x; + int xtemp = xpos + ypos - 1; + if (xpos < 0) + xpos = 0; + + if (xtemp > 319) + xtemp = 319; + + for (; xpos < xtemp; ++xpos) { + if (!(_screen->getShapeFlag1(xpos, y) & 0xFF)) + return false; + } + + return true; +} + +int KyraEngine::getMoveTableSize(int *moveTable) { + int retValue = 0; + if (moveTable[0] == 8) + return 0; + + static const int facingTable[] = { + 4, 5, 6, 7, 0, 1, 2, 3 + }; + static const int unkTable[] = { + -1, -1, 1, 2, -1, 6, 7, -1, + -1, -1, -1, -1, 2, -1, 0, -1, + 1, -1, -1, -1, 3, 4, -1, 0, + 2, -1, -1, -1, -1, -1, 4, -1, + -1, 2, 3, -1, -1, -1, 5, 6, + 6, -1, 4, -1, -1, -1, -1, -1, + 7, 0, -1, 4, 5, -1, -1, -1, + -1, -1, 0, -1, 6, -1, -1, -1 + }; + + int *oldPosition = moveTable; + int *tempPosition = moveTable; + int *curPosition = &moveTable[1]; + + while (*curPosition != 8) { + if (*curPosition == facingTable[*oldPosition]) { + retValue -= 2; + *oldPosition = 9; + *curPosition = 9; + + while (tempPosition != moveTable) { + --tempPosition; + if (*tempPosition != 9) + break; + } + + if (tempPosition == moveTable && *tempPosition == 9) { + while (*tempPosition == 8 || *tempPosition != 9) { + ++tempPosition; + } + if (*tempPosition == 8) { + return 0; + } + } + + while (*curPosition == 8 || *curPosition != 9) { + ++curPosition; + } + } + + if (unkTable[*curPosition+(*oldPosition*8)] != -1) { + --retValue; + *oldPosition = unkTable[*curPosition+(*oldPosition*8)]; + *curPosition = 9; + + if (tempPosition != oldPosition) { + curPosition = oldPosition; + oldPosition = tempPosition; + if (tempPosition != moveTable) { + --tempPosition; + while (*tempPosition == 9) { + ++tempPosition; + } + } + } else { + ++curPosition; + while (*curPosition == 9) { + ++curPosition; + } + } + continue; + } + + tempPosition = oldPosition; + oldPosition = curPosition; + ++retValue; + ++curPosition; + while (*curPosition == 9) { + ++curPosition; + } + } + + return retValue; +} } // End of namespace Kyra diff --git a/kyra/kyra.h b/kyra/kyra.h index f93b8f5d91a..d0e1c6d4e3c 100644 --- a/kyra/kyra.h +++ b/kyra/kyra.h @@ -411,6 +411,12 @@ protected: int findDuplicateItemShape(int shape); int16 fetchAnimWidth(const uint8 *shape, int16 mult); int8 fetchAnimHeight(const uint8 *shape, int8 mult); + int findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize); + int findSubPath(int x, int y, int toX, int toY, int *moveTable, int start, int end); + int getFacingFromPointToPoint(int x, int y, int toX, int toY); + void changePosTowardsFacing(int &x, int &y, int facing); + bool lineIsPassable(int x, int y); + int getMoveTableSize(int *moveTable); AnimObject *objectRemoveQueue(AnimObject *queue, AnimObject *rem); AnimObject *objectAddHead(AnimObject *queue, AnimObject *head); @@ -484,7 +490,7 @@ protected: uint16 _walkBlockWest; int32 _scaleMode; - uint16 _scaleTable[145]; + int16 _scaleTable[145]; Rect _noDropRects[11]; @@ -511,7 +517,8 @@ protected: uint16 _currentRoom; uint8 *_maskBuffer; - int _movUnkVar1; + int _pathfinderFlag; + int _pathfinderFlag2; int _lastFindWayRet; int *_movFacingTable; @@ -578,7 +585,9 @@ protected: static const int _xmidiFilesCount; static const int8 _charXPosTable[]; + static const int8 _addXPosTable[]; static const int8 _charYPosTable[]; + static const int8 _addYPosTable[]; }; } // End of namespace Kyra diff --git a/kyra/screen.cpp b/kyra/screen.cpp index 939f5c63608..9a7a694bb39 100644 --- a/kyra/screen.cpp +++ b/kyra/screen.cpp @@ -1775,4 +1775,16 @@ uint8 *Screen::getPalette(int num) { return _palettes[num-1]; } +byte Screen::getShapeFlag1(int x, int y) { + debug(9, "getShapeFlag1(%d, %d)", x, y); + uint8 color = _shapePages[0][y * SCREEN_W + x]; + color &= 0x80; + color ^= 0x80; + + if (color & 0x80) { + return (color << 1) + 1; + } + return (color << 1); +} + } // End of namespace Kyra diff --git a/kyra/screen.h b/kyra/screen.h index 6cae20df88d..67bf4f138c3 100644 --- a/kyra/screen.h +++ b/kyra/screen.h @@ -125,6 +125,8 @@ public: void setShapePages(int page1, int page2); byte *setMouseCursor(int x, int y, byte *shape); uint8 *getPalette(int num); + + byte getShapeFlag1(int x, int y); int _charWidth; int _charOffset; diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp index b61aa144d87..51615a4c433 100644 --- a/kyra/script_v1.cpp +++ b/kyra/script_v1.cpp @@ -841,25 +841,80 @@ int KyraEngine::cmd_setCharactersLocation(ScriptState *script) { } int KyraEngine::cmd_walkCharacterToPoint(ScriptState *script) { - warning("STUB: cmd_walkCharacterToPoint"); -// debug(9, "cmd_walkCharacterToPoint(0x%X)", script); -// int character = stackPos(0); -// int toX = stackPos(1); -// int toY = stackPos(2); -// _movUnkVar1 = 1; -// int findWayReturn = findWay(_characterList[character].x1, _characterList[character].y1, toX, toY, _movFacingTable, 150); -// _movUnkVar1 = 0; -// if (_lastFindWayRet < findWayReturn) { -// _lastFindWayRet = findWayReturn; -// } -// if (findWayReturn == 0x7D00 || findWayReturn == 0) { -// return 0; -// } -// int *curPos = _movFacingTable; -// bool running = true; -// while (running) { -// // XXX -// } + debug(9, "cmd_walkCharacterToPoint(0x%X)", script); + int character = stackPos(0) - 1; + int toX = stackPos(1); + int toY = stackPos(2); + _pathfinderFlag2 = 1; + int findWayReturn = findWay(_characterList[character].x1, _characterList[character].y1, toX, toY, _movFacingTable, 150); + _pathfinderFlag2 = 0; + if (_lastFindWayRet < findWayReturn) { + _lastFindWayRet = findWayReturn; + } + if (findWayReturn == 0x7D00 || findWayReturn == 0) { + return 0; + } + int *curPos = _movFacingTable; + bool running = true; + while (running) { + bool forceContinue = false; + switch (*curPos) { + case 0: + _characterList[character].facing = 2; + break; + + case 1: + _characterList[character].facing = 1; + break; + + case 2: + _characterList[character].facing = 0; + break; + + case 3: + _characterList[character].facing = 7; + break; + + case 4: + _characterList[character].facing = 6; + break; + + case 5: + _characterList[character].facing = 5; + break; + + case 6: + _characterList[character].facing = 4; + break; + + case 7: + _characterList[character].facing = 3; + break; + + case 8: + running = 0; + break; + + default: + ++curPos; + forceContinue = true; + break; + } + + if (forceContinue || !running) { + continue; + } + + setCharacterPosition(character, 0); + ++curPos; + // XXX + waitTicks(10); + // XXX updateAnimFlags(); + // XXX updateMouseCursor(); + // XXX updateGameTimers(); + updateAllObjectShapes(); + // XXX processPalette(); + } return 0; } diff --git a/kyra/staticres.cpp b/kyra/staticres.cpp index cff46c22764..4d70f9ae5bb 100644 --- a/kyra/staticres.cpp +++ b/kyra/staticres.cpp @@ -574,11 +574,19 @@ const char *KyraEngine::_xmidiFiles[] = { const int KyraEngine::_xmidiFilesCount = ARRAYSIZE(_xmidiFiles); const int8 KyraEngine::_charXPosTable[] = { - 0x00, 0x04, 0x04, 0x04, 0x00, 0xFC, 0xFC, 0xFC + 0, 4, 4, 4, 0, -4, -4, -4 +}; + +const int8 KyraEngine::_addXPosTable[] = { + 4, 4, 0, -4, -4, -4, 0, 4 }; const int8 KyraEngine::_charYPosTable[] = { - 0xFE, 0xFE, 0x00, 0x03, 0x02, 0x02, 0x00, 0xFE + -2, -2, 0, 3, 2, 2, 0, -2 +}; + +const int8 KyraEngine::_addYPosTable[] = { + 0, -2, -2, -2, 0, 2, 2, 2 }; } // End of namespace Kyra