diff options
author | Max Horn | 2006-02-11 22:45:04 +0000 |
---|---|---|
committer | Max Horn | 2006-02-11 22:45:04 +0000 |
commit | 26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch) | |
tree | 26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/saga/isomap.cpp | |
parent | 2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff) | |
download | scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2 scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip |
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/saga/isomap.cpp')
-rw-r--r-- | engines/saga/isomap.cpp | 1694 |
1 files changed, 1694 insertions, 0 deletions
diff --git a/engines/saga/isomap.cpp b/engines/saga/isomap.cpp new file mode 100644 index 0000000000..6acbf8ba70 --- /dev/null +++ b/engines/saga/isomap.cpp @@ -0,0 +1,1694 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004-2006 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +// Isometric level module +#include "saga/saga.h" + +#include "saga/gfx.h" + +#include "saga/resnames.h" +#include "saga/scene.h" +#include "saga/isomap.h" +#include "saga/stream.h" + +namespace Saga { + +enum MaskRules { + kMaskRuleNever = 0, + kMaskRuleAlways, + kMaskRuleUMIN, + kMaskRuleUMID, + kMaskRuleUMAX, + kMaskRuleVMIN, + kMaskRuleVMID, + kMaskRuleVMAX, + kMaskRuleYMIN, + kMaskRuleYMID, + kMaskRuleYMAX, + kMaskRuleUVMAX, + kMaskRuleUVMIN, + kMaskRuleUorV, + kMaskRuleUandV +}; + + +static const IsoMap::TilePoint normalDirTable[8] = { + { 1, 1, 0, SAGA_DIAG_NORMAL_COST}, + { 1, 0, 0, SAGA_STRAIGHT_NORMAL_COST}, + { 1,-1, 0, SAGA_DIAG_NORMAL_COST}, + { 0,-1, 0, SAGA_STRAIGHT_NORMAL_COST}, + {-1,-1, 0, SAGA_DIAG_NORMAL_COST}, + {-1, 0, 0, SAGA_STRAIGHT_NORMAL_COST}, + {-1, 1, 0, SAGA_DIAG_NORMAL_COST}, + { 0, 1, 0, SAGA_STRAIGHT_NORMAL_COST}, +}; + +static const IsoMap::TilePoint easyDirTable[8] = { + { 1, 1, 0, SAGA_DIAG_EASY_COST}, + { 1, 0, 0, SAGA_STRAIGHT_EASY_COST}, + { 1,-1, 0, SAGA_DIAG_EASY_COST}, + { 0,-1, 0, SAGA_STRAIGHT_EASY_COST}, + {-1,-1, 0, SAGA_DIAG_EASY_COST}, + {-1, 0, 0, SAGA_STRAIGHT_EASY_COST}, + {-1, 1, 0, SAGA_DIAG_EASY_COST}, + { 0, 1, 0, SAGA_STRAIGHT_EASY_COST}, +}; + +static const IsoMap::TilePoint hardDirTable[8] = { + { 1, 1, 0, SAGA_DIAG_HARD_COST}, + { 1, 0, 0, SAGA_STRAIGHT_HARD_COST}, + { 1,-1, 0, SAGA_DIAG_HARD_COST}, + { 0,-1, 0, SAGA_STRAIGHT_HARD_COST}, + {-1,-1, 0, SAGA_DIAG_HARD_COST}, + {-1, 0, 0, SAGA_STRAIGHT_HARD_COST}, + {-1, 1, 0, SAGA_DIAG_HARD_COST}, + { 0, 1, 0, SAGA_STRAIGHT_HARD_COST}, +}; + +IsoMap::IsoMap(SagaEngine *vm) : _vm(vm) { + _tileData = NULL; + _tilesCount = 0; + _tilePlatformList = NULL; + _tilePlatformsCount = 0; + _metaTileList = NULL; + _metaTilesCount = 0; + _multiTable = NULL; + _multiCount = 0; + _multiTableData = NULL; + _multiDataCount = 0; + _viewScroll.x = (128 - 8) * 16; + _viewScroll.x = (128 - 8) * 16 - 64; + _viewDiff = 1; + +} + +void IsoMap::loadImages(const byte *resourcePointer, size_t resourceLength) { + IsoTileData *tileData; + uint16 i; + + if (resourceLength == 0) { + error("IsoMap::loadImages wrong resourceLength"); + } + + _tileData = (byte*)malloc(resourceLength); + _tileDataLength = resourceLength; + memcpy(_tileData, resourcePointer, resourceLength); + + MemoryReadStreamEndian readS(_tileData, _tileDataLength, _vm->isBigEndian()); + readS.readUint16(); // skip + _tilesCount = readS.readUint16(); + _tilesCount = _tilesCount / SAGA_ISOTILEDATA_LEN; + + readS.seek(0); + + _tilesTable = (IsoTileData *)malloc(_tilesCount * sizeof(*_tilesTable)); + if (_tilesTable == NULL) { + memoryError("IsoMap::loadImages"); + } + + for (i = 0; i < _tilesCount; i++) { + tileData = &_tilesTable[i]; + tileData->height = readS.readByte(); + tileData->attributes = readS.readSByte(); + tileData->offset = readS.readUint16(); + tileData->terrainMask = readS.readUint16(); + tileData->FGDBGDAttr = readS.readByte(); + readS.readByte(); //skip + } + +} + +void IsoMap::loadPlatforms(const byte * resourcePointer, size_t resourceLength) { + TilePlatformData *tilePlatformData; + uint16 i, x, y; + + if (resourceLength == 0) { + error("IsoMap::loadPlatforms wrong resourceLength"); + } + + MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian()); + + _tilePlatformsCount = resourceLength / SAGA_TILEPLATFORMDATA_LEN; + _tilePlatformList = (TilePlatformData *)malloc(_tilePlatformsCount * sizeof(*_tilePlatformList)); + if (_tilePlatformList == NULL) { + memoryError("IsoMap::loadPlatforms"); + } + + for (i = 0; i < _tilePlatformsCount; i++) { + tilePlatformData = &_tilePlatformList[i]; + tilePlatformData->metaTile = readS.readSint16(); + tilePlatformData->height = readS.readSint16(); + tilePlatformData->highestPixel = readS.readSint16(); + tilePlatformData->vBits = readS.readByte(); + tilePlatformData->uBits = readS.readByte(); + for (x = 0; x < SAGA_PLATFORM_W; x++) { + for (y = 0; y < SAGA_PLATFORM_W; y++) { + tilePlatformData->tiles[x][y] = readS.readSint16(); + } + } + } + +} + +void IsoMap::loadMap(const byte * resourcePointer, size_t resourceLength) { + uint16 x, y; + + if (resourceLength != SAGA_TILEMAP_LEN) { + error("IsoMap::loadMap wrong resourceLength"); + } + + MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian()); + _tileMap.edgeType = readS.readByte(); + readS.readByte(); //skip + + for (x = 0; x < SAGA_TILEMAP_W; x++) { + for (y = 0; y < SAGA_TILEMAP_H; y++) { + _tileMap.tilePlatforms[x][y] = readS.readSint16(); + } + } + +} + +void IsoMap::loadMetaTiles(const byte * resourcePointer, size_t resourceLength) { + MetaTileData *metaTileData; + uint16 i, j; + + if (resourceLength == 0) { + error("IsoMap::loadMetaTiles wrong resourceLength"); + } + + MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian()); + _metaTilesCount = resourceLength / SAGA_METATILEDATA_LEN; + + _metaTileList = (MetaTileData *)malloc(_metaTilesCount * sizeof(*_metaTileList)); + if (_metaTileList == NULL) { + memoryError("IsoMap::loadMetaTiles"); + } + + for (i = 0; i < _metaTilesCount; i++) { + metaTileData = &_metaTileList[i]; + metaTileData->highestPlatform = readS.readUint16(); + metaTileData->highestPixel = readS.readUint16(); + for (j = 0; j < SAGA_MAX_PLATFORM_H; j++) { + metaTileData->stack[j] = readS.readSint16(); + } + } +} + +void IsoMap::loadMulti(const byte * resourcePointer, size_t resourceLength) { + MultiTileEntryData *multiTileEntryData; + uint16 i; + int16 offsetDiff; + + if (resourceLength < 2) { + error("IsoMap::loadMetaTiles wrong resourceLength"); + } + + MemoryReadStreamEndian readS(resourcePointer, resourceLength, _vm->isBigEndian()); + _multiCount = readS.readUint16(); + _multiTable = (MultiTileEntryData *)malloc(_multiCount * sizeof(*_multiTable)); + if (_multiTable == NULL) { + memoryError("IsoMap::loadMulti"); + } + + for (i = 0; i < _multiCount; i++) { + multiTileEntryData = &_multiTable[i]; + readS.readUint32();//skip + multiTileEntryData->offset = readS.readSint16(); + multiTileEntryData->u = readS.readByte(); + multiTileEntryData->v = readS.readByte(); + multiTileEntryData->h = readS.readByte(); + multiTileEntryData->uSize = readS.readByte(); + multiTileEntryData->vSize = readS.readByte(); + multiTileEntryData->numStates = readS.readByte(); + multiTileEntryData->currentState = readS.readByte(); + readS.readByte();//skip + } + + offsetDiff = (readS.pos() - 2); + + for (i = 0; i < _multiCount; i++) { + _multiTable[i].offset -= offsetDiff; + } + + _multiDataCount = (readS.size() - readS.pos()) / 2; + + _multiTableData = (int16 *)malloc(_multiDataCount * sizeof(*_multiTableData)); + for (i = 0; i < _multiDataCount; i++) { + _multiTableData[i] = readS.readSint16(); + } +} + +void IsoMap::freeMem() { + free(_tileData); + _tileData = NULL; + _tilesCount = 0; + free(_tilePlatformList); + _tilePlatformList = NULL; + _tilePlatformsCount = 0; + free(_metaTileList); + _metaTileList = NULL; + _metaTilesCount = 0; + free(_multiTable); + _multiTable = NULL; + _multiCount = 0; + free(_multiTableData); + _multiTableData = NULL; + _multiDataCount = 0; +} + +void IsoMap::adjustScroll(bool jump) { + Point playerPoint; + Point minScrollPos; + Point maxScrollPos; + + + tileCoordsToScreenPoint(_vm->_actor->_centerActor->_location, playerPoint); + + if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { + _mapPosition.x = (playerPoint.x + _viewScroll.x) * 30 / 100 - (381); + _mapPosition.y = (playerPoint.y + _viewScroll.y) * 30 / 100 - (342); + } + + if (_vm->_actor->_centerActor != _vm->_actor->_protagonist) { + playerPoint.y -= 24; + } + playerPoint.y -= 28; + + playerPoint.x += _viewScroll.x - _vm->getDisplayWidth()/2; + playerPoint.y += _viewScroll.y - _vm->_scene->getHeight()/2; + + minScrollPos.x = playerPoint.x - SAGA_SCROLL_LIMIT_X1; + minScrollPos.y = playerPoint.y - SAGA_SCROLL_LIMIT_Y1; + + maxScrollPos.x = playerPoint.x + SAGA_SCROLL_LIMIT_X1; + maxScrollPos.y = playerPoint.y + SAGA_SCROLL_LIMIT_Y2; + + if (jump) { + if (_viewScroll.y < minScrollPos.y) { + _viewScroll.y = minScrollPos.y; + } + if (_viewScroll.y > maxScrollPos.y) { + _viewScroll.y = maxScrollPos.y; + } + if (_viewScroll.x < minScrollPos.x) { + _viewScroll.x = minScrollPos.x; + } + if (_viewScroll.x > maxScrollPos.x) { + _viewScroll.x = maxScrollPos.x; + } + } else { + _viewScroll.y = smoothSlide( _viewScroll.y, minScrollPos.y, maxScrollPos.y ); + _viewScroll.x = smoothSlide( _viewScroll.x, minScrollPos.x, maxScrollPos.x ); + } + + if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE) { + ObjectData *obj; + uint16 objectId; + objectId = _vm->_actor->objIndexToId(ITE_OBJ_MAP); + obj = _vm->_actor->getObj(objectId); + if (obj->_sceneNumber != ITE_SCENE_INV) { + _viewScroll.x = 1552 + 8; + _viewScroll.y = 1456 + 8; + } + } +} + +int16 IsoMap::findMulti(int16 tileIndex, int16 absU, int16 absV, int16 absH) { + MultiTileEntryData *multiTileEntryData; + int16 ru; + int16 rv; + int16 mu; + int16 mv; + int16 state; + uint16 i, offset; + int16 *tiles; + + ru = (tileIndex >> 13) & 0x03; + rv = (tileIndex >> 11) & 0x03; + mu = absU - ru; + mv = absV - rv; + + tileIndex = 0; + for (i = 0; i < _multiCount; i++) { + multiTileEntryData = &_multiTable[i]; + + if ((multiTileEntryData->u == mu) && + (multiTileEntryData->v == mv) && + (multiTileEntryData->h == absH)) { + state = multiTileEntryData->currentState; + + offset = (ru + state * multiTileEntryData->uSize) * multiTileEntryData->vSize + rv; + offset *= sizeof(*_multiTableData); + offset += multiTileEntryData->offset; + if (offset + sizeof(*_multiTableData) - 1 >= _multiDataCount * sizeof(*_multiTableData)) { + error("wrong multiTileEntryData->offset"); + } + tiles = (int16*)((byte*)_multiTableData + offset); + tileIndex = *tiles; + if (tileIndex >= 256) { + warning("something terrible happened"); + return 1; + } + return tileIndex; + } + } + + return 1; +} + +void IsoMap::draw(Surface *ds) { + + _tileClip = _vm->_scene->getSceneClip(); + ds->drawRect(_tileClip, 0); + drawTiles(ds, NULL); +} + +void IsoMap::setMapPosition(int x, int y) { + _mapPosition.x = x; + _mapPosition.y = y; +} + +void IsoMap::drawSprite(Surface *ds, SpriteList &spriteList, int spriteNumber, const Location &location, const Point &screenPosition, int scale) { + int width; + int height; + int xAlign; + int yAlign; + const byte *spriteBuffer; + Point spritePointer; + Rect clip(_vm->_scene->getSceneClip()); + + _vm->_sprite->getScaledSpriteBuffer(spriteList, spriteNumber, scale, width, height, xAlign, yAlign, spriteBuffer); + + spritePointer.x = screenPosition.x + xAlign; + spritePointer.y = screenPosition.y + yAlign; + + _tileClip.left = spritePointer.x; + _tileClip.top = spritePointer.y; + _tileClip.right = spritePointer.x + width; + _tileClip.bottom = spritePointer.y + height; + + if (_tileClip.left < 0) { + _tileClip.left = 0; + } + if (_tileClip.right > _vm->getDisplayWidth()) { + _tileClip.right = _vm->getDisplayWidth(); + } + if (_tileClip.top < 0) { + _tileClip.top = 0; + } + if (_tileClip.bottom > _vm->_scene->getHeight()) { + _tileClip.bottom = _vm->_scene->getHeight(); + } + + _vm->_sprite->drawClip(ds, clip, spritePointer, width, height, spriteBuffer); + drawTiles(ds, &location); +} + + +void IsoMap::drawTiles(Surface *ds, const Location *location) { + Point view1; + Point fineScroll; + Point tileScroll; + Point metaTileY; + Point metaTileX; + int16 u0, v0, + u1, v1, + u2, v2, + uc, vc; + uint16 metaTileIndex; + Location rLocation; + int16 workAreaWidth; + int16 workAreaHeight; + + tileScroll.x = _viewScroll.x >> 4; + tileScroll.y = _viewScroll.y >> 4; + + fineScroll.x = _viewScroll.x & 0xf; + fineScroll.y = _viewScroll.y & 0xf; + + view1.x = tileScroll.x - (8 * SAGA_TILEMAP_W); + view1.y = (8 * SAGA_TILEMAP_W) - tileScroll.y; + + u0 = ((view1.y + 64) * 2 + view1.x) >> 4; + v0 = ((view1.y + 64) * 2 - view1.x) >> 4; + + metaTileY.x = (u0 - v0) * 128 - (view1.x * 16 + fineScroll.x); + metaTileY.y = (view1.y * 16 - fineScroll.y) - (u0 + v0) * 64; + + workAreaWidth = _vm->getDisplayWidth() + 128; + workAreaHeight = _vm->_scene->getHeight() + 128 + 80; + + for (u1 = u0, v1 = v0; metaTileY.y < workAreaHeight; u1--, v1-- ) { + metaTileX = metaTileY; + + for (u2 = u1, v2 = v1; metaTileX.x < workAreaWidth; u2++, v2--, metaTileX.x += 256) { + + uc = u2 & (SAGA_TILEMAP_W - 1); + vc = v2 & (SAGA_TILEMAP_W - 1); + + if (uc != u2 || vc != v2) { + metaTileIndex = 0; + switch ( _tileMap.edgeType) { + case kEdgeTypeBlack: + continue; + case kEdgeTypeFill0: + break; + case kEdgeTypeFill1: + metaTileIndex = 1; + break; + case kEdgeTypeRpt: + uc = clamp( 0, u2, SAGA_TILEMAP_W - 1); + vc = clamp( 0, v2, SAGA_TILEMAP_W - 1); + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + break; + case kEdgeTypeWrap: + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + break; + } + } else { + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + } + + if (location != NULL) { + rLocation.u() = location->u() - (u2 << 7); + rLocation.v() = location->v() - (v2 << 7); + rLocation.z = location->z; + drawSpriteMetaTile(ds, metaTileIndex, metaTileX, rLocation, u2 << 3, v2 << 3); + } else { + drawMetaTile(ds, metaTileIndex, metaTileX, u2 << 3, v2 << 3); + } + } + + metaTileY.y += 64; + + metaTileX = metaTileY; + + metaTileX.x -= 128; + + for (u2 = u1 - 1, v2 = v1; metaTileX.x < workAreaWidth; u2++, v2--, metaTileX.x += 256) { + + uc = u2 & (SAGA_TILEMAP_W - 1); + vc = v2 & (SAGA_TILEMAP_W - 1); + + if (uc != u2 || vc != v2) { + metaTileIndex = 0; + switch ( _tileMap.edgeType) { + case kEdgeTypeBlack: + continue; + case kEdgeTypeFill0: + break; + case kEdgeTypeFill1: + metaTileIndex = 1; + break; + case kEdgeTypeRpt: + uc = clamp( 0, u2, SAGA_TILEMAP_W - 1); + vc = clamp( 0, v2, SAGA_TILEMAP_W - 1); + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + break; + case kEdgeTypeWrap: + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + break; + } + } else { + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + } + + if (location != NULL) { + rLocation.u() = location->u() - (u2 << 7); + rLocation.v() = location->v() - (v2 << 7); + rLocation.z = location->z; + drawSpriteMetaTile(ds, metaTileIndex, metaTileX, rLocation, u2 << 3, v2 << 3); + } else { + drawMetaTile(ds, metaTileIndex, metaTileX, u2 << 3, v2 << 3); + } + } + metaTileY.y += 64; + } + +} + +void IsoMap::drawSpriteMetaTile(Surface *ds, uint16 metaTileIndex, const Point &point, Location &location, int16 absU, int16 absV) { + MetaTileData * metaTile; + uint16 high; + int16 platformIndex; + Point platformPoint; + platformPoint = point; + + if (_metaTilesCount <= metaTileIndex) { + error("IsoMap::drawMetaTile wrong metaTileIndex"); + } + + metaTile = &_metaTileList[metaTileIndex]; + + if (metaTile->highestPlatform > 18) { + metaTile->highestPlatform = 0; + } + + for (high = 0; high <= metaTile->highestPlatform; high++, platformPoint.y -= 8, location.z -= 8) { + assert(SAGA_MAX_PLATFORM_H > high); + platformIndex = metaTile->stack[high]; + + if (platformIndex >= 0) { + drawSpritePlatform( ds, platformIndex, platformPoint, location, absU, absV, high ); + } + } +} + +void IsoMap::drawMetaTile(Surface *ds, uint16 metaTileIndex, const Point &point, int16 absU, int16 absV) { + MetaTileData * metaTile; + uint16 high; + int16 platformIndex; + Point platformPoint; + platformPoint = point; + + if (_metaTilesCount <= metaTileIndex) { + error("IsoMap::drawMetaTile wrong metaTileIndex"); + } + + metaTile = &_metaTileList[metaTileIndex]; + + if (metaTile->highestPlatform > 18) { + metaTile->highestPlatform = 0; + } + + for (high = 0; high <= metaTile->highestPlatform; high++, platformPoint.y -= 8) { + assert(SAGA_MAX_PLATFORM_H > high); + platformIndex = metaTile->stack[high]; + + if (platformIndex >= 0) { + drawPlatform( ds, platformIndex, platformPoint, absU, absV, high ); + } + } +} + +void IsoMap::drawSpritePlatform(Surface *ds, uint16 platformIndex, const Point &point, const Location &location, int16 absU, int16 absV, int16 absH) { + TilePlatformData *tilePlatform; + int16 u, v; + Point s; + Point s0; + uint16 tileIndex; + Location copyLocation(location); + + if (_tilePlatformsCount <= platformIndex) { + error("IsoMap::drawPlatform wrong platformIndex"); + } + + tilePlatform = &_tilePlatformList[platformIndex]; + + if ((point.y <= _tileClip.top) || (point.y - SAGA_MAX_TILE_H - SAGA_PLATFORM_W * SAGA_TILE_NOMINAL_H >= _tileClip.bottom)) { + return; + } + + s0 = point; + s0.y -= (((SAGA_PLATFORM_W - 1) + (SAGA_PLATFORM_W - 1)) * 8); + + for (v = SAGA_PLATFORM_W - 1, + copyLocation.v() = location.v() - ((SAGA_PLATFORM_W - 1) << 4); + v >= 0 && s0.y - SAGA_MAX_TILE_H < _tileClip.bottom && s0.x - 128 < _tileClip.right; + v--, copyLocation.v() += 16, s0.x += 16, s0.y += 8) { + + if ((tilePlatform->vBits & (1 << v)) == 0) { + continue; + } + + if (s0.x + 128 + 32 < _tileClip.left) { + continue; + } + + s = s0; + + for (u = SAGA_PLATFORM_W - 1, + copyLocation.u() = location.u() - ((SAGA_PLATFORM_W - 1) << 4); + u >= 0 && s.x + 32 > _tileClip.left && s.y - SAGA_MAX_TILE_H < _tileClip.bottom; + u--, copyLocation.u() += 16, s.x -= 16, s.y += 8 ) { + if (s.x < _tileClip.right && s.y > _tileClip.top) { + + tileIndex = tilePlatform->tiles[u][v]; + if (tileIndex != 0) { + if (tileIndex & SAGA_MULTI_TILE) { + tileIndex = findMulti(tileIndex, absU + u, absV + v, absH); + } + + drawTile(ds, tileIndex, s, ©Location); + } + } + } + } +} + +void IsoMap::drawPlatform(Surface *ds, uint16 platformIndex, const Point &point, int16 absU, int16 absV, int16 absH) { + TilePlatformData *tilePlatform; + int16 u, v; + Point s; + Point s0; + uint16 tileIndex; + + if (_tilePlatformsCount <= platformIndex) { + error("IsoMap::drawPlatform wrong platformIndex"); + } + + tilePlatform = &_tilePlatformList[platformIndex]; + + if ((point.y <= _tileClip.top) || (point.y - SAGA_MAX_TILE_H - SAGA_PLATFORM_W * SAGA_TILE_NOMINAL_H >= _tileClip.bottom)) { + return; + } + + s0 = point; + s0.y -= (((SAGA_PLATFORM_W - 1) + (SAGA_PLATFORM_W - 1)) * 8); + + for (v = SAGA_PLATFORM_W - 1; + v >= 0 && s0.y - SAGA_MAX_TILE_H < _tileClip.bottom && s0.x - 128 < _tileClip.right; + v--, s0.x += 16, s0.y += 8) { + + if ((tilePlatform->vBits & (1 << v)) == 0) { + continue; + } + + if (s0.x + 128 + 32 < _tileClip.left) { + continue; + } + + s = s0; + + for (u = SAGA_PLATFORM_W - 1; + u >= 0 && s.x + 32 > _tileClip.left && s.y - SAGA_MAX_TILE_H < _tileClip.bottom; + u--, s.x -= 16, s.y += 8 ) { + if (s.x < _tileClip.right && s.y > _tileClip.top) { + + tileIndex = tilePlatform->tiles[u][v]; + if (tileIndex > 1) { + if (tileIndex & SAGA_MULTI_TILE) { + tileIndex = findMulti(tileIndex, absU + u, absV + v, absH); + } + + drawTile(ds, tileIndex, s, NULL); + } + } + } + } +} + +#define THRESH0 0 +#define THRESH8 8 +#define THRESH16 16 + +void IsoMap::drawTile(Surface *ds, uint16 tileIndex, const Point &point, const Location *location) { + const byte *tilePointer; + const byte *readPointer; + byte *drawPointer; + Point drawPoint; + int height; + int widthCount = 0; + int row, col, count, lowBound; + int bgRunCount; + int fgRunCount; + + + if (tileIndex >= _tilesCount) { + error("IsoMap::drawTile wrong tileIndex"); + } + + + if (point.x + SAGA_ISOTILE_WIDTH < _tileClip.left) { + return; + } + + if (point.x - SAGA_ISOTILE_WIDTH >= _tileClip.right) { + return; + } + + tilePointer = _tileData + _tilesTable[tileIndex].offset; + height = _tilesTable[tileIndex].height; + + if ((height <= 8) || (height > 64)) { + return; + } + + drawPoint = point; + drawPoint.y -= height; + + if (drawPoint.y >= _tileClip.bottom) { + return; + } + + if (location != NULL) { + if (location->z <= -16) { + if (location->z <= -48) { + if (location->u() < -THRESH8 || location->v() < -THRESH8) { + return; + } + } else { + if (location->u() < THRESH0 || location->v() < THRESH0) { + return; + } + } + } else { + if (location->z >= 16) { + return; + } else { + switch (_tilesTable[tileIndex].GetMaskRule()) { + case kMaskRuleNever: + return; + case kMaskRuleAlways: + break; + case kMaskRuleUMIN: + if (location->u() < THRESH0) { + return; + } + break; + case kMaskRuleUMID: + if (location->u() < THRESH8) { + return; + } + break; + case kMaskRuleUMAX: + if (location->u() < THRESH16) { + return; + } + break; + case kMaskRuleVMIN: + if (location->v() < THRESH0) { + return; + } + break; + case kMaskRuleVMID: + if (location->v() < THRESH8) { + return; + } + break; + case kMaskRuleVMAX: + if (location->v() < THRESH16) { + return; + } + break; + case kMaskRuleYMIN: + if (location->uv() < THRESH0 * 2) { + return; + } + break; + case kMaskRuleYMID: + if (location->uv() < THRESH8 * 2) { + return; + } + break; + case kMaskRuleYMAX: + if (location->uv() < THRESH16 * 2) { + return; + } + break; + case kMaskRuleUVMAX: + if (location->u() < THRESH16 && location->v() < THRESH16) { + return; + } + break; + case kMaskRuleUVMIN: + if (location->u() < THRESH0 || location->v() < THRESH0) { + return; + } + break; + case kMaskRuleUorV: + if (location->u() < THRESH8 && location->v() < THRESH8) { + return; + } + break; + case kMaskRuleUandV: + if (location->u() < THRESH8 || location->v() < THRESH8) { + return; + } + break; + } + } + } + } + + readPointer = tilePointer; + lowBound = MIN((int)(drawPoint.y + height), (int)_tileClip.bottom); + for (row = drawPoint.y; row < lowBound; row++) { + widthCount = 0; + if (row >= _tileClip.top) { + drawPointer = (byte *)ds->pixels + drawPoint.x + (row * ds->pitch); + col = drawPoint.x; + for (;;) { + bgRunCount = *readPointer++; + widthCount += bgRunCount; + if (widthCount >= SAGA_ISOTILE_WIDTH) { + break; + } + + drawPointer += bgRunCount; + col += bgRunCount; + fgRunCount = *readPointer++; + widthCount += fgRunCount; + + count = 0; + while ((col < _tileClip.left) && (count < fgRunCount)) { + count++; + col++; + } + while ((col < _tileClip.right) && (count < fgRunCount)) { + assert((byte *)ds->pixels <= (byte *)(drawPointer + count)); + assert((byte *)((byte *)ds->pixels + (_vm->getDisplayWidth() * + _vm->getDisplayHeight())) > (byte *)(drawPointer + count)); + drawPointer[count] = readPointer[count]; + count++; + col++; + } + readPointer += fgRunCount; + drawPointer += fgRunCount; + } + } else { + for (;;) { + bgRunCount = *readPointer++; + widthCount += bgRunCount; + if (widthCount >= SAGA_ISOTILE_WIDTH) { + break; + } + + fgRunCount = *readPointer++; + widthCount += fgRunCount; + + readPointer += fgRunCount; + } + } + } + +} + +bool IsoMap::checkDragonPoint(int16 u, int16 v, uint16 direction) { + DragonPathCell *pathCell; + + if ((u < 1) || (u >= SAGA_DRAGON_SEARCH_DIAMETER - 1) || (v < 1) || (v >= SAGA_DRAGON_SEARCH_DIAMETER - 1)) { + return false; + } + + pathCell = _dragonSearchArray.getPathCell(u, v); + + if (pathCell->visited) { + return false; + } + + pathCell->visited = 1; + pathCell->direction = direction; + return true; +} + +void IsoMap::pushDragonPoint(int16 u, int16 v, uint16 direction) { + DragonTilePoint *tilePoint; + DragonPathCell *pathCell; + + if ((u < 1) || (u >= SAGA_DRAGON_SEARCH_DIAMETER - 1) || (v < 1) || (v >= SAGA_DRAGON_SEARCH_DIAMETER - 1)) { + return; + } + + pathCell = _dragonSearchArray.getPathCell(u, v); + + if (pathCell->visited) { + return; + } + + tilePoint = _dragonSearchArray.getQueue(_queueCount); + _queueCount++; + if (_queueCount >= SAGA_SEARCH_QUEUE_SIZE) { + _queueCount = 0; + } + + tilePoint->u = u; + tilePoint->v = v; + tilePoint->direction = direction; + + pathCell->visited = 1; + pathCell->direction = direction; +} + +void IsoMap::pushPoint(int16 u, int16 v, uint16 cost, uint16 direction) { + int16 upper; + int16 lower; + int16 mid; + TilePoint *tilePoint; + PathCell *pathCell; + + upper = _queueCount; + lower = 0; + + if ((u < 1) || (u >= SAGA_SEARCH_DIAMETER - 1) || (v < 1) || (v >= SAGA_SEARCH_DIAMETER - 1)) { + return; + } + + pathCell = _searchArray.getPathCell(u, v); + + if ((pathCell->visited) && (pathCell->cost <= cost)) { + return; + } + + if (_queueCount >= SAGA_SEARCH_QUEUE_SIZE) { + return; + } + + while (1) { + mid = (upper + lower) / 2; + tilePoint = _searchArray.getQueue(mid); + + if (upper <= lower) { + break; + } + + if (cost < tilePoint->cost) { + lower = mid + 1; + } else { + upper = mid; + } + } + + if (mid < _queueCount ) { + memmove(tilePoint + 1, tilePoint, (_queueCount - mid) * sizeof (*tilePoint)); + } + _queueCount++; + + tilePoint->u = u; + tilePoint->v = v; + tilePoint->cost = cost; + tilePoint->direction = direction; + + pathCell->visited = 1; + pathCell->direction = direction; + pathCell->cost = cost; +} + +int16 IsoMap::getTileIndex(int16 u, int16 v, int16 z) { + int16 mtileU; + int16 mtileV; + int16 uc; + int16 vc; + int16 u0; + int16 v0; + int16 platformIndex; + int16 metaTileIndex; + + mtileU = u >> 3; + mtileV = v >> 3; + uc = mtileU & (SAGA_TILEMAP_W - 1); + vc = mtileV & (SAGA_TILEMAP_W - 1); + u0 = u & (SAGA_PLATFORM_W - 1); + v0 = v & (SAGA_PLATFORM_W - 1); + + if ((uc != mtileU) || (vc != mtileV)) { + metaTileIndex = 0; + switch ( _tileMap.edgeType) { + case kEdgeTypeBlack: + return 0; + case kEdgeTypeFill0: + break; + case kEdgeTypeFill1: + metaTileIndex = 1; + break; + case kEdgeTypeRpt: + uc = clamp( 0, mtileU, SAGA_TILEMAP_W - 1); + vc = clamp( 0, mtileV, SAGA_TILEMAP_W - 1); + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + break; + case kEdgeTypeWrap: + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + break; + } + } else { + metaTileIndex = _tileMap.tilePlatforms[uc][vc]; + } + + if (_metaTilesCount <= metaTileIndex) { + error("IsoMap::getTile wrong metaTileIndex"); + } + + platformIndex = _metaTileList[metaTileIndex].stack[z]; + if (platformIndex < 0) { + return 0; + } + + if (_tilePlatformsCount <= platformIndex) { + error("IsoMap::getTile wrong platformIndex"); + } + + return _tilePlatformList[platformIndex].tiles[u0][v0]; +} + +IsoTileData *IsoMap::getTile(int16 u, int16 v, int16 z) { + int16 tileIndex; + + tileIndex = getTileIndex(u, v, z); + + if (tileIndex == 0) { + return NULL; + } + + if (tileIndex & SAGA_MULTI_TILE) { + tileIndex = findMulti(tileIndex, u, v, z); + } + + return &_tilesTable[tileIndex]; +} + +void IsoMap::testPossibleDirections(int16 u, int16 v, uint16 terraComp[8], int skipCenter) { + IsoTileData *tile; + uint16 fgdMask; + uint16 bgdMask; + uint16 mask; + + + memset(terraComp, 0, 8 * sizeof(uint16)); + +#define FILL_MASK(index, testMask) \ + if ( mask & testMask) { \ + terraComp[index] |= fgdMask; \ + } \ + if (~mask & testMask) { \ + terraComp[index] |= bgdMask; \ + } + +#define TEST_TILE_PROLOG(offsetU, offsetV) \ + tile = getTile(u + offsetU, v + offsetV , _platformHeight); \ + if (tile != NULL) { \ + fgdMask = tile->GetFGDMask(); \ + bgdMask = tile->GetBGDMask(); \ + mask = tile->terrainMask; + +#define TEST_TILE_EPILOG(index) \ + } else { \ + if (_vm->_actor->_protagonist->_location.z > 0) { \ + terraComp[index] = SAGA_IMPASSABLE; \ + } \ + } + +#define TEST_TILE_END } + + TEST_TILE_PROLOG(0, 0) + if (skipCenter) { + if ((mask & 0x0660) && (fgdMask & SAGA_IMPASSABLE)) { + fgdMask = 0; + } + if ((~mask & 0x0660) && (bgdMask & SAGA_IMPASSABLE)) { + bgdMask = 0; + } + } + + FILL_MASK(0, 0xcc00) + FILL_MASK(1, 0x6600) + FILL_MASK(2, 0x3300) + FILL_MASK(3, 0x0330) + FILL_MASK(4, 0x0033) + FILL_MASK(5, 0x0066) + FILL_MASK(6, 0x00cc) + FILL_MASK(7, 0x0cc0) + TEST_TILE_END + + TEST_TILE_PROLOG(1, 1) + FILL_MASK(0, 0x0673) + TEST_TILE_EPILOG(0) + + + TEST_TILE_PROLOG(1, 0) + FILL_MASK(0, 0x0008) + FILL_MASK(1, 0x0666) + FILL_MASK(2, 0x0001) + TEST_TILE_EPILOG(1) + + + TEST_TILE_PROLOG(1, -1) + FILL_MASK(2, 0x06ec) + TEST_TILE_EPILOG(2) + + TEST_TILE_PROLOG(0, 1) + FILL_MASK(0, 0x1000) + FILL_MASK(7, 0x0770) + FILL_MASK(6, 0x0001) + TEST_TILE_EPILOG(7) + + + TEST_TILE_PROLOG(0, -1) + FILL_MASK(2, 0x8000) + FILL_MASK(3, 0x0ee0) + FILL_MASK(4, 0x0008) + TEST_TILE_EPILOG(3) + + + TEST_TILE_PROLOG(-1, 1) + FILL_MASK(6, 0x3670) + TEST_TILE_EPILOG(6) + + + TEST_TILE_PROLOG(-1, 0) + FILL_MASK(6, 0x8000) + FILL_MASK(5, 0x6660) + FILL_MASK(4, 0x1000) + TEST_TILE_EPILOG(5) + + TEST_TILE_PROLOG(-1, -1) + FILL_MASK(4, 0xce60) + TEST_TILE_EPILOG(4) +} + +void IsoMap::placeOnTileMap(const Location &start, Location &result, int16 distance, uint16 direction) { + int16 bestDistance; + int16 bestU; + int16 bestV; + int16 uBase; + int16 vBase; + int16 u; + int16 v; + int i; + ActorData *actor; + TilePoint tilePoint; + uint16 dir; + int16 dist; + uint16 terraComp[8]; + const TilePoint *tdir; + uint16 terrainMask; + + bestDistance = 0; + + + uBase = (start.u() >> 4) - SAGA_SEARCH_CENTER; + vBase = (start.v() >> 4) - SAGA_SEARCH_CENTER; + + bestU = SAGA_SEARCH_CENTER; + bestV = SAGA_SEARCH_CENTER; + + _platformHeight = _vm->_actor->_protagonist->_location.z / 8; + + memset( &_searchArray, 0, sizeof(_searchArray)); + + for (i = 0; i < _vm->_actor->_actorsCount; i++) { + actor = _vm->_actor->_actors[i]; + if (!actor->_inScene) continue; + + u = (actor->_location.u() >> 4) - uBase; + v = (actor->_location.v() >> 4) - vBase; + if ((u >= 0) && (u < SAGA_SEARCH_DIAMETER) && + (v >= 0) && (v < SAGA_SEARCH_DIAMETER) && + ((u != SAGA_SEARCH_CENTER) || (v != SAGA_SEARCH_CENTER))) { + _searchArray.getPathCell(u, v)->visited = 1; + } + } + + _queueCount = 0; + pushPoint(SAGA_SEARCH_CENTER, SAGA_SEARCH_CENTER, 0, 0); + + while (_queueCount > 0) { + + _queueCount--; + tilePoint = *_searchArray.getQueue(_queueCount); + + + dist = ABS(tilePoint.u - SAGA_SEARCH_CENTER) + ABS(tilePoint.v - SAGA_SEARCH_CENTER); + + if (dist > bestDistance) { + bestU = tilePoint.u; + bestV = tilePoint.v; + bestDistance = dist; + + if (dist >= distance) { + break; + } + } + + testPossibleDirections(uBase + tilePoint.u, vBase + tilePoint.v, terraComp, 0); + + + for (dir = 0; dir < 8; dir++) { + terrainMask = terraComp[dir]; + + if (terrainMask & SAGA_IMPASSABLE ) { + continue; + } + + if (dir == direction) { + tdir = &easyDirTable[ dir ]; + } else { + if (dir + 1 == direction || dir - 1 == direction) { + tdir = &normalDirTable[ dir ]; + } else { + tdir = &hardDirTable[ dir ]; + } + } + + pushPoint(tilePoint.u + tdir->u,tilePoint.v + tdir->v, tilePoint.cost + tdir->cost, dir); + } + } + + result.u() = ((uBase + bestU) << 4) + 8; + result.v() = ((vBase + bestV) << 4) + 8; +} + +bool IsoMap::findNearestChasm(int16 &u0, int16 &v0, uint16 &direction) { + int16 u, v; + uint16 i; + u = u0; + v = v0; + + for (i = 1; i < 5; i++) { + if (getTile( u - i, v, 6) == NULL) { + u0 = u - i - 1; + v0 = v; + direction = kDirDownLeft; + return true; + } + + if (getTile( u, v - i, 6) == NULL) { + u0 = u; + v0 = v - i - 1; + direction = kDirDownRight; + return true; + } + + if (getTile( u - i, v - i, 6) == NULL) { + u0 = u - i - 1; + v0 = v - i - 1; + direction = kDirDown; + return true; + } + + if (getTile( u + i, v - i, 6) == NULL) { + u0 = u + i + 1; + v0 = v - i - 1; + direction = kDirDownRight; + return true; + } + + if (getTile( u - i, v + i, 6) == NULL) { + u0 = u + i + 1; + v0 = v - i - 1; + direction = kDirLeft; + return true; + } + } + + for (i = 1; i < 5; i++) { + if (getTile( u + i, v, 6) == NULL) { + u0 = u + i + 1; + v0 = v; + direction = kDirUpRight; + return true; + } + + if (getTile( u, v + i, 6) == NULL) { + u0 = u; + v0 = v + i + 1; + direction = kDirUpLeft; + return true; + } + + if (getTile( u + i, v + i, 6) == NULL) { + u0 = u + i + 1; + v0 = v + i + 1; + direction = kDirUp; + return true; + } + } + return false; +} + +void IsoMap::findDragonTilePath(ActorData* actor,const Location &start, const Location &end, uint16 initialDirection) { + byte *res; + int i; + int16 u; + int16 v; + int16 u1; + int16 v1; + uint16 dir; + + int16 bestDistance; + int16 bestU; + int16 bestV; + + int16 uBase; + int16 vBase; + int16 uFinish; + int16 vFinish; + DragonPathCell *pcell; + IsoTileData *tile; + uint16 mask; + DragonTilePoint *tilePoint; + + int16 dist; + bool first; + + bestDistance = SAGA_DRAGON_SEARCH_DIAMETER; + bestU = SAGA_DRAGON_SEARCH_CENTER, + bestV = SAGA_DRAGON_SEARCH_CENTER; + + uBase = (start.u() >> 4) - SAGA_DRAGON_SEARCH_CENTER; + vBase = (start.v() >> 4) - SAGA_DRAGON_SEARCH_CENTER; + uFinish = (end.u() >> 4) - uBase; + vFinish = (end.v() >> 4) - vBase; + + _platformHeight = _vm->_actor->_protagonist->_location.z / 8; + + memset( &_dragonSearchArray, 0, sizeof(_dragonSearchArray)); + + for (u = 0; u < SAGA_DRAGON_SEARCH_DIAMETER; u++) { + for (v = 0; v < SAGA_DRAGON_SEARCH_DIAMETER; v++) { + + pcell = _dragonSearchArray.getPathCell(u, v); + + u1 = uBase + u; + v1 = vBase + v; + + if ((u1 > 127) || (u1 < 48) || (v1 > 127) || (v1 < 0)) { + pcell->visited = 1; + continue; + } + + tile = getTile(u1, v1, _platformHeight ); + if (tile != NULL) { + mask = tile->terrainMask; + if ( ((mask != 0) && (tile->GetFGDAttr() >= kTerrBlock)) || + ((mask != 0xFFFF) && (tile->GetBGDAttr() >= kTerrBlock)) ) { + pcell->visited = 1; + } + } else { + pcell->visited = 1; + } + } + } + + first = true; + _queueCount = _readCount = 0; + pushDragonPoint( SAGA_DRAGON_SEARCH_CENTER, SAGA_DRAGON_SEARCH_CENTER, initialDirection); + + while (_queueCount != _readCount) { + + tilePoint = _dragonSearchArray.getQueue(_readCount++); + if (_readCount >= SAGA_SEARCH_QUEUE_SIZE) { + _readCount = 0; + } + + + dist = ABS(tilePoint->u - uFinish) + ABS(tilePoint->v - vFinish); + + if (dist < bestDistance) { + + bestU = tilePoint->u; + bestV = tilePoint->v; + bestDistance = dist; + if (dist == 0) { + break; + } + } + + switch (tilePoint->direction) { + case kDirUpRight: + if (checkDragonPoint( tilePoint->u + 1, tilePoint->v + 0, kDirUpRight)) { + pushDragonPoint( tilePoint->u + 2, tilePoint->v + 0, kDirUpRight); + pushDragonPoint( tilePoint->u + 1, tilePoint->v + 1, kDirUpLeft); + pushDragonPoint( tilePoint->u + 1, tilePoint->v - 1, kDirDownRight); + } + break; + case kDirDownRight: + if (checkDragonPoint( tilePoint->u + 0, tilePoint->v - 1, kDirDownRight)) { + pushDragonPoint( tilePoint->u + 0, tilePoint->v - 2, kDirDownRight); + pushDragonPoint( tilePoint->u + 1, tilePoint->v - 1, kDirUpRight); + pushDragonPoint( tilePoint->u - 1, tilePoint->v - 1, kDirDownLeft); + } + break; + case kDirDownLeft: + if (checkDragonPoint( tilePoint->u - 1, tilePoint->v + 0, kDirDownLeft)) { + pushDragonPoint( tilePoint->u - 2, tilePoint->v + 0, kDirDownLeft); + pushDragonPoint( tilePoint->u - 1, tilePoint->v - 1, kDirDownRight); + pushDragonPoint( tilePoint->u - 1, tilePoint->v + 1, kDirUpLeft); + } + break; + case kDirUpLeft: + if (checkDragonPoint( tilePoint->u + 0, tilePoint->v + 1, kDirUpLeft)) { + pushDragonPoint( tilePoint->u + 0, tilePoint->v + 2, kDirUpLeft); + pushDragonPoint( tilePoint->u - 1, tilePoint->v + 1, kDirDownLeft); + pushDragonPoint( tilePoint->u + 1, tilePoint->v + 1, kDirUpRight); + } + break; + } + + if (first && (_queueCount == _readCount)) { + pushDragonPoint( tilePoint->u + 1, tilePoint->v + 0, kDirUpRight); + pushDragonPoint( tilePoint->u + 0, tilePoint->v - 1, kDirDownRight); + pushDragonPoint( tilePoint->u - 1, tilePoint->v + 0, kDirDownLeft); + pushDragonPoint( tilePoint->u + 0, tilePoint->v + 1, kDirUpLeft); + } + first = false; + } + + res = &_pathDirections[SAGA_MAX_PATH_DIRECTIONS]; + i = 0; + while ((bestU != SAGA_DRAGON_SEARCH_CENTER) || (bestV != SAGA_DRAGON_SEARCH_CENTER)) { + pcell = _dragonSearchArray.getPathCell(bestU, bestV); + + *--res = pcell->direction; + i++; + if (i >= SAGA_MAX_PATH_DIRECTIONS) { + break; + } + + dir = (pcell->direction + 4) & 0x07; + + bestU += normalDirTable[dir].u; + bestV += normalDirTable[dir].v; + } + +/* if (i > 64) { + i = 64; + }*/ + + actor->_walkStepsCount = i; + if (i) { + actor->setTileDirectionsSize(i, false); + memcpy(actor->_tileDirections, res, i ); + } + +} + +void IsoMap::findTilePath(ActorData* actor, const Location &start, const Location &end) { + ActorData *other; + int i; + int16 u; + int16 v; + int16 bestDistance; + int16 bestU; + int16 bestV; + + int16 uBase; + int16 vBase; + int16 uFinish; + int16 vFinish; + + TilePoint tilePoint; + uint16 dir; + int16 dist; + uint16 terraComp[8]; + const TilePoint *tdir; + uint16 terrainMask; + const PathCell *pcell; + byte *res; + + + bestDistance = SAGA_SEARCH_DIAMETER; + bestU = SAGA_SEARCH_CENTER, + bestV = SAGA_SEARCH_CENTER; + + uBase = (start.u() >> 4) - SAGA_SEARCH_CENTER; + vBase = (start.v() >> 4) - SAGA_SEARCH_CENTER; + uFinish = (end.u() >> 4) - uBase; + vFinish = (end.v() >> 4) - vBase; + + _platformHeight = _vm->_actor->_protagonist->_location.z / 8; + + + + memset( &_searchArray, 0, sizeof(_searchArray)); + + if (!(actor->_actorFlags & kActorNoCollide) && + (_vm->_scene->currentSceneResourceId() != RID_ITE_OVERMAP_SCENE)) { + for (i = 0; i < _vm->_actor->_actorsCount; i++) { + other = _vm->_actor->_actors[i]; + if (!other->_inScene) continue; + if (other == actor) continue; + + u = (other->_location.u() >> 4) - uBase; + v = (other->_location.v() >> 4) - vBase; + if ((u >= 1) && (u < SAGA_SEARCH_DIAMETER) && + (v >= 1) && (v < SAGA_SEARCH_DIAMETER) && + ((u != SAGA_SEARCH_CENTER) || (v != SAGA_SEARCH_CENTER))) { + _searchArray.getPathCell(u, v)->visited = 1; + } + } + } + + _queueCount = 0; + pushPoint(SAGA_SEARCH_CENTER, SAGA_SEARCH_CENTER, 0, 0); + + + while (_queueCount > 0) { + + _queueCount--; + tilePoint = *_searchArray.getQueue(_queueCount); + + if (tilePoint.cost > 100 && actor == _vm->_actor->_protagonist) continue; + + dist = ABS(tilePoint.u - uFinish) + ABS(tilePoint.v - vFinish); + + if (dist < bestDistance) { + bestU = tilePoint.u; + bestV = tilePoint.v; + bestDistance = dist; + + if (dist == 0) { + break; + } + } + + testPossibleDirections(uBase + tilePoint.u, vBase + tilePoint.v, terraComp, + (tilePoint.u == SAGA_SEARCH_CENTER && tilePoint.v == SAGA_SEARCH_CENTER)); + + for (dir = 0; dir < 8; dir++) { + terrainMask = terraComp[dir]; + + if (terrainMask & SAGA_IMPASSABLE) { + continue; + } else { + if (terrainMask & (1 << kTerrRough)) { + tdir = &hardDirTable[ dir ]; + } else { + if (terrainMask & (1 << kTerrNone)) { + tdir = &normalDirTable[ dir ]; + } else { + tdir = &easyDirTable[ dir ]; + } + } + } + + + pushPoint(tilePoint.u + tdir->u, tilePoint.v + tdir->v, tilePoint.cost + tdir->cost, dir); + } + } + + res = &_pathDirections[SAGA_MAX_PATH_DIRECTIONS]; + i = 0; + while ((bestU != SAGA_SEARCH_CENTER) || (bestV != SAGA_SEARCH_CENTER)) { + pcell = _searchArray.getPathCell(bestU, bestV); + + *--res = pcell->direction; + i++; + if (i >= SAGA_MAX_PATH_DIRECTIONS) { + break; + } + + dir = (pcell->direction + 4) & 0x07; + + bestU += normalDirTable[dir].u; + bestV += normalDirTable[dir].v; + } + +/* if (i > 64) { + i = 64; + }*/ + actor->_walkStepsCount = i; + if (i) { + actor->setTileDirectionsSize(i, false); + memcpy(actor->_tileDirections, res, i ); + } +} + +void IsoMap::setTileDoorState(int doorNumber, int doorState) { + MultiTileEntryData *multiTileEntryData; + + if ((doorNumber < 0) || (doorNumber >= _multiCount)) { + error("setTileDoorState: doorNumber >= _multiCount"); + } + + multiTileEntryData = &_multiTable[doorNumber]; + multiTileEntryData->currentState = doorState; +} + +static const int16 directions[8][2] = { + { 16, 16}, + { 16, 0}, + { 16, -16}, + { 0, -16}, + { -16, -16}, + { -16, 0}, + { -16, 16}, + { 0, 16} +}; + + + +bool IsoMap::nextTileTarget(ActorData* actor) { + uint16 dir; + + if (actor->_walkStepIndex >= actor->_walkStepsCount) { + return false; + } + + + actor->_actionDirection = dir = actor->_tileDirections[actor->_walkStepIndex++]; + + actor->_partialTarget.u() = + (actor->_location.u() & ~0x0f) + 8 + directions[dir][0]; + + actor->_partialTarget.v() = + (actor->_location.v() & ~0x0f) + 8 + directions[dir][1]; + + + if (dir == 0) { + actor->_facingDirection = kDirUp; + } else { + if (dir == 4) { + actor->_facingDirection = kDirDown; + } else { + if (dir < 4) { + actor->_facingDirection = kDirRight; + } else { + actor->_facingDirection = kDirLeft; + } + } + } + + return true; +} + +void IsoMap::screenPointToTileCoords(const Point &position, Location &location) { + Point mPos(position); + int x,y; + + if (_vm->_scene->currentSceneResourceId() == RID_ITE_OVERMAP_SCENE){ + if (mPos.y < 16) { + mPos.y = 16; + } + } + + x = mPos.x + _viewScroll.x - (128 * SAGA_TILEMAP_W) - 16; + y = mPos.y + _viewScroll.y - (128 * SAGA_TILEMAP_W) + _vm->_actor->_protagonist->_location.z; + + location.u() = (x - y * 2) >> 1; + location.v() = - (x + y * 2) >> 1; + location.z = _vm->_actor->_protagonist->_location.z; +} + +} // End of namespace Saga |