Initial commit
This commit is contained in:
587
engines/gob/map.cpp
Normal file
587
engines/gob/map.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* This file is dual-licensed.
|
||||
* In addition to the GPLv3 license mentioned above, this code is also
|
||||
* licensed under LGPL 2.1. See LICENSES/COPYING.LGPL file for the
|
||||
* full text of the license.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gob/gob.h"
|
||||
#include "gob/map.h"
|
||||
#include "gob/goblin.h"
|
||||
#include "gob/scenery.h"
|
||||
#include "gob/mult.h"
|
||||
|
||||
namespace Gob {
|
||||
|
||||
Map::Map(GobEngine *vm) : _vm(vm) {
|
||||
_mapVersion = 0;
|
||||
|
||||
_passWidth = 0;
|
||||
_mapWidth = -1;
|
||||
_mapHeight = -1;
|
||||
_passMap = nullptr;
|
||||
|
||||
_screenWidth = 0;
|
||||
_screenHeight = 0;
|
||||
|
||||
_tilesWidth = 0;
|
||||
_tilesHeight = 0;
|
||||
|
||||
_bigTiles = false;
|
||||
|
||||
_usesObliqueCoordinates = false;
|
||||
|
||||
_wayPointCount = 0;
|
||||
_wayPoints = nullptr;
|
||||
|
||||
_nearestWayPoint = 0;
|
||||
_nearestDest = 0;
|
||||
|
||||
_itemsMap = nullptr;
|
||||
|
||||
for (int i = 0; i < 40; i++) {
|
||||
_itemPoses[i].x = 0;
|
||||
_itemPoses[i].y = 0;
|
||||
_itemPoses[i].orient = 0;
|
||||
}
|
||||
|
||||
_curGoblinX = 0;
|
||||
_curGoblinY = 0;
|
||||
_destX = 0;
|
||||
_destY = 0;
|
||||
|
||||
_sourceFile[0] = 0;
|
||||
|
||||
_loadFromAvo = false;
|
||||
}
|
||||
|
||||
Map::~Map() {
|
||||
delete[] _passMap;
|
||||
|
||||
if (_itemsMap) {
|
||||
for (int i = 0; i < _mapHeight; i++)
|
||||
delete[] _itemsMap[i];
|
||||
delete[] _itemsMap;
|
||||
}
|
||||
|
||||
delete[] _wayPoints;
|
||||
}
|
||||
|
||||
uint8 Map::getVersion() const {
|
||||
return _mapVersion;
|
||||
}
|
||||
|
||||
int16 Map::getMapWidth() const {
|
||||
return _mapWidth;
|
||||
}
|
||||
|
||||
int16 Map::getMapHeight() const {
|
||||
return _mapHeight;
|
||||
}
|
||||
|
||||
int16 Map::getScreenWidth() const {
|
||||
return _screenWidth;
|
||||
}
|
||||
|
||||
int16 Map::getScreenHeight() const {
|
||||
return _screenHeight;
|
||||
}
|
||||
|
||||
int16 Map::getTilesWidth() const {
|
||||
return _tilesWidth;
|
||||
}
|
||||
|
||||
int16 Map::getTilesHeight() const {
|
||||
return _tilesHeight;
|
||||
}
|
||||
|
||||
bool Map::hasBigTiles() const {
|
||||
return _bigTiles;
|
||||
}
|
||||
|
||||
int8 Map::getPass(int x, int y, int width) const {
|
||||
if (!_passMap)
|
||||
return 0;
|
||||
|
||||
if ((x < 0) || (y < 0) || (x >= _mapWidth) || (y >= _mapHeight))
|
||||
return 0;
|
||||
|
||||
if (width == -1)
|
||||
width = _passWidth;
|
||||
return _passMap[y * width + x];
|
||||
}
|
||||
|
||||
void Map::setPass(int x, int y, int8 pass, int width) {
|
||||
if (!_passMap)
|
||||
return;
|
||||
|
||||
if ((x < 0) || (y < 0) || (x >= _mapWidth) || (y >= _mapHeight))
|
||||
return;
|
||||
|
||||
if (width == -1)
|
||||
width = _passWidth;
|
||||
_passMap[y * width + x] = pass;
|
||||
}
|
||||
|
||||
const WayPoint &Map::getWayPoint(int n) const {
|
||||
assert(_wayPoints);
|
||||
assert(n < _wayPointCount);
|
||||
|
||||
return _wayPoints[n];
|
||||
}
|
||||
|
||||
int16 Map::getItem(int x, int y) const {
|
||||
assert(_itemsMap);
|
||||
|
||||
x = CLIP<int>(x, 0, _mapWidth - 1);
|
||||
y = CLIP<int>(y, 0, _mapHeight - 1);
|
||||
|
||||
return _itemsMap[y][x];
|
||||
}
|
||||
|
||||
void Map::setItem(int x, int y, int16 item) {
|
||||
assert(_itemsMap);
|
||||
|
||||
x = CLIP<int>(x, 0, _mapWidth - 1);
|
||||
y = CLIP<int>(y, 0, _mapHeight - 1);
|
||||
|
||||
_itemsMap[y][x] = item;
|
||||
}
|
||||
|
||||
void Map::placeItem(int16 x, int16 y, int16 id) {
|
||||
if ((getItem(x, y) & 0xFF00) != 0)
|
||||
setItem(x, y, (getItem(x, y) & 0xFF00) | id);
|
||||
else
|
||||
setItem(x, y, (getItem(x, y) & 0x00FF) | (id << 8));
|
||||
}
|
||||
|
||||
Direction Map::getDirection(int16 x0, int16 y0, int16 x1, int16 y1) {
|
||||
if ((x0 == x1) && (y0 == y1))
|
||||
// Already at the destination
|
||||
return kDirNone;
|
||||
|
||||
if ((x1 < 0) || (x1 > _mapWidth) || (y1 < 0) || (y1 > _mapHeight))
|
||||
// Destination out of range
|
||||
return kDirNone;
|
||||
|
||||
RelativeDirection relDir = kRelDirNone;
|
||||
|
||||
// Find the direct direction we want to move
|
||||
if (y1 > y0)
|
||||
relDir = kRelDirDown;
|
||||
else if (y1 < y0)
|
||||
relDir = kRelDirUp;
|
||||
|
||||
if (x1 > x0)
|
||||
relDir = (RelativeDirection)(relDir | kRelDirRight);
|
||||
else if (x1 < x0)
|
||||
relDir = (RelativeDirection)(relDir | kRelDirLeft);
|
||||
|
||||
|
||||
// Are we on ladders and can continue the ladder in the wanted direction?
|
||||
if ((getPass(x0, y0) == 3) && (relDir & kRelDirUp ) && (getPass(x0, y0 - 1) != 0))
|
||||
return kDirN;
|
||||
|
||||
if ((getPass(x0, y0) == 3) && (relDir & kRelDirDown) && (getPass(x0, y0 + 1) != 0))
|
||||
return kDirS;
|
||||
|
||||
if ((getPass(x0, y0) == 6) && (relDir & kRelDirUp ) && (getPass(x0, y0 - 1) != 0))
|
||||
return kDirN;
|
||||
|
||||
if ((getPass(x0, y0) == 6) && (relDir & kRelDirDown) && (getPass(x0, y0 + 1) != 0))
|
||||
return kDirS;
|
||||
|
||||
|
||||
// Want to go left
|
||||
if (relDir == kRelDirLeft) {
|
||||
if (getPass(x0 - 1, y0) != 0)
|
||||
// Can go west
|
||||
return kDirW;
|
||||
|
||||
// Can't go
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
// Want to go left
|
||||
if (relDir == kRelDirRight) {
|
||||
if (getPass(x0 + 1, y0) != 0)
|
||||
// Can go east
|
||||
return kDirE;
|
||||
|
||||
// Can't go
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
|
||||
// Want to go up
|
||||
if (relDir == kRelDirUp) {
|
||||
if (getPass(x0 , y0 - 1) != 0)
|
||||
// Can go north
|
||||
return kDirN;
|
||||
|
||||
if (getPass(x0 - 1, y0 - 1) != 0)
|
||||
// Can up north-west instead
|
||||
return kDirNW;
|
||||
|
||||
if (getPass(x0 + 1, y0 - 1) != 0)
|
||||
// Can up north-east instead
|
||||
return kDirNE;
|
||||
|
||||
// Can't go at all
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
// Want to go down
|
||||
if (relDir == kRelDirDown) {
|
||||
if (getPass(x0 , y0 + 1) != 0)
|
||||
// Can go south
|
||||
return kDirS;
|
||||
|
||||
if (getPass(x0 - 1, y0 + 1) != 0)
|
||||
// Can up south-west instead
|
||||
return kDirSW;
|
||||
|
||||
if (getPass(x0 + 1, y0 + 1) != 0)
|
||||
// Can up south-east instead
|
||||
return kDirSE;
|
||||
|
||||
// Can't go at all
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
|
||||
// Want to go up and right
|
||||
if (relDir == kRelDirRightUp) {
|
||||
if (getPass(x0 + 1, y0 - 1) != 0)
|
||||
// Can go north-east
|
||||
return kDirNE;
|
||||
|
||||
if (getPass(x0 , y0 - 1) != 0)
|
||||
// Can only go north
|
||||
return kDirN;
|
||||
|
||||
if (getPass(x0 + 1, y0 ) != 0)
|
||||
// Can only go east
|
||||
return kDirE;
|
||||
|
||||
// Can't go at all
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
// Want to go down and right
|
||||
if (relDir == kRelDirRightDown) {
|
||||
if (getPass(x0 + 1, y0 + 1) != 0)
|
||||
// Can go south-east
|
||||
return kDirSE;
|
||||
|
||||
if (getPass(x0 , y0 + 1) != 0)
|
||||
// Can only go south
|
||||
return kDirS;
|
||||
|
||||
if (getPass(x0 + 1, y0 ) != 0)
|
||||
// Can only go east
|
||||
return kDirE;
|
||||
|
||||
// Can't go at all
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
// Want to go up and left
|
||||
if (relDir == kRelDirLeftUp) {
|
||||
if (getPass(x0 - 1, y0 - 1) != 0)
|
||||
// Can go north-west
|
||||
return kDirNW;
|
||||
|
||||
if (getPass(x0 , y0 - 1) != 0)
|
||||
// Can only go north
|
||||
return kDirN;
|
||||
|
||||
if (getPass(x0 - 1, y0 ) != 0)
|
||||
// Can only go west
|
||||
return kDirW;
|
||||
|
||||
// Can't go at all
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
// Want to go left and down
|
||||
if (relDir == kRelDirLeftDown) {
|
||||
if (getPass(x0 - 1, y0 + 1) != 0)
|
||||
// Can go south-west
|
||||
return kDirSW;
|
||||
|
||||
if (getPass(x0 , y0 + 1) != 0)
|
||||
// Can only go south
|
||||
return kDirS;
|
||||
|
||||
if (getPass(x0 - 1, y0 ) != 0)
|
||||
// Can only go west
|
||||
return kDirW;
|
||||
|
||||
// Can't go at all
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
warning("Map::getDirection(): Invalid direction?!?");
|
||||
return kDirNone;
|
||||
}
|
||||
|
||||
int16 Map::findNearestWayPoint(int16 x, int16 y) {
|
||||
int16 nearestWayPoint = -1;
|
||||
int16 length;
|
||||
int16 tmp;
|
||||
|
||||
length = 30000;
|
||||
|
||||
for (int i = 0; i < _wayPointCount; 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;
|
||||
}
|
||||
|
||||
void Map::findNearestWalkable(int16 &gobDestX, int16 &gobDestY,
|
||||
int16 mouseX, int16 mouseY) {
|
||||
int16 mapWidth, mapHeight;
|
||||
int16 pos1 = -1, pos2 = -1;
|
||||
int16 distance;
|
||||
int16 direction;
|
||||
int i;
|
||||
|
||||
mapWidth = _screenWidth / _tilesWidth;
|
||||
mapHeight = _vm->_height / _tilesHeight;
|
||||
direction = 0;
|
||||
|
||||
for (i = 1; i <= gobDestX; i++)
|
||||
if (getPass(gobDestX - i, gobDestY) != 0)
|
||||
break;
|
||||
if (i <= gobDestX)
|
||||
pos1 = ((i - 1) * _tilesWidth) + (mouseX % _tilesWidth) + 1;
|
||||
distance = i;
|
||||
|
||||
for (i = 1; (gobDestX + i) < mapWidth; i++)
|
||||
if (getPass(gobDestX + i, gobDestY) != 0)
|
||||
break;
|
||||
if ((gobDestX + i) < mapWidth)
|
||||
pos2 = (i * _tilesWidth) - (mouseX % _tilesWidth);
|
||||
|
||||
if ((pos2 != -1) && ((pos1 == -1) || (pos1 > pos2))) {
|
||||
pos1 = pos2;
|
||||
direction = 1;
|
||||
distance = i;
|
||||
}
|
||||
pos2 = -1;
|
||||
|
||||
for (i = 1; (gobDestY + i) < mapHeight; i++)
|
||||
if (getPass(gobDestX, gobDestY + i) != 0)
|
||||
break;
|
||||
if ((gobDestY + i) < mapHeight)
|
||||
pos2 = (i * _tilesHeight) - (mouseY % _tilesHeight);
|
||||
|
||||
if ((pos2 != -1) && ((pos1 == -1) || (pos1 > pos2))) {
|
||||
pos1 = pos2;
|
||||
direction = 2;
|
||||
distance = i;
|
||||
}
|
||||
pos2 = -1;
|
||||
|
||||
for (i = 1; i <= gobDestY; i++)
|
||||
if (getPass(gobDestX, gobDestY - i) != 0)
|
||||
break;
|
||||
if (i <= gobDestY)
|
||||
pos2 = ((i - 1) * _tilesHeight) + (mouseY % _tilesHeight) + 1;
|
||||
|
||||
if ((pos2 != -1) && ((pos1 == -1) || (pos1 > pos2))) {
|
||||
direction = 3;
|
||||
distance = i;
|
||||
}
|
||||
|
||||
if (direction == 0)
|
||||
gobDestX -= distance;
|
||||
else if (direction == 1)
|
||||
gobDestX += distance;
|
||||
else if (direction == 2)
|
||||
gobDestY += distance;
|
||||
else if (direction == 3)
|
||||
gobDestY -= distance;
|
||||
}
|
||||
|
||||
void Map::moveDirection(Direction dir, int16 &x, int16 &y) {
|
||||
switch (dir) {
|
||||
case kDirNW:
|
||||
x--;
|
||||
y--;
|
||||
break;
|
||||
|
||||
case kDirN:
|
||||
y--;
|
||||
break;
|
||||
|
||||
case kDirNE:
|
||||
x++;
|
||||
y--;
|
||||
break;
|
||||
|
||||
case kDirW:
|
||||
x--;
|
||||
break;
|
||||
|
||||
case kDirE:
|
||||
x++;
|
||||
break;
|
||||
|
||||
case kDirSW:
|
||||
x--;
|
||||
y++;
|
||||
break;
|
||||
|
||||
case kDirS:
|
||||
y++;
|
||||
break;
|
||||
|
||||
case kDirSE:
|
||||
x++;
|
||||
y++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int16 Map::checkDirectPath(Mult::Mult_Object *obj, int16 x0, int16 y0, int16 x1, int16 y1) {
|
||||
|
||||
while (1) {
|
||||
Direction dir = getDirection(x0, y0, x1, y1);
|
||||
|
||||
if (obj) {
|
||||
// Check for a blocking waypoint
|
||||
|
||||
if (obj->nearestWayPoint < obj->nearestDest)
|
||||
if ((obj->nearestWayPoint + 1) < _wayPointCount)
|
||||
if (_wayPoints[obj->nearestWayPoint + 1].notWalkable == 1)
|
||||
return 3;
|
||||
|
||||
if (obj->nearestWayPoint > obj->nearestDest)
|
||||
if (obj->nearestWayPoint > 0)
|
||||
if (_wayPoints[obj->nearestWayPoint - 1].notWalkable == 1)
|
||||
return 3;
|
||||
}
|
||||
|
||||
if ((x0 == x1) && (y0 == y1))
|
||||
// Successfully reached the destination
|
||||
return 1;
|
||||
|
||||
if (dir == kDirNone)
|
||||
// No way
|
||||
return 3;
|
||||
|
||||
moveDirection(dir, x0, y0);
|
||||
}
|
||||
}
|
||||
|
||||
int16 Map::checkLongPath(int16 x0, int16 y0, int16 x1, int16 y1, int16 i0, int16 i1) {
|
||||
int16 curX = x0;
|
||||
int16 curY = y0;
|
||||
int16 nextLink = 1;
|
||||
|
||||
while (1) {
|
||||
if ((x0 == curX) && (y0 == curY))
|
||||
nextLink = 1;
|
||||
|
||||
if (nextLink != 0) {
|
||||
if (checkDirectPath(nullptr, 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(nullptr, x0, y0, x1, y1) == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Direction dir = getDirection(x0, y0, curX, curY);
|
||||
if (dir == kDirNone)
|
||||
// No way
|
||||
return 0;
|
||||
|
||||
moveDirection(dir, x0, y0);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::loadMapsInitGobs() {
|
||||
int16 layer;
|
||||
|
||||
if (!_loadFromAvo)
|
||||
error("Map::loadMapsInitGobs(): Loading .pas/.pos files is not supported");
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
_vm->_goblin->nextLayer(_vm->_goblin->_goblins[i]);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Goblin::Gob_Object &gob = *_vm->_goblin->_goblins[i];
|
||||
|
||||
layer = gob.stateMach[gob.state][0]->layer;
|
||||
_vm->_scenery->updateAnim(layer, 0, gob.animation, 0,
|
||||
gob.xPos, gob.yPos, 0);
|
||||
gob.yPos = (_vm->_goblin->_gobPositions[i].y + 1) * 6 -
|
||||
(_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop);
|
||||
gob.xPos = _vm->_goblin->_gobPositions[i].x * 12 -
|
||||
(_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
|
||||
gob.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
|
||||
Reference in New Issue
Block a user