diff options
author | Eugene Sandulenko | 2018-05-04 10:58:50 +0200 |
---|---|---|
committer | Eugene Sandulenko | 2018-05-05 23:17:35 +0200 |
commit | 7352737a696e8b9889dce408482f8860cf92d287 (patch) | |
tree | b0be93fe9d3b0aa0f876e2791112a04044b0934b /engines/prince/walk.cpp | |
parent | 788a1fab82177d7964f4c16ca20366fa18a8bc6a (diff) | |
download | scummvm-rg350-7352737a696e8b9889dce408482f8860cf92d287.tar.gz scummvm-rg350-7352737a696e8b9889dce408482f8860cf92d287.tar.bz2 scummvm-rg350-7352737a696e8b9889dce408482f8860cf92d287.zip |
PRINCE: Even more prince.cpp refactoring. Inventory and pathfinding
Diffstat (limited to 'engines/prince/walk.cpp')
-rw-r--r-- | engines/prince/walk.cpp | 1610 |
1 files changed, 1610 insertions, 0 deletions
diff --git a/engines/prince/walk.cpp b/engines/prince/walk.cpp new file mode 100644 index 0000000000..0e81c36f3f --- /dev/null +++ b/engines/prince/walk.cpp @@ -0,0 +1,1610 @@ +/* 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 "prince/prince.h" +#include "prince/hero.h" +#include "prince/script.h" + +namespace Prince { + +void PrinceEngine::walkTo() { + if (_mainHero->_visible) { + _mainHero->freeHeroAnim(); + _mainHero->freeOldMove(); + _interpreter->storeNewPC(_script->_scriptInfo.usdCode); + int destX, destY; + if (_optionsMob != -1) { + destX = _mobList[_optionsMob]._examPosition.x; + destY = _mobList[_optionsMob]._examPosition.y; + _mainHero->_destDirection = _mobList[_optionsMob]._examDirection; + } else { + Common::Point mousePos = _system->getEventManager()->getMousePos(); + destX = mousePos.x + _picWindowX; + destY = mousePos.y + _picWindowY; + _mainHero->_destDirection = 0; + } + _mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY); + if (_mainHero->_coords != nullptr) { + _mainHero->_currCoords = _mainHero->_coords; + _mainHero->_dirTab = _directionTable; + _mainHero->_currDirTab = _directionTable; + _directionTable = nullptr; + _mainHero->_state = Hero::kHeroStateMove; + moveShandria(); + } + } +} + +void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) { + Hero *hero = nullptr; + if (!heroId) { + hero = _mainHero; + } else if (heroId == 1) { + hero = _secondHero; + } + + if (hero != nullptr) { + if (dir) { + hero->_destDirection = dir; + } + if (x || y) { + hero->freeOldMove(); + hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y); + if (hero->_coords != nullptr) { + hero->_currCoords = hero->_coords; + hero->_dirTab = _directionTable; + hero->_currDirTab = _directionTable; + _directionTable = nullptr; + if (runHeroFlag) { + hero->_state = Hero::kHeroStateRun; + } else { + hero->_state = Hero::kHeroStateMove; + } + if (heroId == kMainHero && _mouseFlag) { + moveShandria(); + } + } + } else { + hero->freeOldMove(); + hero->_state = Hero::kHeroStateTurn; + } + hero->freeHeroAnim(); + hero->_visible = 1; + } +} + +// Modified version of Graphics::drawLine() to allow breaking the loop and return value +int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) { + // Bresenham's line algorithm, as described by Wikipedia + const bool steep = ABS(y1 - y0) > ABS(x1 - x0); + + if (steep) { + SWAP(x0, y0); + SWAP(x1, y1); + } + + const int delta_x = ABS(x1 - x0); + const int delta_y = ABS(y1 - y0); + const int delta_err = delta_y; + int x = x0; + int y = y0; + int err = 0; + + const int x_step = (x0 < x1) ? 1 : -1; + const int y_step = (y0 < y1) ? 1 : -1; + + int stopFlag = 0; + if (steep) + stopFlag = (*plotProc)(y, x, data); + else + stopFlag = (*plotProc)(x, y, data); + + while (x != x1 && !stopFlag) { + x += x_step; + err += delta_err; + if (2 * err > delta_x) { + y += y_step; + err -= delta_x; + } + if (steep) + stopFlag = (*plotProc)(y, x, data); + else + stopFlag = (*plotProc)(x, y, data); + } + return stopFlag; +} + +int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) { + int mask = 128 >> (x & 7); + byte value = pathBitmap[x / 8 + y * 80]; + return (mask & value); +} + +void PrinceEngine::findPoint(int x, int y) { + _fpX = x; + _fpY = y; + + if (getPixelAddr(_roomPathBitmap, x, y)) { + return; + } + + int fpL = x; + int fpU = y; + int fpR = x; + int fpD = y; + + while (1) { + if (fpD != kMaxPicHeight) { + if (getPixelAddr(_roomPathBitmap, x, fpD)) { + _fpX = x; + _fpY = fpD; + break; + } + fpD++; + } + if (fpU) { + if (getPixelAddr(_roomPathBitmap, x, fpU)) { + _fpX = x; + _fpY = fpU; + break; + } + fpU--; + } + if (fpL) { + if (getPixelAddr(_roomPathBitmap, fpL, y)) { + _fpX = fpL; + _fpY = y; + break; + } + fpL--; + } + if (fpR != _sceneWidth) { + if (getPixelAddr(_roomPathBitmap, fpR, y)) { + _fpX = fpR; + _fpY = y; + break; + } + fpR++; + } + if (!fpU && (fpD == kMaxPicHeight)) { + if (!fpL && (fpR == _sceneWidth)) { + break; + } + } + } +} + +Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) { + if (x1 != x2) { + if (y1 != y2) { + if (x1 > x2) { + if (y1 > y2) { + if (x1 - x2 >= y1 - y2) { + return kDirLU; + } else { + return kDirUL; + } + } else { + if (x1 - x2 >= y2 - y1) { + return kDirLD; + } else { + return kDirDL; + } + } + } else { + if (y1 > y2) { + if (x2 - x1 >= y1 - y2) { + return kDirRU; + } else { + return kDirUR; + } + } else { + if (x2 - x1 >= y2 - y1) { + return kDirRD; + } else { + return kDirDR; + } + } + } + } else { + if (x1 >= x2) { + return kDirL; + } else { + return kDirR; + } + } + } else { + if (y1 >= y2) { + return kDirU; + } else { + return kDirD; + } + } +} + +void PrinceEngine::specialPlot(int x, int y) { + if (_coords < _coordsBufEnd) { + WRITE_LE_UINT16(_coords, x); + _coords += 2; + WRITE_LE_UINT16(_coords, y); + _coords += 2; + specialPlot2(x, y); + } +} + +void PrinceEngine::specialPlot2(int x, int y) { + int mask = 128 >> (x & 7); + _roomPathBitmapTemp[x / 8 + y * 80] |= mask; +} + +void PrinceEngine::specialPlotInside(int x, int y) { + if (_coords < _coordsBufEnd) { + WRITE_LE_UINT16(_coords, x); + _coords += 2; + WRITE_LE_UINT16(_coords, y); + _coords += 2; + } +} + +int PrinceEngine::plotTraceLine(int x, int y, void *data) { + PrinceEngine *traceLine = (PrinceEngine *)data; + if (!traceLine->_traceLineFirstPointFlag) { + if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) { + if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) { + traceLine->specialPlotInside(x, y); + traceLine->_traceLineLen++; + return 0; + } else { + return -1; + } + } else { + return 1; + } + } else { + traceLine->_traceLineFirstPointFlag = false; + return 0; + } +} + +int PrinceEngine::leftDownDir() { + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::leftDir() { + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::leftUpDir() { + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::rightDownDir() { + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::rightDir() { + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::rightUpDir() { + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::upLeftDir() { + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::upDir() { + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::upRightDir() { + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::downLeftDir() { + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::downDir() { + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::downRightDir() { + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::cpe() { + if ((*(_checkBitmap - kPBW) & _checkMask)) { + if ((*(_checkBitmap + kPBW) & _checkMask)) { + int value; + switch (_checkMask) { + case 128: + value = READ_LE_UINT16(_checkBitmap - 1); + value &= 0x4001; + if (value != 0x4001) { + return 0; + } + break; + case 64: + value = *_checkBitmap; + value &= 0xA0; + if (value != 0xA0) { + return 0; + } + break; + case 32: + value = *_checkBitmap; + value &= 0x50; + if (value != 0x50) { + return 0; + } + break; + case 16: + value = *_checkBitmap; + value &= 0x28; + if (value != 0x28) { + return 0; + } + break; + case 8: + value = *_checkBitmap; + value &= 0x14; + if (value != 0x14) { + return 0; + } + break; + case 4: + value = *_checkBitmap; + value &= 0xA; + if (value != 0xA) { + return 0; + } + break; + case 2: + value = *_checkBitmap; + value &= 0x5; + if (value != 0x5) { + return 0; + } + break; + case 1: + value = READ_LE_UINT16(_checkBitmap); + value &= 0x8002; + if (value != 0x8002) { + return 0; + } + break; + default: + error("Wrong _checkMask value - cpe()"); + break; + } + _checkX = _rembX; + _checkY = _rembY; + _checkBitmapTemp = _rembBitmapTemp; + _checkBitmap = _rembBitmap; + _checkMask = _rembMask; + return -1; + } + return 0; + } + return 0; +} + +int PrinceEngine::checkLeftDownDir() { + if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) { + int tempMask = _checkMask; + if (tempMask != 128) { + tempMask <<= 1; + if ((*(_checkBitmap + kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp + kPBW) & tempMask)) { + _checkBitmap += kPBW; + _checkBitmapTemp += kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap + kPBW - 1) & 1)) { + if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) { + _checkBitmap += (kPBW - 1); + _checkBitmapTemp += (kPBW - 1); + _checkMask = 1; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX--; + _checkY++; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkLeftDir() { + if (_checkX) { + int tempMask = _checkMask; + if (tempMask != 128) { + tempMask <<= 1; + if ((*(_checkBitmap) & tempMask)) { + if (!(*(_checkBitmapTemp) & tempMask)) { + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap - 1) & 1)) { + if (!(*(_checkBitmapTemp - 1) & 1)) { + _checkBitmap--; + _checkBitmapTemp--; + _checkMask = 1; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX--; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkDownDir() { + if (_checkY != (kMaxPicHeight / 2 - 1)) { + if ((*(_checkBitmap + kPBW) & _checkMask)) { + if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) { + _checkBitmap += kPBW; + _checkBitmapTemp += kPBW; + _checkY++; + return cpe(); + } else { + return 1; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int PrinceEngine::checkUpDir() { + if (_checkY) { + if ((*(_checkBitmap - kPBW) & _checkMask)) { + if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) { + _checkBitmap -= kPBW; + _checkBitmapTemp -= kPBW; + _checkY--; + return cpe(); + } else { + return 1; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int PrinceEngine::checkRightDir() { + if (_checkX != (kMaxPicWidth / 2 - 1)) { + int tempMask = _checkMask; + if (tempMask != 1) { + tempMask >>= 1; + if ((*(_checkBitmap) & tempMask)) { + if (!(*(_checkBitmapTemp) & tempMask)) { + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap + 1) & 128)) { + if (!(*(_checkBitmapTemp + 1) & 128)) { + _checkBitmap++; + _checkBitmapTemp++; + _checkMask = 128; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX++; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkLeftUpDir() { + if (_checkX && _checkY) { + int tempMask = _checkMask; + if (tempMask != 128) { + tempMask <<= 1; + if ((*(_checkBitmap - kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp - kPBW) & tempMask)) { + _checkBitmap -= kPBW; + _checkBitmapTemp -= kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap - (kPBW + 1)) & 1)) { + if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) { + _checkBitmap -= (kPBW + 1); + _checkBitmapTemp -= (kPBW + 1); + _checkMask = 1; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX--; + _checkY--; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkRightDownDir() { + if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) { + int tempMask = _checkMask; + if (tempMask != 1) { + tempMask >>= 1; + if ((*(_checkBitmap + kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp + kPBW) & tempMask)) { + _checkBitmap += kPBW; + _checkBitmapTemp += kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap + kPBW + 1) & 128)) { + if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) { + _checkBitmap += kPBW + 1; + _checkBitmapTemp += kPBW + 1; + _checkMask = 128; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX++; + _checkY++; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkRightUpDir() { + if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) { + int tempMask = _checkMask; + if (tempMask != 1) { + tempMask >>= 1; + if ((*(_checkBitmap - kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp - kPBW) & tempMask)) { + _checkBitmap -= kPBW; + _checkBitmapTemp -= kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap - kPBW + 1) & 128)) { + if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) { + _checkBitmap -= (kPBW - 1); + _checkBitmapTemp -= (kPBW - 1); + _checkMask = 128; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX++; + _checkY--; + return cpe(); + } else { + return -1; + } +} + +bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) { + for (uint i = 0; i < kPathBitmapLen; i++) { + _roomPathBitmapTemp[i] = 0; + } + if (x1 != x2 || y1 != y2) { + if (getPixelAddr(_roomPathBitmap, x1, y1)) { + if (getPixelAddr(_roomPathBitmap, x2, y2)) { + _coords = _coordsBuf; + specialPlot(x1, y1); + + int x = x1; + int y = y1; + + while (1) { + int btx = x; + int bty = y; + byte *bcad = _coords; + + _traceLineLen = 0; + _traceLineFirstPointFlag = true; + int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this); + + if (!drawLineFlag) { + return true; + } else if (drawLineFlag == -1 && _traceLineLen >= 2) { + byte *tempCorrds = bcad; + while (tempCorrds != _coords) { + x = READ_LE_UINT16(tempCorrds); + y = READ_LE_UINT16(tempCorrds + 2); + tempCorrds += 4; + specialPlot2(x, y); + } + } else { + _coords = bcad; + x = btx; + y = bty; + } + + Direction dir = makeDirection(x, y, x2, y2); + + _rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80]; + _rembBitmap = &_roomPathBitmap[x / 8 + y * 80]; + _rembMask = 128 >> (x & 7); + _rembX = x; + _rembY = y; + + _checkBitmapTemp = _rembBitmapTemp; + _checkBitmap = _rembBitmap; + _checkMask = _rembMask; + _checkX = _rembX; + _checkY = _rembY; + + int result; + switch (dir) { + case kDirLD: + result = leftDownDir(); + break; + case kDirL: + result = leftDir(); + break; + case kDirLU: + result = leftUpDir(); + break; + case kDirRD: + result = rightDownDir(); + break; + case kDirR: + result = rightDir(); + break; + case kDirRU: + result = rightUpDir(); + break; + case kDirUL: + result = upLeftDir(); + break; + case kDirU: + result = upDir(); + break; + case kDirUR: + result = upRightDir(); + break; + case kDirDL: + result = downLeftDir(); + break; + case kDirD: + result = downDir(); + break; + case kDirDR: + result = downRightDir(); + break; + default: + result = -1; + error("tracePath: wrong direction %d", dir); + break; + } + + if (result) { + byte *tempCoords = _coords; + tempCoords -= 4; + if (tempCoords > _coordsBuf) { + int tempX = READ_LE_UINT16(tempCoords); + int tempY = READ_LE_UINT16(tempCoords + 2); + if (_checkX == tempX && _checkY == tempY) { + _coords = tempCoords; + } + x = READ_LE_UINT16(tempCoords); + y = READ_LE_UINT16(tempCoords + 2); + } else { + return false; + } + } else { + x = _checkX; + y = _checkY; + } + } + return true; + } else { + error("tracePath: wrong destination point"); + } + } else { + error("tracePath: wrong start point"); + } + } else { + error("tracePath: same point"); + } +} + +void PrinceEngine::specialPlotInside2(int x, int y) { + WRITE_LE_UINT16(_coords2, x); + _coords2 += 2; + WRITE_LE_UINT16(_coords2, y); + _coords2 += 2; +} + +int PrinceEngine::plotTracePoint(int x, int y, void *data) { + PrinceEngine *tracePoint = (PrinceEngine *)data; + if (!tracePoint->_tracePointFirstPointFlag) { + if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) { + tracePoint->specialPlotInside2(x, y); + return 0; + } else { + return -1; + } + } else { + tracePoint->_tracePointFirstPointFlag = false; + return 0; + } +} + +void PrinceEngine::approxPath() { + byte *oldCoords; + _coords2 = _coordsBuf2; + byte *tempCoordsBuf = _coordsBuf; // first point on path + byte *tempCoords = _coords; + if (tempCoordsBuf != tempCoords) { + tempCoords -= 4; // last point on path + while (tempCoordsBuf != tempCoords) { + int x1 = READ_LE_UINT16(tempCoords); + int y1 = READ_LE_UINT16(tempCoords + 2); + int x2 = READ_LE_UINT16(tempCoordsBuf); + int y2 = READ_LE_UINT16(tempCoordsBuf + 2); + tempCoordsBuf += 4; + //TracePoint + oldCoords = _coords2; + if (_coords2 == _coordsBuf2) { + WRITE_LE_UINT16(_coords2, x1); + WRITE_LE_UINT16(_coords2 + 2, y1); + _coords2 += 4; + } else { + int testX = READ_LE_UINT16(_coords2 - 4); + int testY = READ_LE_UINT16(_coords2 - 2); + if (testX != x1 || testY != y1) { + WRITE_LE_UINT16(_coords2, x1); + WRITE_LE_UINT16(_coords2 + 2, y1); + _coords2 += 4; + } + } + _tracePointFirstPointFlag = true; + bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this); + if (!drawLineFlag) { + tempCoords = tempCoordsBuf - 4; + tempCoordsBuf = _coordsBuf; + } else { + _coords2 = oldCoords; + } + } + } +} + +void PrinceEngine::freeDirectionTable() { + if (_directionTable != nullptr) { + free(_directionTable); + _directionTable = nullptr; + } +} + +int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) { + + int tempX, tempY, direction; + + tempX = Hero::kHeroDirLeft; + if (xDiff < 0) { + tempX = Hero::kHeroDirRight; + } + + tempY = Hero::kHeroDirUp; + if (yDiff < 0) { + tempY = Hero::kHeroDirDown; + } + + while (1) { + int againPointX1 = READ_LE_UINT16(tempCoordsBuf); + int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2); + tempCoordsBuf += 4; + + if (tempCoordsBuf == _coords) { + direction = tempX; + break; + } + + int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf); + int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2); + + if (dX != xDiff) { + direction = tempY; + break; + } + + if (dY != yDiff) { + direction = tempX; + break; + } + } + return direction; +} + +void PrinceEngine::scanDirections() { + freeDirectionTable(); + byte *tempCoordsBuf = _coordsBuf; + if (tempCoordsBuf != _coords) { + int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker + _directionTable = (byte *)malloc(size); + byte *tempDirTab = _directionTable; + int direction = -1; + int lastDirection = -1; + + while (1) { + int x1 = READ_LE_UINT16(tempCoordsBuf); + int y1 = READ_LE_UINT16(tempCoordsBuf + 2); + tempCoordsBuf += 4; + if (tempCoordsBuf == _coords) { + break; + } + int x2 = READ_LE_UINT16(tempCoordsBuf); + int y2 = READ_LE_UINT16(tempCoordsBuf + 2); + + int xDiff = x1 - x2; + int yDiff = y1 - y2; + + if (xDiff) { + if (yDiff) { + if (lastDirection != -1) { + direction = lastDirection; + if (direction == Hero::kHeroDirLeft) { + if (xDiff < 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else if (direction == Hero::kHeroDirRight) { + if (xDiff >= 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else if (direction == Hero::kHeroDirUp) { + if (yDiff < 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else { + if (yDiff >= 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } + } else { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else { + direction = Hero::kHeroDirLeft; + if (xDiff < 0) { + direction = Hero::kHeroDirRight; + } + } + } else { + if (yDiff) { + direction = Hero::kHeroDirUp; + if (yDiff < 0) { + direction = Hero::kHeroDirDown; + } + } else { + direction = lastDirection; + } + } + lastDirection = direction; + *tempDirTab = direction; + tempDirTab++; + } + *tempDirTab = *(tempDirTab - 1); + tempDirTab++; + *tempDirTab = 0; + } +} + +void PrinceEngine::moveShandria() { + int shanLen1 = _shanLen; + if (_flags->getFlagValue(Flags::SHANDOG)) { + _secondHero->freeHeroAnim(); + _secondHero->freeOldMove(); + byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4; + int shanX = READ_LE_UINT16(shanCoords - 4); + int shanY = READ_LE_UINT16(shanCoords - 2); + int xDiff = shanX - _secondHero->_middleX; + if (xDiff < 0) { + xDiff *= -1; + } + int yDiff = shanY - _secondHero->_middleY; + if (yDiff < 0) { + yDiff *= -1; + } + shanCoords -= 4; + if (shanCoords != _mainHero->_currCoords) { + yDiff *= 1.5; + int shanDis = xDiff * xDiff + yDiff * yDiff; + if (shanDis >= kMinDistance) { + while (1) { + shanCoords -= 4; + if (shanCoords == _mainHero->_currCoords) { + break; + } + int x = READ_LE_UINT16(shanCoords); + int y = READ_LE_UINT16(shanCoords + 2); + int pointDiffX = x - shanX; + if (pointDiffX < 0) { + pointDiffX *= -1; + } + int pointDiffY = y - shanY; + if (pointDiffY < 0) { + pointDiffY *= -1; + } + pointDiffY *= 1.5; + int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY; + if (distance >= kMinDistance) { + break; + } + } + int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4; + int destDir = *(_mainHero->_currDirTab + pathSizeDiff); + _secondHero->_destDirection = destDir; + int destX = READ_LE_UINT16(shanCoords); + int destY = READ_LE_UINT16(shanCoords + 2); + _secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY); + if (_secondHero->_coords != nullptr) { + _secondHero->_currCoords = _secondHero->_coords; + int delay = shanLen1 - _shanLen; + if (delay < 6) { + delay = 6; + } + _secondHero->_moveDelay = delay / 2; + _secondHero->_state = Hero::kHeroStateDelayMove; + _secondHero->_dirTab = _directionTable; + _secondHero->_currDirTab = _directionTable; + _directionTable = nullptr; + } + } + } + } +} + +byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) { + int realDestX = destX; + int realDestY = destY; + _flags->setFlagValue(Flags::MOVEDESTX, destX); + _flags->setFlagValue(Flags::MOVEDESTY, destY); + + int x1 = currX / 2; + int y1 = currY / 2; + int x2 = destX / 2; + int y2 = destY / 2; + + if ((x1 != x2) || (y1 != y2)) { + findPoint(x1, y1); + if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) { + return nullptr; + } + if ((x1 != _fpX) || (y1 != _fpY)) { + x1 = _fpX; + y1 = _fpY; + } + findPoint(x2, y2); + if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) { + return nullptr; + } + if ((x2 != _fpX) || (y2 != _fpY)) { + x2 = _fpX; + y2 = _fpY; + if (!_flags->getFlagValue(Flags::EXACTMOVE)) { + realDestX = x2 * 2; + realDestY = y2 * 2; + _flags->setFlagValue(Flags::MOVEDESTX, realDestX); + _flags->setFlagValue(Flags::MOVEDESTY, realDestY); + } else { + return nullptr; + } + } + + if ((x1 == x2) && (y1 == y2)) { + if (!heroId) { + _mainHero->freeOldMove(); + _mainHero->_state = Hero::kHeroStateTurn; + } else if (heroId == 1) { + _secondHero->freeOldMove(); + _secondHero->_state = Hero::kHeroStateTurn; + } + return nullptr; + } + + int pathLen1 = 0; + int pathLen2 = 0; + int stX = x1; + int stY = y1; + int sizeCoords2 = 0; + + if (tracePath(x1, y1, x2, y2)) { + allocCoords2(); + approxPath(); + sizeCoords2 = _coords2 - _coordsBuf2; + for (int i = 0; i < sizeCoords2; i++) { + _coordsBuf[i] = _coordsBuf2[i]; + } + _coords = _coordsBuf + sizeCoords2; + approxPath(); + _coordsBuf3 = _coordsBuf2; + _coordsBuf2 = nullptr; + _coords3 = _coords2; + _coords2 = nullptr; + pathLen1 = _coords3 - _coordsBuf3; + } + if (tracePath(x2, y2, x1, y1)) { + allocCoords2(); + approxPath(); + sizeCoords2 = _coords2 - _coordsBuf2; + for (int i = 0; i < sizeCoords2; i++) { + _coordsBuf[i] = _coordsBuf2[i]; + } + _coords = _coordsBuf + sizeCoords2; + approxPath(); + pathLen2 = _coords2 - _coordsBuf2; + } + + byte *chosenCoordsBuf = _coordsBuf2; + byte *choosenCoords = _coords2; + int choosenLength = pathLen1; + if (pathLen1 < pathLen2) { + chosenCoordsBuf = _coordsBuf3; + choosenCoords = _coords3; + choosenLength = pathLen2; + } + + if (choosenLength) { + if (chosenCoordsBuf != nullptr) { + int tempXBegin = READ_LE_UINT16(chosenCoordsBuf); + int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2); + if (stX != tempXBegin || stY != tempYBegin) { + SWAP(chosenCoordsBuf, choosenCoords); + chosenCoordsBuf -= 4; + byte *tempCoordsBuf = _coordsBuf; + while (1) { + int cord = READ_LE_UINT32(chosenCoordsBuf); + WRITE_LE_UINT32(tempCoordsBuf, cord); + tempCoordsBuf += 4; + if (chosenCoordsBuf == choosenCoords) { + break; + } + chosenCoordsBuf -= 4; + } + _coords = tempCoordsBuf; + } else { + int sizeChoosen = choosenCoords - chosenCoordsBuf; + for (int i = 0; i < sizeChoosen; i++) { + _coordsBuf[i] = chosenCoordsBuf[i]; + } + _coords = _coordsBuf + sizeChoosen; + } + WRITE_LE_UINT32(_coords, 0xFFFFFFFF); + freeCoords2(); + freeCoords3(); + scanDirections(); + + byte *tempCoordsBuf = _coordsBuf; + byte *tempCoords = _coords; + byte *newCoords; + if (tempCoordsBuf != tempCoords) { + int normCoordsSize = _coords - _coordsBuf + 4; + newCoords = (byte *)malloc(normCoordsSize); + byte *newCoordsBegin = newCoords; + while (tempCoordsBuf != tempCoords) { + int newValueX = READ_LE_UINT16(tempCoordsBuf); + WRITE_LE_UINT16(newCoords, newValueX * 2); + newCoords += 2; + int newValueY = READ_LE_UINT16(tempCoordsBuf + 2); + WRITE_LE_UINT16(newCoords, newValueY * 2); + newCoords += 2; + tempCoordsBuf += 4; + } + WRITE_LE_UINT16(newCoords - 4, realDestX); + WRITE_LE_UINT16(newCoords - 2, realDestY); + WRITE_LE_UINT32(newCoords, 0xFFFFFFFF); + newCoords += 4; + _shanLen = (newCoords - newCoordsBegin); + _shanLen /= 4; + return newCoordsBegin; + } + } + } + _coords = _coordsBuf; + freeCoords2(); + freeCoords3(); + return nullptr; + } else { + if (!heroId) { + _mainHero->freeOldMove(); + _mainHero->_state = Hero::kHeroStateTurn; + } else if (heroId == 1) { + _secondHero->freeOldMove(); + _secondHero->_state = Hero::kHeroStateTurn; + } + return nullptr; + } +} + +void PrinceEngine::allocCoords2() { + if (_coordsBuf2 == nullptr) { + _coordsBuf2 = (byte *)malloc(kTracePts * 4); + _coords2 = _coordsBuf2; + } +} + +void PrinceEngine::freeCoords2() { + if (_coordsBuf2 != nullptr) { + free(_coordsBuf2); + _coordsBuf2 = nullptr; + _coords2 = nullptr; + } +} + +void PrinceEngine::freeCoords3() { + if (_coordsBuf3 != nullptr) { + free(_coordsBuf3); + _coordsBuf3 = nullptr; + _coords3 = nullptr; + } +} + +} // End of namespace Prince |