mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-09 03:10:22 +00:00
1611 lines
34 KiB
C++
1611 lines
34 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.
|
|
*
|
|
*/
|
|
|
|
#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
|