void Being::setDestination(int dstX, int dstY) { // We can't calculate anything without a map anyway. if (!mMap) return; // Don't handle flawed destinations from server... if (dstX <= 0 || dstY <= 0) return; // If the destination is unwalkable, don't bother trying to get there const int tileWidth = mMap->getTileWidth(); const int tileHeight = mMap->getTileHeight(); if (!mMap->getWalk(dstX / tileWidth, dstY / tileHeight)) return; Position dest(0, 0); Path thisPath; if (Net::getPlayerHandler()->usePixelPrecision()) { dest = mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), dstX, dstY); thisPath = mMap->findPixelPath((int) mPos.x, (int) mPos.y, dest.x, dest.y, getCollisionRadius(), getWalkMask()); } else { // We center the destination. dest.x = (dstX / tileWidth) * tileWidth + tileWidth / 2; dest.y = (dstY / tileHeight) * tileHeight + tileHeight / 2; // and find a tile centered pixel path thisPath = mMap->findTilePath((int) mPos.x, (int) mPos.y, dest.x, dest.y, getWalkMask()); } if (thisPath.empty()) { // If there is no path but the destination is on the same walkable tile, // we accept it. if ((int)mPos.x / tileWidth == dest.x / tileWidth && (int)mPos.y / tileHeight == dest.y / tileHeight) { mDest.x = dest.x; mDest.y = dest.y; } setPath(Path()); return; } // The destination is valid, so we set it. mDest.x = dest.x; mDest.y = dest.y; setPath(thisPath); }
void Being::nextStep() { if (mPath.empty()) { setAction(STAND); return; } Position pos = mPath.front(); mPath.pop_front(); int dir = 0; if (pos.x > mX) dir |= RIGHT; else if (pos.x < mX) dir |= LEFT; if (pos.y > mY) dir |= DOWN; else if (pos.y < mY) dir |= UP; setDirection(dir); if (!mMap->getWalk(pos.x, pos.y, getWalkMask())) { setAction(STAND); return; } mX = pos.x; mY = pos.y; setAction(WALK); mWalkTime += mWalkSpeed / 10; }
int Monster::calculatePositionPriority(Point position, int targetPriority) { Point thisPos = getPosition(); unsigned range = mSpecy->getTrackRange(); Map *map = getMap()->getMap(); int tileWidth = map->getTileWidth(); int tileHeight = map->getTileHeight(); // Check if we already are on this position if (thisPos.x / tileWidth == position.x / tileWidth && thisPos.y / tileHeight == position.y / tileHeight) { return targetPriority *= range; } Path path; path = map->findPath(thisPos.x / tileWidth, thisPos.y / tileHeight, position.x / tileWidth, position.y / tileHeight, getWalkMask(), range); if (path.empty() || path.size() >= range) { return 0; } else { return targetPriority * (range - path.size()); } }
bool Being::destinationReachable(Uint16 destX, Uint16 destY) { if(mMap) { if(mMap->findPath2(mX, mY, destX, destY, getWalkMask(),100)) return true; } return false; }
void LocalPlayer::setDestination(Uint16 x, Uint16 y) #endif { #ifdef TMWSERV_SUPPORT // Fix coordinates so that the player does not seem to dig into walls. 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; #endif // Only send a new message to the server when destination changes if (x != mDestX || y != mDestY) { mDestX = x; mDestY = y; Net::getPlayerHandler()->setDestination(x, y, mDirection); } mPickUpTarget = NULL; mKeepAttacking = false; Being::setDestination(x, y); }
void LocalPlayer::walk(unsigned char dir) { // TODO: Evaluate the implementation of this method for tmwserv if (!mMap || !dir) return; #ifdef TMWSERV_SUPPORT const Vector &pos = getPosition(); #endif if (mAction == WALK && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync #ifdef TMWSERV_SUPPORT Being::setDestination(pos.x, pos.y); #else Being::setDestination(getTileX(), getTileY()); #endif return; } int dx = 0, dy = 0; if (dir & UP) dy--; if (dir & DOWN) dy++; if (dir & LEFT) dx--; if (dir & RIGHT) dx++; // Prevent skipping corners over colliding tiles #ifdef TMWSERV_SUPPORT 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; #else if (dx && !mMap->getWalk(getTileX() + dx, getTileY(), getWalkMask())) dx = 0; if (dy && !mMap->getWalk(getTileX(), getTileY() + dy, getWalkMask())) dy = 0; #endif // Choose a straight direction when diagonal target is blocked #ifdef TMWSERV_SUPPORT if (dx && dy && !mMap->getWalk((pos.x + dx) / 32, (pos.y + dy) / 32, getWalkMask())) dx = 16 - (int) pos.x % 32; int dScaler; // Distance to walk // Checks our path up to 1 tiles, if a blocking tile is found // We go to the last good tile, and break out of the loop for (dScaler = 1; dScaler <= 32; dScaler++) { if ( (dx || dy) && !mMap->getWalk( ((int) pos.x + (dx * dScaler)) / 32, ((int) pos.y + (dy * dScaler)) / 32, getWalkMask()) ) { dScaler--; break; } } if (dScaler >= 0) { effectManager->trigger(15, (int) pos.x + (dx * dScaler), (int) pos.y + (dy * dScaler)); setDestination((int) pos.x + (dx * dScaler), (int) pos.y + (dy * dScaler)); } #else if (dx && dy && !mMap->getWalk(getTileX() + dx, getTileY() + dy, getWalkMask())) dx = 0; // Walk to where the player can actually go if ((dx || dy) && mMap->getWalk(getTileX() + dx, getTileY() + dy, getWalkMask())) { setDestination(getTileX() + dx, getTileY() + dy); } #endif else if (dir) { // If the being can't move, just change direction Net::getPlayerHandler()->setDirection(dir); setDirection(dir); } }
void Being::adjustCourse(int srcX, int srcY, int dstX, int 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()); } // 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(Position(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, getWalkMask()); if (p1.empty()) { // No path, but don't teleport since it could be user input. 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. p1.pop_back(); for (Path::iterator i = p1.begin(), i_end = p1.end(); i != i_end; ++i) { // 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; } // Do not set any offset for intermediate steps. i->x = i->x * 32; i->y = i->y * 32; ++j; } p1_length = mMap->getMetaTile(dstX / 32, dstY / 32)->Gcost; p1_dist[p1_size - 1] = p1_length; } p1.push_back(Position(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, getWalkMask()); 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? Still, don't teleport since it could be // user input instead of server command. 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; i->y = i->y * 32; } // 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::setDestination(Uint16 destX, Uint16 destY) { if (mMap) setPath(mMap->findPath(mX, mY, destX, destY, getWalkMask(),100)); }