summaryrefslogtreecommitdiff
path: root/src/being.cpp
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2006-09-09 22:59:22 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2006-09-09 22:59:22 +0000
commit81c7e13077dde99ea360f2ab8432aa48444f3b88 (patch)
treeeb9afd47e2e5dd2b8c6a3de1278fa77765d8b85b /src/being.cpp
parentd342307c408c687405bae557c1fff7ac0e9891b9 (diff)
downloadmana-81c7e13077dde99ea360f2ab8432aa48444f3b88.tar.gz
mana-81c7e13077dde99ea360f2ab8432aa48444f3b88.tar.bz2
mana-81c7e13077dde99ea360f2ab8432aa48444f3b88.tar.xz
mana-81c7e13077dde99ea360f2ab8432aa48444f3b88.zip
Fitted being trajectories to synchronization messages.
Diffstat (limited to 'src/being.cpp')
-rw-r--r--src/being.cpp157
1 files changed, 142 insertions, 15 deletions
diff --git a/src/being.cpp b/src/being.cpp
index a4bee426..982b0ebf 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -23,6 +23,7 @@
#include "being.h"
#include <algorithm>
+#include <cassert>
#include <cmath>
#include "animatedsprite.h"
@@ -58,6 +59,7 @@ Being::Being(Uint16 id, Uint16 job, Map *map):
mSex(2),
mWeapon(0),
mWalkSpeed(150),
+ mSpeedModifier(1024),
mMap(NULL),
mHairStyle(0), mHairColor(0),
mSpeechTime(0),
@@ -75,34 +77,157 @@ Being::~Being()
setMap(NULL);
}
-void
-Being::setDestination(Uint16 destX, Uint16 destY)
+void Being::adjustCourse(Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY)
{
- if (!mMap || (mX == destX && mY == destY))
+ if (!mMap || (mX == dstX && mY == dstY))
{
+ setPath(Path());
return;
}
- Path p;
- if (mX / 32 != destX / 32 || mY / 32 != destY / 32)
+ if (mX / 32 == dstX / 32 && mY / 32 == dstY / 32)
{
- p = mMap->findPath(mX / 32, mY / 32, destX / 32, destY / 32);
- if (p.empty())
+ // The being is already on the last tile of the path.
+ Path p;
+ p.push_back(PATH_NODE(dstX, dstY));
+ setPath(p);
+ return;
+ }
+
+ Path p1;
+ int p1_size, p1_length;
+ Uint16 *p1_dist;
+ int onPath = -1;
+ if (srcX / 32 == dstX / 32 && srcY / 32 == dstY / 32)
+ {
+ p1_dist = new Uint16[1];
+ p1_size = 1;
+ p1_dist[0] = 0;
+ p1_length = 0;
+ }
+ else
+ {
+ p1 = mMap->findPath(srcX / 32, srcY / 32, dstX / 32, dstY / 32);
+ if (p1.empty())
{
- setPath(p);
+ // No path? Better teleport.
+ mX = dstX;
+ mY = dstY;
+ setPath(p1);
return;
}
+ p1_size = p1.size();
+ p1_dist = new Uint16[p1_size];
+ int j = 0;
// Remove last tile so that it can be replaced by the exact destination.
- p.pop_back();
- for (Path::iterator i = p.begin(), i_end = p.end(); i != i_end; ++i)
+ p1.pop_back();
+ for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i)
{
- // Set intermediate step to tile centers.
+ // Get distance from source to tile i.
+ p1_dist[j] = mMap->getMetaTile(i->x, i->y)->Gcost;
+ // Check if the being is already walking on the path.
+ if (i->x == mX / 32 && i->y == mY / 32)
+ {
+ onPath = j;
+ }
+ // Set intermediate steps to tile centers.
i->x = i->x * 32 + 16;
i->y = i->y * 32 + 16;
+ ++j;
}
+ p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost;
+ p1_dist[p1_size - 1] = p1_length;
}
- p.push_back(PATH_NODE(destX, destY));
- setPath(p);
+ p1.push_back(PATH_NODE(dstX, dstY));
+
+ if (mX / 32 == srcX / 32 && mY / 32 == srcY / 32)
+ {
+ // The being is at the start of the path.
+ setPath(p1);
+ delete[] p1_dist;
+ return;
+ }
+
+ if (onPath >= 0)
+ {
+ // The being is already on the path, but it needs to be slowed down.
+ for (int j = onPath; j >= 0; --j)
+ {
+ p1.pop_front();
+ }
+ int r = p1_length - p1_dist[onPath]; // remaining length
+ assert(r > 0);
+ setPath(p1, p1_length * 1024 / r);
+ delete[] p1_dist;
+ return;
+ }
+
+ Path bestPath;
+ int bestRating = -1, bestStart = 0, bestLength = 0;
+ int j = 0;
+
+ for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i)
+ {
+ // Look if it is worth passing by tile i.
+ Path p2 = mMap->findPath(mX / 32, mY / 32, i->x / 32, i->y / 32);
+ if (!p2.empty())
+ {
+ int l1 = mMap->getMetaTile(i->x / 32, i->y / 32)->Gcost;
+ int l2 = p1_length - p1_dist[j];
+ int r = l1 + l2 / 2; // TODO: tune rating formula
+ assert(r > 0);
+ if (bestRating < 0 || r < bestRating)
+ {
+ bestPath.swap(p2);
+ bestRating = r;
+ bestStart = j;
+ bestLength = l1 + l2;
+ }
+ }
+ ++j;
+ }
+
+ if (bestRating < 0)
+ {
+ // Unable to reach the path? Better teleport.
+ mX = srcX;
+ mY = srcY;
+ setPath(p1);
+ delete[] p1_dist;
+ return;
+ }
+
+ bestPath.pop_back();
+ for (Path::iterator i = bestPath.begin(), i_end = bestPath.end(); i != i_end; ++i)
+ {
+ i->x = i->x * 32 + 16;
+ i->y = i->y * 32 + 16;
+ }
+
+ // Concatenate paths.
+ for (int j = bestStart; j > 0; --j)
+ {
+ p1.pop_front();
+ }
+ p1.splice(p1.begin(), bestPath);
+
+ assert(bestLength > 0);
+ setPath(p1, p1_length * 1024 / bestLength);
+ delete[] p1_dist;
+}
+
+void Being::adjustCourse(Uint16 srcX, Uint16 srcY)
+{
+ if (!mPath.empty())
+ {
+ adjustCourse(srcX, srcY, mPath.back().x, mPath.back().y);
+ }
+}
+
+void
+Being::setDestination(Uint16 destX, Uint16 destY)
+{
+ adjustCourse(mX, mY, destX, destY);
}
void
@@ -112,9 +237,10 @@ Being::clearPath()
}
void
-Being::setPath(const Path &path)
+Being::setPath(const Path &path, int mod)
{
mPath = path;
+ mSpeedModifier = mod >= 512 ? (mod <= 2048 ? mod : 2048) : 512; // TODO: tune bounds
if (mAction != WALK && mAction != DEAD)
{
@@ -305,7 +431,8 @@ Being::nextStep()
mY = node.y;
setAction(WALK);
mWalkTime += mStepTime / 10;
- mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) / 32;
+ mStepTime = mWalkSpeed * (int)std::sqrt((double)mStepX * mStepX + (double)mStepY * mStepY) *
+ mSpeedModifier / (32 * 1024);
}
void