diff options
author | Robert Špalek | 2009-10-30 00:52:05 +0000 |
---|---|---|
committer | Robert Špalek | 2009-10-30 00:52:05 +0000 |
commit | a20e42efb9272e74e8bd36b74c485a0d5ca88ee2 (patch) | |
tree | b6931b814cec52dd550047869b8d2e00845290de | |
parent | 1526fda715118d75b37dafbf1da58770289cbcae (diff) | |
download | scummvm-rg350-a20e42efb9272e74e8bd36b74c485a0d5ca88ee2.tar.gz scummvm-rg350-a20e42efb9272e74e8bd36b74c485a0d5ca88ee2.tar.bz2 scummvm-rg350-a20e42efb9272e74e8bd36b74c485a0d5ca88ee2.zip |
Move WalkingMap into new module.
Also, fix a bug when loading the default walking map (wasn't implemented)
and setting font size. The reason I move this code into a new module is
because I will augment it with other walking-related algorithms soon.
svn-id: r45510
-rw-r--r-- | engines/draci/game.cpp | 132 | ||||
-rw-r--r-- | engines/draci/game.h | 67 | ||||
-rw-r--r-- | engines/draci/module.mk | 3 | ||||
-rw-r--r-- | engines/draci/script.cpp | 5 | ||||
-rw-r--r-- | engines/draci/sprite.cpp | 3 | ||||
-rw-r--r-- | engines/draci/walking.cpp | 165 | ||||
-rw-r--r-- | engines/draci/walking.h | 71 |
7 files changed, 254 insertions, 192 deletions
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp index 625580fbef..2fbbe54a8d 100644 --- a/engines/draci/game.cpp +++ b/engines/draci/game.cpp @@ -1044,9 +1044,7 @@ void Game::loadRoom(int roomNum) { // Music will be played by the GPL2 command startMusic when needed. setMusicTrack(roomReader.readByte()); - int mapID = roomReader.readByte() - 1; - loadWalkingMap(mapID); - + _currentRoom._mapID = roomReader.readByte() - 1; _currentRoom._palette = roomReader.readByte() - 1; _currentRoom._numOverlays = roomReader.readSint16LE(); _currentRoom._init = roomReader.readSint16LE(); @@ -1078,7 +1076,7 @@ void Game::loadRoom(int roomNum) { _currentRoom._numGates = roomReader.readByte(); debugC(4, kDraciLogicDebugLevel, "Music: %d", getMusicTrack()); - debugC(4, kDraciLogicDebugLevel, "Map: %d", mapID); + debugC(4, kDraciLogicDebugLevel, "Map: %d", _currentRoom._mapID); debugC(4, kDraciLogicDebugLevel, "Palette: %d", _currentRoom._palette); debugC(4, kDraciLogicDebugLevel, "Overlays: %d", _currentRoom._numOverlays); debugC(4, kDraciLogicDebugLevel, "Init: %d", _currentRoom._init); @@ -1096,13 +1094,14 @@ void Game::loadRoom(int roomNum) { debugC(4, kDraciLogicDebugLevel, "Gates: %d", _currentRoom._numGates); // Read in the gates' numbers - _currentRoom._gates.clear(); - for (uint i = 0; i < _currentRoom._numGates; ++i) { _currentRoom._gates.push_back(roomReader.readSint16LE()); } + // Load the walking map + loadWalkingMap(_currentRoom._mapID); + // Load the room's objects for (uint i = 0; i < _info._numObjects; ++i) { debugC(7, kDraciLogicDebugLevel, @@ -1258,6 +1257,9 @@ void Game::loadObject(uint objNum) { } void Game::loadWalkingMap(int mapID) { + if (mapID < 0) { + mapID = _currentRoom._mapID; + } const BAFile *f; f = _vm->_walkingMapsArchive->getFile(mapID); _currentRoom._walkingMap.load(f->_data, f->_length); @@ -1665,124 +1667,6 @@ void Game::DoSync(Common::Serializer &s) { } -bool WalkingMap::isWalkable(int x, int y) const { - // Convert to map pixels - x = x / _deltaX; - y = y / _deltaY; - - int pixelIndex = _mapWidth * y + x; - int byteIndex = pixelIndex / 8; - int mapByte = _data[byteIndex]; - - return mapByte & (1 << pixelIndex % 8); -} - -/** - * @brief For a given point, find a nearest walkable point on the walking map - * - * @param startX x coordinate of the point - * @param startY y coordinate of the point - * - * @return A Common::Point representing the nearest walkable point - * - * The algorithm was copied from the original engine for exactness. - * TODO: Study this algorithm in more detail so it can be documented properly and - * possibly improved / simplified. - */ -Common::Point WalkingMap::findNearestWalkable(int startX, int startY, Common::Rect searchRect) const { - // If the starting point is walkable, just return that - if (searchRect.contains(startX, startY) && isWalkable(startX, startY)) { - return Common::Point(startX, startY); - } - - int signs[] = { 1, -1 }; - const uint kSignsNum = 2; - - int radius = 0; - int x, y; - int dx, dy; - int prediction; - - // The place where, eventually, the result coordinates will be stored - int finalX, finalY; - - // The algorithm appears to start off with an ellipse with the minor radius equal to - // zero and the major radius equal to the walking map delta (the number of pixels - // one map pixel represents). It then uses a heuristic to gradually reshape it into - // a circle (by shortening the major radius and lengthening the minor one). At each - // such resizing step, it checks some select points on the ellipse for walkability. - // It also does the same check for the ellipse perpendicular to it (rotated by 90 degrees). - - while (1) { - // The default major radius - radius += _deltaX; - - // The ellipse radii (minor, major) that get resized - x = 0; - y = radius; - - // Heuristic variables - prediction = 1 - radius; - dx = 3; - dy = 2 * radius - 2; - - do { - // The following two loops serve the purpose of checking the points on the two - // ellipses for walkability. The signs[] array is there to obliterate the need - // of writing out all combinations manually. - - for (uint i = 0; i < kSignsNum; ++i) { - finalY = startY + y * signs[i]; - - for (uint j = 0; j < kSignsNum; ++j) { - finalX = startX + x * signs[j]; - - // If the current point is walkable, return it - if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { - return Common::Point(finalX, finalY); - } - } - } - - if (x == y) { - // If the starting point is walkable, just return that - if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { - return Common::Point(finalX, finalY); - } - } - - for (uint i = 0; i < kSignsNum; ++i) { - finalY = startY + x * signs[i]; - - for (uint j = 0; j < kSignsNum; ++j) { - finalX = startX + y * signs[j]; - - // If the current point is walkable, return it - if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { - return Common::Point(finalX, finalY); - } - } - } - - // If prediction is non-negative, we need to decrease the major radius of the - // ellipse - if (prediction >= 0) { - prediction -= dy; - dy -= 2 * _deltaX; - y -= _deltaX; - } - - // Increase the minor radius of the ellipse and update heuristic variables - prediction += dx; - dx += 2 * _deltaX; - x += _deltaX; - - // If the current ellipse has been reshaped into a circle, - // end this loop and enlarge the radius - } while (x <= y); - } -} - static double real_to_double(byte real[6]) { // Extract sign bit int sign = real[0] & (1 << 7); diff --git a/engines/draci/game.h b/engines/draci/game.h index 1366ffd9ec..181b93d0a7 100644 --- a/engines/draci/game.h +++ b/engines/draci/game.h @@ -32,6 +32,7 @@ #include "draci/script.h" #include "draci/animation.h" #include "draci/sprite.h" +#include "draci/walking.h" namespace Draci { @@ -64,12 +65,6 @@ enum { kNoItem = -1 }; -// Used as a default parameter in Game::loadWalkingMap() to specify that the default -// walking map to the room is to be loaded. -enum { - kDefaultRoomMap = -1 -}; - enum { kNoDialogue = -1, kDialogueLines = 4 @@ -104,51 +99,6 @@ enum InventoryConstants { kInventorySlots = kInventoryLines * kInventoryColumns }; -class WalkingMap { -public: - WalkingMap() { - _realWidth = 0; - _realHeight = 0; - _mapWidth = 0; - _mapHeight = 0; - _byteWidth = 0; - _data = NULL; - } - - void load(const byte *data, uint length) { - Common::MemoryReadStream mapReader(data, length); - - _realWidth = mapReader.readUint16LE(); - _realHeight = mapReader.readUint16LE(); - _deltaX = mapReader.readUint16LE(); - _deltaY = mapReader.readUint16LE(); - _mapWidth = mapReader.readUint16LE(); - _mapHeight = mapReader.readUint16LE(); - _byteWidth = mapReader.readUint16LE(); - - // Set the data pointer to raw map data - _data = data + mapReader.pos(); - } - - bool isWalkable(int x, int y) const; - Common::Point findNearestWalkable(int x, int y, Common::Rect searchRect) const; - -private: - int _realWidth, _realHeight; - int _deltaX, _deltaY; - int _mapWidth, _mapHeight; - int _byteWidth; - const byte *_data; -}; - -/* - * Enumerates the directions the dragon can look into when arrived. - */ -enum SightDirection { - kDirectionLast, kDirectionMouse, kDirectionUnknown, - kDirectionRight, kDirectionLeft, kDirectionIntelligent -}; - struct GameObject { uint _init, _look, _use, _canUse; bool _imInit, _imLook, _imUse; @@ -201,6 +151,7 @@ struct Room { int _roomNum; byte _music; WalkingMap _walkingMap; + int _mapID; int _palette; int _numOverlays; int _init, _look, _use, _canUse; @@ -227,18 +178,6 @@ enum LoopSubstatus { kSubstatusStrange }; -/** - * Enumerates the animations for the dragon's movement. - */ -enum Movement { - kMoveUndefined = -1, - kMoveDown, kMoveUp, kMoveRight, kMoveLeft, - kMoveRightDown, kMoveRightUp, kMoveLeftDown, kMoveLeftUp, - kMoveDownRight, kMoveUpRight, kMoveDownLeft, kMoveUpLeft, - kMoveLeftRight, kMoveRightLeft, kMoveUpStopLeft, kMoveUpStopRight, - kSpeakRight, kSpeakLeft, kStopRight, kStopLeft -}; - class Game { public: Game(DraciEngine *vm); @@ -281,7 +220,7 @@ public: int loadAnimation(uint animNum, uint z); void loadOverlays(); void loadObject(uint numObj); - void loadWalkingMap(int mapID = kDefaultRoomMap); + void loadWalkingMap(int mapID); void loadItem(int itemID); uint getNumObjects() const; diff --git a/engines/draci/module.mk b/engines/draci/module.mk index 2005c0b095..b5f25d1b33 100644 --- a/engines/draci/module.mk +++ b/engines/draci/module.mk @@ -14,7 +14,8 @@ MODULE_OBJS := \ surface.o \ mouse.o \ game.o \ - animation.o + animation.o \ + walking.o MODULE_DIRS += \ engines/draci diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp index 5b0443c6c3..1868bfed34 100644 --- a/engines/draci/script.cpp +++ b/engines/draci/script.cpp @@ -728,10 +728,9 @@ void Script::talk(Common::Queue<int> ¶ms) { // HACK: Some strings in the English data files are too long to fit the screen // This is a temporary resolution. + speechFrame->setFont(_vm->_bigFont); if (speechFrame->getWidth() >= kScreenWidth) { speechFrame->setFont(_vm->_smallFont); - } else { - speechFrame->setFont(_vm->_bigFont); } // Set the loop substatus to an appropriate value @@ -838,7 +837,7 @@ void Script::exitDialogue(Common::Queue<int> ¶ms) { void Script::roomMap(Common::Queue<int> ¶ms) { // Load the default walking map for the room - _vm->_game->loadWalkingMap(); + _vm->_game->loadWalkingMap(-1); } void Script::disableQuickHero(Common::Queue<int> ¶ms) { diff --git a/engines/draci/sprite.cpp b/engines/draci/sprite.cpp index 19bb4ea86b..0b9d61e8c1 100644 --- a/engines/draci/sprite.cpp +++ b/engines/draci/sprite.cpp @@ -341,6 +341,9 @@ Common::Rect Text::getRect(const Displacement &displacement) const { } void Text::setFont(const Font *font) { + if (font == _font) { + return; + } _font = font; _width = _font->getStringWidth(_text, _spacing); diff --git a/engines/draci/walking.cpp b/engines/draci/walking.cpp new file mode 100644 index 0000000000..f05fca6e57 --- /dev/null +++ b/engines/draci/walking.cpp @@ -0,0 +1,165 @@ +/* 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. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/draci/game.cpp $ + * $Id: game.cpp 45505 2009-10-29 18:15:12Z eriktorbjorn $ + * + */ + +#include "common/stream.h" + +#include "draci/walking.h" + +namespace Draci { + +void WalkingMap::load(const byte *data, uint length) { + Common::MemoryReadStream mapReader(data, length); + + _realWidth = mapReader.readUint16LE(); + _realHeight = mapReader.readUint16LE(); + _deltaX = mapReader.readUint16LE(); + _deltaY = mapReader.readUint16LE(); + _mapWidth = mapReader.readUint16LE(); + _mapHeight = mapReader.readUint16LE(); + _byteWidth = mapReader.readUint16LE(); + + // Set the data pointer to raw map data + _data = data + mapReader.pos(); +} + +bool WalkingMap::isWalkable(int x, int y) const { + // Convert to map pixels + x = x / _deltaX; + y = y / _deltaY; + + int pixelIndex = _mapWidth * y + x; + int byteIndex = pixelIndex / 8; + int mapByte = _data[byteIndex]; + + return mapByte & (1 << pixelIndex % 8); +} + +/** + * @brief For a given point, find a nearest walkable point on the walking map + * + * @param startX x coordinate of the point + * @param startY y coordinate of the point + * + * @return A Common::Point representing the nearest walkable point + * + * The algorithm was copied from the original engine for exactness. + * TODO: Study this algorithm in more detail so it can be documented properly and + * possibly improved / simplified. + */ +Common::Point WalkingMap::findNearestWalkable(int startX, int startY, Common::Rect searchRect) const { + // If the starting point is walkable, just return that + if (searchRect.contains(startX, startY) && isWalkable(startX, startY)) { + return Common::Point(startX, startY); + } + + int signs[] = { 1, -1 }; + const uint kSignsNum = 2; + + int radius = 0; + int x, y; + int dx, dy; + int prediction; + + // The place where, eventually, the result coordinates will be stored + int finalX, finalY; + + // The algorithm appears to start off with an ellipse with the minor radius equal to + // zero and the major radius equal to the walking map delta (the number of pixels + // one map pixel represents). It then uses a heuristic to gradually reshape it into + // a circle (by shortening the major radius and lengthening the minor one). At each + // such resizing step, it checks some select points on the ellipse for walkability. + // It also does the same check for the ellipse perpendicular to it (rotated by 90 degrees). + + while (1) { + // The default major radius + radius += _deltaX; + + // The ellipse radii (minor, major) that get resized + x = 0; + y = radius; + + // Heuristic variables + prediction = 1 - radius; + dx = 3; + dy = 2 * radius - 2; + + do { + // The following two loops serve the purpose of checking the points on the two + // ellipses for walkability. The signs[] array is there to obliterate the need + // of writing out all combinations manually. + + for (uint i = 0; i < kSignsNum; ++i) { + finalY = startY + y * signs[i]; + + for (uint j = 0; j < kSignsNum; ++j) { + finalX = startX + x * signs[j]; + + // If the current point is walkable, return it + if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { + return Common::Point(finalX, finalY); + } + } + } + + if (x == y) { + // If the starting point is walkable, just return that + if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { + return Common::Point(finalX, finalY); + } + } + + for (uint i = 0; i < kSignsNum; ++i) { + finalY = startY + x * signs[i]; + + for (uint j = 0; j < kSignsNum; ++j) { + finalX = startX + y * signs[j]; + + // If the current point is walkable, return it + if (searchRect.contains(finalX, finalY) && isWalkable(finalX, finalY)) { + return Common::Point(finalX, finalY); + } + } + } + + // If prediction is non-negative, we need to decrease the major radius of the + // ellipse + if (prediction >= 0) { + prediction -= dy; + dy -= 2 * _deltaX; + y -= _deltaX; + } + + // Increase the minor radius of the ellipse and update heuristic variables + prediction += dx; + dx += 2 * _deltaX; + x += _deltaX; + + // If the current ellipse has been reshaped into a circle, + // end this loop and enlarge the radius + } while (x <= y); + } +} + +} diff --git a/engines/draci/walking.h b/engines/draci/walking.h new file mode 100644 index 0000000000..aff4fe7f95 --- /dev/null +++ b/engines/draci/walking.h @@ -0,0 +1,71 @@ +/* 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. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/draci/game.h $ + * $Id: game.h 45501 2009-10-29 15:26:48Z spalek $ + * + */ + +#ifndef DRACI_WALKING_H +#define DRACI_WALKING_H + +#include "common/rect.h" + +namespace Draci { + +class WalkingMap { +public: + WalkingMap() : _realWidth(0), _realHeight(0), _mapWidth(0), _mapHeight(0), _byteWidth(0), _data(NULL) { } + + void load(const byte *data, uint length); + bool isWalkable(int x, int y) const; + Common::Point findNearestWalkable(int x, int y, Common::Rect searchRect) const; + +private: + int _realWidth, _realHeight; + int _deltaX, _deltaY; + int _mapWidth, _mapHeight; + int _byteWidth; + const byte *_data; +}; + +/* + * Enumerates the directions the dragon can look into when arrived. + */ +enum SightDirection { + kDirectionLast, kDirectionMouse, kDirectionUnknown, + kDirectionRight, kDirectionLeft, kDirectionIntelligent +}; + +/** + * Enumerates the animations for the dragon's movement. + */ +enum Movement { + kMoveUndefined = -1, + kMoveDown, kMoveUp, kMoveRight, kMoveLeft, + kMoveRightDown, kMoveRightUp, kMoveLeftDown, kMoveLeftUp, + kMoveDownRight, kMoveUpRight, kMoveDownLeft, kMoveUpLeft, + kMoveLeftRight, kMoveRightLeft, kMoveUpStopLeft, kMoveUpStopRight, + kSpeakRight, kSpeakLeft, kStopRight, kStopLeft +}; + +} // End of namespace Draci + +#endif // DRACI_WALKING_H |