summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBjørn Lindeijer <bjorn@lindeijer.nl>2008-10-09 19:42:13 +0000
committerBjørn Lindeijer <bjorn@lindeijer.nl>2008-10-09 19:42:13 +0000
commit3fe1772b1e00344365e3cf8204225be19925b9e5 (patch)
tree0f66dddac8e14787096c01368611efa53f453134 /src
parent8cc0423b0c0aaa5dd9e91f673a691e5e634988c1 (diff)
downloadmana-3fe1772b1e00344365e3cf8204225be19925b9e5.tar.gz
mana-3fe1772b1e00344365e3cf8204225be19925b9e5.tar.bz2
mana-3fe1772b1e00344365e3cf8204225be19925b9e5.tar.xz
mana-3fe1772b1e00344365e3cf8204225be19925b9e5.zip
Merged the movement branch into trunk
I consider this the only way forward. In my tests this code isn't actually doing worse than what was there before. Of course some cases are a bit broken, and I'm open to any kind of feedback so that we can fix those issues.
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/Makefile.am7
-rw-r--r--src/animatedsprite.cpp26
-rw-r--r--src/being.cpp230
-rw-r--r--src/being.h110
-rw-r--r--src/beingmanager.cpp15
-rw-r--r--src/game.cpp9
-rw-r--r--src/gui/minimap.cpp7
-rw-r--r--src/gui/playerbox.cpp7
-rw-r--r--src/gui/updatewindow.cpp4
-rw-r--r--src/gui/viewport.cpp91
-rw-r--r--src/gui/viewport.h11
-rw-r--r--src/localplayer.cpp63
-rw-r--r--src/map.cpp35
-rw-r--r--src/map.h12
-rw-r--r--src/monster.cpp1
-rw-r--r--src/net/beinghandler.cpp370
-rw-r--r--src/net/playerhandler.cpp7
-rw-r--r--src/npc.cpp10
-rw-r--r--src/particleemitter.cpp5
-rw-r--r--src/player.cpp11
-rw-r--r--src/position.cpp47
-rw-r--r--src/position.h60
-rw-r--r--src/resources/spritedef.cpp5
-rw-r--r--src/simpleanimation.cpp5
-rw-r--r--src/vector.cpp30
-rw-r--r--src/vector.h68
27 files changed, 507 insertions, 742 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index aee99d2e..688f8787 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -390,6 +390,8 @@ SET(SRCS
particleemitter.h
player.cpp
player.h
+ position.cpp
+ position.h
properties.h
serverinfo.h
shopitem.cpp
@@ -402,6 +404,7 @@ SET(SRCS
textparticle.cpp
textparticle.h
tileset.h
+ vector.cpp
vector.h
)
diff --git a/src/Makefile.am b/src/Makefile.am
index e7752477..e1de3a34 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,8 +7,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
gui/widgets/layout.h \
gui/widgets/resizegrip.cpp \
gui/widgets/resizegrip.h \
- gui/widgets/tab.cpp \
- gui/widgets/tab.h \
+ gui/widgets/tab.cpp \
+ gui/widgets/tab.h \
gui/widgets/tabbedarea.cpp \
gui/widgets/tabbedarea.h \
gui/box.h \
@@ -342,6 +342,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
particleemitter.h \
player.cpp \
player.h \
+ position.cpp \
+ position.h \
properties.h \
serverinfo.h \
shopitem.cpp \
@@ -354,6 +356,7 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
textparticle.cpp \
textparticle.h \
tileset.h \
+ vector.cpp \
vector.h
# set the include path found by configure
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index 466779fd..13596a70 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -160,9 +160,7 @@ bool
AnimatedSprite::draw(Graphics* graphics, int posX, int posY) const
{
if (!mFrame || !mFrame->image)
- {
return false;
- }
return graphics->drawImage(mFrame->image,
posX + mFrame->offsetX,
@@ -177,9 +175,7 @@ AnimatedSprite::setDirection(SpriteDirection direction)
mDirection = direction;
if (!mAction)
- {
return;
- }
Animation *animation = mAction->getAnimation(mDirection);
@@ -192,26 +188,12 @@ AnimatedSprite::setDirection(SpriteDirection direction)
}
}
-int
-AnimatedSprite::getWidth() const
+int AnimatedSprite::getWidth() const
{
- if (mFrame)
- {
- return mFrame->image->getWidth();
- }
- else {
- return 0;
- }
+ return mFrame ? mFrame->image->getWidth() : 0;
}
-int
-AnimatedSprite::getHeight() const
+int AnimatedSprite::getHeight() const
{
- if (mFrame)
- {
- return mFrame->image->getHeight();
- }
- else {
- return 0;
- }
+ return mFrame ? mFrame->image->getHeight() : 0;
}
diff --git a/src/being.cpp b/src/being.cpp
index cf2e3772..7b77ed5a 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -43,27 +43,27 @@
#include "utils/dtor.h"
#include "utils/tostring.h"
+namespace {
+const bool debug_movement = true;
+}
+
int Being::instances = 0;
ImageSet *Being::emotionSet = NULL;
Being::Being(int id, int job, Map *map):
- mX(0), mY(0),
mEmotion(0), mEmotionTime(0),
mAttackSpeed(350),
- mWalkTime(0),
mAction(STAND),
mJob(job),
mId(id),
- mWalkSpeed(150),
- mSpeedModifier(1024),
mSpriteDirection(DIRECTION_DOWN), mDirection(DOWN),
mMap(NULL),
mEquippedWeapon(NULL),
mSpeechTime(0),
- mPx(0), mPy(0),
mSprites(VECTOREND_SPRITE, NULL),
mSpriteIDs(VECTOREND_SPRITE, 0),
- mSpriteColors(VECTOREND_SPRITE, "")
+ mSpriteColors(VECTOREND_SPRITE, ""),
+ mWalkSpeed(100)
{
setMap(map);
@@ -106,27 +106,36 @@ Being::~Being()
delete mSpeechBubble;
}
-void Being::setPositionInPixels(int x, int y)
+void Being::setPosition(const Vector &pos)
{
- mMap->freeTile(mX / 32, mY / 32, getBlockType());
- mX = x;
- mY = y;
- mMap->blockTile(x / 32, y / 32, getBlockType());
+ mPos = pos;
+ mDest = pos;
}
-void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY)
+void Being::adjustCourse(int srcX, int srcY, int dstX, int dstY)
{
- if (!mMap || (mX == dstX && mY == dstY))
- {
+ if (debug_movement)
+ printf("%p adjustCourse(%d, %d, %d, %d)\n",
+ (void*) this, srcX, srcY, dstX, dstY);
+
+ mDest.x = dstX;
+ mDest.y = dstY;
+
+ // Find a path to the destination when it is at least a tile away
+ if (mMap && fabsf((mDest - mPos).length()) > 32) {
+ setPath(mMap->findPath((int) mPos.x / 32, (int) mPos.y / 32,
+ dstX / 32, dstY / 32, getWalkMask()));
+ } else {
setPath(Path());
- return;
}
+ // TODO: Evaluate the implementation of this method
+ /*
if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32)
{
// The being is already on the last tile of the path.
Path p;
- p.push_back(PATH_NODE(dstX, dstY));
+ p.push_back(Position(dstX, dstY));
setPath(p);
return;
}
@@ -173,7 +182,7 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY)
p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost;
p1_dist[p1_size - 1] = p1_length;
}
- p1.push_back(PATH_NODE(dstX, dstY));
+ p1.push_back(Position(dstX, dstY));
if (mX / 32 == srcX / 32 && mY / 32 == srcY / 32)
{
@@ -248,19 +257,24 @@ void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY)
assert(bestLength > 0);
setPath(p1, p1_length * 1024 / bestLength);
delete[] p1_dist;
+ */
}
-void Being::adjustCourse(Uint16 srcX, Uint16 srcY)
+void Being::adjustCourse(int srcX, int srcY)
{
+ if (debug_movement)
+ printf("%p adjustCourse(%d, %d)\n", (void*) this, srcX, srcY);
+
if (!mPath.empty())
- {
- adjustCourse(srcX, srcY, mPath.back().x, mPath.back().y);
- }
+ adjustCourse(srcX, srcY, mPath.back().x * 32, mPath.back().y * 32);
}
-void Being::setDestination(Uint16 destX, Uint16 destY)
+void Being::setDestination(int destX, int destY)
{
- adjustCourse(mX, mY, destX, destY);
+ if (debug_movement)
+ printf("%p setDestination(%d, %d)\n", (void*) this, destX, destY);
+
+ adjustCourse((int) mPos.x, (int) mPos.y, destX, destY);
}
void Being::clearPath()
@@ -268,34 +282,10 @@ void Being::clearPath()
mPath.clear();
}
-void Being::setPath(const Path &path, int mod)
+void Being::setPath(const Path &path)
{
+ std::cout << this << " New path: " << path << std::endl;
mPath = path;
- mSpeedModifier = mod >= 512 ? (mod <= 2048 ? mod : 2048) : 512; // TODO: tune bounds
-
- int sz = mPath.size();
- if (sz > 1)
- {
- // The path contains intermediate steps, so avoid going through tile
- // centers for them. Instead, interpolate the tile offset.
- int sx = mX & 31, sy = mY & 31;
- int dx = (mPath.back().x & 31) - sx;
- int dy = (mPath.back().y & 31) - sy;
- Path::iterator j = mPath.begin();
- for (int i = 0; i < sz - 1; ++i)
- {
- j->x |= sx + dx * (i + 1) / (sz - 1);
- j->y |= sy + dy * (i + 1) / (sz - 1);
- ++j;
- }
- }
-
- if (mAction != WALK && mAction != DEAD)
- {
- mWalkTime = tick_time;
- mStepTime = 0;
- nextStep();
- }
}
void Being::setSprite(int slot, int id, const std::string &color)
@@ -339,7 +329,8 @@ void Being::takeDamage(int amount)
// Show damage number
particleEngine->addTextSplashEffect(damage, 255, 255, 255, font,
- mPx + 16, mPy + 16);
+ (int) mPos.x + 16,
+ (int) mPos.y + 16);
}
void Being::handleAttack()
@@ -349,11 +340,9 @@ void Being::handleAttack()
void Being::setMap(Map *map)
{
-
// Remove sprite from potential previous map
if (mMap)
{
- mMap->freeTile(mX / 32, mY / 32, getBlockType());
mMap->removeSprite(mSpriteIterator);
}
@@ -363,7 +352,6 @@ void Being::setMap(Map *map)
if (mMap)
{
mSpriteIterator = mMap->addSprite(this);
- mMap->blockTile(mX / 32, mY / 32, getBlockType());
}
// Clear particle effect list because child particles became invalid
@@ -447,21 +435,13 @@ void Being::setDirection(Uint8 direction)
SpriteDirection dir;
if (mFaceDirection & UP)
- {
dir = DIRECTION_UP;
- }
else if (mFaceDirection & RIGHT)
- {
dir = DIRECTION_RIGHT;
- }
else if (mFaceDirection & DOWN)
- {
dir = DIRECTION_DOWN;
- }
else
- {
dir = DIRECTION_LEFT;
- }
mSpriteDirection = dir;
for (int i = 0; i < VECTOREND_SPRITE; i++)
@@ -471,57 +451,48 @@ void Being::setDirection(Uint8 direction)
}
}
-void Being::nextStep()
-{
- if (mPath.empty())
- {
- setAction(STAND);
- return;
- }
-
- PATH_NODE node = mPath.front();
- mPath.pop_front();
-
- mStepX = node.x - mX;
- mStepY = node.y - mY;
-
- int dir = 0, dx = std::abs(mStepX), dy = std::abs(mStepY);
- if (dx * 2 > dy)
- dir |= mStepX > 0 ? RIGHT : LEFT;
- if (dy * 2 > dx)
- dir |= mStepY > 0 ? DOWN : UP;
-
- setDirection(dir);
-
- if (!mMap->getWalk(node.x / 32, node.y / 32))
- {
- setAction(STAND);
- return;
- }
-
- setPositionInPixels(node.x, node.y);
- setAction(WALK);
- mWalkTime += mStepTime / 10;
- mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) *
- mSpeedModifier / (32 * 1024);
-}
-
void Being::logic()
{
- // Determine whether the being should take another step
- if (mAction == WALK && get_elapsed_time(mWalkTime) >= mStepTime)
- {
- nextStep();
+ const Vector dest = (mPath.empty()) ?
+ mDest : Vector(mPath.front().x * 32 + 16,
+ mPath.front().y * 32 + 16);
+
+ Vector dir = dest - mPos;
+ const float length = dir.length();
+
+ // When we're over 2 pixels from our destination, move to it
+ // TODO: Should be possible to make it even pixel exact, but this solves
+ // the jigger caused by moving too far.
+ if (length > 2.0f) {
+ const float speed = mWalkSpeed / 100.0f;
+ dir /= (length / speed);
+ mPos += dir;
+
+ if (mAction != WALK)
+ setAction(WALK);
+
+ // Update the player sprite direction
+ int direction = 0;
+ const float dx = std::abs(dir.x);
+ const float dy = std::abs(dir.y);
+ if (dx * 2 > dy)
+ direction |= (dir.x > 0) ? RIGHT : LEFT;
+ if (dy * 2 > dx)
+ direction |= (dir.y > 0) ? DOWN : UP;
+ setDirection(direction);
+ }
+ else if (!mPath.empty()) {
+ // TODO: Pop as soon as there is a direct unblocked line to the next
+ // point on the path.
+ mPath.pop_front();
+ } else if (mAction == WALK) {
+ setAction(STAND);
}
// Reduce the time that speech is still displayed
if (mSpeechTime > 0)
mSpeechTime--;
- // Update pixel coordinates
- mPx = mX - 16 + getXOffset();
- mPy = mY - 16 + getYOffset();
-
if (mEmotion != 0)
{
mEmotionTime--;
@@ -543,7 +514,7 @@ void Being::logic()
for (std::list<Particle *>::iterator i = mChildParticleEffects.begin();
i != mChildParticleEffects.end();)
{
- (*i)->setPosition((float)mPx + 16.0f, (float)mPy + 32.0f);
+ (*i)->setPosition(mPos.x, mPos.y);
if (!(*i)->isAlive())
{
(*i)->kill();
@@ -557,14 +528,16 @@ void Being::logic()
void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
{
- int px = mPx + offsetX;
- int py = mPy + offsetY;
+ int px = (int) mPos.x + offsetX;
+ int py = (int) mPos.y + offsetY;
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
if (mSprites[i] != NULL)
{
- mSprites[i]->draw(graphics, px, py);
+ // TODO: Eventually, we probably should fix all sprite offsets so
+ // that this translation isn't necessary anymore.
+ mSprites[i]->draw(graphics, px - 16, py - 32);
}
}
}
@@ -574,18 +547,18 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
if (!mEmotion)
return;
- const int px = mPx + offsetX + 3;
- const int py = mPy + offsetY - 60;
+ const int px = (int) mPos.x + offsetX + 3;
+ const int py = (int) mPos.y + offsetY - 60;
const int emotionIndex = mEmotion - 1;
- if ( emotionIndex >= 0 && emotionIndex < (int) emotionSet->size() )
+ if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size())
graphics->drawImage(emotionSet->get(emotionIndex), px, py);
}
void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
{
- int px = mPx + offsetX;
- int py = mPy + offsetY;
+ int px = (int) mPos.x + offsetX;
+ int py = (int) mPos.y + offsetY;
// Draw speech above this being
if (mSpeechTime > 0)
@@ -605,32 +578,7 @@ Being::Type Being::getType() const
return UNKNOWN;
}
-int Being::getOffset(int step) const
-{
- // Check whether we're walking in the requested direction
- if (mAction != WALK || step == 0) {
- return 0;
- }
-
- int offset = (get_elapsed_time(mWalkTime) * std::abs(step)) / mStepTime;
-
- // We calculate the offset _from_ the _target_ location
- offset -= std::abs(step);
- if (offset > 0) {
- offset = 0;
- }
-
- // Going into negative direction? Invert the offset.
- if (step < 0) {
- offset = -offset;
- }
-
- return offset;
-}
-
-
-int
-Being::getWidth() const
+int Being::getWidth() const
{
if (mSprites[BASE_SPRITE])
{
@@ -641,9 +589,7 @@ Being::getWidth() const
}
}
-
-int
-Being::getHeight() const
+int Being::getHeight() const
{
if (mSprites[BASE_SPRITE])
{
diff --git a/src/being.h b/src/being.h
index 9d04f383..567a0d98 100644
--- a/src/being.h
+++ b/src/being.h
@@ -29,9 +29,11 @@
#include <SDL_types.h>
#include <vector>
+#include "position.h"
#include "sprite.h"
#include "map.h"
#include "animatedsprite.h"
+#include "vector.h"
#define NR_HAIR_STYLES 8
#define NR_HAIR_COLORS 10
@@ -46,24 +48,6 @@ class ImageSet;
class Particle;
class SpeechBubble;
-/**
- * A position along a being's path.
- */
-struct PATH_NODE
-{
- /**
- * Constructor.
- */
- PATH_NODE(unsigned short x, unsigned short y):
- x(x), y(y)
- { }
-
- unsigned short x;
- unsigned short y;
-};
-typedef std::list<PATH_NODE> Path;
-typedef Path::iterator PathIterator;
-
class Being : public Sprite
{
public:
@@ -113,11 +97,9 @@ class Being : public Sprite
enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 };
std::string mName; /**< Name of character */
- Uint16 mX, mY; /**< Pixel coordinates of tile center */
Uint8 mEmotion; /**< Currently showing emotion */
Uint8 mEmotionTime; /**< Time until emotion disappears */
Uint16 mAttackSpeed; /**< Attack speed */
- Uint16 mWalkTime;
Action mAction; /**< Action the being is performing */
Uint16 mJob; /**< Job (player job, npc, monster, creature ) */
@@ -139,17 +121,17 @@ class Being : public Sprite
/**
* Sets a new destination for this being to walk to.
*/
- void setDestination(Uint16 destX, Uint16 destY);
+ void setDestination(int x, int y);
/**
* Adjusts course to expected stat point.
*/
- void adjustCourse(Uint16, Uint16);
+ void adjustCourse(int, int);
/**
* Adjusts course to expected start and end points.
*/
- void adjustCourse(Uint16, Uint16, Uint16, Uint16);
+ void adjustCourse(int, int, int, int);
/**
* Puts a "speech balloon" above this being for the specified amount
@@ -195,12 +177,6 @@ class Being : public Sprite
setSprite(int slot, int id, const std::string &color = "");
/**
- * Makes this being take the next step of his path.
- */
- virtual void
- nextStep();
-
- /**
* Performs being logic.
*/
virtual void
@@ -231,15 +207,14 @@ class Being : public Sprite
/**
* Gets the walk speed.
+ * @see setWalkSpeed(int)
*/
- Uint16
- getWalkSpeed() const { return mWalkSpeed; }
+ int getWalkSpeed() const { return mWalkSpeed; }
/**
- * Sets the walk speed.
+ * Sets the walk speed (in pixels per second).
*/
- void
- setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; }
+ void setWalkSpeed(int speed) { mWalkSpeed = speed; }
/**
* Gets the being id.
@@ -269,8 +244,6 @@ class Being : public Sprite
*/
bool isAlive() { return mAction != DEAD; }
- int getWalkTime() { return mWalkTime; }
-
/**
* Returns the direction the being is facing.
*/
@@ -287,57 +260,49 @@ class Being : public Sprite
*
* @see Sprite::draw(Graphics, int, int)
*/
- virtual void
- draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
/**
* Returns the pixel X coordinate.
*/
- int
- getPixelX() const { return mPx; }
+ int getPixelX() const { return (int) mPos.x; }
/**
* Returns the pixel Y coordinate.
*
* @see Sprite::getPixelY()
*/
- int
- getPixelY() const { return mPy; }
+ int getPixelY() const { return (int) mPos.y; }
/**
- * sets the position in pixels using pixel coordinates
+ * Sets the position of this being.
*/
- void setPositionInPixels(int x, int y);
+ void setPosition(const Vector &pos);
/**
- * sets the position in pixels using tile coordinates
- */
- void setPositionInTiles(int x, int y)
- { setPositionInPixels(x * 32 + 16, y * 32 + 16); }
-
- /**
- * Get the current X pixel offset.
+ * Overloaded method provided for convenience.
+ *
+ * @see setPosition(const Vector &pos)
*/
- int
- getXOffset() const { return getOffset(mStepX); }
+ void setPosition(float x, float y, float z = 0.0f)
+ {
+ setPosition(Vector(x, y, z));
+ }
/**
- * Get the current Y pixel offset.
+ * Returns the position of this being.
*/
- int
- getYOffset() const { return getOffset(mStepY); }
+ const Vector &getPosition() const { return mPos; }
/**
- * Returns the horizontal size of the current base sprite of the being
+ * Returns the horizontal size of the current base sprite of the being.
*/
- virtual int
- getWidth() const;
+ virtual int getWidth() const;
/**
- * Returns the vertical size of the current base sprite of the being
+ * Returns the vertical size of the current base sprite of the being.
*/
- virtual int
- getHeight() const;
+ virtual int getHeight() const;
/**
* Returns the required size of a target cursor for this being.
@@ -351,16 +316,22 @@ class Being : public Sprite
void controlParticle(Particle *particle);
/**
- * Gets the way the object is blocked by other objects
+ * Gets the way the object is blocked by other objects.
*/
virtual unsigned char getWalkMask() const
{ return 0x00; } //can walk through everything
+ /**
+ * Returns the path this being is following. An empty path is returned
+ * when this being isn't following any path currently.
+ */
+ const Path &getPath() const { return mPath; }
+
protected:
/**
* Sets the new path for this being.
*/
- void setPath(const Path &path, int mod = 1024);
+ void setPath(const Path &path);
/**
* Gets the way the object blocks pathfinding for other objects
@@ -369,8 +340,6 @@ class Being : public Sprite
{ return Map::BLOCKTYPE_NONE; }
Uint16 mId; /**< Unique being id */
- Uint16 mWalkSpeed; /**< Walking speed */
- Uint16 mSpeedModifier; /**< Modifier to keep course on sync (1024 = normal speed) */
Uint8 mSpriteDirection; /**< Facing direction */
Uint8 mDirection; /**< Walking direction */
Map *mMap; /**< Map on which this being resides */
@@ -382,7 +351,6 @@ class Being : public Sprite
Path mPath;
std::string mSpeech;
Uint32 mSpeechTime;
- Sint32 mPx, mPy; /**< Pixel coordinates */
std::vector<AnimatedSprite*> mSprites;
std::vector<int> mSpriteIDs;
@@ -390,13 +358,13 @@ class Being : public Sprite
std::list<Particle *> mChildParticleEffects;
private:
- int getOffset(int step) const;
-
// Speech Bubble components
SpeechBubble *mSpeechBubble;
- Sint16 mStepX, mStepY;
- Uint16 mStepTime;
+ int mWalkSpeed; /**< Walking speed (pixels/sec) */
+
+ Vector mPos;
+ Vector mDest;
static int instances; /**< Number of Being instances */
static ImageSet *emotionSet; /**< Emoticons used by beings */
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index a58c97e7..abb23f5e 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -39,8 +39,9 @@ class FindBeingFunctor
bool operator() (Being *being)
{
Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0);
- return (being->mX / 32 == x &&
- (being->mY / 32 == y || being->mY / 32 == other_y) &&
+ const Vector &pos = being->getPosition();
+ return ((int) pos.x / 32 == x &&
+ ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) &&
being->mAction != Being::DEAD &&
(type == Being::UNKNOWN || being->getType() == type));
}
@@ -165,7 +166,8 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
{
Being *being = (*i);
- int d = abs(being->mX - x) + abs(being->mY - y);
+ const Vector &pos = being->getPosition();
+ int d = abs((int) pos.x - x) + abs((int) pos.y - y);
if ((being->getType() == type || type == Being::UNKNOWN)
&& (d < dist || closestBeing == NULL) // it is closer
@@ -185,13 +187,14 @@ Being* BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist,
{
Being *closestBeing = NULL;
int dist = 0;
- int x = aroundBeing->mX;
- int y = aroundBeing->mY;
+ const Vector &aroundBeingPos = aroundBeing->getPosition();
for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
{
Being *being = (*i);
- int d = abs(being->mX - x) + abs(being->mY - y);
+ const Vector &pos = being->getPosition();
+ int d = abs((int) pos.x - aroundBeingPos.x) +
+ abs((int) pos.y - aroundBeingPos.y);
if ((being->getType() == type || type == Being::UNKNOWN)
&& (d < dist || closestBeing == NULL) // it is closer
diff --git a/src/game.cpp b/src/game.cpp
index e2343f39..fb434be2 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -580,8 +580,9 @@ void Game::handleInput()
switch (tKey) {
case KeyboardConfig::KEY_PICKUP:
{
- Uint16 x = player_node->mX / 32;
- Uint16 y = player_node->mY / 32;
+ const Vector &pos = player_node->getPosition();
+ Uint16 x = (int) pos.x / 32;
+ Uint16 y = (int) pos.y / 32;
FloorItem *item =
floorItemManager->findByCoordinates(x, y);
@@ -754,7 +755,9 @@ void Game::handleInput()
// Get the state of the keyboard keys
keyboard.refreshActiveKeys();
- Uint16 x = player_node->mX / 32, y = player_node->mY / 32;
+ const Vector &pos = player_node->getPosition();
+ Uint16 x = (int) pos.x / 32;
+ Uint16 y = (int) pos.y / 32;
unsigned char direction = 0;
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index 4e5664d6..ca6f4fd7 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -113,11 +113,12 @@ void Minimap::draw(gcn::Graphics *graphics)
break;
}
- int offset = (dotSize - 1) / 2;
+ const int offset = (dotSize - 1) / 2;
+ const Vector &pos = being->getPosition();
graphics->fillRectangle(gcn::Rectangle(
- being->mX / 64 + getPadding() - offset,
- being->mY / 64 + getTitleBarHeight() - offset,
+ (int) pos.x / 64 + getPadding() - offset,
+ (int) pos.y / 64 + getTitleBarHeight() - offset,
dotSize, dotSize));
}
}
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index 2c633b72..e9237110 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -82,10 +82,9 @@ PlayerBox::draw(gcn::Graphics *graphics)
if (mPlayer)
{
// Draw character
- int x, y, bs;
- bs = getFrameSize();
- x = getWidth() / 2 - 16 + bs;
- y = getHeight() / 2 + bs;
+ const int bs = getFrameSize();
+ const int x = getWidth() / 2 + bs;
+ const int y = getHeight() - bs - 8;
mPlayer->draw(static_cast<Graphics*>(graphics), x, y);
}
}
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index abae69f6..10d0c826 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -60,9 +60,9 @@ unsigned long fadler32(FILE *file)
// Calculate Adler-32 checksum
char *buffer = (char*) malloc(fileSize);
- fread(buffer, 1, fileSize, file);
+ const size_t read = fread(buffer, 1, fileSize, file);
unsigned long adler = adler32(0L, Z_NULL, 0);
- adler = adler32(adler, (Bytef*) buffer, fileSize);
+ adler = adler32(adler, (Bytef*) buffer, read);
free(buffer);
return adler;
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 9677f81a..80dcf489 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -58,7 +58,6 @@ Viewport::Viewport():
mShowDebugPath(false),
mVisibleNames(false),
mPlayerFollowMouse(false),
- mWalkTime(0),
mLocalWalkTime(-1)
{
setOpaque(false);
@@ -91,9 +90,9 @@ Viewport::Viewport():
true, Being::TC_LARGE);
}
-void
-Viewport::loadTargetCursor(std::string filename, int width, int height,
- bool outRange, Being::TargetCursorSize size)
+void Viewport::loadTargetCursor(const std::string &filename,
+ int width, int height,
+ bool outRange, Being::TargetCursorSize size)
{
assert(size >= Being::TC_SMALL);
assert(size < Being::NUM_TC);
@@ -125,7 +124,7 @@ Viewport::loadTargetCursor(std::string filename, int width, int height,
Viewport::~Viewport()
{
delete mPopupMenu;
-
+
config.removeListener("visiblenames", this);
for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
@@ -137,14 +136,12 @@ Viewport::~Viewport()
}
}
-void
-Viewport::setMap(Map *map)
+void Viewport::setMap(Map *map)
{
mMap = map;
}
-void
-Viewport::draw(gcn::Graphics *gcnGraphics)
+void Viewport::draw(gcn::Graphics *gcnGraphics)
{
static int lastTick = tick_time;
@@ -163,8 +160,9 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2;
int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2;
- int player_x = player_node->mX - midTileX + player_node->getXOffset();
- int player_y = player_node->mY - midTileY + player_node->getYOffset();
+ const Vector &playerPos = player_node->getPosition();
+ const int player_x = (int) playerPos.x - midTileX;
+ const int player_y = (int) playerPos.y - midTileY;
if (mScrollLaziness < 1)
mScrollLaziness = 1; // Avoids division by zero
@@ -203,8 +201,10 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
};
// Don't move camera so that the end of the map is on screen
- int viewXmax = mMap->getWidth() * 32 - graphics->getWidth();
- int viewYmax = mMap->getHeight() * 32 - graphics->getHeight();
+ const int viewXmax =
+ mMap->getWidth() * mMap->getTileWidth() - graphics->getWidth();
+ const int viewYmax =
+ mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight();
if (mMap)
{
if (mViewX < 0) {
@@ -227,10 +227,11 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
mMap->draw(graphics, (int) mViewX, (int) mViewY);
drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite
drawTargetName(graphics);
-
if (mShowDebugPath) {
mMap->drawCollision(graphics, (int) mViewX, (int) mViewY);
+#if 0
drawDebugPath(graphics);
+#endif
}
}
@@ -239,19 +240,21 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
(*i)->drawSpeech(graphics, -(int) mViewX, -(int) mViewY);
- if(mVisibleNames)
+ if (mVisibleNames)
(*i)->drawName(graphics, -(int) mViewX, -(int) mViewY);
- else if((*i) == mSelectedBeing)
+ else if ((*i) == mSelectedBeing)
(*i)->drawName(graphics, -(int) mViewX, -(int) mViewY);
(*i)->drawEmotion(graphics, -(int) mViewX, -(int) mViewY);
+
+ if (mShowDebugPath && !(*i)->getPath().empty())
+ drawPath(graphics, (*i)->getPath());
}
// Draw contained widgets
WindowContainer::draw(gcnGraphics);
}
-void
-Viewport::logic()
+void Viewport::logic()
{
WindowContainer::logic();
@@ -262,13 +265,11 @@ Viewport::logic()
Uint8 button = SDL_GetMouseState(&mouseX, &mouseY);
if (mPlayerFollowMouse && button & SDL_BUTTON(1) &&
- mWalkTime != player_node->mWalkTime &&
get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
{
mLocalWalkTime = tick_time;
player_node->setDestination(mouseX + (int) mViewX,
mouseY + (int) mViewY);
- mWalkTime = player_node->mWalkTime;
}
for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
@@ -278,8 +279,7 @@ Viewport::logic()
}
}
-void
-Viewport::drawTargetCursor(Graphics *graphics)
+void Viewport::drawTargetCursor(Graphics *graphics)
{
// Draw target marker if needed
Being *target = player_node->getTarget();
@@ -288,9 +288,11 @@ Viewport::drawTargetCursor(Graphics *graphics)
// Calculate target circle position
// Find whether target is in range
- int rangeX = abs(target->mX - player_node->mX);
- int rangeY = abs(target->mY - player_node->mY);
- int attackRange = player_node->getAttackRange();
+ const Vector &dist =
+ target->getPosition() - player_node->getPosition();
+ const int rangeX = abs((int) dist.x);
+ const int rangeY = abs((int) dist.y);
+ const int attackRange = player_node->getAttackRange();
// Get the correct target cursors graphic
Being::TargetCursorSize cursorSize = target->getTargetCursorSize();
@@ -313,8 +315,7 @@ Viewport::drawTargetCursor(Graphics *graphics)
}
}
-void
-Viewport::drawTargetName(Graphics *graphics)
+void Viewport::drawTargetName(Graphics *graphics)
{
// Draw target marker if needed
Being *target = player_node->getTarget();
@@ -331,8 +332,7 @@ Viewport::drawTargetName(Graphics *graphics)
}
}
-void
-Viewport::drawDebugPath(Graphics *graphics)
+void Viewport::drawDebugPath(Graphics *graphics)
{
// Get the current mouse position
int mouseX, mouseY;
@@ -340,13 +340,20 @@ Viewport::drawDebugPath(Graphics *graphics)
const int mouseTileX = (mouseX + (int) mViewX) / 32;
const int mouseTileY = (mouseY + (int) mViewY) / 32;
+ const Vector &playerPos = player_node->getPosition();
Path debugPath = mMap->findPath(
- player_node->mX / 32, player_node->mY / 32,
+ (int) playerPos.x / 32,
+ (int) playerPos.y / 32,
mouseTileX, mouseTileY, 0xFF);
+ drawPath(graphics, debugPath);
+}
+
+void Viewport::drawPath(Graphics *graphics, const Path &path)
+{
graphics->setColor(gcn::Color(255, 0, 0));
- for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
+ for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
{
int squareX = i->x * 32 - (int) mViewX + 12;
int squareY = i->y * 32 - (int) mViewY + 12;
@@ -358,8 +365,7 @@ Viewport::drawDebugPath(Graphics *graphics)
}
}
-void
-Viewport::mousePressed(gcn::MouseEvent &event)
+void Viewport::mousePressed(gcn::MouseEvent &event)
{
// Check if we are alive and kickin'
if (!mMap || !player_node || player_node->mAction == Being::DEAD)
@@ -435,13 +441,12 @@ Viewport::mousePressed(gcn::MouseEvent &event)
}
}
-void
-Viewport::mouseDragged(gcn::MouseEvent &event)
+void Viewport::mouseDragged(gcn::MouseEvent &event)
{
if (!mMap || !player_node)
return;
- if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime
+ if (mPlayerFollowMouse
&& get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay)
{
mLocalWalkTime = tick_time;
@@ -450,31 +455,27 @@ Viewport::mouseDragged(gcn::MouseEvent &event)
}
}
-void
-Viewport::mouseReleased(gcn::MouseEvent &event)
+void Viewport::mouseReleased(gcn::MouseEvent &event)
{
mPlayerFollowMouse = false;
}
-void
-Viewport::showPopup(int x, int y, Item *item)
+void Viewport::showPopup(int x, int y, Item *item)
{
mPopupMenu->showPopup(x, y, item);
}
-void
-Viewport::optionChanged(const std::string &name)
+void Viewport::optionChanged(const std::string &name)
{
mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
mScrollRadius = (int) config.getValue("ScrollRadius", 32);
if (name == "visiblenames") {
- mVisibleNames = config.getValue("visiblenames", 1);
+ mVisibleNames = config.getValue("visiblenames", 1);
}
}
-void
-Viewport::mouseMoved(gcn::MouseEvent &event)
+void Viewport::mouseMoved(gcn::MouseEvent &event)
{
// Check if we are on the map
if (!mMap || !player_node)
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 82587938..5dedcea8 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -145,9 +145,10 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
private:
/**
- * Helper function for loading target cursors
+ * Helper function for loading target cursors.
*/
- void loadTargetCursor(std::string filename, int width, int height,
+ void loadTargetCursor(const std::string &filename,
+ int width, int height,
bool outRange, Being::TargetCursorSize size);
/**
@@ -166,6 +167,11 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
*/
void drawDebugPath(Graphics *graphics);
+ /**
+ * Draws the given path.
+ */
+ void drawPath(Graphics *graphics, const Path &path);
+
Map *mMap; /**< The current map. */
@@ -191,7 +197,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
SimpleAnimation *mTargetCursorOutRange[Being::NUM_TC];
bool mPlayerFollowMouse;
- int mWalkTime;
int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */
PopupMenu *mPopupMenu; /**< Popup menu. */
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 00ea6a49..f596a8d9 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -87,14 +87,16 @@ void LocalPlayer::logic()
}
// Show XP messages
- if(!mExpMessages.empty())
+ if (!mExpMessages.empty())
{
if (mExpMessageTime == 0)
{
+ const Vector &pos = getPosition();
particleEngine->addTextRiseFadeOutEffect(mExpMessages.front(),
0, 128, 255,
speechFont,
- mPx + 16, mPy - 16);
+ (int) pos.x + 16,
+ (int) pos.y - 16);
mExpMessages.pop_front();
mExpMessageTime = 30;
}
@@ -106,6 +108,8 @@ void LocalPlayer::logic()
void LocalPlayer::nextStep()
{
+ // TODO: Fix picking up when reaching target (this method is obsolete)
+ // TODO: Fix holding walking button to keep walking smoothly
if (mPath.empty())
{
if (mPickUpTarget)
@@ -118,8 +122,6 @@ void LocalPlayer::nextStep()
walk(mWalkingDir);
}
}
-
- Player::nextStep();
}
bool LocalPlayer::checkInviteRights(const std::string &guildName)
@@ -165,8 +167,7 @@ void LocalPlayer::setInvItem(int index, int id, int amount)
mInventory->setItem(index, id, amount);
}
-void
-LocalPlayer::moveInvItem(Item *item, int newIndex)
+void LocalPlayer::moveInvItem(Item *item, int newIndex)
{
// special case, the old and new cannot copy over each other.
if (item->getInvIndex() == newIndex)
@@ -218,13 +219,12 @@ void LocalPlayer::splitItem(Item *item, int quantity)
Net::GameServer::Player::moveItem(
item->getInvIndex(), newIndex, quantity);
}
-
}
void LocalPlayer::pickUp(FloorItem *item)
{
- int dx = item->getX() - mX / 32;
- int dy = item->getY() - mY / 32;
+ int dx = item->getX() - (int) getPosition().x / 32;
+ int dy = item->getY() - (int) getPosition().y / 32;
if (dx * dx + dy * dy < 4) {
int id = item->getId();
@@ -238,13 +238,16 @@ void LocalPlayer::pickUp(FloorItem *item)
void LocalPlayer::walk(unsigned char dir)
{
+ // TODO: Evaluate the implementation of this method
if (!mMap || !dir)
return;
+ const Vector &pos = getPosition();
+
if (mAction == WALK && !mPath.empty())
{
// Just finish the current action, otherwise we get out of sync
- Being::setDestination(mX, mY);
+ Being::setDestination(pos.x, pos.y);
return;
}
@@ -259,19 +262,23 @@ void LocalPlayer::walk(unsigned char dir)
dx += 32;
// Prevent skipping corners over colliding tiles
- if (dx && !mMap->getWalk((mX + dx) / 32, mY / 32, getWalkMask()))
- dx = 16 - mX % 32;
- if (dy && !mMap->getWalk(mX / 32, (mY + dy) / 32, getWalkMask()))
- dy = 16 - mY % 32;
+ if (dx && !mMap->getWalk(((int) pos.x + dx) / 32,
+ (int) pos.y / 32, getWalkMask()))
+ dx = 16 - (int) pos.x % 32;
+ if (dy && !mMap->getWalk((int) pos.x / 32,
+ ((int) pos.y + dy) / 32, getWalkMask()))
+ dy = 16 - (int) pos.y % 32;
// Choose a straight direction when diagonal target is blocked
- if (dx && dy && !mMap->getWalk((mX + dx) / 32, (mY + dy) / 32, getWalkMask()))
- dx = 16 - mX % 32;
+ if (dx && dy && !mMap->getWalk((pos.x + dx) / 32,
+ (pos.y + dy) / 32, getWalkMask()))
+ dx = 16 - (int) pos.x % 32;
// Walk to where the player can actually go
- if ((dx || dy) && mMap->getWalk((mX + dx) / 32, (mY + dy) / 32, getWalkMask()))
+ if ((dx || dy) && mMap->getWalk(((int) pos.x + dx) / 32,
+ ((int) pos.y + dy) / 32, getWalkMask()))
{
- setDestination(mX + dx, mY + dy);
+ setDestination((int) pos.x + dx, (int) pos.y + dy);
}
else if (dir)
{
@@ -284,10 +291,20 @@ void LocalPlayer::walk(unsigned char dir)
void LocalPlayer::setDestination(Uint16 x, Uint16 y)
{
// Fix coordinates so that the player does not seem to dig into walls.
- int tx = x / 32, ty = y / 32, fx = x % 32, fy = y % 32;
- if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty, getWalkMask())) fx = 16;
- if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1, getWalkMask())) fy = 16;
- if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty + fy / 16 * 2 - 1, getWalkMask())) fx = 16;
+ const int tx = x / 32;
+ const int ty = y / 32;
+ int fx = x % 32;
+ int fy = y % 32;
+
+ if (fx != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1, ty, getWalkMask()))
+ fx = 16;
+ if (fy != 16 && !mMap->getWalk(tx, ty + fy / 16 * 2 - 1, getWalkMask()))
+ fy = 16;
+ if (fx != 16 && fy != 16 && !mMap->getWalk(tx + fx / 16 * 2 - 1,
+ ty + fy / 16 * 2 - 1,
+ getWalkMask()))
+ fx = 16;
+
x = tx * 32 + fx;
y = ty * 32 + fy;
@@ -375,7 +392,6 @@ void LocalPlayer::attack()
return;
mLastAction = tick_time;
- mWalkTime = tick_time;
setAction(ATTACK);
@@ -449,7 +465,6 @@ const struct LocalPlayer::SkillInfo& LocalPlayer::getSkillInfo(int skill)
{
return skills[skill];
}
-
}
void LocalPlayer::setExperience(int skill, int current, int next)
diff --git a/src/map.cpp b/src/map.cpp
index 888ea3a8..e10e4fad 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -113,7 +113,7 @@ void MapLayer::draw(Graphics *graphics,
// If drawing the fringe layer, make sure all sprites above this row of
// tiles have been drawn
if (mIsFringeLayer) {
- while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) {
+ while (si != sprites.end() && (*si)->getPixelY() <= y * 32) {
(*si)->draw(graphics, -scrollX, -scrollY);
si++;
}
@@ -383,35 +383,6 @@ void Map::blockTile(int x, int y, BlockType type)
}
}
-void Map::freeTile(int x, int y, BlockType type)
-{
- if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight)
- {
- return;
- }
-
- int tileNum = x + y * mWidth;
-
- if ((--mOccupation[type][tileNum]) <= 0)
- {
- switch (type)
- {
- case BLOCKTYPE_WALL:
- mMetaTiles[tileNum].blockmask &= (BLOCKMASK_WALL xor 0xff);
- break;
- case BLOCKTYPE_CHARACTER:
- mMetaTiles[tileNum].blockmask &= (BLOCKMASK_CHARACTER xor 0xff);
- break;
- case BLOCKTYPE_MONSTER:
- mMetaTiles[tileNum].blockmask &= (BLOCKMASK_MONSTER xor 0xff);
- break;
- default:
- // shut up!
- break;
- }
- }
-}
-
bool Map::getWalk(int x, int y, char walkmask) const
{
// You can't walk outside of the map
@@ -450,7 +421,7 @@ static int const basicCost = 100;
Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost)
{
// Path to be built up (empty by default)
- std::list<PATH_NODE> path;
+ std::list<Position> path;
// Declare open list, a list with open tiles sorted on F cost
std::priority_queue<Location> openList;
@@ -612,7 +583,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w
while (pathX != startX || pathY != startY)
{
// Add the new path node to the start of the path list
- path.push_front(PATH_NODE(pathX, pathY));
+ path.push_front(Position(pathX, pathY));
// Find out the next parent
MetaTile *tile = getMetaTile(pathX, pathY);
diff --git a/src/map.h b/src/map.h
index 31c6be00..c4a4fc0b 100644
--- a/src/map.h
+++ b/src/map.h
@@ -27,6 +27,7 @@
#include <list>
#include <vector>
+#include "position.h"
#include "properties.h"
class AmbientOverlay;
@@ -37,8 +38,6 @@ class Particle;
class Sprite;
class Tileset;
-struct PATH_NODE;
-
typedef std::vector<Tileset*> Tilesets;
typedef std::list<Sprite*> Sprites;
typedef Sprites::iterator SpriteIterator;
@@ -189,11 +188,6 @@ class Map : public Properties
void blockTile(int x, int y, BlockType type);
/**
- * Marks a tile as unoccupied
- */
- void freeTile(int x, int y, BlockType type);
-
- /**
* Gets walkability for a tile with a blocking bitmask. When called
* without walkmask, only blocks against colliding tiles.
*/
@@ -226,8 +220,8 @@ class Map : public Properties
/**
* Find a path from one location to the next.
*/
- std::list<PATH_NODE>
- findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost = 20);
+ Path findPath(int startX, int startY, int destX, int destY,
+ unsigned char walkmask, int maxCost = 20);
/**
* Adds a sprite to the map.
diff --git a/src/monster.cpp b/src/monster.cpp
index 1561b2ea..396d0c06 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -55,7 +55,6 @@ Monster::Monster(Uint16 id, Uint16 job, Map *map):
Monster::~Monster()
{
- if (mMap) mMap->freeTile(mX / 32, mY / 32, getBlockType());
}
Being::Type
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index b1c502e1..7e37aa27 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -48,18 +48,6 @@ const int EMOTION_TIME = 150; /**< Duration of emotion icon */
BeingHandler::BeingHandler()
{
static const Uint16 _messages[] = {
- //SMSG_BEING_VISIBLE,
- //SMSG_BEING_MOVE,
- //SMSG_BEING_REMOVE,
- //SMSG_BEING_ACTION,
- //SMSG_BEING_LEVELUP,
- //SMSG_BEING_EMOTION,
- //SMSG_BEING_CHANGE_LOOKS,
- //SMSG_BEING_NAME_RESPONSE,
- //SMSG_PLAYER_UPDATE_1,
- //SMSG_PLAYER_UPDATE_2,
- //SMSG_PLAYER_MOVE,
- //0x0119,
GPMSG_BEING_ATTACK,
GPMSG_BEING_ENTER,
GPMSG_BEING_LEAVE,
@@ -74,15 +62,6 @@ BeingHandler::BeingHandler()
void BeingHandler::handleMessage(MessageIn &msg)
{
- /*
- Uint32 id;
- Uint16 job, speed;
- Uint16 headBottom, headTop, headMid;
- Sint16 param1;
- Sint8 type;
- Being *srcBeing, *dstBeing;
- */
-
switch (msg.getId())
{
case GPMSG_BEING_ENTER:
@@ -106,322 +85,6 @@ void BeingHandler::handleMessage(MessageIn &msg)
case GPMSG_BEING_LOOKS_CHANGE:
handleBeingLooksChangeMessage(msg);
break;
-
-
- /*
- case SMSG_BEING_VISIBLE:
- case SMSG_BEING_MOVE:
- // Information about a being in range
- id = msg.readInt32();
- speed = msg.readInt16();
- msg.readInt16(); // unknown
- msg.readInt16(); // unknown
- msg.readInt16(); // option
- job = msg.readInt16(); // class
-
- dstBeing = beingManager->findBeing(id);
-
- if (!dstBeing)
- {
- // Being with id >= 110000000 and job 0 are better
- // known as ghosts, so don't create those.
- if (job == 0 && id >= 110000000)
- {
- break;
- }
-
- dstBeing = beingManager->createBeing(id, job);
- }
- else if (msg.getId() == 0x0078)
- {
- dstBeing->clearPath();
- dstBeing->mFrame = 0;
- dstBeing->mWalkTime = tick_time;
- dstBeing->setAction(Being::STAND);
- }
-
- // Prevent division by 0 when calculating frame
- if (speed == 0) { speed = 150; }
-
- dstBeing->setWalkSpeed(speed);
- dstBeing->mJob = job;
- dstBeing->setHairStyle(msg->readInt16());
- dstBeing->setSprite(
- Being::WEAPON_SPRITE, msg->readInt16());
- dstBeing->setSprite(
- Being::BOTTOMCLOTHES_SPRITE, msg->readInt16());
-
- if (msg.getId() == SMSG_BEING_MOVE)
- {
- msg.readInt32(); // server tick
- }
-
- msg->readInt16(); // shield
- headTop = msg->readInt16();
- headMid = msg->readInt16();
- dstBeing->setSprite(Being::HAT_SPRITE, headTop);
- dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
- dstBeing->setHairColor(msg->readInt16());
- msg->readInt16(); // unknown
- msg->readInt16(); // head dir
- msg->readInt16(); // guild
- msg->readInt16(); // unknown
- msg->readInt16(); // unknown
- msg->readInt16(); // manner
- msg->readInt16(); // karma
- msg->readInt8(); // unknown
- dstBeing->setSex(1 - msg->readInt8()); // sex
-
- if (msg.getId() == SMSG_BEING_MOVE)
- {
- //Uint16 srcX, srcY, dstX, dstY;
- //msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- //dstBeing->setAction(Being::STAND);
- //dstBeing->mX = srcX;
- //dstBeing->mY = srcY;
- //dstBeing->setDestination(dstX, dstY);
- }
- else
- {
- //Uint8 dir;
- //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir);
- //dstBeing->setDirection(dir);
- }
-
- msg.readInt8(); // unknown
- msg.readInt8(); // unknown
- msg.readInt8(); // unknown / sit
- break;
-
- case SMSG_BEING_REMOVE:
- // A being should be removed or has died
- dstBeing = beingManager->findBeing(msg.readInt32());
-
- if (!dstBeing)
- break;
-
- if (msg.readInt8() == 1)
- {
- dstBeing->setAction(Being::DEAD);
- }
- else
- {
- beingManager->destroyBeing(dstBeing);
- }
-
- if (dstBeing == player_node->getTarget())
- {
- player_node->stopAttack();
- }
- break;
-
- case SMSG_BEING_ACTION:
- srcBeing = beingManager->findBeing(msg.readInt32());
- dstBeing = beingManager->findBeing(msg.readInt32());
- msg.readInt32(); // server tick
- msg.readInt32(); // src speed
- msg.readInt32(); // dst speed
- param1 = msg.readInt16();
- msg.readInt16(); // param 2
- type = msg.readInt8();
- msg.readInt16(); // param 3
-
- switch (type)
- {
- case 0: // Damage
- if (dstBeing) {
- dstBeing->takeDamage(param1);
- }
- if (srcBeing) {
- srcBeing->handleAttack(dstBeing, param1);
- }
- break;
-
- case 2: // Sit
- if (srcBeing) {
- srcBeing->mFrame = 0;
- srcBeing->setAction(Being::SIT);
- }
- break;
-
- case 3: // Stand up
- if (srcBeing) {
- srcBeing->mFrame = 0;
- srcBeing->setAction(Being::STAND);
- }
- break;
- }
- break;
-
- case SMSG_BEING_LEVELUP:
- id = (Uint32) msg->readInt32();
-
- if (id == player_node->getId()) {
- logger->log("Level up");
- sound.playSfx("sfx/levelup.ogg");
- }
- else {
- logger->log("Someone else went level up");
- }
- Particle *levelupFX;
- if (msg->readInt32() == 0) { // type
- levelupFX = particleEngine->addEffect(
- "graphics/particles/levelup.particle.xml", 0, 0);
- }
- else {
- levelupFX = particleEngine->addEffect(
- "graphics/particles/skillup.particle.xml", 0, 0);
- }
- beingManager->findBeing(id)->controlParticle(levelupFX);
- break;
-
- case SMSG_BEING_EMOTION:
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
- {
- break;
- }
-
- dstBeing->mEmotion = msg.readInt8();
- dstBeing->mEmotionTime = EMOTION_TIME;
- break;
-
- case SMSG_BEING_CHANGE_LOOKS:
- {
- if (!(dstBeing = beingManager->findBeing(msg.readInt32())))
- {
- break;
- }
-
- int type = msg.readInt8();
- int id = msg.readInt8();
-
- switch (type) {
- case 1:
- dstBeing->setHairStyle(id);
- break;
- case 2:
- dstBeing->setSprite(Being::WEAPON_SPRITE, id);
- break;
- case 3: // Change lower headgear for eAthena, pants for us
- dstBeing->setSprite(
- Being::BOTTOMCLOTHES_SPRITE, id);
- break;
- case 4: // Change upper headgear for eAthena, hat for us
- dstBeing->setSprite(
- Being::HAT_SPRITE, id);
- break;
- case 5: // Change middle headgear for eathena, armor for us
- dstBeing->setSprite(
- Being::TOPCLOTHES_SPRITE, id);
- break;
- case 6:
- dstBeing->setHairColor(id);
- break;
- default:
- logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: "
- "%d, id: %d", type, id);
- break;
- }
- }
- break;
-
- case SMSG_BEING_NAME_RESPONSE:
- if ((dstBeing = beingManager->findBeing(msg.readInt32())))
- {
- dstBeing->setName(msg.readString(24));
- }
- break;
-
- case SMSG_PLAYER_UPDATE_1:
- case SMSG_PLAYER_UPDATE_2:
- case SMSG_PLAYER_MOVE:
- // An update about a player, potentially including movement.
- id = msg.readInt32();
- speed = msg.readInt16();
- msg.readInt16(); // option 1
- msg.readInt16(); // option 2
- msg.readInt16(); // option
- job = msg.readInt16();
-
- dstBeing = beingManager->findBeing(id);
-
- if (!dstBeing)
- {
- dstBeing = beingManager->createBeing(id, job);
- }
-
- dstBeing->setWalkSpeed(speed);
- dstBeing->mJob = job;
- dstBeing->setHairStyle(msg->readInt16());
- dstBeing->setSprite(
- Being::WEAPON_SPRITE, msg->readInt16());
- msg->readInt16(); // item id 2
- headBottom = msg->readInt16();
-
- if (msg.getId() == SMSG_PLAYER_MOVE)
- {
- msg.readInt32(); // server tick
- }
-
- headTop = msg.readInt16();
- headMid = msg.readInt16();
- dstBeing->setHairColor(msg.readInt16());
- msg.readInt16(); // unknown
- msg.readInt16(); // head dir
- msg.readInt32(); // guild
- msg.readInt32(); // emblem
- msg.readInt16(); // manner
- msg.readInt8(); // karma
- dstBeing->setSex(1 - msg.readInt8()); // sex
- dstBeing->setSprite(
- Being::BOTTOMCLOTHES_SPRITE, headBottom);
- dstBeing->setSprite(Being::HAT_SPRITE, headTop);
- dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
-
- if (msg.getId() == SMSG_PLAYER_MOVE)
- {
- //Uint16 srcX, srcY, dstX, dstY;
- //msg.readCoordinatePair(srcX, srcY, dstX, dstY);
- //dstBeing->mX = srcX;
- //dstBeing->mY = srcY;
- //dstBeing->setDestination(dstX, dstY);
- }
- else
- {
- //Uint8 dir;
- //msg->readCoordinates(dstBeing->mX, dstBeing->mY, dir);
- //dstBeing->setDirection(dir);
- }
-
- msg.readInt8(); // unknown
- msg.readInt8(); // unknown
-
- if (msg.getId() == SMSG_PLAYER_UPDATE_1)
- {
- if (msg.readInt8() == 2)
- {
- dstBeing->setAction(Being::SIT);
- }
- }
- else if (msg.getId() == SMSG_PLAYER_MOVE)
- {
- msg.readInt8(); // unknown
- }
-
- msg.readInt8(); // Lv
- msg.readInt8(); // unknown
-
- dstBeing->mWalkTime = tick_time;
- dstBeing->mFrame = 0;
- break;
-
- case 0x0119:
- // Change in players look
- logger->log("0x0119 %i %i %i %x %i", msg->readInt32(),
- msg->readInt16(), msg->readInt16(), msg->readInt16(),
- msg->readInt8());
- break;
- */
}
}
@@ -453,8 +116,7 @@ static void handleLooks(Player *being, MessageIn &msg)
}
}
-void
-BeingHandler::handleBeingEnterMessage(MessageIn &msg)
+void BeingHandler::handleBeingEnterMessage(MessageIn &msg)
{
int type = msg.readInt8();
int id = msg.readInt16();
@@ -481,7 +143,8 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg)
Player *p = static_cast< Player * >(being);
int hs = msg.readInt8(), hc = msg.readInt8();
p->setHairStyle(hs, hc);
- p->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE);
+ p->setGender(msg.readInt8() == GENDER_MALE ?
+ GENDER_MALE : GENDER_FEMALE);
handleLooks(p, msg);
} break;
@@ -498,7 +161,7 @@ BeingHandler::handleBeingEnterMessage(MessageIn &msg)
return;
}
- being->setPositionInPixels(px, py);
+ being->setPosition(px, py);
being->setDestination(px, py);
being->setAction(action);
}
@@ -518,7 +181,17 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg)
int id = msg.readInt16();
int flags = msg.readInt8();
Being *being = beingManager->findBeing(id);
- int sx = 0, sy = 0, dx = 0, dy = 0, speed = 0;
+ int sx = 0;
+ int sy = 0;
+ int dx = 0;
+ int dy = 0;
+ int speed = 0;
+
+ printf("handleBeingsMoveMessage for %p (%s | %s)\n",
+ (void*) being,
+ (flags & MOVING_POSITION) ? "pos" : "",
+ (flags & MOVING_DESTINATION) ? "dest" : "");
+
if (flags & MOVING_POSITION)
{
Uint16 sx2, sy2;
@@ -543,12 +216,19 @@ void BeingHandler::handleBeingsMoveMessage(MessageIn &msg)
}
if (speed)
{
- being->setWalkSpeed(speed * 10);
+ /* The speed on the server is the cost of moving from one tile to
+ * the next. Beings get 1000 cost units per second. The speed is
+ * transferred as devided by 10, so that slower speeds fit in a
+ * byte. Here we convert the speed to pixels per second.
+ */
+ const float tilesPerSecond = 100.0f / speed;
+ being->setWalkSpeed((int) (tilesPerSecond * 32));
}
- if (abs(being->getPixelX() - sx) + abs(being->getPixelY() - sy) > 4 * 32)
+ if (abs(being->getPixelX() - sx) +
+ abs(being->getPixelY() - sy) > 4 * 32)
{
// Too large a desynchronization.
- being->setPositionInPixels(sx, sy);
+ being->setPosition(sx, sy);
being->setDestination(dx, dy);
}
else if (!(flags & MOVING_POSITION))
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
index ea581095..3c0a1835 100644
--- a/src/net/playerhandler.cpp
+++ b/src/net/playerhandler.cpp
@@ -302,11 +302,12 @@ PlayerHandler::handleMapChangeMessage(MessageIn &msg)
current_npc = 0;
- const float scrollOffsetX = x - player_node->mX;
- const float scrollOffsetY = y - player_node->mY;
+ const Vector &playerPos = player_node->getPosition();
+ const float scrollOffsetX = x - (int) playerPos.x;
+ const float scrollOffsetY = y - (int) playerPos.y;
player_node->setAction(Being::STAND);
- player_node->setPositionInPixels(x, y);
+ player_node->setPosition(x, y);
logger->log("Adjust scrolling by %d,%d", (int) scrollOffsetX,
(int) scrollOffsetY);
diff --git a/src/npc.cpp b/src/npc.cpp
index c2b266ff..a7302e0d 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -69,15 +69,15 @@ NPC::getType() const
return Being::NPC;
}
-void
-NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY)
+void NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY)
{
- int px = mPx + offsetX;
- int py = mPy + offsetY;
+ const Vector &pos = getPosition();
+ const int px = (int) pos.x + offsetX;
+ const int py = (int) pos.y + offsetY;
graphics->setFont(speechFont);
graphics->setColor(gcn::Color(200, 200, 255));
- graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER);
+ graphics->drawText(mName, px, py, gcn::Graphics::CENTER);
}
void
diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp
index f03490ac..23c6879e 100644
--- a/src/particleemitter.cpp
+++ b/src/particleemitter.cpp
@@ -195,7 +195,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
if (!img)
{
- logger->log("No image at index " + (index));
+ logger->log("No image at index %d", index);
continue;
}
@@ -218,8 +218,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
if (!img)
{
- logger->log("No image at index " +
- (start));
+ logger->log("No image at index %d", start);
continue;
}
diff --git a/src/player.cpp b/src/player.cpp
index 49f0221d..97c60789 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -46,7 +46,6 @@ Player::Player(int id, int job, Map *map):
Player::~Player()
{
- if (mMap) mMap->freeTile(mX / 32, mY / 32, getBlockType());
}
Being::Type
@@ -55,15 +54,15 @@ Player::getType() const
return PLAYER;
}
-void
-Player::drawName(Graphics *graphics, int offsetX, int offsetY)
+void Player::drawName(Graphics *graphics, int offsetX, int offsetY)
{
- int px = mPx + offsetX;
- int py = mPy + offsetY;
+ const Vector &pos = getPosition();
+ const int px = (int) pos.x + offsetX;
+ const int py = (int) pos.y + offsetY;
graphics->setFont(speechFont);
graphics->setColor(gcn::Color(255, 255, 255));
- graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER);
+ graphics->drawText(mName, px, py, gcn::Graphics::CENTER);
}
void Player::setGender(Gender gender)
diff --git a/src/position.cpp b/src/position.cpp
new file mode 100644
index 00000000..334079bb
--- /dev/null
+++ b/src/position.cpp
@@ -0,0 +1,47 @@
+/*
+ * The Mana World
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include "position.h"
+
+std::ostream& operator <<(std::ostream &os, const Position &p)
+{
+ os << "(" << p.x << ", " << p.y << ")";
+ return os;
+}
+
+std::ostream& operator <<(std::ostream &os, const Path &path)
+{
+ Path::const_iterator i = path.begin();
+
+ os << "(";
+ while (i != path.end())
+ {
+ os << *i;
+ ++i;
+ if (i != path.end())
+ os << ", ";
+ }
+ os << ")";
+
+ return os;
+}
diff --git a/src/position.h b/src/position.h
new file mode 100644
index 00000000..d1aa2ee6
--- /dev/null
+++ b/src/position.h
@@ -0,0 +1,60 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: being.h 4570 2008-09-04 20:59:34Z b_lindeijer $
+ */
+
+#ifndef TMW_POSITION_H
+#define TMW_POSITION_H
+
+#include <list>
+#include <iostream>
+
+/**
+ * A position along a being's path.
+ */
+struct Position
+{
+ /**
+ * Constructor.
+ */
+ Position(int x, int y):
+ x(x), y(y)
+ { }
+
+ int x;
+ int y;
+};
+
+typedef std::list<Position> Path;
+typedef Path::iterator PathIterator;
+
+/**
+ * Appends a string representation of a position to the output stream.
+ */
+std::ostream& operator <<(std::ostream &os, const Position &p);
+
+/**
+ * Appends a string representation of a path (sequence of positions) to the
+ * output stream.
+ */
+std::ostream& operator <<(std::ostream &os, const Path &path);
+
+#endif // TMW_POSITION_H
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 9d98184a..dcfee165 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -232,7 +232,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
if (!img)
{
- logger->log("No image at index " + (index + variant_offset));
+ logger->log("No image at index %d", index + variant_offset);
continue;
}
@@ -255,8 +255,7 @@ SpriteDef::loadAnimation(xmlNodePtr animationNode,
if (!img)
{
- logger->log("No image at index " +
- (start + variant_offset));
+ logger->log("No image at index %d", start + variant_offset);
continue;
}
diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp
index 18e732ef..f425d3c1 100644
--- a/src/simpleanimation.cpp
+++ b/src/simpleanimation.cpp
@@ -68,7 +68,7 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode):
if (!img)
{
- logger->log("No image at index " + (index));
+ logger->log("No image at index %d", index);
continue;
}
@@ -91,8 +91,7 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode):
if (!img)
{
- logger->log("No image at index " +
- (start));
+ logger->log("No image at index %d", start);
continue;
}
diff --git a/src/vector.cpp b/src/vector.cpp
new file mode 100644
index 00000000..88092c9b
--- /dev/null
+++ b/src/vector.cpp
@@ -0,0 +1,30 @@
+/*
+ * The Mana World
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id: vector.h 4592 2008-09-07 20:38:52Z b_lindeijer $
+ */
+
+#include "vector.h"
+
+std::ostream& operator <<(std::ostream &os, const Vector &v)
+{
+ os << "Vector(" << v.x << ", " << v.y << ", " << v.z << ")";
+ return os;
+}
diff --git a/src/vector.h b/src/vector.h
index 7a5da241..7251eff0 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -24,6 +24,10 @@
#ifndef _TMW_VECTOR_H_
#define _TMW_VECTOR_H_
+#include <math.h>
+
+#include <iostream>
+
/**
* Vector class. Represents either a 3D point in space, a velocity or a force.
* Provides several convenient operator overloads.
@@ -43,7 +47,7 @@ class Vector
/**
* Constructor.
*/
- Vector(float x, float y, float z):
+ Vector(float x, float y, float z = 0.0f):
x(x),
y(y),
z(z)
@@ -71,11 +75,12 @@ class Vector
/**
* In-place scale vector operator.
*/
- void operator*=(float c)
+ Vector &operator*=(float c)
{
x *= c;
y *= c;
z *= c;
+ return *this;
}
/**
@@ -89,6 +94,17 @@ class Vector
}
/**
+ * In-place scale vector operator.
+ */
+ Vector &operator/=(float c)
+ {
+ x /= c;
+ y /= c;
+ z /= c;
+ return *this;
+ }
+
+ /**
* Add vector operator.
*/
Vector operator+(const Vector &v) const
@@ -101,11 +117,12 @@ class Vector
/**
* In-place add vector operator.
*/
- void operator+=(const Vector &v)
+ Vector &operator+=(const Vector &v)
{
x += v.x;
y += v.y;
z += v.z;
+ return *this;
}
/**
@@ -121,14 +138,55 @@ class Vector
/**
* In-place substract vector operator.
*/
- void operator-=(const Vector &v)
+ Vector &operator-=(const Vector &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
+ return *this;
+ }
+
+ /**
+ * Returns the length of this vector. This method does a relatively
+ * slow square root.
+ */
+ float length() const
+ {
+ return sqrtf(x * x + y * y + z * z);
+ }
+
+ /**
+ * Returns the squared length of this vector. Avoids the square root.
+ */
+ float squaredLength() const
+ {
+ return x * x + y * y + z * z;
+ }
+
+ /**
+ * Returns the manhattan length of this vector.
+ */
+ float manhattanLength() const
+ {
+ return fabsf(x) + fabsf(y) + fabsf(z);
+ }
+
+ /**
+ * Returns a normalized version of this vector. This is a unit vector
+ * running parallel to it.
+ */
+ Vector normalized() const
+ {
+ const float l = length();
+ return Vector(x / l, y / l, z / l);
}
float x, y, z;
};
-#endif
+/**
+ * Appends a string representation of a vector to the output stream.
+ */
+std::ostream& operator <<(std::ostream &os, const Vector &v);
+
+#endif // _TMW_VECTOR_H_