/* ScummVM - Scumm Interpreter * Copyright (C) 2004 Ivan Dubrov * Copyright (C) 2004-2006 The ScummVM project * * 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$ * */ #include "common/stdafx.h" #include "common/endian.h" #include "gob/gob.h" #include "gob/map.h" #include "gob/video.h" #include "gob/util.h" #include "gob/dataio.h" #include "gob/inter.h" #include "gob/goblin.h" #include "gob/sound.h" #include "gob/scenery.h" #include "gob/mult.h" namespace Gob { Map::Map(GobEngine *vm) : _vm(vm) { int i; _mapWidth = -1; _mapHeight = -1; _screenWidth = 0; _tilesWidth = 0; _tilesHeight = 0; _passWidth = 0; _passMap = 0; _itemsMap = 0; _wayPointsCount = 0; _wayPoints = 0; _bigTiles = false; for (i = 0; i < 40; i++) { _itemPoses[i].x = 0; _itemPoses[i].y = 0; _itemPoses[i].orient = 0; } _nearestWayPoint = 0; _nearestDest = 0; _curGoblinX = 0; _curGoblinY = 0; _destX = 0; _destY = 0; _loadFromAvo = 0; _sourceFile[0] = 0; _avoDataPtr = 0; } Map::~Map() { if (_passMap) delete[] _passMap; if (_itemsMap) { for (int i = 0; i < _mapHeight; i++) delete[] _itemsMap[i]; delete[] _itemsMap; } if (_wayPoints) delete[] _wayPoints; } void Map::placeItem(int16 x, int16 y, int16 id) { if ((_itemsMap[y][x] & 0xff00) != 0) _itemsMap[y][x] = (_itemsMap[y][x] & 0xff00) | id; else _itemsMap[y][x] = (_itemsMap[y][x] & 0x00ff) | (id << 8); } enum { kLeft = (1 << 0), kUp = (1 << 1), kRight = (1 << 2), kDown = (1 << 3) }; int16 Map::getDirection(int16 x0, int16 y0, int16 x1, int16 y1) { int16 dir = 0; if (x0 == x1 && y0 == y1) return 0; if ((x1 < 0) || (x1 > _mapWidth) || (y1 < 0) || (y1 > _mapHeight)) return 0; if (y1 > y0) dir |= kDown; else if (y1 < y0) dir |= kUp; if (x1 > x0) dir |= kRight; else if (x1 < x0) dir |= kLeft; if (getPass(x0, y0) == 3 && (dir & kUp)) { if (getPass(x0, y0 - 1) != 0) return kDirN; } if (getPass(x0, y0) == 3 && (dir & kDown)) { if (getPass(x0, y0 + 1) != 0) return kDirS; } if (getPass(x0, y0) == 6 && (dir & kUp)) { if (getPass(x0, y0 - 1) != 0) return kDirN; } if (getPass(x0, y0) == 6 && (dir & kDown)) { if (getPass(x0, y0 + 1) != 0) return kDirS; } if (dir == kLeft) { if (x0 - 1 >= 0 && getPass(x0 - 1, y0) != 0) return kDirW; return 0; } if (dir == kRight) { if (x0 + 1 < _mapWidth && getPass(x0 + 1, y0) != 0) return kDirE; return 0; } if (dir == kUp) { if (y0 - 1 >= 0 && getPass(x0, y0 - 1) != 0) return kDirN; if (y0 - 1 >= 0 && x0 - 1 >= 0 && getPass(x0 - 1, y0 - 1) != 0) return kDirNW; if (y0 - 1 >= 0 && x0 + 1 < _mapWidth && getPass(x0 + 1, y0 - 1) != 0) return kDirNE; return 0; } if (dir == kDown) { if (y0 + 1 < _mapHeight && getPass(x0, y0 + 1) != 0) return kDirS; if (y0 + 1 < _mapHeight && x0 - 1 >= 0 && getPass(x0 - 1, y0 + 1) != 0) return kDirSW; if (y0 + 1 < _mapHeight && x0 + 1 < _mapWidth && getPass(x0 + 1, y0 + 1) != 0) return kDirSE; return 0; } if (dir == (kRight | kUp)) { if (y0 - 1 >= 0 && x0 + 1 < _mapWidth && getPass(x0 + 1, y0 - 1) != 0) return kDirNE; if (y0 - 1 >= 0 && getPass(x0, y0 - 1) != 0) return kDirN; if (x0 + 1 < _mapWidth && getPass(x0 + 1, y0) != 0) return kDirE; return 0; } if (dir == (kRight | kDown)) { if (x0 + 1 < _mapWidth && y0 + 1 < _mapHeight && getPass(x0 + 1, y0 + 1) != 0) return kDirSE; if (y0 + 1 < _mapHeight && getPass(x0, y0 + 1) != 0) return kDirS; if (x0 + 1 < _mapWidth && getPass(x0 + 1, y0) != 0) return kDirE; return 0; } if (dir == (kLeft | kUp)) { if (x0 - 1 >= 0 && y0 - 1 >= 0 && getPass(x0 - 1, y0 - 1) != 0) return kDirNW; if (y0 - 1 >= 0 && getPass(x0, y0 - 1) != 0) return kDirN; if (x0 - 1 >= 0 && getPass(x0 - 1, y0) != 0) return kDirW; return 0; } if (dir == (kLeft | kDown)) { if (x0 - 1 >= 0 && y0 + 1 < _mapHeight && getPass(x0 - 1, y0 + 1) != 0) return kDirSW; if (y0 + 1 < _mapHeight && getPass(x0, y0 + 1) != 0) return kDirS; if (x0 - 1 >= 0 && getPass(x0 - 1, y0) != 0) return kDirW; return 0; } return -1; } int16 Map::findNearestWayPoint(int16 x, int16 y) { int16 nearestWayPoint = -1; int16 length; int16 i; int16 tmp; length = 30000; for (i = 0; i < _wayPointsCount; i++) { if (_wayPoints[i].x < 0 || _wayPoints[i].x >= _mapWidth || _wayPoints[i].y < 0 || _wayPoints[i].y >= _mapHeight) break; tmp = ABS(x - _wayPoints[i].x) + ABS(y - _wayPoints[i].y); if (tmp <= length) { nearestWayPoint = i; length = tmp; } } return nearestWayPoint; } int16 Map::checkDirectPath(Mult::Mult_Object *obj, int16 x0, int16 y0, int16 x1, int16 y1) { uint16 dir; while (1) { dir = getDirection(x0, y0, x1, y1); if (obj) { if (obj->nearestWayPoint < obj->nearestDest) { if (_wayPoints[obj->nearestWayPoint + 1].field_2 == 1) return 3; } else if (obj->nearestWayPoint > obj->nearestDest) { if (obj->nearestDest > 0) if (_wayPoints[obj->nearestDest - 1].field_2 == 1) return 3; } } if (x0 == x1 && y0 == y1) return 1; if (dir == 0) return 3; switch (dir) { case kDirNW: x0--; y0--; break; case kDirN: y0--; break; case kDirNE: x0++; y0--; break; case kDirW: x0--; break; case kDirE: x0++; break; case kDirSW: x0--; y0++; break; case kDirS: y0++; break; case kDirSE: x0++; y0++; break; } } } int16 Map::checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1) { uint16 dir; int16 curX; int16 curY; int16 nextLink; curX = x0; curY = y0; dir = 0; nextLink = 1; while (1) { if (x0 == curX && y0 == curY) nextLink = 1; if (nextLink != 0) { if (checkDirectPath(0, x0, y0, x1, y1) == 1) return 1; nextLink = 0; if (i0 > i1) { curX = _wayPoints[i0].x; curY = _wayPoints[i0].y; i0--; } else if (i0 < i1) { curX = _wayPoints[i0].x; curY = _wayPoints[i0].y; i0++; } else if (i0 == i1) { curX = _wayPoints[i0].x; curY = _wayPoints[i0].y; } } if (i0 == i1 && _wayPoints[i0].x == x0 && _wayPoints[i0].y == y0) { if (checkDirectPath(0, x0, y0, x1, y1) == 1) return 1; return 0; } dir = getDirection(x0, y0, curX, curY); switch (dir) { case 0: return 0; case kDirNW: x0--; y0--; break; case kDirN: y0--; break; case kDirNE: x0++; y0--; break; case kDirW: x0--; break; case kDirE: x0++; break; case kDirSW: x0--; y0++; break; case kDirS: y0++; break; case kDirSE: x0++; y0++; break; } } } void Map::loadDataFromAvo(char *dest, int16 size) { memcpy(dest, _avoDataPtr, size); _avoDataPtr += size; } uint16 Map::loadFromAvo_LE_UINT16() { uint16 tmp = READ_LE_UINT16(_avoDataPtr); _avoDataPtr += 2; return tmp; } void Map::loadItemToObject(void) { int16 flag; int16 count; int16 i; flag = loadFromAvo_LE_UINT16(); if (flag == 0) return; _avoDataPtr += 1456; count = loadFromAvo_LE_UINT16(); for (i = 0; i < count; i++) { _avoDataPtr += 20; _vm->_goblin->_itemToObject[i] = loadFromAvo_LE_UINT16(); _avoDataPtr += 5; } } void Map::loadMapsInitGobs(void) { int16 layer; int16 i; if (_loadFromAvo == 0) error("load: Loading .pas/.pos files is not supported!"); for (i = 0; i < 3; i++) { _vm->_goblin->nextLayer(_vm->_goblin->_goblins[i]); } for (i = 0; i < 3; i++) { layer = _vm->_goblin->_goblins[i]->stateMach[_vm->_goblin->_goblins[i]->state][0]->layer; _vm->_scenery->updateAnim(layer, 0, _vm->_goblin->_goblins[i]->animation, 0, _vm->_goblin->_goblins[i]->xPos, _vm->_goblin->_goblins[i]->yPos, 0); _vm->_goblin->_goblins[i]->yPos = (_vm->_goblin->_gobPositions[i].y + 1) * 6 - (_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop); _vm->_goblin->_goblins[i]->xPos = _vm->_goblin->_gobPositions[i].x * 12 - (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft); _vm->_goblin->_goblins[i]->order = _vm->_scenery->_toRedrawBottom / 24 + 3; } _vm->_goblin->_currentGoblin = 0; _vm->_goblin->_pressedMapX = _vm->_goblin->_gobPositions[0].x; _vm->_goblin->_pressedMapY = _vm->_goblin->_gobPositions[0].y; _vm->_goblin->_pathExistence = 0; _vm->_goblin->_goblins[0]->doAnim = 0; _vm->_goblin->_goblins[1]->doAnim = 1; _vm->_goblin->_goblins[2]->doAnim = 1; } } // End of namespace Gob