summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/being.cpp62
-rw-r--r--src/being.h18
-rw-r--r--src/localplayer.cpp149
-rw-r--r--src/localplayer.h23
-rw-r--r--src/map.cpp29
-rw-r--r--src/map.h6
-rw-r--r--src/simpleanimation.cpp32
-rw-r--r--src/simpleanimation.h10
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);
diff --git a/src/map.h b/src/map.h
index 1423565f..9703c5b3 100644
--- a/src/map.h
+++ b/src/map.h
@@ -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;