diff options
-rw-r--r-- | src/being.cpp | 62 | ||||
-rw-r--r-- | src/being.h | 18 | ||||
-rw-r--r-- | src/localplayer.cpp | 149 | ||||
-rw-r--r-- | src/localplayer.h | 23 | ||||
-rw-r--r-- | src/map.cpp | 29 | ||||
-rw-r--r-- | src/map.h | 6 | ||||
-rw-r--r-- | src/simpleanimation.cpp | 32 | ||||
-rw-r--r-- | src/simpleanimation.h | 10 |
8 files changed, 162 insertions, 167 deletions
diff --git a/src/being.cpp b/src/being.cpp index 0ac86d13..5676ec3f 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -28,20 +28,18 @@ #include "effectmanager.h" #include "game.h" #include "graphics.h" -#include "localplayer.h" #include "log.h" #include "map.h" #include "particle.h" +#include "simpleanimation.h" #include "sound.h" #include "text.h" #include "gui/speechbubble.h" #include "resources/colordb.h" - #include "resources/emotedb.h" #include "resources/image.h" -#include "resources/imageset.h" #include "resources/itemdb.h" #include "resources/iteminfo.h" #include "resources/resourcemanager.h" @@ -88,7 +86,8 @@ Being::Being(int id, int job, Map *map): mSpriteIDs(VECTOREND_SPRITE, 0), mSpriteColors(VECTOREND_SPRITE, ""), mStatusParticleEffects(&mStunParticleEffects, false), - mChildParticleEffects(&mStatusParticleEffects, false) + mChildParticleEffects(&mStatusParticleEffects, false), + mUsedTargetCursor(NULL) { setMap(map); @@ -106,7 +105,8 @@ Being::Being(int id, int job, Map *map): emotionSet.push_back(AnimatedSprite::load(file, variant)); } - // Hairstyles are encoded as negative numbers. Count how far negative we can go. + // Hairstyles are encoded as negative numbers. Count how far negative + // we can go. int hairstyles = 1; while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != "error.xml") { @@ -123,6 +123,7 @@ Being::Being(int id, int job, Map *map): Being::~Being() { + mUsedTargetCursor = NULL; delete_all(mSprites); clearPath(); @@ -142,9 +143,7 @@ Being::~Being() void Being::setDestination(Uint16 destX, Uint16 destY) { if (mMap) - { setPath(mMap->findPath(mX, mY, destX, destY)); - } } void Being::clearPath() @@ -225,19 +224,13 @@ void Being::takeDamage(int amount) // Selecting the right color if (damage == "miss") - { font = hitYellowFont; - } else { if (getType() == MONSTER) - { font = hitBlueFont; - } else - { font = hitRedFont; - } } // Show damage number @@ -252,13 +245,9 @@ void Being::showCrit() // Selecting the right color if (getType() == MONSTER) - { font = hitBlueFont; - } else - { font = hitRedFont; - } // Show crit notice particleEngine->addTextSplashEffect(text, 255, 255, 255, font, @@ -276,17 +265,13 @@ void Being::setMap(Map *map) { // Remove sprite from potential previous map if (mMap) - { mMap->removeSprite(mSpriteIterator); - } mMap = map; // Add sprite to potential new map if (mMap) - { mSpriteIterator = mMap->addSprite(this); - } // Clear particle effect list because child particles became invalid mChildParticleEffects.clear(); @@ -321,9 +306,7 @@ void Being::setAction(Action action) for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i]) - { mSprites[i]->reset(); - } } break; case HURT: @@ -344,9 +327,7 @@ void Being::setAction(Action action) for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i]) - { mSprites[i]->play(currentAction); - } } mAction = action; } @@ -454,18 +435,18 @@ void Being::logic() if (mEmotion != 0) { mEmotionTime--; - if (mEmotionTime == 0) { + if (mEmotionTime == 0) mEmotion = 0; - } } // Update sprite animations + if (mUsedTargetCursor != NULL) + mUsedTargetCursor->update(tick_time * 10); + for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i] != NULL) - { mSprites[i]->update(tick_time * 10); - } } // Update particle effects @@ -479,6 +460,14 @@ void Being::draw(Graphics *graphics, int offsetX, int offsetY) const int px = mPx + offsetX; int py = mPy + offsetY; + if (mUsedTargetCursor != NULL) + { + const int width = mSprites[BASE_SPRITE]->getWidth(); + const int height = mSprites[BASE_SPRITE]->getHeight(); + + mUsedTargetCursor->draw(graphics, px, py); + } + for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i] != NULL) @@ -517,11 +506,12 @@ void Being::drawSpeech(int offsetX, int offsetY) mSpeechBubble->setCaption(mName, mNameColor); - // Not quite centered, but close enough. However, it's not too important to get - // it right right now, as it doesn't take bubble collision into account yet. + // Not quite centered, but close enough. However, it's not too important + // to get it right right now, as it doesn't take bubble collision into + // account yet. mSpeechBubble->setText(mSpeech); - mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() * 4 / 11), py - 70 - - (mSpeechBubble->getNumRows()*14)); + mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() * 4 / 11), + py - 70 - (mSpeechBubble->getNumRows() * 14)); mSpeechBubble->setVisible(true); } else if (mSpeechTime > 0 && !config.getValue("speechbubble", 1)) @@ -586,7 +576,6 @@ int Being::getWidth() const } } - int Being::getHeight() const { if (mSprites[BASE_SPRITE]) @@ -602,3 +591,8 @@ int Being::getHeight() const } } +void Being::setTargetAnimation(SimpleAnimation* animation) +{ + mUsedTargetCursor = animation; + mUsedTargetCursor->reset(); +} diff --git a/src/being.h b/src/being.h index dcbd3553..ef02eeb2 100644 --- a/src/being.h +++ b/src/being.h @@ -50,6 +50,7 @@ class Map; class Graphics; class Particle; class Position; +class SimpleAnimation; class SpeechBubble; class Text; @@ -112,7 +113,6 @@ class Being : public Sprite NUM_TC }; - /** * Directions, to be used as bitmask values */ @@ -359,6 +359,16 @@ class Being : public Sprite */ void controlParticle(Particle *particle); + /** + * Sets the target animation for this being. + */ + void setTargetAnimation(SimpleAnimation* animation); + + /** + * Untargets the being + */ + void untarget() { mUsedTargetCursor = NULL; } + AnimatedSprite* getEmote(int index) { return emotionSet[index]; } void setEmote(Uint8 emotion, Uint8 emote_time) @@ -367,9 +377,6 @@ class Being : public Sprite mEmotionTime = emote_time; } - // Target cursor being used by the being - Image *mTargetCursor; - static int getHairColorsNr(void); static int getHairStylesNr(void); @@ -444,6 +451,9 @@ class Being : public Sprite // Speech Bubble components SpeechBubble *mSpeechBubble; + // Target cursor being used + SimpleAnimation* mUsedTargetCursor; + static int instances; /**< Number of Being instances */ static std::vector<AnimatedSprite*> emotionSet; /**< Emoticons used by beings */ }; diff --git a/src/localplayer.cpp b/src/localplayer.cpp index d047cc80..3c477b08 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -41,7 +41,6 @@ #include "net/protocol.h" #include "resources/animation.h" -#include "resources/image.h" #include "resources/imageset.h" #include "resources/resourcemanager.h" @@ -95,10 +94,10 @@ LocalPlayer::~LocalPlayer() for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) { - delete mTargetCursorInRange[i]; - delete mTargetCursorOutRange[i]; - mInRangeImages[i]->decRef(); - mOutRangeImages[i]->decRef(); + delete mTargetCursor[0][i]; + delete mTargetCursor[1][i]; + mTargetCursorImages[0][i]->decRef(); + mTargetCursorImages[1][i]->decRef(); } } @@ -119,33 +118,32 @@ void LocalPlayer::logic() case WALK: mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed; - if (mFrame >= 6) { + if (mFrame >= 6) nextStep(); - } break; case ATTACK: int frames = 4; - if ( mEquippedWeapon - && mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW) - { + if (mEquippedWeapon && + mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW) frames = 5; - } + mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed; - if (mFrame >= frames) { + + if (mFrame >= frames) nextStep(); - } + break; } // Actions are allowed once per second - if (get_elapsed_time(mLastAction) >= 1000) { + if (get_elapsed_time(mLastAction) >= 1000) mLastAction = -1; - } + // Targeting allowed 4 times a second - if (get_elapsed_time(mLastTarget) >= 250) { + 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) { @@ -156,20 +154,20 @@ void LocalPlayer::logic() 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); - } - - for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) - { - player_node->mTargetCursorInRange[i]->update(10); - player_node->mTargetCursorOutRange[i]->update(10); - } } Being::logic(); @@ -192,13 +190,9 @@ void LocalPlayer::setName(const std::string &name) } if (config.getValue("showownname", false) && mMapInitialized) - { Player::setName(name); - } else - { Being::setName(name); - } } void LocalPlayer::nextStep() @@ -206,15 +200,10 @@ void LocalPlayer::nextStep() if (mPath.empty()) { if (mPickUpTarget) - { pickUp(mPickUpTarget); - } if (mWalkingDir) - { walk(mWalkingDir); - } - } if (mGoingToTarget && mTarget && withinAttackRange(mTarget)) @@ -278,12 +267,15 @@ void LocalPlayer::pickUp(FloorItem *item) int dx = item->getX() - mX; int dy = item->getY() - mY; - if (dx * dx + dy * dy < 4) { + if (dx * dx + dy * dy < 4) + { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_ITEM_PICKUP); outMsg.writeInt32(item->getId()); mPickUpTarget = NULL; - } else { + } + else + { setDestination(item->getX(), item->getY()); mPickUpTarget = item; stopAttack(); @@ -339,27 +331,32 @@ void LocalPlayer::setTarget(Being *target) { if (mLastTarget != -1 || target == this) return; + mLastTarget = tick_time; - if ((target == NULL) || target == mTarget) - { + if (target == mTarget) target = NULL; - mKeepAttacking = false; - mTargetTime = -1; - } + if (target) { mTargetTime = tick_time; } - if (mTarget && mTarget->getType() == Being::MONSTER) + else { - static_cast<Monster *>(mTarget)->showName(false); + mKeepAttacking = false; + mTargetTime = -1; } + + 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); - } } void LocalPlayer::setDestination(Uint16 x, Uint16 y) @@ -541,7 +538,8 @@ void LocalPlayer::attack(Being *target, bool keep) std::string soundFile = mEquippedWeapon->getSound(EQUIP_EVENT_STRIKE); if (soundFile != "") sound.playSfx(soundFile); } - else { + else + { sound.playSfx("sfx/fist-swish.ogg"); } @@ -551,9 +549,7 @@ void LocalPlayer::attack(Being *target, bool keep) outMsg.writeInt8(0); if (!keep) - { stopAttack(); - } } void LocalPlayer::stopAttack() @@ -643,54 +639,19 @@ void LocalPlayer::loadTargetCursor(std::string filename, int width, int height, 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, 0, 0); - } - currentCursor = new SimpleAnimation(anim); - if (outRange) - { - mOutRangeImages[size] = currentImageSet; - mTargetCursorOutRange[size] = currentCursor; - } - else + for (unsigned int i = 0; i < currentImageSet->size(); ++i) { - mInRangeImages[size] = currentImageSet; - mTargetCursorInRange[size] = currentCursor; + anim->addFrame(currentImageSet->get(i), 75, + (16 - (currentImageSet->getWidth() / 2)), + (16 - (currentImageSet->getHeight() / 2))); } -} - -void LocalPlayer::drawTargetCursor(Graphics *graphics, int scrollX, int scrollY) -{ - - // Draw target marker if needed - if (mTarget) - { - // Calculate target circle position - - // Find whether target is in range - int rangeX = abs(mTarget->mX - mX); - int rangeY = abs(mTarget->mY - mY); - int attackRange = getAttackRange(); - // Get the correct target cursors graphic - TargetCursorSize cursorSize = mTarget->getTargetCursorSize(); - - if (rangeX > attackRange || rangeY > attackRange) - { - mTarget->mTargetCursor = mTargetCursorOutRange[cursorSize]->getCurrentImage(); - } - else - { - mTarget->mTargetCursor = mTargetCursorInRange[cursorSize]->getCurrentImage(); - } + currentCursor = new SimpleAnimation(anim); - // Draw the target cursor at the correct position - int posX = mTarget->getPixelX() + 16 - mTarget->mTargetCursor->getWidth() / 2 - scrollX; - int posY = mTarget->getPixelY() + 16 - mTarget->mTargetCursor->getHeight() / 2 - scrollY; + const int index = outRange ? 1 : 0; - graphics->drawImage(mTarget->mTargetCursor, posX, posY); - } - return; + mTargetCursorImages[index][size] = currentImageSet; + mTargetCursor[index][size] = currentCursor; } + diff --git a/src/localplayer.h b/src/localplayer.h index d6d5ad2e..a4625f73 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -39,7 +39,6 @@ class Inventory; class Item; class Map; class Network; -class SimpleAnimation; /** * The local player character. @@ -231,14 +230,6 @@ class LocalPlayer : public Player float mLastAttackTime; /**< Used to synchronize the charge dialog */ - void drawTargetCursor(Graphics *graphics, int offsetX, int offsetY); - - /** Animated in range target cursor. */ - SimpleAnimation *mTargetCursorInRange[NUM_TC]; - - /** Animated out of range target cursor. */ - SimpleAnimation *mTargetCursorOutRange[NUM_TC]; - const std::auto_ptr<Equipment> mEquipment; protected: @@ -264,20 +255,20 @@ class LocalPlayer : public Player Inventory *mInventory; Inventory *mStorage; + // Load the target cursors into memory + void initTargetCursor(); + /** * Helper function for loading target cursors */ void loadTargetCursor(std::string filename, int width, int height, bool outRange, Being::TargetCursorSize size); - /** Images of in range target cursor. */ - ImageSet *mInRangeImages[NUM_TC]; - - /** Images of out of range target cursor. */ - ImageSet *mOutRangeImages[NUM_TC]; + /** Images of the target cursor. */ + ImageSet *mTargetCursorImages[2][NUM_TC]; - // Load the target cursors into memory - void initTargetCursor(); + /** Animated target cursors. */ + SimpleAnimation *mTargetCursor[2][NUM_TC]; }; extern LocalPlayer *player_node; diff --git a/src/map.cpp b/src/map.cpp index 716e9aee..16882540 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -25,9 +25,9 @@ #include "configuration.h" #include "game.h" #include "graphics.h" -#include "localplayer.h" #include "map.h" #include "particle.h" +#include "simpleanimation.h" #include "sprite.h" #include "tileset.h" @@ -63,34 +63,35 @@ struct Location }; TileAnimation::TileAnimation(Animation *ani): - mAnimation(ani), mLastImage(NULL) { + mAnimation = new SimpleAnimation(ani); } TileAnimation::~TileAnimation() { - delete mLastImage; + delete mAnimation; } void TileAnimation::update() { + if (!mAnimation) + return; + //update animation - mAnimation.update(1); + mAnimation->update(1); // exchange images - Image *img = mAnimation.getCurrentImage(); + Image *img = mAnimation->getCurrentImage(); if (img != mLastImage) { - for (std::list<std::pair<MapLayer*, int> >::iterator i = mAffected.begin(); - i != mAffected.end(); - i++) + for (std::list<std::pair<MapLayer*, int> >::iterator i = + mAffected.begin(); i != mAffected.end(); i++) { i->first->setTile(i->second, img); } mLastImage = img; } - } MapLayer::MapLayer(int x, int y, int width, int height, bool isFringeLayer): @@ -140,9 +141,10 @@ void MapLayer::draw(Graphics *graphics, { // If drawing the fringe layer, make sure all sprites above this row of // tiles have been drawn - if (mIsFringeLayer) { - player_node->drawTargetCursor(graphics, scrollX, scrollY); - while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) { + if (mIsFringeLayer) + { + while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) + { (*si)->draw(graphics, -scrollX, -scrollY); si++; } @@ -151,7 +153,8 @@ void MapLayer::draw(Graphics *graphics, for (int x = startX; x < endX; x++) { Image *img = getTile(x, y); - if (img) { + if (img) + { const int px = (x + mX) * 32 - scrollX; const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight(); graphics->drawImage(img, px, py); @@ -27,7 +27,6 @@ #include "position.h" #include "properties.h" -#include "simpleanimation.h" class Animation; class AmbientOverlay; @@ -35,6 +34,7 @@ class Graphics; class Image; class MapLayer; class Particle; +class SimpleAnimation; class Sprite; class Tileset; @@ -78,8 +78,8 @@ class TileAnimation { mAffected.push_back(std::make_pair(layer, index)); } private: std::list<std::pair<MapLayer*, int> > mAffected; - SimpleAnimation mAnimation; - Image* mLastImage; + SimpleAnimation *mAnimation; + Image *mLastImage; }; /** diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index 9066ed7f..030619ce 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "graphics.h" #include "log.h" #include "simpleanimation.h" @@ -112,17 +113,42 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): mCurrentFrame = mAnimation->getFrame(0); } +bool SimpleAnimation::draw(Graphics* graphics, int posX, int posY) const +{ + if (!mCurrentFrame || !mCurrentFrame->image) + return false; + + return graphics->drawImage(mCurrentFrame->image, + posX + mCurrentFrame->offsetX, + posY + mCurrentFrame->offsetY); +} + +void SimpleAnimation::reset() +{ + mAnimationTime = 0; + mAnimationPhase = 0; +} + void SimpleAnimation::update(unsigned int timePassed) { + // Avoid freaking out at first frame or when tick_time overflows + if (timePassed < mLastTime || mLastTime == 0) + mLastTime = timePassed; + + // If not enough time has passed yet, do nothing + if (timePassed <= mLastTime || !mAnimation) + return; + mAnimationTime += timePassed; - while (mAnimationTime > mCurrentFrame->delay) + + while (mAnimationTime > mCurrentFrame->delay && mCurrentFrame->delay > 0) { mAnimationTime -= mCurrentFrame->delay; mAnimationPhase++; + if (mAnimationPhase >= mAnimation->getLength()) - { mAnimationPhase = 0; - } + mCurrentFrame = mAnimation->getFrame(mAnimationPhase); } } diff --git a/src/simpleanimation.h b/src/simpleanimation.h index 16ac2906..a639cf14 100644 --- a/src/simpleanimation.h +++ b/src/simpleanimation.h @@ -50,12 +50,22 @@ class SimpleAnimation void update(unsigned int timePassed); + bool draw(Graphics* graphics, int posX, int posY) const; + + /** + * Resets the animation. + */ + void reset(); + Image *getCurrentImage() const; private: /** The hosted animation. */ Animation *mAnimation; + /**< The last time update was called. */ + unsigned int mLastTime; + /** Time in game ticks the current frame is shown. */ unsigned int mAnimationTime; |