diff options
Diffstat (limited to 'src/localplayer.cpp')
-rw-r--r-- | src/localplayer.cpp | 700 |
1 files changed, 648 insertions, 52 deletions
diff --git a/src/localplayer.cpp b/src/localplayer.cpp index ffb4aac9..21ee3a22 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -1,57 +1,77 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 2004 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 + * This program 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, + * This program 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 + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <cassert> -#include "localplayer.h" - +#include "configuration.h" #include "equipment.h" #include "floor_item.h" #include "game.h" -#include "guild.h" +#include "graphics.h" #include "inventory.h" #include "item.h" -#include "main.h" +#include "localplayer.h" +#include "map.h" +#include "monster.h" #include "particle.h" +#include "simpleanimation.h" #include "sound.h" -#include "log.h" +#include "statuseffect.h" +#include "text.h" + +#include "gui/gui.h" +#include "gui/ministatus.h" + +#ifdef TMWSERV_SUPPORT #include "effectmanager.h" +#include "guild.h" #include "net/gameserver/player.h" #include "net/chatserver/guild.h" #include "net/chatserver/party.h" +#endif -#include "gui/gui.h" - +#ifdef EATHENA_SUPPORT #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" +#endif + +#include "resources/animation.h" +#include "resources/imageset.h" +#include "resources/resourcemanager.h" -#include "utils/tostring.h" #include "utils/gettext.h" +#include "utils/stringutils.h" +#ifdef TMWSERV_SUPPORT const short walkingKeyboardDelay = 100; +#endif LocalPlayer *player_node = NULL; +static const int NAME_X_OFFSET = 15; +static const int NAME_Y_OFFSET = 30; + +#ifdef TMWSERV_SUPPORT LocalPlayer::LocalPlayer(): Player(65535, 0, NULL), - mInventory(new Inventory), mEquipment(new Equipment), mAttributeBase(NB_CHARACTER_ATTRIBUTES, -1), mAttributeEffective(NB_CHARACTER_ATTRIBUTES, -1), @@ -59,32 +79,114 @@ LocalPlayer::LocalPlayer(): mExpNext(CHAR_SKILL_NB, -1), mCharacterPoints(-1), mCorrectionPoints(-1), - mLevel(1), mLevelProgress(0), + mLevelProgress(0), +#else +LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): + Player(id, job, map), + mCharId(0), + mJobXp(0), + mJobLevel(0), + mXpForNextLevel(0), mJobXpForNextLevel(0), + mMp(0), mMaxMp(0), + mAttackRange(0), + ATK(0), MATK(0), DEF(0), MDEF(0), HIT(0), FLEE(0), + ATK_BONUS(0), MATK_BONUS(0), DEF_BONUS(0), MDEF_BONUS(0), FLEE_BONUS(0), + mStatPoint(0), mSkillPoint(0), + mStatsPointsToAttribute(0), + mEquipment(new Equipment), + mNetwork(0), + mXp(0), + mInStorage(false), + mTargetTime(-1), + mLastTarget(-1), +#endif + mLevel(1), mMoney(0), mTotalWeight(1), mMaxWeight(1), - mHP(1), mMaxHP(1), + mHp(1), mMaxHp(1), mTarget(NULL), mPickUpTarget(NULL), mTrading(false), mGoingToTarget(false), mLastAction(-1), mWalkingDir(0), mDestX(0), mDestY(0), +#ifdef TMWSERV_SUPPORT mLocalWalkTime(-1), - mExpMessageTime(0) +#endif + mInventory(new Inventory(INVENTORY_SIZE)) +#ifdef EATHENA_SUPPORT + , mStorage(new Inventory(STORAGE_SIZE)) +#else + , mExpMessageTime(0) +#endif { + // Variable to keep the local player from doing certain actions before a map + // is initialized. e.g. drawing a player's name using the TextManager, since + // it appears to be dependant upon map coordinates for updating drawing. + mMapInitialized = false; + + mUpdateName = true; + + initTargetCursor(); } LocalPlayer::~LocalPlayer() { delete mInventory; +#ifdef EATHENA_SUPPORT + delete mStorage; +#endif + + 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(); + } } void LocalPlayer::logic() { +#ifdef EATHENA_SUPPORT + switch (mAction) { + case STAND: + break; + + case SIT: + break; + + case DEAD: + break; + + case HURT: + break; + + case WALK: + mFrame = (get_elapsed_time(mWalkTime) * 6) / getWalkSpeed(); + if (mFrame >= 6) + nextStep(); + break; + + case ATTACK: + int frames = 4; + if (mEquippedWeapon && + mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW) + frames = 5; + + mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed; + + if (mFrame >= frames) + nextStep(); + + break; + } +#endif + // Actions are allowed once per second - if (get_elapsed_time(mLastAction) >= 1000) { + if (get_elapsed_time(mLastAction) >= 1000) mLastAction = -1; - } +#ifdef TMWSERV_SUPPORT // Show XP messages if (!mExpMessages.empty()) { @@ -93,7 +195,7 @@ void LocalPlayer::logic() const Vector &pos = getPosition(); particleEngine->addTextRiseFadeOutEffect(mExpMessages.front(), 0, 128, 255, - speechFont, + gui->getFont(), (int) pos.x + 16, (int) pos.y - 16); mExpMessages.pop_front(); @@ -101,10 +203,63 @@ void LocalPlayer::logic() } mExpMessageTime--; } +#else + // Targeting allowed 4 times a second + if (get_elapsed_time(mLastTarget) >= 250) + mLastTarget = -1; + + // Remove target if its been on a being for more than a minute + if (get_elapsed_time(mTargetTime) >= 60000) + { + mTargetTime = -1; + setTarget(NULL); + mLastTarget = -1; + } + + if (mTarget) + { + // Find whether target is in range + const int rangeX = abs(mTarget->mX - mX); + const int rangeY = abs(mTarget->mY - mY); + const int attackRange = getAttackRange(); + const int inRange = rangeX > attackRange || rangeY > attackRange ? 1 : 0; + + mTarget->setTargetAnimation( + mTargetCursor[inRange][mTarget->getTargetCursorSize()]); + + if (mTarget->mAction == DEAD) + stopAttack(); + + if (mKeepAttacking && mTarget) + attack(mTarget, true); + } +#endif Being::logic(); } +void LocalPlayer::setGM() +{ + mIsGM = !mIsGM; + mNameColor = mIsGM ? 0x009000: 0x202020; + setName(getName()); + config.setValue(getName() + "GMassert", mIsGM); +} + +void LocalPlayer::setName(const std::string &name) +{ + if (mName) + { + delete mName; + mName = 0; + } + + if (config.getValue("showownname", false) && mMapInitialized) + Player::setName(name); + else + Being::setName(name); +} + void LocalPlayer::nextStep() { // TODO: Fix picking up when reaching target (this method is obsolete) @@ -112,21 +267,19 @@ void LocalPlayer::nextStep() if (mPath.empty()) { if (mPickUpTarget) - { pickUp(mPickUpTarget); - } if (mWalkingDir) - { walk(mWalkingDir); - } } // TODO: Fix automatically walking within range of target, when wanted if (mGoingToTarget && mTarget && withinAttackRange(mTarget)) { mAction = Being::STAND; - //attack(mTarget, true); +#ifdef EATHENA_SUPPORT + attack(mTarget, true); +#endif mGoingToTarget = false; mPath.clear(); return; @@ -136,8 +289,13 @@ void LocalPlayer::nextStep() mGoingToTarget = false; mPath.clear(); } + +#ifdef EATHENA_SUPPORT + Player::nextStep(); +#endif } +#ifdef TMWSERV_SUPPORT bool LocalPlayer::checkInviteRights(const std::string &guildName) { Guild *guild = getGuild(guildName); @@ -181,34 +339,35 @@ void LocalPlayer::setInvItem(int index, int id, int amount) mInventory->setItem(index, id, amount); } +#endif + void LocalPlayer::moveInvItem(Item *item, int newIndex) { // special case, the old and new cannot copy over each other. if (item->getInvIndex() == newIndex) return; +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::moveItem( item->getInvIndex(), newIndex, item->getQuantity()); -} - -Item* LocalPlayer::searchForItem(int itemId) -{ - for (int i = 0; i < INVENTORY_SIZE; i++) - { - if (Item *item = mInventory->getItem(i)) { - if (item->getId() == itemId) { - return item; - } - } - } - return NULL; +#endif + // TODO: eAthena support } void LocalPlayer::equipItem(Item *item) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::equip(item->getInvIndex()); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_EQUIP); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt16(0); +#endif } +#ifdef TMWSERV_SUPPORT + void LocalPlayer::unequipItem(int slot) { Net::GameServer::Player::unequip(slot); @@ -222,11 +381,46 @@ void LocalPlayer::useItem(int slot) Net::GameServer::Player::useItem(slot); } +#else + +void LocalPlayer::unequipItem(Item *item) +{ + if (!item) + return; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_UNEQUIP); + outMsg.writeInt16(item->getInvIndex()); + + // Tidy equipment directly to avoid weapon still shown bug, for instance + mEquipment->removeEquipment(item->getInvIndex()); +} + +void LocalPlayer::useItem(Item *item) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_INVENTORY_USE); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt32(item->getId()); + // Note: id is dest of item, usually player_node->account_ID ?? +} + +#endif + void LocalPlayer::dropItem(Item *item, int quantity) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::drop(item->getInvIndex(), quantity); +#else + // TODO: Fix wrong coordinates of drops, serverside? + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_INVENTORY_DROP); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt16(quantity); +#endif } +#ifdef TMWSERV_SUPPORT void LocalPlayer::splitItem(Item *item, int quantity) { int newIndex = mInventory->getFreeSlot(); @@ -236,39 +430,68 @@ void LocalPlayer::splitItem(Item *item, int quantity) item->getInvIndex(), newIndex, quantity); } } +#endif void LocalPlayer::pickUp(FloorItem *item) { +#ifdef TMWSERV_SUPPORT int dx = item->getX() - (int) getPosition().x / 32; int dy = item->getY() - (int) getPosition().y / 32; +#else + int dx = item->getX() - mX; + int dy = item->getY() - mY; +#endif - if (dx * dx + dy * dy < 4) { + if (dx * dx + dy * dy < 4) + { +#ifdef TMWSERV_SUPPORT int id = item->getId(); Net::GameServer::Player::pickUp(id >> 16, id & 0xFFFF); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_ITEM_PICKUP); + outMsg.writeInt32(item->getId()); +#endif mPickUpTarget = NULL; - } else { + } + else + { +#ifdef TMWSERV_SUPPORT setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); +#else + setDestination(item->getX(), item->getY()); +#endif mPickUpTarget = item; +#ifdef EATHENA_SUPPORT + stopAttack(); +#endif } } void LocalPlayer::walk(unsigned char dir) { - // TODO: Evaluate the implementation of this method + // TODO: Evaluate the implementation of this method for tmwserv if (!mMap || !dir) return; +#ifdef TMWSERV_SUPPORT const Vector &pos = getPosition(); int dScaler; // Distance to walk +#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(mX, mY); +#endif return; } int dx = 0, dy = 0; +#ifdef TMWSERV_SUPPORT if (dir & UP) dy -= 32; if (dir & DOWN) @@ -277,17 +500,35 @@ void LocalPlayer::walk(unsigned char dir) dx -= 32; if (dir & RIGHT) dx += 32; +#else + if (dir & UP) + dy--; + if (dir & DOWN) + dy++; + if (dir & LEFT) + dx--; + if (dir & RIGHT) + dx++; +#endif // 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(mX + dx, mY, getWalkMask())) + dx = 0; + if (dy && !mMap->getWalk(mX, mY + 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; @@ -309,16 +550,74 @@ void LocalPlayer::walk(unsigned char dir) { setDestination((int) pos.x + (dx * dScaler), (int) pos.y + (dy * dScaler)); } +#else + if (dx && dy && !mMap->getWalk(mX + dx, mY + dy, getWalkMask())) + dx = 0; + + // Walk to where the player can actually go + if ((dx || dy) && mMap->getWalk(mX + dx, mY + dy, getWalkMask())) + { + setDestination(mX + dx, mY + dy); + } +#endif else if (dir) { // If the being can't move, just change direction +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::changeDir(dir); +#else + // TODO: Communicate this to the server +#endif setDirection(dir); } } +Being* LocalPlayer::getTarget() const +{ + return mTarget; +} + +void LocalPlayer::setTarget(Being *target) +{ +#ifdef EATHENA_SUPPORT + if (mLastTarget != -1 || target == this) + return; + + mLastTarget = tick_time; + + if (target == mTarget) + target = NULL; + + if (target || mAction == ATTACK) + { + mTargetTime = tick_time; + } + else + { + mKeepAttacking = false; + mTargetTime = -1; + } +#endif + + if (mTarget) + mTarget->untarget(); + + if (mTarget && mTarget->getType() == Being::MONSTER) + static_cast<Monster *>(mTarget)->showName(false); + + mTarget = target; + + if (target && target->getType() == Being::MONSTER) + static_cast<Monster *>(target)->showName(true); +} + +#ifdef TMWSERV_SUPPORT +void LocalPlayer::setDestination(int x, int y) +#else 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; @@ -336,15 +635,25 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y) 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; +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::walk(x, y); //Debugging fire burst effectManager->trigger(15,x,y); +#else + char temp[4] = ""; + MessageOut outMsg(mNetwork); + set_coordinates(temp, x, y, mDirection); + outMsg.writeInt16(0x0085); + outMsg.writeString(temp, 3); +#endif } mPickUpTarget = NULL; @@ -357,12 +666,16 @@ void LocalPlayer::setWalkingDir(int dir) // If we're not already walking, start walking. if (mAction != WALK && dir - && get_elapsed_time(mLocalWalkTime) >= walkingKeyboardDelay) +#ifdef TMWSERV_SUPPORT + && get_elapsed_time(mLocalWalkTime) >= walkingKeyboardDelay +#endif + ) { walk(dir); } } +#ifdef TMWSERV_SUPPORT void LocalPlayer::stopWalking(bool sendToServer) { if (mAction == WALK && mWalkingDir) { @@ -376,6 +689,53 @@ void LocalPlayer::stopWalking(bool sendToServer) clearPath(); } +#endif + +#ifdef EATHENA_SUPPORT +void LocalPlayer::raiseAttribute(Attribute attr) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_STAT_UPDATE_REQUEST); + + switch (attr) + { + case STR: + outMsg.writeInt16(0x000d); + break; + + case AGI: + outMsg.writeInt16(0x000e); + break; + + case VIT: + outMsg.writeInt16(0x000f); + break; + + case INT: + outMsg.writeInt16(0x0010); + break; + + case DEX: + outMsg.writeInt16(0x0011); + break; + + case LUK: + outMsg.writeInt16(0x0012); + break; + } + outMsg.writeInt8(1); +} + +void LocalPlayer::raiseSkill(Uint16 skillId) +{ + if (mSkillPoint <= 0) + return; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_SKILL_LEVELUP_REQUEST); + outMsg.writeInt16(skillId); +} +#endif void LocalPlayer::toggleSit() { @@ -386,13 +746,20 @@ void LocalPlayer::toggleSit() Being::Action newAction; switch (mAction) { - case Being::STAND: newAction = Being::SIT; break; - case Being::SIT: newAction = Being::STAND; break; + case STAND: newAction = SIT; break; + case SIT: newAction = STAND; break; default: return; } +#ifdef TMWSERV_SUPPORT setAction(newAction); Net::GameServer::Player::changeAction(newAction); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0089); + outMsg.writeInt32(0); + outMsg.writeInt8((newAction == SIT) ? 2 : 3); +#endif } void LocalPlayer::emote(Uint8 emotion) @@ -402,19 +769,38 @@ void LocalPlayer::emote(Uint8 emotion) mLastAction = tick_time; // XXX Convert for new server - /* - MessageOut outMsg(0x00bf); +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x00bf); outMsg.writeInt8(emotion); - */ +#endif } +#ifdef EATHENA_SUPPORT +void LocalPlayer::tradeReply(bool accept) +{ + if (!accept) + mTrading = false; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_RESPONSE); + outMsg.writeInt8(accept ? 3 : 4); +} +#endif + void LocalPlayer::trade(Being *being) const { +#ifdef TMWSERV_SUPPORT extern std::string tradePartnerName; extern int tradePartnerID; tradePartnerName = being->getName(); tradePartnerID = being->getId(); Net::GameServer::Player::requestTrade(tradePartnerID); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_REQUEST); + outMsg.writeInt32(being->getId()); +#endif } bool LocalPlayer::tradeRequestOk() const @@ -422,6 +808,8 @@ bool LocalPlayer::tradeRequestOk() const return !mTrading; } +#ifdef TMWSERV_SUPPORT + void LocalPlayer::attack() { if (mLastAction != -1) @@ -477,20 +865,97 @@ void LocalPlayer::useSpecial(int special) Net::GameServer::Player::useSpecial(special); } -Being* LocalPlayer::getTarget() const +#else + +void LocalPlayer::attack(Being *target, bool keep) { - return mTarget; + mKeepAttacking = keep; + + if (!target) + return; + + if ((mTarget != target) || !mTarget) + { + mLastTarget = -1; + setTarget(target); + } + + int dist_x = target->mX - mX; + int dist_y = target->mY - mY; + + // Must be standing and be within attack range to continue + if ((mAction != STAND) || (mAttackRange < abs(dist_x)) || + (mAttackRange < abs(dist_y))) + return; + + 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); + } + + // Implement charging attacks here + mLastAttackTime = 0; + + mWalkTime = tick_time; + mTargetTime = tick_time; + + setAction(ATTACK); + + if (mEquippedWeapon) + { + std::string soundFile = mEquippedWeapon->getSound(EQUIP_EVENT_STRIKE); + if (!soundFile.empty()) + sound.playSfx(soundFile); + } + else + { + sound.playSfx("sfx/fist-swish.ogg"); + } + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0089); + outMsg.writeInt32(target->getId()); + outMsg.writeInt8(0); + + if (!keep) + stopAttack(); +} + +void LocalPlayer::stopAttack() +{ + if (mTarget) + { + setAction(STAND); + mLastTarget = -1; + } + setTarget(NULL); + mLastTarget = -1; } +#endif // no TMWSERV_SUPPORT + void LocalPlayer::revive() { // XXX Convert for new server - /* - MessageOut outMsg(0x00b2); +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x00b2); outMsg.writeInt8(0); - */ +#endif } +#ifdef TMWSERV_SUPPORT + void LocalPlayer::raiseAttribute(size_t attr) { // we assume that the server allows the change. When not we will undo it later. @@ -556,8 +1021,28 @@ std::pair<int, int> LocalPlayer::getExperience(int skill) return std::pair<int, int> (mExpCurrent.at(skill), mExpNext.at(skill)); } +#else + +void LocalPlayer::setXp(int xp) +{ + if (mMap && xp > mXp) + { + const std::string text = toString(xp - mXp) + " xp"; + + // Show XP number + particleEngine->addTextRiseFadeOutEffect(text, + 255, 255, 0, + hitYellowFont, + mPx + 16, mPy - 16); + } + mXp = xp; +} + +#endif + int LocalPlayer::getAttackRange() { +#ifdef TMWSERV_SUPPORT Item *weapon = mEquipment->getEquipment(EQUIP_FIGHT1_SLOT); if (weapon) { @@ -565,10 +1050,14 @@ int LocalPlayer::getAttackRange() return info.getAttackRange(); } return 32; // unarmed range +#else + return mAttackRange; +#endif } bool LocalPlayer::withinAttackRange(Being *target) { +#ifdef TMWSERV_SUPPORT const Vector &targetPos = target->getPosition(); const Vector &pos = getPosition(); const int dx = abs(targetPos.x - pos.x); @@ -576,12 +1065,119 @@ bool LocalPlayer::withinAttackRange(Being *target) const int range = getAttackRange(); return !(dx > range || dy > range); +#else + int dist_x = abs(target->mX - mX); + int dist_y = abs(target->mY - mY); + + if (dist_x > getAttackRange() || dist_y > getAttackRange()) + { + return false; + } + + return true; +#endif } void LocalPlayer::setGotoTarget(Being *target) { +#ifdef TMWSERV_SUPPORT mTarget = target; mGoingToTarget = true; const Vector &targetPos = target->getPosition(); setDestination(targetPos.x, targetPos.y); +#else + mLastTarget = -1; + setTarget(target); + mGoingToTarget = true; + setDestination(target->mX, target->mY); +#endif } + + +extern MiniStatusWindow *miniStatusWindow; + +void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId) +{ + Being::handleStatusEffect(effect, effectId); + + + + if (effect) { + effect->deliverMessage(); + effect->playSFX(); + + AnimatedSprite *sprite = effect->getIcon(); + + 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++; + } else { + // 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 (!found) { // add new + int offset = mStatusEffectIcons.size(); + miniStatusWindow->setIcon(offset, sprite); + mStatusEffectIcons.push_back(effectId); + } + } + } +} + +void LocalPlayer::initTargetCursor() +{ + // Load target cursors + loadTargetCursor("graphics/gui/target-cursor-blue-s.png", 44, 35, + false, TC_SMALL); + loadTargetCursor("graphics/gui/target-cursor-red-s.png", 44, 35, + true, TC_SMALL); + loadTargetCursor("graphics/gui/target-cursor-blue-m.png", 62, 44, + false, TC_MEDIUM); + loadTargetCursor("graphics/gui/target-cursor-red-m.png", 62, 44, + true, TC_MEDIUM); + loadTargetCursor("graphics/gui/target-cursor-blue-l.png", 82, 60, + false, TC_LARGE); + loadTargetCursor("graphics/gui/target-cursor-red-l.png", 82, 60, + true, TC_LARGE); +} + +void LocalPlayer::loadTargetCursor(std::string filename, int width, int height, + bool outRange, TargetCursorSize size) +{ + assert(size > -1); + assert(size < 3); + + ImageSet* currentImageSet; + SimpleAnimation* currentCursor; + + ResourceManager *resman = ResourceManager::getInstance(); + + currentImageSet = resman->getImageSet(filename, width, height); + Animation *anim = new Animation; + + for (unsigned int i = 0; i < currentImageSet->size(); ++i) + { + anim->addFrame(currentImageSet->get(i), 75, + (16 - (currentImageSet->getWidth() / 2)), + (16 - (currentImageSet->getHeight() / 2))); + } + + currentCursor = new SimpleAnimation(anim); + + const int index = outRange ? 1 : 0; + + mTargetCursorImages[index][size] = currentImageSet; + mTargetCursor[index][size] = currentCursor; +} + |