diff options
author | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2006-09-09 22:59:22 +0000 |
---|---|---|
committer | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2006-09-09 22:59:22 +0000 |
commit | 81c7e13077dde99ea360f2ab8432aa48444f3b88 (patch) | |
tree | eb9afd47e2e5dd2b8c6a3de1278fa77765d8b85b /src/being.cpp | |
parent | d342307c408c687405bae557c1fff7ac0e9891b9 (diff) | |
download | mana-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.cpp | 157 |
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 |