diff options
Diffstat (limited to 'src/localplayer.cpp')
-rw-r--r-- | src/localplayer.cpp | 950 |
1 files changed, 274 insertions, 676 deletions
diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 4d0ad17e..1a7f20e1 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -23,30 +23,19 @@ #include "client.h" #include "configuration.h" -#include "effectmanager.h" -#include "equipment.h" +#include "event.h" #include "flooritem.h" #include "graphics.h" #include "guild.h" -#include "inventory.h" #include "item.h" -#include "log.h" #include "map.h" -#include "monster.h" #include "particle.h" +#include "playerinfo.h" #include "simpleanimation.h" #include "sound.h" -#include "statuseffect.h" -#include "text.h" #include "gui/gui.h" -#include "gui/inventorywindow.h" -#include "gui/ministatus.h" #include "gui/okdialog.h" -#include "gui/skilldialog.h" -#include "gui/statuswindow.h" -#include "gui/theme.h" -#include "gui/userpalette.h" #include "gui/widgets/chattab.h" @@ -61,9 +50,8 @@ #include "resources/animation.h" #include "resources/imageset.h" -#include "resources/itemdb.h" #include "resources/iteminfo.h" -#include "resources/resourcemanager.h" +#include "resources/userpalette.h" #include "utils/gettext.h" #include "utils/stringutils.h" @@ -80,70 +68,45 @@ const short walkingKeyboardDelay = 1000; LocalPlayer *player_node = NULL; LocalPlayer::LocalPlayer(int id, int subtype): - Player(id, subtype, 0), - mEquipment(new Equipment), - mAttackRange(0), + Being(id, PLAYER, subtype, 0), + mAttackRange(ATTACK_RANGE_NOT_SET), mTargetTime(-1), mLastTarget(-1), - mCharacterPoints(0), - mCorrectionPoints(0), - mSpecialRechargeUpdateNeeded(0), - mLevel(1), - mExp(0), mExpNeeded(0), - mMp(0), mMaxMp(0), - mMoney(0), - mTotalWeight(1), mMaxWeight(1), - mHp(1), mMaxHp(1), - mSkillPoints(0), mTarget(NULL), mPickUpTarget(NULL), - mTrading(false), mGoingToTarget(false), mKeepAttacking(false), + mGoingToTarget(false), mKeepAttacking(false), mLastAction(-1), mWalkingDir(0), mPathSetByMouse(false), - mInventory(new Inventory(Inventory::INVENTORY)), mLocalWalkTime(-1), mMessageTime(0), + mShowIp(false), mAwayDialog(0), mAfkTime(0), - mAwayMode(false), - mShowIp(false) + mAwayMode(false) { + listen(Event::AttributesChannel); + mAwayListener = new AwayListener(); mUpdateName = true; - mTextColor = &Theme::getThemeColor(Theme::PLAYER); - mNameColor = &userPalette->getColor(UserPalette::SELF); - - initTargetCursor(); - - config.addListener("showownname", this); setShowName(config.getValue("showownname", 1)); + + listen(Event::ConfigChannel); + listen(Event::ActorSpriteChannel); } LocalPlayer::~LocalPlayer() { - delete mInventory; - - config.removeListener("showownname", this); - - for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) - { - delete mTargetCursor[0][i]; - delete mTargetCursor[1][i]; - mTargetCursorImages[0][i]->decRef(); - mTargetCursorImages[1][i]->decRef(); - } - delete mAwayDialog; delete mAwayListener; } void LocalPlayer::logic() { - // Actions are allowed once per second - if (get_elapsed_time(mLastAction) >= 1000) + // Actions are allowed at 5.5 per second + if (get_elapsed_time(mLastAction) >= 182) mLastAction = -1; // Show XP messages @@ -151,16 +114,12 @@ void LocalPlayer::logic() { if (mMessageTime == 0) { - //const Vector &pos = getPosition(); - MessagePair info = mMessages.front(); particleEngine->addTextRiseFadeOutEffect( info.first, - /*(int) pos.x, - (int) pos.y - 48,*/ getPixelX(), - getPixelY() - 48, + getPixelY() - 32 - 16, &userPalette->getColor(info.second), gui->getInfoParticleFont(), true); @@ -170,21 +129,7 @@ void LocalPlayer::logic() mMessageTime--; } - if ((mSpecialRechargeUpdateNeeded%11) == 0) - { - mSpecialRechargeUpdateNeeded = 0; - for (std::map<int, Special>::iterator i = mSpecials.begin(); - i != mSpecials.end(); - i++) - { - i->second.currentMana += i->second.recharge; - if (i->second.currentMana > i->second.neededMana) - { - i->second.currentMana = i->second.neededMana; - } - } - } - mSpecialRechargeUpdateNeeded++; + PlayerInfo::logic(); // Targeting allowed 4 times a second if (get_elapsed_time(mLastTarget) >= 250) @@ -200,30 +145,22 @@ void LocalPlayer::logic() if (mTarget) { - if (mTarget->getType() == Being::NPC) + if (mTarget->getType() == ActorSprite::NPC) { // NPCs are always in range - mTarget->setTargetAnimation( - mTargetCursor[0][mTarget->getTargetCursorSize()]); + mTarget->setTargetType(TCT_IN_RANGE); } else { // Find whether target is in range - // TODO: Make this nicer, probably using getPosition() only - const int rangeX = - (Net::getNetworkType() == ServerInfo::MANASERV) ? - abs(mTarget->getPosition().x - getPosition().x) : - abs(mTarget->getTileX() - getTileX()); - const int rangeY = - (Net::getNetworkType() == ServerInfo::MANASERV) ? - abs(mTarget->getPosition().y - getPosition().y) : - abs(mTarget->getTileY() - getTileY()); + const int rangeX = abs(mTarget->getPosition().x - getPosition().x); + const int rangeY = abs(mTarget->getPosition().y - getPosition().y); const int attackRange = getAttackRange(); - const int inRange = rangeX > attackRange || rangeY > attackRange - ? 1 : 0; - mTarget->setTargetAnimation( - mTargetCursor[inRange][mTarget->getTargetCursorSize()]); + const TargetCursorType targetType = rangeX > attackRange || + rangeY > attackRange ? + TCT_NORMAL : TCT_IN_RANGE; + mTarget->setTargetType(targetType); if (!mTarget->isAlive()) stopAttack(); @@ -233,10 +170,10 @@ void LocalPlayer::logic() } } - Player::logic(); + Being::logic(); } -void LocalPlayer::setAction(Action action, int attackType) +void LocalPlayer::setAction(Action action, int attackId) { if (action == DEAD) { @@ -244,12 +181,7 @@ void LocalPlayer::setAction(Action action, int attackType) setTarget(NULL); } - Player::setAction(action, attackType); -} - -void LocalPlayer::setGM(bool gm) -{ - mIsGM = gm; + Being::setAction(action, attackId); } void LocalPlayer::setGMLevel(int level) @@ -281,11 +213,14 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) if (!mMap || (!dx && !dy)) return Position((int)pos.x, (int)pos.y); + const int tileW = mMap->getTileWidth(); + const int tileH = mMap->getTileHeight(); + // Get the current tile pos and its offset - int tileX = (int)pos.x / mMap->getTileWidth(); - int tileY = (int)pos.y / mMap->getTileHeight(); - int offsetX = (int)pos.x % mMap->getTileWidth(); - int offsetY = (int)pos.y % mMap->getTileHeight(); + const int tileX = (int)pos.x / tileW; + const int tileY = (int)pos.y / tileH; + int offsetX = (int)pos.x % tileW; + int offsetY = (int)pos.y % tileH; // Get the walkability of every surrounding tiles. bool wTopLeft = mMap->getWalk(tileX - 1, tileY - 1, getWalkMask()); @@ -330,14 +265,14 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else if (wTop && !wRight) dx = 0; else if (!wTop && !wRight) - return Position(tileX * 32 + 32 - getCollisionRadius(), - tileY * 32 + getCollisionRadius()); + return Position(tileX * tileW + tileW + - getCollisionRadius(), + tileY * tileH + getCollisionRadius()); else // Both straight direction are walkable { // Go right when below the corner - if (offsetY >= (offsetX / mMap->getTileHeight() - - (offsetX / mMap->getTileWidth() - * mMap->getTileHeight()) )) + if (offsetY >= + (offsetX / tileH - (offsetX / tileW * tileH))) dy = 0; else // Go up otherwise dx = 0; @@ -346,7 +281,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else // The diagonal is walkable return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x + 32, (int)pos.y - 32)); + Position((int)pos.x + tileW, + (int)pos.y - tileH)); } // Going top-left @@ -360,8 +296,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else if (wTop && !wLeft) dx = 0; else if (!wTop && !wLeft) - return Position(tileX * 32 + getCollisionRadius(), - tileY * 32 + getCollisionRadius()); + return Position(tileX * tileW + getCollisionRadius(), + tileY * tileH + getCollisionRadius()); else // Both straight direction are walkable { // Go left when below the corner @@ -375,7 +311,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else // The diagonal is walkable return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x - 32, (int)pos.y - 32)); + Position((int)pos.x - tileW, + (int)pos.y - tileH)); } // Going bottom-left @@ -389,8 +326,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else if (wBottom && !wLeft) dx = 0; else if (!wBottom && !wLeft) - return Position(tileX * 32 + getCollisionRadius(), - tileY * 32 + 32 - getCollisionRadius()); + return Position(tileX * tileW + getCollisionRadius(), + tileY * tileH + tileH - getCollisionRadius()); else // Both straight direction are walkable { // Go down when below the corner @@ -405,7 +342,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else // The diagonal is walkable return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x - 32, (int)pos.y + 32)); + Position((int)pos.x - tileW, + (int)pos.y + tileH)); } // Going bottom-right @@ -419,8 +357,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else if (wBottom && !wRight) dx = 0; else if (!wBottom && !wRight) - return Position(tileX * 32 + 32 - getCollisionRadius(), - tileY * 32 + 32 - getCollisionRadius()); + return Position(tileX * tileW + tileW - getCollisionRadius(), + tileY * tileH + tileH - getCollisionRadius()); else // Both straight direction are walkable { // Go down when below the corner @@ -434,7 +372,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) else // The diagonal is walkable return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x + 32, (int)pos.y + 32)); + Position((int)pos.x + tileW, + (int)pos.y + tileH)); } } // End of diagonal cases @@ -446,7 +385,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) // If the straight destination is blocked, // Make the player go the closest possible. if (!wRight) - return Position(tileX * 32 + 32 - getCollisionRadius(), (int)pos.y); + return Position(tileX * tileW + tileW - getCollisionRadius(), + (int)pos.y); else { if (!wTopRight) @@ -456,8 +396,9 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + 32 - getCollisionRadius(), - tileY * 32 + getCollisionRadius()); + return Position(tileX * tileW + + tileW - getCollisionRadius(), + tileY * tileH + getCollisionRadius()); } } @@ -465,18 +406,21 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) if (!wBottomRight) { // If we're going to collide with the bottom-right corner - if (offsetY + getCollisionRadius() > 32) + if (offsetY + getCollisionRadius() > tileH) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + 32 - getCollisionRadius(), - tileY * 32 + 32 - getCollisionRadius()); + return Position(tileX * tileW + + tileW - getCollisionRadius(), + tileY * tileH + + tileH - getCollisionRadius()); } } // If the way is clear, step up one checked tile ahead. return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x + 32, (int)pos.y)); + Position((int)pos.x + tileW, + (int)pos.y)); } } @@ -486,7 +430,7 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) // If the straight destination is blocked, // Make the player go the closest possible. if (!wLeft) - return Position(tileX * 32 + getCollisionRadius(), (int)pos.y); + return Position(tileX * tileW + getCollisionRadius(), (int)pos.y); else { if (!wTopLeft) @@ -496,8 +440,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + getCollisionRadius(), - tileY * 32 + getCollisionRadius()); + return Position(tileX * tileW + getCollisionRadius(), + tileY * tileH + getCollisionRadius()); } } @@ -505,18 +449,20 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) if (!wBottomLeft) { // If we're going to collide with the bottom-left corner - if (offsetY + getCollisionRadius() > 32) + if (offsetY + getCollisionRadius() > tileH) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + getCollisionRadius(), - tileY * 32 + 32 - getCollisionRadius()); + return Position(tileX * tileW + getCollisionRadius(), + tileY * tileH + + tileH - getCollisionRadius()); } } // If the way is clear, step up one checked tile ahead. return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x - 32, (int)pos.y)); + Position((int)pos.x - tileW, + (int)pos.y)); } } @@ -526,7 +472,7 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) // If the straight destination is blocked, // Make the player go the closest possible. if (!wTop) - return Position((int)pos.x, tileY * 32 + getCollisionRadius()); + return Position((int)pos.x, tileY * tileH + getCollisionRadius()); else { if (!wTopLeft) @@ -536,8 +482,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + getCollisionRadius(), - tileY * 32 + getCollisionRadius()); + return Position(tileX * tileW + getCollisionRadius(), + tileY * tileH + getCollisionRadius()); } } @@ -545,18 +491,20 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) if (!wTopRight) { // If we're going to collide with the top-right corner - if (offsetX + getCollisionRadius() > 32) + if (offsetX + getCollisionRadius() > tileW) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + 32 - getCollisionRadius(), - tileY * 32 + getCollisionRadius()); + return Position(tileX * tileW + + tileW - getCollisionRadius(), + tileY * tileH + getCollisionRadius()); } } // If the way is clear, step up one checked tile ahead. return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x, (int)pos.y - 32)); + Position((int)pos.x, + (int)pos.y - tileH)); } } @@ -566,7 +514,8 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) // If the straight destination is blocked, // Make the player go the closest possible. if (!wBottom) - return Position((int)pos.x, tileY * 32 + 32 - getCollisionRadius()); + return Position((int)pos.x, tileY * tileH + + tileH - getCollisionRadius()); else { if (!wBottomLeft) @@ -576,27 +525,30 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + getCollisionRadius(), - tileY * 32 + 32 - getCollisionRadius()); - + return Position(tileX * tileW + getCollisionRadius(), + tileY * tileH + + tileH - getCollisionRadius()); } } if (!wBottomRight) { // If we're going to collide with the bottom-right corner - if (offsetX + getCollisionRadius() > 32) + if (offsetX + getCollisionRadius() > tileW) { // We make the player corrects its offset // before going further - return Position(tileX * 32 + 32 - getCollisionRadius(), - tileY * 32 + 32 - getCollisionRadius()); + return Position(tileX * tileW + + tileW - getCollisionRadius(), + tileY * tileH + + tileH - getCollisionRadius()); } } // If the way is clear, step up one checked tile ahead. return mMap->checkNodeOffsets(getCollisionRadius(), getWalkMask(), - Position((int)pos.x, (int)pos.y + 32)); + Position((int)pos.x, + (int)pos.y + tileH)); } } @@ -606,56 +558,22 @@ Position LocalPlayer::getNextWalkPosition(unsigned char dir) void LocalPlayer::nextTile(unsigned char dir = 0) { - if (Net::getNetworkType() == ServerInfo::TMWATHENA) - { - // 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) - pickUp(mPickUpTarget); - - if (mWalkingDir) - startWalking(mWalkingDir); - } - - // TODO: Fix automatically walking within range of target, when wanted - if (mGoingToTarget && mTarget && withinAttackRange(mTarget)) - { - mAction = Being::STAND; - attack(mTarget, true); - mGoingToTarget = false; - mPath.clear(); - return; - } - else if (mGoingToTarget && !mTarget) - { - mGoingToTarget = false; - mPath.clear(); - } + if (!mMap || !dir) + return; + const Vector &pos = getPosition(); + Position destination = getNextWalkPosition(dir); - Player::nextTile(); + if ((int)pos.x != destination.x + || (int)pos.y != destination.y) + { + setDestination(destination.x, destination.y); } - else + else if (dir != mDirection) { - if (!mMap || !dir) - return; - - const Vector &pos = getPosition(); - Position destination = getNextWalkPosition(dir); - - if ((int)pos.x != destination.x - || (int)pos.y != destination.y) - { - setDestination(destination.x, destination.y); - } - else if (dir != mDirection) - { - // If the being can't move, just change direction - Net::getPlayerHandler()->setDirection(dir); - setDirection(dir); - } + // If the being can't move, just change direction + Net::getPlayerHandler()->setDirection(dir); + setDirection(dir); } } @@ -674,7 +592,6 @@ void LocalPlayer::inviteToGuild(Being *being) { if (being->getType() != PLAYER) return; - Player *player = static_cast<Player*>(being); // TODO: Allow user to choose which guild to invite being to // For now, just invite to the first guild you have permissions to invite with @@ -684,31 +601,21 @@ void LocalPlayer::inviteToGuild(Being *being) { if (checkInviteRights(itr->second->getName())) { - Net::getGuildHandler()->invite(itr->second->getId(), player); + Net::getGuildHandler()->invite(itr->second->getId(), being); return; } } } -void LocalPlayer::clearInventory() -{ - mEquipment->clear(); - mInventory->clear(); -} - -void LocalPlayer::setInvItem(int index, int id, int amount) -{ - bool equipment = false; - int itemType = ItemDB::get(id).getType(); - if (itemType != ITEM_UNUSABLE && itemType != ITEM_USABLE) - equipment = true; - mInventory->setItem(index, id, amount, equipment); -} - void LocalPlayer::pickUp(FloorItem *item) { - int dx = item->getX() - getTileX(); - int dy = item->getY() - getTileY(); + if (!item) + return; + + int tileWidth = mMap->getTileWidth(); + int tileHeight = mMap->getTileHeight(); + int dx = item->getTileX() - (int) getPosition().x / tileWidth; + int dy = item->getTileY() - ((int) getPosition().y - 1) / tileHeight; if (dx * dx + dy * dy < 4) { @@ -717,17 +624,9 @@ void LocalPlayer::pickUp(FloorItem *item) } else { - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); - mPickUpTarget = item; - } - else - { - setDestination(item->getX(), item->getY()); - mPickUpTarget = item; - stopAttack(); - } + setDestination(item->getTileX() * tileWidth + tileWidth / 2, + item->getTileY() * tileHeight + tileHeight / 2); + mPickUpTarget = item; } } @@ -757,31 +656,63 @@ void LocalPlayer::setTarget(Being *target) mTargetTime = -1; } + Being *oldTarget = 0; if (mTarget) + { mTarget->untarget(); + oldTarget = mTarget; + } - if (mTarget && mTarget->getType() == Being::MONSTER) + if (mTarget && mTarget->getType() == ActorSprite::MONSTER) mTarget->setShowName(false); mTarget = target; - if (target && target->getType() == Being::MONSTER) + if (oldTarget) + oldTarget->updateName(); + if (mTarget) + mTarget->updateName(); + + if (target && target->getType() == ActorSprite::MONSTER) target->setShowName(true); } void LocalPlayer::setDestination(int x, int y) { + int srcX = x; + int srcY = y; + int dstX = (int)mDest.x; + int dstY = (int)mDest.y; + int tileWidth = mMap->getTileWidth(); + int tileHeight = mMap->getTileHeight(); + if (!Net::getPlayerHandler()->usePixelPrecision()) + { + // For tile-based clients, we accept positions on the same tile. + srcX = srcX / tileWidth; + srcY = srcY / tileHeight; + dstX = dstX / tileWidth; + dstY = dstY / tileHeight; + } + // Only send a new message to the server when destination changes - if (x != mDest.x || y != mDest.y) + if (srcX != dstX || srcY != dstY) { Being::setDestination(x, y); + // Note: Being::setDestination() updates mDest, so we get the new + // destination. + dstX = (int)mDest.x; + dstY = (int)mDest.y; + + if (!Net::getPlayerHandler()->usePixelPrecision()) + { + dstX = dstX / tileWidth; + dstY = dstY / tileHeight; + } - // Manaserv: // If the destination given to being class is accepted, // we inform the Server. - if ((x == mDest.x && y == mDest.y) - || Net::getNetworkType() == ServerInfo::TMWATHENA) - Net::getPlayerHandler()->setDestination(x, y, mDirection); + if (srcX == dstX && srcY == dstY) + Net::getPlayerHandler()->setDestination(x, y, mDirection); } mPickUpTarget = NULL; @@ -792,41 +723,35 @@ void LocalPlayer::setWalkingDir(int dir) { // This function is called by Game::handleInput() - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - // First if player is pressing key for the direction he is already - // going, do nothing more... - - // Else if he is pressing a key, and its different from what he has - // been pressing, stop (do not send this stop to the server) and - // start in the new direction - if (dir && (dir != getWalkingDir())) - player_node->stopWalking(false); - - // Else, he is not pressing a key, - // and the current path hasn't been sent by mouse, - // then, stop (sending to server). - else if (!dir) - { - if (!mPathSetByMouse) - player_node->stopWalking(true); - return; - } + // First if player is pressing key for the direction he is already + // going, do nothing more... - // If the delay to send another walk message to the server hasn't expired, - // don't do anything or we could get disconnected for spamming the server - if (get_elapsed_time(mLocalWalkTime) < walkingKeyboardDelay) - return; - } + // Else if he is pressing a key, and its different from what he has + // been pressing, stop (do not send this stop to the server) and + // start in the new direction + if (dir && (dir != getWalkingDir())) + player_node->stopWalking(false); + + // Else, he is not pressing a key, + // and the current path hasn't been sent by mouse, + // then let the path die (1/2 tile after that.) + // This permit to avoid desyncs with other clients. + else if (!dir) + return; + + // If the delay to send another walk message to the server hasn't expired, + // don't do anything or we could get disconnected for spamming the server + if (get_elapsed_time(mLocalWalkTime) < walkingKeyboardDelay) + return; mWalkingDir = dir; // If we're not already walking, start walking. - if (mAction != WALK && dir) + if (mAction != MOVE && dir) { startWalking(dir); } - else if (mAction == WALK && (Net::getNetworkType() == ServerInfo::MANASERV)) + else if (mAction == MOVE) { nextTile(dir); } @@ -839,16 +764,11 @@ void LocalPlayer::startWalking(unsigned char dir) if (!mMap || !dir) return; - if (mAction == WALK && !mPath.empty()) + if (mAction == MOVE && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - const Vector &pos = getPosition(); - Being::setDestination(pos.x, pos.y); - } - else - Being::setDestination(getTileX(), getTileY()); + const Vector &pos = getPosition(); + Being::setDestination(pos.x, pos.y); return; } @@ -862,39 +782,15 @@ void LocalPlayer::startWalking(unsigned char dir) if (dir & RIGHT) dx++; - if (Net::getNetworkType() == ServerInfo::TMWATHENA) - { - // Prevent skipping corners over colliding tiles - if (dx && !mMap->getWalk(getTileX() + dx, getTileY(), getWalkMask())) - dx = 0; - if (dy && !mMap->getWalk(getTileX(), getTileY() + dy, getWalkMask())) - dy = 0; - - // Choose a straight direction when diagonal target is blocked - 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); - } - else if (dir != mDirection) - { - // If the being can't move, just change direction - Net::getPlayerHandler()->setDirection(dir); - setDirection(dir); - } - } - else - nextTile(dir); + // Update the direction when the walk just start + setDirection(dir); + + nextTile(dir); } void LocalPlayer::stopWalking(bool sendToServer) { - if (mAction == WALK && mWalkingDir) + if (mAction == MOVE && mWalkingDir) { mWalkingDir = 0; mLocalWalkTime = 0; @@ -938,97 +834,55 @@ void LocalPlayer::emote(Uint8 emotion) Net::getPlayerHandler()->emote(emotion); } -void LocalPlayer::useSpecial(int special) -{ - Net::getSpecialHandler()->use(special); -} - -void LocalPlayer::setSpecialStatus(int id, int current, int max, int recharge) -{ - logger->log("SpecialUpdate Skill #%d -- (%d/%d) -> %d", id, current, max, - recharge); - mSpecials[id].currentMana = current; - mSpecials[id].neededMana = max; - mSpecials[id].recharge = recharge; -} - void LocalPlayer::attack(Being *target, bool keep) { - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - if (mLastAction != -1) - return; + if (mLastAction != -1) + return; - // Can only attack when standing still - if (mAction != STAND && mAction != ATTACK) - return; - } + // Can only attack when standing still + if (mAction != STAND && mAction != ATTACK) + return; - mKeepAttacking = keep; + if (!target || target->getType() == ActorSprite::NPC) + return; - if (!target || target->getType() == Being::NPC) + // Can't attack more times than its attack speed + static int lastAttackTime = 0; + if (get_elapsed_time(lastAttackTime) < mAttackSpeed) return; + lastAttackTime = tick_time; + + mKeepAttacking = keep; + if (mTarget != target || !mTarget) { mLastTarget = -1; setTarget(target); } - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - Vector plaPos = this->getPosition(); - Vector tarPos = mTarget->getPosition(); - int dist_x = plaPos.x - tarPos.x; - int dist_y = plaPos.y - tarPos.y; - if (abs(dist_y) >= abs(dist_x)) - { - if (dist_y < 0) - setDirection(DOWN); - else - setDirection(UP); - } - else - { - if (dist_x < 0) - setDirection(RIGHT); - else - setDirection(LEFT); - } + Vector plaPos = this->getPosition(); + Vector tarPos = mTarget->getPosition(); + int dist_x = plaPos.x - tarPos.x; + int dist_y = plaPos.y - tarPos.y; - mLastAction = tick_time; + if (abs(dist_y) >= abs(dist_x)) + { + if (dist_y < 0) + setDirection(DOWN); + else + setDirection(UP); } else { - int dist_x = target->getTileX() - getTileX(); - int dist_y = target->getTileY() - getTileY(); - - // Must be standing to attack - if (mAction != STAND) - return; - - Uint8 direction = 0; - if (abs(dist_y) >= abs(dist_x)) - { - if (dist_y > 0) - direction = DOWN; - else - direction = UP; - } + if (dist_x < 0) + setDirection(RIGHT); else - { - if (dist_x > 0) - direction = RIGHT; - else - direction = LEFT; - } - Net::getPlayerHandler()->setDirection(direction); - setDirection(direction); - - mWalkTime = tick_time; - mTargetTime = tick_time; + setDirection(LEFT); } + mLastAction = tick_time; + setAction(ATTACK); if (mEquippedWeapon) @@ -1038,11 +892,11 @@ void LocalPlayer::attack(Being *target, bool keep) sound.playSfx(soundFile); } else + { sound.playSfx(paths.getValue("attackSfxFile", "fist-swish.ogg")); + } Net::getPlayerHandler()->attack(target->getId()); - if ((Net::getNetworkType() == ServerInfo::TMWATHENA) && !keep) - stopAttack(); } void LocalPlayer::stopAttack() @@ -1056,190 +910,6 @@ void LocalPlayer::stopAttack() mLastTarget = -1; } -void LocalPlayer::raiseAttribute(int attr) -{ - // we assume that the server allows the change. - // When not we will undo it later. - mCharacterPoints--; - IntMap::iterator it = mAttributeBase.find(attr); - if (it != mAttributeBase.end()) - (*it).second++; - Net::getPlayerHandler()->increaseAttribute(attr); -} - -void LocalPlayer::lowerAttribute(int attr) -{ - // we assume that the server allows the change. - // When not we will undo it later. - mCorrectionPoints--; - mCharacterPoints++; - IntMap::iterator it = mAttributeBase.find(attr); - if (it != mAttributeBase.end()) - (*it).second--; - Net::getPlayerHandler()->decreaseAttribute(attr); -} - -void LocalPlayer::setTotalWeight(int value) -{ - mTotalWeight = value; - - inventoryWindow->updateWeight(); -} - -void LocalPlayer::setMaxWeight(int value) -{ - mMaxWeight = value; - - if (inventoryWindow) - inventoryWindow->updateWeight(); -} - -void LocalPlayer::setAttributeBase(int num, int value, bool notify) -{ - int old = mAttributeBase[num]; - - mAttributeBase[num] = value; - if (skillDialog) - { - if (skillDialog->update(num).empty() || !(value > old)) - return; - - if (old != 0 && notify) - effectManager->trigger(1, this); - } - - if (statusWindow) - statusWindow->update(num); -} - -void LocalPlayer::setAttributeEffective(int num, int value) -{ - mAttributeEffective[num] = value; - if (skillDialog) - skillDialog->update(num); - - if (statusWindow) - statusWindow->update(num); -} - -void LocalPlayer::setCharacterPoints(int n) -{ - mCharacterPoints = n; - - if (statusWindow) - statusWindow->update(StatusWindow::CHAR_POINTS); -} - -void LocalPlayer::setCorrectionPoints(int n) -{ - mCorrectionPoints = n; - - if (statusWindow) - statusWindow->update(StatusWindow::CHAR_POINTS); -} - -void LocalPlayer::setSkillPoints(int points) -{ - mSkillPoints = points; - if (skillDialog) - skillDialog->update(); -} - -void LocalPlayer::setExperience(int skill, int current, int next, bool notify) -{ - std::pair<int, int> cur = getExperience(skill); - int diff = current - cur.first; - - cur = std::pair<int, int>(current, next); - - mSkillExp[skill] = cur; - - std::string name; - if (skillDialog) - name = skillDialog->update(skill); - - if (mMap && notify && cur.first != -1 && diff > 0 && !name.empty()) - { - addMessageToQueue(strprintf("%d %s xp", diff, name.c_str())); - } - - if (statusWindow) - statusWindow->update(skill); -} - -std::pair<int, int> LocalPlayer::getExperience(int skill) -{ - return mSkillExp[skill]; -} - -void LocalPlayer::setHp(int value) -{ - mHp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::HP); -} - -void LocalPlayer::setMaxHp(int value) -{ - mMaxHp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::HP); -} - -void LocalPlayer::setLevel(int value) -{ - mLevel = value; - - if (statusWindow) - statusWindow->update(StatusWindow::LEVEL); -} - -void LocalPlayer::setExp(int value, bool notify) -{ - if (mMap && notify && value > mExp) - { - addMessageToQueue(toString(value - mExp) + " xp"); - } - mExp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::EXP); -} - -void LocalPlayer::setExpNeeded(int value) -{ - mExpNeeded = value; - - if (statusWindow) - statusWindow->update(StatusWindow::EXP); -} - -void LocalPlayer::setMP(int value) -{ - mMp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::MP); -} - -void LocalPlayer::setMaxMP(int value) -{ - mMaxMp = value; - - if (statusWindow) - statusWindow->update(StatusWindow::MP); -} - -void LocalPlayer::setMoney(int value) -{ - mMoney = value; - - if (statusWindow) - statusWindow->update(StatusWindow::MONEY); -} - void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, unsigned char fail) { @@ -1260,9 +930,9 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, } if (config.getValue("showpickupchat", 1)) { - localChatTab->chatLog(_(msg), BY_SERVER); + SERVER_NOTICE(_(msg)) } - if (mMap && config.getValue("showpickupparticle", 0)) + if (mMap && config.getBoolValue("showpickupparticle")) { // Show pickup notification addMessageToQueue(_(msg), UserPalette::PICKUP_INFO); @@ -1270,17 +940,16 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, } else { - if (config.getValue("showpickupchat", 1)) + if (config.getBoolValue("showpickupchat")) { // TRANSLATORS: This sentence may be translated differently // for different grammatical numbers (singular, plural, ...) - localChatTab->chatLog(strprintf(ngettext("You picked up %d " + SERVER_NOTICE(strprintf(ngettext("You picked up %d " "[@@%d|%s@@].", "You picked up %d [@@%d|%s@@].", amount), - amount, itemInfo.getId(), itemInfo.getName().c_str()), - BY_SERVER); + amount, itemInfo.getId(), itemInfo.getName().c_str())) } - if (mMap && config.getValue("showpickupparticle", 0)) + if (mMap && config.getBoolValue("showpickupparticle")) { // Show pickup notification std::string msg = ""; @@ -1292,162 +961,91 @@ void LocalPlayer::pickedUp(const ItemInfo &itemInfo, int amount, } } -int LocalPlayer::getAttackRange() +void LocalPlayer::setAttackRange(int range) { - if (mAttackRange > -1) + // When the range is more than the minimal, we accept it + if (range > ATTACK_RANGE_NOT_SET) { - return mAttackRange; + mAttackRange = range; } - else + else if (Net::getNetworkType() == ServerInfo::TMWATHENA) { - Item *weapon = mEquipment->getEquipment(EQUIP_FIGHT1_SLOT); + // TODO: Fix this to be more generic + Item *weapon = PlayerInfo::getEquipment(TmwAthena::EQUIP_FIGHT1_SLOT); if (weapon) { const ItemInfo info = weapon->getInfo(); - return info.getAttackRange(); + if (info.getAttackRange() > ATTACK_RANGE_NOT_SET) + mAttackRange = info.getAttackRange(); } - return 48; // unarmed range } } bool LocalPlayer::withinAttackRange(Being *target) { - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - const Vector &targetPos = target->getPosition(); - const Vector &pos = getPosition(); - const int dx = abs(targetPos.x - pos.x); - const int dy = abs(targetPos.y - pos.y); - const int range = getAttackRange(); + const Vector &targetPos = target->getPosition(); + const Vector &pos = getPosition(); + const int dx = abs(targetPos.x - pos.x); + const int dy = abs(targetPos.y - pos.y); + const int range = getAttackRange(); - return !(dx > range || dy > range); - } - else - { - int dist_x = abs(target->getTileX() - getTileX()); - int dist_y = abs(target->getTileY() - getTileY()); - - if (dist_x > getAttackRange() || dist_y > getAttackRange()) - return false; - - return true; - } + return !(dx > range || dy > range); } void LocalPlayer::setGotoTarget(Being *target) { mLastTarget = -1; - if (Net::getNetworkType() == ServerInfo::MANASERV) - { - mTarget = target; - mGoingToTarget = true; - const Vector &targetPos = target->getPosition(); - setDestination(targetPos.x, targetPos.y); - } - else - { - setTarget(target); - mGoingToTarget = true; - setDestination(target->getTileX(), target->getTileY()); - } -} -extern MiniStatusWindow *miniStatusWindow; + mTarget = target; + mGoingToTarget = true; + const Vector &targetPos = target->getPosition(); + setDestination(targetPos.x, targetPos.y); +} -void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId) +void LocalPlayer::addMessageToQueue(const std::string &message, int color) { - Being::handleStatusEffect(effect, effectId); + mMessages.push_back(MessagePair(message, color)); +} - if (effect) +void LocalPlayer::event(Event::Channel channel, const Event &event) +{ + if (channel == Event::ActorSpriteChannel) { - effect->deliverMessage(); - effect->playSFX(); + if (event.getType() == Event::Destroyed) + { + ActorSprite *actor = event.getActor("source"); - AnimatedSprite *sprite = effect->getIcon(); + if (mPickUpTarget == actor) + mPickUpTarget = 0; - if (!sprite) - { - // delete sprite, if necessary - for (unsigned int i = 0; i < mStatusEffectIcons.size();) - if (mStatusEffectIcons[i] == effectId) - { - mStatusEffectIcons.erase(mStatusEffectIcons.begin() + i); - miniStatusWindow->eraseIcon(i); - } - else - i++; + if (mTarget == actor) + mTarget = 0; } - else + } + else if (channel == Event::AttributesChannel) + { + if (event.getType() == Event::UpdateAttribute) { - // replace sprite or append - bool found = false; - - for (unsigned int i = 0; i < mStatusEffectIcons.size(); i++) - if (mStatusEffectIcons[i] == effectId) - { - miniStatusWindow->setIcon(i, sprite); - found = true; - break; - } + if (event.getInt("id") == EXP) + { + int change = event.getInt("newValue") + - event.getInt("oldValue"); - if (!found) - { // add new - int offset = mStatusEffectIcons.size(); - miniStatusWindow->setIcon(offset, sprite); - mStatusEffectIcons.push_back(effectId); + addMessageToQueue(toString(change) + " xp"); } } } -} - -void LocalPlayer::initTargetCursor() -{ - // Load target cursors - loadTargetCursor("target-cursor-blue-s.png", 44, 35, false, TC_SMALL); - loadTargetCursor("target-cursor-red-s.png", 44, 35, true, TC_SMALL); - loadTargetCursor("target-cursor-blue-m.png", 62, 44, false, TC_MEDIUM); - loadTargetCursor("target-cursor-red-m.png", 62, 44, true, TC_MEDIUM); - loadTargetCursor("target-cursor-blue-l.png", 82, 60, false, TC_LARGE); - loadTargetCursor("target-cursor-red-l.png", 82, 60, true, TC_LARGE); -} - -void LocalPlayer::loadTargetCursor(const std::string &filename, - int width, int height, - bool outRange, TargetCursorSize size) -{ - assert(size > -1); - assert(size < 3); - - ImageSet *currentImageSet = Theme::getImageSetFromTheme(filename, - width, height); - Animation *anim = new Animation; - - for (unsigned int i = 0; i < currentImageSet->size(); ++i) + else if (channel == Event::ConfigChannel) { - anim->addFrame(currentImageSet->get(i), 75, - (16 - (currentImageSet->getWidth() / 2)), - (16 - (currentImageSet->getHeight() / 2))); - } - - SimpleAnimation *currentCursor = new SimpleAnimation(anim); - - const int index = outRange ? 1 : 0; - - mTargetCursorImages[index][size] = currentImageSet; - mTargetCursor[index][size] = currentCursor; -} - -void LocalPlayer::addMessageToQueue(const std::string &message, int color) -{ - mMessages.push_back(MessagePair(message, color)); -} + if (event.getType() == Event::ConfigOptionChanged && + event.getString("option") == "showownname") + { + setShowName(config.getValue("showownname", 1)); + } -void LocalPlayer::optionChanged(const std::string &value) -{ - if (value == "showownname") - { - setShowName(config.getValue("showownname", 1)); } + + Being::event(channel, event); } void LocalPlayer::changeAwayMode() |