aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Špalek2009-10-30 00:52:05 +0000
committerRobert Špalek2009-10-30 00:52:05 +0000
commita20e42efb9272e74e8bd36b74c485a0d5ca88ee2 (patch)
treeb6931b814cec52dd550047869b8d2e00845290de
parent1526fda715118d75b37dafbf1da58770289cbcae (diff)
downloadscummvm-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.cpp132
-rw-r--r--engines/draci/game.h67
-rw-r--r--engines/draci/module.mk3
-rw-r--r--engines/draci/script.cpp5
-rw-r--r--engines/draci/sprite.cpp3
-rw-r--r--engines/draci/walking.cpp165
-rw-r--r--engines/draci/walking.h71
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> &params) {
// 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> &params) {
void Script::roomMap(Common::Queue<int> &params) {
// Load the default walking map for the room
- _vm->_game->loadWalkingMap();
+ _vm->_game->loadWalkingMap(-1);
}
void Script::disableQuickHero(Common::Queue<int> &params) {
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