summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mana.cbp7
-rw-r--r--mana.files7
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/Makefile.am7
-rw-r--r--src/actor.cpp3
-rw-r--r--src/actor.h9
-rw-r--r--src/actorsprite.cpp326
-rw-r--r--src/actorsprite.h192
-rw-r--r--src/animatedsprite.cpp10
-rw-r--r--src/animatedsprite.h47
-rw-r--r--src/being.cpp291
-rw-r--r--src/being.h167
-rw-r--r--src/compoundsprite.cpp121
-rw-r--r--src/compoundsprite.h67
-rw-r--r--src/flooritem.cpp50
-rw-r--r--src/flooritem.h42
-rw-r--r--src/flooritemmanager.cpp9
-rw-r--r--src/flooritemmanager.h5
-rw-r--r--src/game.cpp1
-rw-r--r--src/gui/popupmenu.cpp9
-rw-r--r--src/gui/widgets/playerbox.cpp4
-rw-r--r--src/imageparticle.cpp10
-rw-r--r--src/imageparticle.h2
-rw-r--r--src/imagesprite.cpp44
-rw-r--r--src/imagesprite.h63
-rw-r--r--src/item.cpp3
-rw-r--r--src/monster.cpp34
-rw-r--r--src/monster.h3
-rw-r--r--src/npc.cpp34
-rw-r--r--src/npc.h10
-rw-r--r--src/particle.cpp4
-rw-r--r--src/particle.h8
-rw-r--r--src/player.cpp32
-rw-r--r--src/player.h2
-rw-r--r--src/resources/itemdb.cpp32
-rw-r--r--src/resources/iteminfo.h10
-rw-r--r--src/resources/monsterdb.cpp23
-rw-r--r--src/resources/monsterinfo.cpp5
-rw-r--r--src/resources/monsterinfo.h22
-rw-r--r--src/resources/npcdb.cpp18
-rw-r--r--src/resources/npcdb.h20
-rw-r--r--src/resources/resourcemanager.cpp2
-rw-r--r--src/resources/spritedef.h16
-rw-r--r--src/sprite.h92
-rw-r--r--src/textparticle.cpp6
-rw-r--r--src/textparticle.h2
46 files changed, 1158 insertions, 720 deletions
diff --git a/mana.cbp b/mana.cbp
index 1be2b57e..272b7f06 100644
--- a/mana.cbp
+++ b/mana.cbp
@@ -96,6 +96,8 @@
<Unit filename="src\SDLMain.m" />
<Unit filename="src\actor.cpp" />
<Unit filename="src\actor.h" />
+ <Unit filename="src\actorsprite.cpp" />
+ <Unit filename="src\actorsprite.h" />
<Unit filename="src\animatedsprite.cpp" />
<Unit filename="src\animatedsprite.h" />
<Unit filename="src\animationparticle.cpp" />
@@ -116,6 +118,8 @@
<Unit filename="src\client.h" />
<Unit filename="src\commandhandler.cpp" />
<Unit filename="src\commandhandler.h" />
+ <Unit filename="src\compoundsprite.cpp" />
+ <Unit filename="src\compoundsprite.h" />
<Unit filename="src\configlistener.h" />
<Unit filename="src\configuration.cpp" />
<Unit filename="src\configuration.h" />
@@ -343,6 +347,8 @@
<Unit filename="src\guild.h" />
<Unit filename="src\imageparticle.cpp" />
<Unit filename="src\imageparticle.h" />
+ <Unit filename="src\imagesprite.cpp" />
+ <Unit filename="src\imagesprite.h" />
<Unit filename="src\inventory.cpp" />
<Unit filename="src\inventory.h" />
<Unit filename="src\item.cpp" />
@@ -563,6 +569,7 @@
<Unit filename="src\simpleanimation.h" />
<Unit filename="src\sound.cpp" />
<Unit filename="src\sound.h" />
+ <Unit filename="src\sprite.h" />
<Unit filename="src\statuseffect.cpp" />
<Unit filename="src\statuseffect.h" />
<Unit filename="src\text.cpp" />
diff --git a/mana.files b/mana.files
index a0441637..b4a4a681 100644
--- a/mana.files
+++ b/mana.files
@@ -40,6 +40,8 @@
./po/CMakeLists.txt
./src/actor.cpp
./src/actor.h
+./src/actorsprite.cpp
+./src/actorsprite.h
./src/animatedsprite.cpp
./src/animatedsprite.h
./src/animationparticle.cpp
@@ -61,6 +63,8 @@
./src/CMakeLists.txt
./src/commandhandler.cpp
./src/commandhandler.h
+./src/compoundsprite.cpp
+./src/compoundsprite.h
./src/configlistener.h
./src/configuration.cpp
./src/configuration.h
@@ -287,6 +291,8 @@
./src/gui/worldselectdialog.h
./src/imageparticle.cpp
./src/imageparticle.h
+./src/imagesprite.cpp
+./src/imagesprite.h
./src/inventory.cpp
./src/inventory.h
./src/item.cpp
@@ -502,6 +508,7 @@
./src/simpleanimation.h
./src/sound.cpp
./src/sound.h
+./src/sprite.h
./src/statuseffect.cpp
./src/statuseffect.h
./src/text.cpp
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 433a1d3d..6ccdd4e2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -402,6 +402,8 @@ SET(SRCS
utils/xml.h
actor.cpp
actor.h
+ actorsprite.cpp
+ actorsprite.h
animatedsprite.cpp
animatedsprite.h
animationparticle.cpp
@@ -422,6 +424,8 @@ SET(SRCS
channelmanager.h
commandhandler.cpp
commandhandler.h
+ compoundsprite.cpp
+ compoundsprite.h
configlistener.h
configuration.cpp
configuration.h
@@ -443,6 +447,8 @@ SET(SRCS
guild.h
imageparticle.cpp
imageparticle.h
+ imagesprite.cpp
+ imagesprite.h
inventory.cpp
inventory.h
item.cpp
@@ -491,6 +497,7 @@ SET(SRCS
simpleanimation.h
sound.cpp
sound.h
+ sprite.h
statuseffect.cpp
statuseffect.h
text.cpp
diff --git a/src/Makefile.am b/src/Makefile.am
index a479f70c..d0ee9948 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -303,6 +303,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
utils/xml.h \
actor.cpp \
actor.h \
+ actorsprite.cpp \
+ actorsprite.h \
animatedsprite.cpp \
animatedsprite.h \
animationparticle.cpp \
@@ -323,6 +325,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
channelmanager.h \
commandhandler.cpp \
commandhandler.h \
+ compoundsprite.cpp \
+ compoundsprite.h \
configlistener.h \
configuration.cpp \
configuration.h \
@@ -344,6 +348,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
guild.h \
imageparticle.cpp \
imageparticle.h \
+ imagesprite.cpp \
+ imagesprite.h \
inventory.cpp \
inventory.h \
item.cpp \
@@ -392,6 +398,7 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \
simpleanimation.h \
sound.cpp \
sound.h \
+ sprite.h \
statuseffect.cpp \
statuseffect.h \
text.cpp \
diff --git a/src/actor.cpp b/src/actor.cpp
index 4fdce5f1..44a89600 100644
--- a/src/actor.cpp
+++ b/src/actor.cpp
@@ -26,8 +26,7 @@
#include "resources/resourcemanager.h"
Actor::Actor():
- mMap(NULL),
- mAlpha(1.0f)
+ mMap(NULL)
{}
Actor::~Actor()
diff --git a/src/actor.h b/src/actor.h
index 59e29b88..367bcd75 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -46,7 +46,7 @@ public:
* would support setting a translation offset. It already does this
* partly with the clipping rectangle support.
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
/**
* Returns the horizontal size of the actors graphical representation
@@ -105,14 +105,12 @@ public:
/**
* Returns the current alpha value used to draw the actor.
*/
- virtual float getAlpha() const
- { return mAlpha; }
+ virtual float getAlpha() const = 0;
/**
* Sets the alpha value used to draw the actor.
*/
- virtual void setAlpha(float alpha)
- { mAlpha = alpha; }
+ virtual void setAlpha(float alpha) = 0;
void setMap(Map *map);
@@ -122,7 +120,6 @@ public:
protected:
Map *mMap;
Vector mPos; /**< Position in pixels relative to map. */
- float mAlpha;
private:
Actors::iterator mMapActor;
diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp
new file mode 100644
index 00000000..ad703bc2
--- /dev/null
+++ b/src/actorsprite.cpp
@@ -0,0 +1,326 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "actorsprite.h"
+
+#include "client.h"
+#include "effectmanager.h"
+#include "imagesprite.h"
+#include "localplayer.h"
+#include "log.h"
+#include "simpleanimation.h"
+#include "sound.h"
+#include "statuseffect.h"
+
+#include "gui/theme.h"
+
+#include "net/net.h"
+
+#include "resources/image.h"
+#include "resources/resourcemanager.h"
+
+#define EFFECTS_FILE "effects.xml"
+
+ActorSprite::ActorSprite(int id):
+ mId(id),
+ mStunMode(0),
+ mStatusParticleEffects(&mStunParticleEffects, false),
+ mChildParticleEffects(&mStatusParticleEffects, false),
+ mMustResetParticles(false),
+ mUsedTargetCursor(NULL)
+{
+ //
+}
+
+ActorSprite::~ActorSprite()
+{
+ setMap(NULL);
+
+ mUsedTargetCursor = NULL;
+
+ if (player_node && player_node->getTarget() == this)
+ player_node->setTarget(NULL);
+}
+
+bool ActorSprite::draw(Graphics *graphics, int offsetX, int offsetY) const
+{
+ // TODO: Eventually, we probably should fix all sprite offsets so that
+ // these translations aren't necessary anymore. The sprites know
+ // best where their base point should be.
+ const int px = getPixelX() + offsetX - 16;
+ // Temporary fix to the Y offset.
+ const int py = getPixelY() + offsetY -
+ ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
+
+ if (mUsedTargetCursor)
+ mUsedTargetCursor->draw(graphics, px, py);
+
+ return drawSpriteAt(graphics, px, py);
+}
+
+bool ActorSprite::drawSpriteAt(Graphics *graphics, int x, int y) const
+{
+ return CompoundSprite::draw(graphics, x, y);
+}
+
+void ActorSprite::logic()
+{
+ // Update sprite animations
+ if (mUsedTargetCursor)
+ mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK);
+
+ update(tick_time * MILLISECONDS_IN_A_TICK);
+
+ // Restart status/particle effects, if needed
+ if (mMustResetParticles)
+ {
+ mMustResetParticles = false;
+ for (std::set<int>::iterator it = mStatusEffects.begin();
+ it != mStatusEffects.end(); it++)
+ {
+ const StatusEffect *effect = StatusEffect::getStatusEffect(*it, true);
+ if (effect && effect->particleEffectIsPersistent())
+ updateStatusEffect(*it, true);
+ }
+ }
+
+ // Update particle effects
+ mChildParticleEffects.moveTo(mPos.x, mPos.y);
+}
+
+void ActorSprite::setMap(Map* map)
+{
+ Actor::setMap(map);
+
+ // Clear particle effect list because child particles became invalid
+ mChildParticleEffects.clear();
+ mMustResetParticles = true; // Reset status particles on next redraw
+}
+
+void ActorSprite::controlParticle(Particle *particle)
+{
+ mChildParticleEffects.addLocally(particle);
+}
+
+void ActorSprite::setTargetAnimation(SimpleAnimation *animation)
+{
+ mUsedTargetCursor = animation;
+ mUsedTargetCursor->reset();
+}
+
+struct EffectDescription {
+ std::string mGFXEffect;
+ std::string mSFXEffect;
+};
+
+static EffectDescription *default_effect = NULL;
+static std::map<int, EffectDescription *> effects;
+static bool effects_initialized = false;
+
+static EffectDescription *getEffectDescription(xmlNodePtr node, int *id)
+{
+ EffectDescription *ed = new EffectDescription;
+
+ *id = atoi(XML::getProperty(node, "id", "-1").c_str());
+ ed->mSFXEffect = XML::getProperty(node, "audio", "");
+ ed->mGFXEffect = XML::getProperty(node, "particle", "");
+
+ return ed;
+}
+
+static EffectDescription *getEffectDescription(int effectId)
+{
+ if (!effects_initialized)
+ {
+ XML::Document doc(EFFECTS_FILE);
+ xmlNodePtr root = doc.rootNode();
+
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
+ {
+ logger->log("Error loading being effects file: "
+ EFFECTS_FILE);
+ return NULL;
+ }
+
+ for_each_xml_child_node(node, root)
+ {
+ int id;
+
+ if (xmlStrEqual(node->name, BAD_CAST "effect"))
+ {
+ EffectDescription *EffectDescription =
+ getEffectDescription(node, &id);
+ effects[id] = EffectDescription;
+ }
+ else if (xmlStrEqual(node->name, BAD_CAST "default"))
+ {
+ EffectDescription *effectDescription =
+ getEffectDescription(node, &id);
+
+ if (default_effect)
+ delete default_effect;
+
+ default_effect = effectDescription;
+ }
+ }
+
+ effects_initialized = true;
+ } // done initializing
+
+ EffectDescription *ed = effects[effectId];
+
+ return ed ? ed : default_effect;
+}
+
+void ActorSprite::setStatusEffect(int index, bool active)
+{
+ const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end();
+
+ if (active != wasActive)
+ {
+ updateStatusEffect(index, active);
+ if (active)
+ mStatusEffects.insert(index);
+ else
+ mStatusEffects.erase(index);
+ }
+}
+
+void ActorSprite::setStatusEffectBlock(int offset, Uint16 newEffects)
+{
+ for (int i = 0; i < STATUS_EFFECTS; i++)
+ {
+ int index = StatusEffect::blockEffectIndexToEffectIndex(offset + i);
+
+ if (index != -1)
+ setStatusEffect(index, (newEffects & (1 << i)) > 0);
+ }
+}
+
+void ActorSprite::internalTriggerEffect(int effectId, bool sfx, bool gfx)
+{
+ logger->log("Special effect #%d on %s", effectId,
+ getId() == player_node->getId() ? "self" : "other");
+
+ EffectDescription *ed = getEffectDescription(effectId);
+
+ if (!ed)
+ {
+ logger->log("Unknown special effect and no default recorded");
+ return;
+ }
+
+ if (gfx && !ed->mGFXEffect.empty())
+ {
+ Particle *selfFX;
+
+ selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
+ controlParticle(selfFX);
+ }
+
+ if (sfx && !ed->mSFXEffect.empty())
+ sound.playSfx(ed->mSFXEffect);
+}
+
+void ActorSprite::updateStunMode(int oldMode, int newMode)
+{
+ handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1);
+ handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1);
+}
+
+void ActorSprite::updateStatusEffect(int index, bool newStatus)
+{
+ handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index);
+}
+
+void ActorSprite::handleStatusEffect(StatusEffect *effect, int effectId)
+{
+ if (!effect)
+ return;
+
+ // TODO: Find out how this is meant to be used
+ // (SpriteAction != Being::Action)
+ //SpriteAction action = effect->getAction();
+ //if (action != ACTION_INVALID)
+ // setAction(action);
+
+ Particle *particle = effect->getParticle();
+
+ if (effectId >= 0)
+ {
+ mStatusParticleEffects.setLocally(effectId, particle);
+ }
+ else
+ {
+ mStunParticleEffects.clearLocally();
+ if (particle)
+ mStunParticleEffects.addLocally(particle);
+ }
+}
+
+void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
+ bool forceDisplay)
+{
+ clear();
+
+ SpriteRefs it, it_end;
+
+ for (it = display.sprites.begin(), it_end = display.sprites.end();
+ it != it_end; it++)
+ {
+ std::string file = "graphics/sprites/" + (*it)->sprite;
+ int variant = (*it)->variant;
+ push_back(AnimatedSprite::load(file, variant));
+ }
+
+ // Ensure that something is shown, if desired
+ if (size() == 0 && forceDisplay)
+ {
+ if (display.image.empty())
+ push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
+ else
+ {
+ ResourceManager *resman = ResourceManager::getInstance();
+ std::string imagePath = "graphics/items/" + display.image;
+ Image *img = resman->getImage(imagePath);
+
+ if (!img)
+ img = Theme::getImageFromTheme("unknown-item.png");
+
+ push_back(new ImageSprite(img));
+ }
+ }
+
+ mChildParticleEffects.clear();
+
+ //setup particle effects
+ if (Particle::enabled)
+ {
+ std::list<std::string>::const_iterator it, it_end;
+ for (it = display.particles.begin(), it_end = display.particles.end();
+ it != it_end; it++)
+ {
+ Particle *p = particleEngine->addEffect(*it, 0, 0);
+ controlParticle(p);
+ }
+ }
+
+ mMustResetParticles = true;
+}
diff --git a/src/actorsprite.h b/src/actorsprite.h
new file mode 100644
index 00000000..b5c402eb
--- /dev/null
+++ b/src/actorsprite.h
@@ -0,0 +1,192 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ACTORSPRITE_H
+#define ACTORSPRITE_H
+
+#include "actor.h"
+#include "compoundsprite.h"
+#include "map.h"
+#include "particlecontainer.h"
+
+#include <SDL_types.h>
+
+#include <set>
+
+class SimpleAnimation;
+class StatusEffect;
+
+class ActorSprite : public CompoundSprite, public Actor
+{
+public:
+ enum Type
+ {
+ UNKNOWN,
+ PLAYER,
+ NPC,
+ MONSTER,
+ FLOOR_ITEM
+ };
+
+ enum TargetCursorSize
+ {
+ TC_SMALL = 0,
+ TC_MEDIUM,
+ TC_LARGE,
+ NUM_TC
+ };
+
+ ActorSprite(int id);
+
+ ~ActorSprite();
+
+ int getId() const
+ { return mId; }
+
+ void setId(int id) { mId = id; }
+
+ /**
+ * Returns the type of the ActorSprite.
+ */
+ virtual Type getType() const { return UNKNOWN; }
+
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
+
+ virtual bool drawSpriteAt(Graphics *graphics, int x, int y) const;
+
+ virtual void logic();
+
+ void setMap(Map* map);
+
+ /**
+ * Gets the way the object blocks pathfinding for other objects
+ */
+ virtual Map::BlockType getBlockType() const
+ { return Map::BLOCKTYPE_NONE; }
+
+ /**
+ * Take control of a particle.
+ */
+ void controlParticle(Particle *particle);
+
+ /**
+ * Returns the required size of a target cursor for this being.
+ */
+ virtual TargetCursorSize getTargetCursorSize() const
+ { return TC_MEDIUM; }
+
+ /**
+ * Sets the target animation for this actor.
+ */
+ void setTargetAnimation(SimpleAnimation *animation);
+
+ /**
+ * Untargets the actor.
+ */
+ void untarget() { mUsedTargetCursor = NULL; }
+
+ /**
+ * Triggers a visual effect, such as `level up'. Only draws the visual
+ * effect, does not play sound effects.
+ *
+ * \param effectId ID of the effect to trigger
+ */
+ virtual void triggerEffect(int effectId)
+ {
+ internalTriggerEffect(effectId, false, true);
+ }
+
+ /**
+ * Sets the actor's stun mode. If zero, the being is `normal', otherwise it
+ * is `stunned' in some fashion.
+ */
+ void setStunMode(int stunMode)
+ {
+ if (mStunMode != stunMode)
+ updateStunMode(mStunMode, stunMode);
+ mStunMode = stunMode;
+ }
+
+ void setStatusEffect(int index, bool active);
+
+ /**
+ * A status effect block is a 16 bit mask of status effects. We assign each
+ * such flag a block ID of offset + bitnr.
+ *
+ * These are NOT the same as the status effect indices.
+ */
+ void setStatusEffectBlock(int offset, Uint16 flags);
+
+ virtual void setAlpha(float alpha)
+ { CompoundSprite::setAlpha(alpha); }
+
+ virtual float getAlpha() const
+ { return CompoundSprite::getAlpha(); }
+
+protected:
+ /**
+ * Trigger visual effect, with components
+ *
+ * \param effectId ID of the effect to trigger
+ * \param sfx Whether to trigger sound effects
+ * \param gfx Whether to trigger graphical effects
+ */
+ void internalTriggerEffect(int effectId, bool sfx, bool gfx);
+
+ /**
+ * Notify self that the stun mode has been updated. Invoked by
+ * setStunMode if something changed.
+ */
+ virtual void updateStunMode(int oldMode, int newMode);
+
+ /**
+ * Notify self that a status effect has flipped.
+ * The new flag is passed.
+ */
+ virtual void updateStatusEffect(int index, bool newStatus);
+
+ /**
+ * Handle an update to a status or stun effect
+ *
+ * \param The StatusEffect to effect
+ * \param effectId -1 for stun, otherwise the effect index
+ */
+ virtual void handleStatusEffect(StatusEffect *effect, int effectId);
+
+ void setupSpriteDisplay(const SpriteDisplay &display,
+ bool forceDisplay = true);
+
+ int mId;
+ Uint16 mStunMode; /**< Stun mode; zero if not stunned */
+ std::set<int> mStatusEffects; /**< set of active status effects */
+
+ ParticleList mStunParticleEffects;
+ ParticleVector mStatusParticleEffects;
+ ParticleList mChildParticleEffects;
+
+private:
+ /** Reset particle status effects on next redraw? */
+ bool mMustResetParticles;
+
+ /** Target cursor being used */
+ SimpleAnimation *mUsedTargetCursor;
+};
+
+#endif // ACTORSPRITE_H
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index 59bf2f88..bc595f79 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -41,11 +41,12 @@ AnimatedSprite::AnimatedSprite(SpriteDef *sprite):
mSprite(sprite),
mAction(0),
mAnimation(0),
- mFrame(0),
- mAlpha(1.0f)
+ mFrame(0)
{
assert(mSprite);
+ mAlpha = 1.0f;
+
// Take possession of the sprite
mSprite->incRef();
@@ -193,3 +194,8 @@ int AnimatedSprite::getHeight() const
else
return 0;
}
+
+Image* AnimatedSprite::getImage() const
+{
+ return mFrame ? mFrame->image : 0;
+}
diff --git a/src/animatedsprite.h b/src/animatedsprite.h
index 54b63cc0..833a07a3 100644
--- a/src/animatedsprite.h
+++ b/src/animatedsprite.h
@@ -22,19 +22,18 @@
#ifndef ANIMATEDSPRITE_H
#define ANIMATEDSPRITE_H
-#include "resources/spritedef.h"
+#include "sprite.h"
#include <map>
#include <string>
class Animation;
-class Graphics;
struct Frame;
/**
* Animates a sprite by adding playback state.
*/
-class AnimatedSprite
+class AnimatedSprite : public Sprite
{
public:
/**
@@ -53,59 +52,26 @@ class AnimatedSprite
static AnimatedSprite *load(const std::string &filename,
int variant = 0);
- /**
- * Destructor.
- */
virtual ~AnimatedSprite();
- /**
- * Resets the animated sprite.
- */
void reset();
- /**
- * Plays an action using the current direction
- */
void play(SpriteAction action);
- /**
- * Inform the animation of the passed time so that it can output the
- * correct animation frame.
- */
void update(int time);
- /**
- * Draw the current animation frame at the coordinates given in screen
- * pixels.
- */
bool draw(Graphics* graphics, int posX, int posY) const;
- /**
- * gets the width in pixels of the image of the current frame
- */
int getWidth() const;
- /**
- * gets the height in pixels of the image of the current frame
- */
int getHeight() const;
- /**
- * Sets the direction.
- */
- void setDirection(SpriteDirection direction);
+ Image* getImage() const;
- /**
- * Sets the alpha value of the animated sprite
- */
- void setAlpha(float alpha)
- { mAlpha = alpha; }
+ void setDirection(SpriteDirection direction);
- /**
- * Returns the current alpha opacity of the animated sprite.
- */
- virtual float getAlpha() const
- { return mAlpha; }
+ int getNumberOfLayers()
+ { return 1; }
private:
bool updateCurrentAnimation(unsigned int dt);
@@ -120,7 +86,6 @@ class AnimatedSprite
Action *mAction; /**< The currently active action. */
Animation *mAnimation; /**< The currently active animation. */
Frame *mFrame; /**< The currently active frame. */
- float mAlpha; /**< The alpha opacity used to draw */
};
#endif
diff --git a/src/being.cpp b/src/being.cpp
index 40a6befd..2ce34f94 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -32,6 +32,7 @@
#include "particle.h"
#include "simpleanimation.h"
#include "sound.h"
+#include "sprite.h"
#include "text.h"
#include "statuseffect.h"
@@ -47,17 +48,16 @@
#include "resources/iteminfo.h"
#include "resources/resourcemanager.h"
+#include "net/net.h"
+#include "net/playerhandler.h"
#include "utils/dtor.h"
#include "utils/stringutils.h"
#include "utils/xml.h"
-#include "net/net.h"
-#include "net/playerhandler.h"
#include <cassert>
#include <cmath>
-#define BEING_EFFECTS_FILE "effects.xml"
#define HAIR_FILE "hair.xml"
static const int DEFAULT_BEING_WIDTH = 32;
@@ -68,6 +68,7 @@ int Being::mNumberOfHairstyles = 1;
// TODO: mWalkTime used by eAthena only
Being::Being(int id, int subtype, Map *map):
+ ActorSprite(id),
mFrame(0),
mWalkTime(0),
mEmotion(0), mEmotionTime(0),
@@ -75,20 +76,14 @@ Being::Being(int id, int subtype, Map *map):
mAttackSpeed(350),
mAction(STAND),
mSubType(subtype),
- mId(id),
mDirection(DOWN),
mSpriteDirection(DIRECTION_DOWN),
mDispName(0),
mShowName(false),
mEquippedWeapon(NULL),
mText(0),
- mStunMode(0),
- mStatusParticleEffects(&mStunParticleEffects, false),
- mChildParticleEffects(&mStatusParticleEffects, false),
- mMustResetParticles(false),
mX(0), mY(0),
- mDamageTaken(0),
- mUsedTargetCursor(NULL)
+ mDamageTaken(0)
{
setMap(map);
@@ -101,12 +96,6 @@ Being::Being(int id, int subtype, Map *map):
Being::~Being()
{
- mUsedTargetCursor = NULL;
- delete_all(mSprites);
-
- if (player_node && player_node->getTarget() == this)
- player_node->setTarget(NULL);
-
delete mSpeechBubble;
delete mDispName;
delete mText;
@@ -356,20 +345,6 @@ void Being::setGuildPos(const std::string &pos)
logger->log("Got guild position \"%s\" for being %s(%i)", pos.c_str(), mName.c_str(), mId);
}
-void Being::setMap(Map *map)
-{
- Actor::setMap(map);
-
- // Clear particle effect list because child particles became invalid
- mChildParticleEffects.clear();
- mMustResetParticles = true; // Reset status particles on next redraw
-}
-
-void Being::controlParticle(Particle *particle)
-{
- mChildParticleEffects.addLocally(particle);
-}
-
void Being::fireMissile(Being *victim, const std::string &particle)
{
if (!victim || particle.empty())
@@ -408,9 +383,7 @@ void Being::setAction(Action action, int attackType)
else
currentAction = ACTION_ATTACK;
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->reset();
+ reset();
break;
case HURT:
//currentAction = ACTION_HURT; // Buggy: makes the player stop
@@ -427,9 +400,7 @@ void Being::setAction(Action action, int attackType)
if (currentAction != ACTION_INVALID)
{
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->play(currentAction);
+ play(currentAction);
mAction = action;
}
}
@@ -457,9 +428,7 @@ void Being::setDirection(Uint8 direction)
dir = DIRECTION_LEFT;
mSpriteDirection = dir;
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->setDirection(dir);
+ CompoundSprite::setDirection(dir);
}
/** TODO: Used by eAthena only */
@@ -607,69 +576,7 @@ void Being::logic()
mEmotion = 0;
}
- // Update sprite animations
- if (mUsedTargetCursor)
- mUsedTargetCursor->update(tick_time * MILLISECONDS_IN_A_TICK);
-
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->update(tick_time * MILLISECONDS_IN_A_TICK);
-
- // Restart status/particle effects, if needed
- if (mMustResetParticles)
- {
- mMustResetParticles = false;
- for (std::set<int>::iterator it = mStatusEffects.begin();
- it != mStatusEffects.end(); it++)
- {
- const StatusEffect *effect = StatusEffect::getStatusEffect(*it, true);
- if (effect && effect->particleEffectIsPersistent())
- updateStatusEffect(*it, true);
- }
- }
-
- // Update particle effects
- mChildParticleEffects.moveTo(mPos.x, mPos.y);
-}
-
-void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
-{
- // TODO: Eventually, we probably should fix all sprite offsets so that
- // these translations aren't necessary anymore. The sprites know
- // best where their base point should be.
- const int px = getPixelX() + offsetX - 16;
- // Temporary fix to the Y offset.
- const int py = getPixelY() + offsetY -
- ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
-
- if (mUsedTargetCursor)
- mUsedTargetCursor->draw(graphics, px, py);
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- {
- if (*it)
- {
- if ((*it)->getAlpha() != mAlpha)
- (*it)->setAlpha(mAlpha);
- (*it)->draw(graphics, px, py);
- }
- }
-}
-
-void Being::drawSpriteAt(Graphics *graphics, int x, int y) const
-{
- const int px = x - 16;
- const int py = y - 32;
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- {
- if (*it)
- {
- if ((*it)->getAlpha() != mAlpha)
- (*it)->setAlpha(mAlpha);
- (*it)->draw(graphics, px, py);
- }
- }
+ ActorSprite::logic();
}
void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
@@ -739,67 +646,6 @@ void Being::drawSpeech(int offsetX, int offsetY)
}
}
-void Being::setStatusEffectBlock(int offset, Uint16 newEffects)
-{
- for (int i = 0; i < STATUS_EFFECTS; i++)
- {
- int index = StatusEffect::blockEffectIndexToEffectIndex(offset + i);
-
- if (index != -1)
- setStatusEffect(index, (newEffects & (1 << i)) > 0);
- }
-}
-
-void Being::handleStatusEffect(StatusEffect *effect, int effectId)
-{
- if (!effect)
- return;
-
- // TODO: Find out how this is meant to be used
- // (SpriteAction != Being::Action)
- //SpriteAction action = effect->getAction();
- //if (action != ACTION_INVALID)
- // setAction(action);
-
- Particle *particle = effect->getParticle();
-
- if (effectId >= 0)
- {
- mStatusParticleEffects.setLocally(effectId, particle);
- }
- else
- {
- mStunParticleEffects.clearLocally();
- if (particle)
- mStunParticleEffects.addLocally(particle);
- }
-}
-
-void Being::updateStunMode(int oldMode, int newMode)
-{
- handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1);
- handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1);
-}
-
-void Being::updateStatusEffect(int index, bool newStatus)
-{
- handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index);
-}
-
-void Being::setStatusEffect(int index, bool active)
-{
- const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end();
-
- if (active != wasActive)
- {
- updateStatusEffect(index, active);
- if (active)
- mStatusEffects.insert(index);
- else
- mStatusEffects.erase(index);
- }
-}
-
/** TODO: eAthena only */
int Being::getOffset(char pos, char neg) const
{
@@ -832,125 +678,12 @@ int Being::getOffset(char pos, char neg) const
int Being::getWidth() const
{
- AnimatedSprite *base = NULL;
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if ((base = (*it)))
- break;
-
- if (base)
- return std::max(base->getWidth(), DEFAULT_BEING_WIDTH);
-
- return DEFAULT_BEING_WIDTH;
+ return std::max(CompoundSprite::getWidth(), DEFAULT_BEING_WIDTH);
}
int Being::getHeight() const
{
- AnimatedSprite *base = NULL;
-
- for (SpriteConstIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if ((base = (*it)))
- break;
-
- if (base)
- return std::max(base->getHeight(), DEFAULT_BEING_HEIGHT);
-
- return DEFAULT_BEING_HEIGHT;
-}
-
-void Being::setTargetAnimation(SimpleAnimation *animation)
-{
- mUsedTargetCursor = animation;
- mUsedTargetCursor->reset();
-}
-
-struct EffectDescription {
- std::string mGFXEffect;
- std::string mSFXEffect;
-};
-
-static EffectDescription *default_effect = NULL;
-static std::map<int, EffectDescription *> effects;
-static bool effects_initialized = false;
-
-static EffectDescription *getEffectDescription(xmlNodePtr node, int *id)
-{
- EffectDescription *ed = new EffectDescription;
-
- *id = atoi(XML::getProperty(node, "id", "-1").c_str());
- ed->mSFXEffect = XML::getProperty(node, "audio", "");
- ed->mGFXEffect = XML::getProperty(node, "particle", "");
-
- return ed;
-}
-
-static EffectDescription *getEffectDescription(int effectId)
-{
- if (!effects_initialized)
- {
- XML::Document doc(BEING_EFFECTS_FILE);
- xmlNodePtr root = doc.rootNode();
-
- if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
- {
- logger->log("Error loading being effects file: "
- BEING_EFFECTS_FILE);
- return NULL;
- }
-
- for_each_xml_child_node(node, root)
- {
- int id;
-
- if (xmlStrEqual(node->name, BAD_CAST "effect"))
- {
- EffectDescription *EffectDescription =
- getEffectDescription(node, &id);
- effects[id] = EffectDescription;
- }
- else if (xmlStrEqual(node->name, BAD_CAST "default"))
- {
- EffectDescription *effectDescription =
- getEffectDescription(node, &id);
-
- if (default_effect)
- delete default_effect;
-
- default_effect = effectDescription;
- }
- }
-
- effects_initialized = true;
- } // done initializing
-
- EffectDescription *ed = effects[effectId];
-
- return ed ? ed : default_effect;
-}
-
-void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx)
-{
- logger->log("Special effect #%d on %s", effectId,
- getId() == player_node->getId() ? "self" : "other");
-
- EffectDescription *ed = getEffectDescription(effectId);
-
- if (!ed)
- {
- logger->log("Unknown special effect and no default recorded");
- return;
- }
-
- if (gfx && !ed->mGFXEffect.empty())
- {
- Particle *selfFX;
-
- selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
- controlParticle(selfFX);
- }
-
- if (sfx && !ed->mSFXEffect.empty())
- sound.playSfx(ed->mSFXEffect);
+ return std::max(CompoundSprite::getHeight(), DEFAULT_BEING_HEIGHT);
}
void Being::updateCoords()
@@ -1001,7 +734,7 @@ void Being::showName()
int Being::getNumberOfLayers() const
{
- return mSprites.size();
+ return size();
}
void Being::load()
diff --git a/src/being.h b/src/being.h
index 6264d56d..95f8c802 100644
--- a/src/being.h
+++ b/src/being.h
@@ -22,6 +22,7 @@
#ifndef BEING_H
#define BEING_H
+#include "actorsprite.h"
#include "configlistener.h"
#include "map.h"
#include "particlecontainer.h"
@@ -44,31 +45,17 @@
#define SPEECH_TIME 500
#define SPEECH_MAX_TIME 1000
-class AnimatedSprite;
class FlashText;
-class Graphics;
-class Image;
class ItemInfo;
class Item;
class Particle;
class Position;
-class SimpleAnimation;
class SpeechBubble;
class Text;
-class StatusEffect;
-
-class Being : public Actor, public ConfigListener
+class Being : public ActorSprite, public ConfigListener
{
public:
- enum Type
- {
- UNKNOWN,
- PLAYER,
- NPC,
- MONSTER
- };
-
/**
* Action the being is currently performing
* WARNING: Has to be in sync with the same enum in the Being class
@@ -84,14 +71,6 @@ class Being : public Actor, public ConfigListener
HURT
};
- enum TargetCursorSize
- {
- TC_SMALL = 0,
- TC_MEDIUM,
- TC_LARGE,
- NUM_TC
- };
-
enum Speech
{
NO_SPEECH = 0,
@@ -275,11 +254,6 @@ class Being : public Actor, public ConfigListener
*/
void drawEmotion(Graphics *graphics, int offsetX, int offsetY);
- /**
- * Returns the type of the being.
- */
- virtual Type getType() const { return UNKNOWN; }
-
/**
* Return Being's current Job (player job, npc, monster, creature )
*/
@@ -317,18 +291,6 @@ class Being : public Actor, public ConfigListener
int getAttackSpeed() const { return mAttackSpeed; }
/**
- * Sets the sprite id.
- */
- void setId(int id) { mId = id; }
-
- int getId() const { return mId; }
-
- /**
- * Sets the map the being is on
- */
- void setMap(Map *map);
-
- /**
* Sets the current action.
*/
virtual void setAction(Action action, int attackType = 0);
@@ -369,21 +331,6 @@ class Being : public Actor, public ConfigListener
SpriteDirection getSpriteDirection() const
{ return SpriteDirection(mSpriteDirection); }
- /**
- * Draws this being to the given graphics context.
- *
- * @see Actor::draw(Graphics, int, int)
- *
- * TODO: The following two functions should be combined.
- * at some point draw(), was changed to use mPx and mPy, with arugements
- * only for the offset, drawSpriteAt() takes x, and y and draws the sprite
- * exactly at those coords (though it does do some computing to work how the
- * old draw() worked).
- */
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
-
- virtual void drawSpriteAt(Graphics *graphics, int x, int y) const;
-
void setPosition(const Vector &pos);
/**
@@ -412,17 +359,6 @@ class Being : public Actor, public ConfigListener
virtual int getCollisionRadius() const;
/**
- * Returns the required size of a target cursor for this being.
- */
- virtual Being::TargetCursorSize getTargetCursorSize() const
- { return TC_MEDIUM; }
-
- /**
- * Take control of a particle.
- */
- void controlParticle(Particle *particle);
-
- /**
* Shoots a missile particle from this being, to target being
*/
void fireMissile(Being *target, const std::string &particle);
@@ -439,16 +375,6 @@ class Being : public Actor, public ConfigListener
*/
const Path &getPath() const { return mPath; }
- /**
- * Sets the target animation for this being.
- */
- void setTargetAnimation(SimpleAnimation *animation);
-
- /**
- * Untargets the being
- */
- void untarget() { mUsedTargetCursor = NULL; }
-
/**
* Set the Emoticon type and time displayed above
@@ -466,42 +392,6 @@ class Being : public Actor, public ConfigListener
*/
Uint8 getEmotion() const { return mEmotion; }
- /**
- * Sets the being's stun mode. If zero, the being is `normal',
- * otherwise it is `stunned' in some fashion.
- */
- void setStunMode(int stunMode)
- {
- if (mStunMode != stunMode)
- updateStunMode(mStunMode, stunMode);
- mStunMode = stunMode;
- };
-
- void setStatusEffect(int index, bool active);
-
- /**
- * A status effect block is a 16 bit mask of status effects.
- * We assign each such flag a block ID of offset + bitnr.
- *
- * These are NOT the same as the status effect indices.
- */
- void setStatusEffectBlock(int offset, Uint16 flags);
-
- /**
- * Triggers a visual effect, such as `level up'
- *
- * Only draws the visual effect, does not play sound effects
- *
- * \param effectId ID of the effect to trigger
- */
- virtual void triggerEffect(int effectId)
- {
- internalTriggerEffect(effectId, false, true);
- }
-
- virtual AnimatedSprite *getSprite(int index) const
- { return mSprites[index]; }
-
static void load();
virtual void optionChanged(const std::string &value) {}
@@ -524,41 +414,6 @@ class Being : public Actor, public ConfigListener
*/
virtual void updateCoords();
- /**
- * Gets the way the object blocks pathfinding for other objects
- */
- virtual Map::BlockType getBlockType() const
- { return Map::BLOCKTYPE_NONE; }
-
- /**
- * Trigger visual effect, with components
- *
- * \param effectId ID of the effect to trigger
- * \param sfx Whether to trigger sound effects
- * \param gfx Whether to trigger graphical effects
- */
- void internalTriggerEffect(int effectId, bool sfx, bool gfx);
-
- /**
- * Notify self that the stun mode has been updated. Invoked by
- * setStunMode if something changed.
- */
- virtual void updateStunMode(int oldMode, int newMode);
-
- /**
- * Notify self that a status effect has flipped.
- * The new flag is passed.
- */
- virtual void updateStatusEffect(int index, bool newStatus);
-
- /**
- * Handle an update to a status or stun effect
- *
- * \param The StatusEffect to effect
- * \param effectId -1 for stun, otherwise the effect index
- */
- virtual void handleStatusEffect(StatusEffect *effect, int effectId);
-
virtual void showName();
/** The current sprite Frame number to be displayed */
@@ -578,7 +433,6 @@ class Being : public Actor, public ConfigListener
Action mAction; /**< Action the being is performing */
Uint16 mSubType; /**< Subtype (graphical view, basically) */
- int mId; /**< Unique sprite id */
Uint8 mDirection; /**< Facing direction */
Uint8 mSpriteDirection; /**< Facing direction */
std::string mName; /**< Name of character */
@@ -600,17 +454,6 @@ class Being : public Actor, public ConfigListener
std::string mSpeech;
Text *mText;
const gcn::Color *mTextColor;
- Uint16 mStunMode; /**< Stun mode; zero if not stunned */
- std::set<int> mStatusEffects; /**< set of active status effects */
-
- typedef std::vector<AnimatedSprite*> Sprites;
- typedef Sprites::iterator SpriteIterator;
- typedef Sprites::const_iterator SpriteConstIterator;
- Sprites mSprites;
-
- ParticleList mStunParticleEffects;
- ParticleVector mStatusParticleEffects;
- ParticleList mChildParticleEffects;
Vector mDest; /**< destination coordinates. */
@@ -623,9 +466,6 @@ class Being : public Actor, public ConfigListener
*/
int getOffset(char pos, char neg) const;
- /** Reset particle status effects on next redraw? */
- bool mMustResetParticles;
-
/** Speech Bubble components */
SpeechBubble *mSpeechBubble;
@@ -640,9 +480,6 @@ class Being : public Actor, public ConfigListener
int mX, mY; /**< Position in tile */
int mDamageTaken;
-
- /** Target cursor being used */
- SimpleAnimation *mUsedTargetCursor;
};
#endif
diff --git a/src/compoundsprite.cpp b/src/compoundsprite.cpp
new file mode 100644
index 00000000..a9a521ef
--- /dev/null
+++ b/src/compoundsprite.cpp
@@ -0,0 +1,121 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "compoundsprite.h"
+
+#include "utils/dtor.h"
+
+CompoundSprite::CompoundSprite()
+{
+ mAlpha = 1.0f;
+}
+
+CompoundSprite::~CompoundSprite()
+{
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ delete (*it);
+
+ clear();
+}
+
+void CompoundSprite::reset()
+{
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ (*it)->reset();
+}
+
+void CompoundSprite::play(SpriteAction action)
+{
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ (*it)->play(action);
+}
+
+void CompoundSprite::update(int time)
+{
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ (*it)->update(time);
+}
+
+bool CompoundSprite::draw(Graphics* graphics, int posX, int posY) const
+{
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ {
+ if (*it)
+ {
+ if ((*it)->getAlpha() != mAlpha)
+ (*it)->setAlpha(mAlpha);
+ (*it)->draw(graphics, posX, posY);
+ }
+ }
+
+ return true;
+}
+
+int CompoundSprite::getWidth() const
+{
+ Sprite *base = NULL;
+
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if ((base = (*it)))
+ break;
+
+ if (base)
+ return base->getWidth();
+
+ return 0;
+}
+
+int CompoundSprite::getHeight() const
+{
+ Sprite *base = NULL;
+
+ SpriteConstIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if ((base = (*it)))
+ break;
+
+ if (base)
+ return base->getHeight();
+
+ return 0;
+}
+
+Image* CompoundSprite::getImage() const
+{
+ // TODO http://bugs.manasource.org/view.php?id=24
+ return NULL;
+}
+
+void CompoundSprite::setDirection(SpriteDirection direction)
+{
+ SpriteIterator it, it_end;
+ for (it = begin(), it_end = end(); it != it_end; it++)
+ if (*it)
+ (*it)->setDirection(direction);
+}
diff --git a/src/compoundsprite.h b/src/compoundsprite.h
new file mode 100644
index 00000000..b3925216
--- /dev/null
+++ b/src/compoundsprite.h
@@ -0,0 +1,67 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMPOUNDSPRITE_H
+#define COMPOUNDSPRITE_H
+
+#include "sprite.h"
+
+#include <vector>
+
+class CompoundSprite : public Sprite, public std::vector<Sprite*>
+{
+public:
+ CompoundSprite();
+
+ ~CompoundSprite();
+
+ virtual void reset();
+
+ virtual void play(SpriteAction action);
+
+ virtual void update(int time);
+
+ virtual bool draw(Graphics* graphics, int posX, int posY) const;
+
+ /**
+ * Gets the width in pixels of the first sprite in the list.
+ */
+ virtual int getWidth() const;
+
+ /**
+ * Gets the height in pixels of the first sprite in the list.
+ */
+ virtual int getHeight() const;
+
+ virtual Image* getImage() const;
+
+ virtual void setDirection(SpriteDirection direction);
+
+ virtual Sprite *getSprite(int index) const
+ { return at(index); }
+
+ int getNumberOfLayers()
+ { return size(); }
+};
+
+typedef CompoundSprite::iterator SpriteIterator;
+typedef CompoundSprite::const_iterator SpriteConstIterator;
+
+#endif // COMPOUNDSPRITE_H
diff --git a/src/flooritem.cpp b/src/flooritem.cpp
index e5a9d215..84e07f35 100644
--- a/src/flooritem.cpp
+++ b/src/flooritem.cpp
@@ -21,52 +21,34 @@
#include "flooritem.h"
-#include "graphics.h"
-#include "item.h"
-#include "map.h"
+#include "net/net.h"
-#include "resources/image.h"
+#include "resources/itemdb.h"
+#include "resources/iteminfo.h"
FloorItem::FloorItem(int id,
int itemId,
int x,
int y,
Map *map):
- mId(id)
+ ActorSprite(id),
+ mItemId(itemId),
+ mX(x),
+ mY(y)
{
setMap(map);
- mPos.x = x * map->getTileWidth();
- mPos.y = y * map->getTileHeight();
- // Create a corresponding item instance
- mItem = new Item(itemId);
-}
-FloorItem::~FloorItem()
-{
- delete mItem;
-}
+ // TODO: Eventually, we probably should fix all sprite offsets so that
+ // these translations aren't necessary anymore. The sprites know
+ // best where their base point should be.
+ mPos.x = x * map->getTileWidth() + 16;
+ mPos.y = y * map->getTileHeight() +
+ ((Net::getNetworkType() == ServerInfo::MANASERV) ? 15 : 32);
-int FloorItem::getItemId() const
-{
- return mItem->getId();
+ setupSpriteDisplay(ItemDB::get(itemId).getDisplay());
}
-Item *FloorItem::getItem() const
+const ItemInfo &FloorItem::getInfo() const
{
- return mItem;
-}
-
-void FloorItem::draw(Graphics *graphics, int offsetX, int offsetY) const
-{
- if (mItem)
- {
- Image *image = mItem->getDrawImage();
-
- if (image)
- if (mAlpha != image->getAlpha())
- image->setAlpha(mAlpha);
-
- graphics->drawImage(image, getPixelX() + offsetX,
- getPixelY() + offsetY);
- }
+ return ItemDB::get(mId);
}
diff --git a/src/flooritem.h b/src/flooritem.h
index 17b7b54d..e599c939 100644
--- a/src/flooritem.h
+++ b/src/flooritem.h
@@ -22,16 +22,14 @@
#ifndef FLOORITEM_H
#define FLOORITEM_H
-#include "map.h"
+#include "actorsprite.h"
-class Graphics;
-class Image;
-class Item;
+class ItemInfo;
/**
* An item lying on the floor.
*/
-class FloorItem : public Actor
+class FloorItem : public ActorSprite
{
public:
/**
@@ -49,39 +47,29 @@ class FloorItem : public Actor
int y,
Map *map);
- ~FloorItem();
-
- /**
- * Returns instance ID of this item.
- */
- int getId() const
- { return mId; }
+ Type getType() const { return FLOOR_ITEM; }
/**
* Returns the item ID.
*/
- int getItemId() const;
+ int getItemId() const
+ { return mItemId; }
/**
- * Returns the item object. Useful for adding an item link for the
- * floor item to chat.
+ * Returns the item info for this floor item. Useful for adding an item
+ * link for the floor item to chat.
*/
- Item *getItem() const;
+ const ItemInfo &getInfo() const;
- /**
- * Draws this floor item to the given graphics context.
- *
- * @see Actor::draw(Graphics, int, int)
- */
- void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual int getTileX() const
+ { return mX; }
- /** We consider flooritems (at least for now) to be one layer-sprites */
- virtual int getNumberOfLayers() const
- { return 1; }
+ virtual int getTileY() const
+ { return mY; }
private:
- int mId;
- Item *mItem;
+ int mItemId;
+ int mX, mY;
};
#endif
diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp
index 9115b704..b4471db8 100644
--- a/src/flooritemmanager.cpp
+++ b/src/flooritemmanager.cpp
@@ -78,3 +78,12 @@ FloorItem *FloorItemManager::findByCoordinates(int x, int y) const
return NULL;
}
+
+void FloorItemManager::logic()
+{
+ FloorItemIterator it, it_end;
+
+ for (it = mFloorItems.begin(), it_end = mFloorItems.end(); it != it_end;
+ it++)
+ (*it)->logic();
+}
diff --git a/src/flooritemmanager.h b/src/flooritemmanager.h
index 62ca8dc2..7df6288e 100644
--- a/src/flooritemmanager.h
+++ b/src/flooritemmanager.h
@@ -41,6 +41,11 @@ class FloorItemManager
FloorItem *findById(int id) const;
FloorItem *findByCoordinates(int x, int y) const;
+ /**
+ * Performs floor item logic.
+ */
+ void logic();
+
private:
typedef std::list<FloorItem*> FloorItems;
typedef FloorItems::iterator FloorItemIterator;
diff --git a/src/game.cpp b/src/game.cpp
index 79f21863..74997b90 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -335,6 +335,7 @@ void Game::logic()
// Handle all necessary game logic
beingManager->logic();
+ floorItemManager->logic();
particleEngine->update();
if (mCurrentMap)
mCurrentMap->update();
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 520b4005..77e919a9 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -182,11 +182,11 @@ void PopupMenu::showPopup(int x, int y, Being *being)
void PopupMenu::showPopup(int x, int y, FloorItem *floorItem)
{
mFloorItem = floorItem;
- mItem = floorItem->getItem();
+ ItemInfo info = floorItem->getInfo();
mBrowserBox->clearRows();
// Floor item can be picked up (single option, candidate for removal)
- std::string name = ItemDB::get(mFloorItem->getItemId()).getName();
+ std::string name = info.getName();
mBrowserBox->addRow(strprintf("@@pickup|%s@@", strprintf(_("Pick up %s"),
name.c_str()).c_str()));
mBrowserBox->addRow(strprintf("@@chat|%s@@", _("Add to chat")));
@@ -283,7 +283,10 @@ void PopupMenu::handleLink(const std::string &link)
else if (link == "chat")
{
- chatWindow->addItemText(mItem->getInfo().getName());
+ if (mItem)
+ chatWindow->addItemText(mItem->getInfo().getName());
+ else if (mFloorItem)
+ chatWindow->addItemText(mFloorItem->getInfo().getName());
}
else if (link == "split")
diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp
index 57cbec6f..a953f474 100644
--- a/src/gui/widgets/playerbox.cpp
+++ b/src/gui/widgets/playerbox.cpp
@@ -86,8 +86,8 @@ void PlayerBox::draw(gcn::Graphics *graphics)
{
// Draw character
const int bs = getFrameSize();
- const int x = getWidth() / 2 + bs;
- const int y = getHeight() - bs;
+ const int x = getWidth() / 2 + bs - 16;
+ const int y = getHeight() - bs - 32;
mPlayer->drawSpriteAt(static_cast<Graphics*>(graphics), x, y);
}
diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp
index feb9548d..76c05d64 100644
--- a/src/imageparticle.cpp
+++ b/src/imageparticle.cpp
@@ -39,10 +39,10 @@ ImageParticle::~ImageParticle()
mImage->decRef();
}
-void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
+bool ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
{
if (!mAlive || !mImage)
- return;
+ return false;
int screenX = (int) mPos.x + offsetX - mImage->getWidth() / 2;
int screenY = (int) mPos.y - (int)mPos.z + offsetY - mImage->getHeight()/2;
@@ -52,9 +52,7 @@ void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
screenX > graphics->getWidth() ||
screenY + mImage->getHeight() < 0 ||
screenY > graphics->getHeight())
- {
- return;
- }
+ return false;
float alphafactor = mAlpha;
@@ -65,5 +63,5 @@ void ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
alphafactor *= (float) mLifetimePast / (float) mFadeIn;
mImage->setAlpha(alphafactor);
- graphics->drawImage(mImage, screenX, screenY);
+ return graphics->drawImage(mImage, screenX, screenY);
}
diff --git a/src/imageparticle.h b/src/imageparticle.h
index bc32400d..23909fa3 100644
--- a/src/imageparticle.h
+++ b/src/imageparticle.h
@@ -49,7 +49,7 @@ class ImageParticle : public Particle
/**
* Draws the particle image
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
protected:
Image *mImage; /**< The image used for this particle. */
diff --git a/src/imagesprite.cpp b/src/imagesprite.cpp
new file mode 100644
index 00000000..504aba96
--- /dev/null
+++ b/src/imagesprite.cpp
@@ -0,0 +1,44 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "imagesprite.h"
+
+#include "graphics.h"
+
+ImageSprite::ImageSprite(Image *image):
+ mImage(image)
+{
+ mAlpha = mImage->getAlpha();
+
+ mImage->incRef();
+}
+
+ImageSprite::~ImageSprite()
+{
+ mImage->decRef();
+}
+
+bool ImageSprite::draw(Graphics* graphics, int posX, int posY) const
+{
+ if (mImage->getAlpha() != mAlpha)
+ mImage->setAlpha(mAlpha);
+
+ return graphics->drawImage(mImage, posX, posY);
+}
diff --git a/src/imagesprite.h b/src/imagesprite.h
new file mode 100644
index 00000000..83fcfa12
--- /dev/null
+++ b/src/imagesprite.h
@@ -0,0 +1,63 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IMAGESPRITE_H
+#define IMAGESPRITE_H
+
+#include "sprite.h"
+
+#include "resources/image.h"
+
+class Graphics;
+
+class ImageSprite : public Sprite
+{
+public:
+ ImageSprite(Image *image);
+
+ ~ImageSprite();
+
+ virtual void reset() {}
+
+ virtual void play(SpriteAction action) {}
+
+ virtual void update(int time) {}
+
+ virtual bool draw(Graphics* graphics, int posX, int posY) const;
+
+ virtual int getWidth() const
+ { return mImage->getWidth(); }
+
+ virtual int getHeight() const
+ { return mImage->getHeight(); }
+
+ virtual Image* getImage() const
+ { return mImage; }
+
+ virtual void setDirection(SpriteDirection direction) {}
+
+ int getNumberOfLayers()
+ { return 1; }
+
+private:
+ Image *mImage;
+};
+
+#endif // IMAGESPRITE_H
diff --git a/src/item.cpp b/src/item.cpp
index 79ccd2c3..19bb7c23 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -57,7 +57,8 @@ void Item::setId(int id)
mDrawImage->decRef();
ResourceManager *resman = ResourceManager::getInstance();
- std::string imagePath = "graphics/items/" + getInfo().getImageName();
+ SpriteDisplay display = getInfo().getDisplay();
+ std::string imagePath = "graphics/items/" + display.image;
mImage = resman->getImage(imagePath);
mDrawImage = resman->getImage(imagePath);
diff --git a/src/monster.cpp b/src/monster.cpp
index d25c6c90..922bfa7a 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -79,8 +79,7 @@ void Monster::setAction(Action action, int attackType)
case ATTACK:
mAttackType = attackType;
currentAction = getInfo().getAttackAction(attackType);
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- (*it)->reset();
+ reset();
//attack particle effect
particleEffect = getInfo().getAttackParticleEffect(attackType);
@@ -112,9 +111,7 @@ void Monster::setAction(Action action, int attackType)
if (currentAction != ACTION_INVALID)
{
- for (SpriteIterator it = mSprites.begin(); it != mSprites.end(); it++)
- if (*it)
- (*it)->play(currentAction);
+ play(currentAction);
mAction = action;
}
}
@@ -125,32 +122,7 @@ void Monster::setSubtype(Uint16 subtype)
const MonsterInfo &info = getInfo();
- // Setup Monster sprites
- const std::list<std::string> &sprites = info.getSprites();
-
- mSprites.clear();
- for (std::list<std::string>::const_iterator i = sprites.begin();
- i != sprites.end(); i++)
- {
- std::string file = "graphics/sprites/" + *i;
- mSprites.push_back(AnimatedSprite::load(file));
- }
-
- // Ensure that something is shown
- if (mSprites.size() == 0)
- {
- mSprites.push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
- }
-
- if (Particle::enabled)
- {
- const std::list<std::string> &particleEffects = info.getParticleEffects();
- for (std::list<std::string>::const_iterator i = particleEffects.begin();
- i != particleEffects.end(); i++)
- {
- controlParticle(particleEngine->addEffect((*i), 0, 0));
- }
- }
+ setupSpriteDisplay(info.getDisplay());
}
void Monster::handleAttack(Being *victim, int damage, AttackType type)
diff --git a/src/monster.h b/src/monster.h
index 9bb8e3b9..843c3fc8 100644
--- a/src/monster.h
+++ b/src/monster.h
@@ -40,8 +40,7 @@ class Monster : public Being
virtual void setSubtype(Uint16 subtype);
- virtual TargetCursorSize
- getTargetCursorSize() const;
+ virtual TargetCursorSize getTargetCursorSize() const;
/**
* Handles an attack of another being by this monster. Plays a hit or
diff --git a/src/npc.cpp b/src/npc.cpp
index cdfe5193..bdbcfb76 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -38,7 +38,7 @@
#include "resources/npcdb.h"
NPC::NPC(int id, int subtype, Map *map):
- Player(id, subtype, map, true)
+ Being(id, subtype, map)
{
setSubtype(subtype);
@@ -60,32 +60,7 @@ void NPC::setSubtype(Uint16 subtype)
{
Being::setSubtype(subtype);
- NPCInfo info = NPCDB::get(subtype);
-
- mSprites.clear();
- // Setup NPC sprites
- for (std::list<NPCsprite*>::const_iterator i = info.sprites.begin();
- i != info.sprites.end();
- i++)
- {
- std::string file = "graphics/sprites/" + (*i)->sprite;
- int variant = (*i)->variant;
- mSprites.push_back(AnimatedSprite::load(file, variant));
- mSpriteIDs.push_back(0);
- mSpriteColors.push_back("");
- }
-
- if (Particle::enabled)
- {
- //setup particle effects
- for (std::list<std::string>::const_iterator i = info.particles.begin();
- i != info.particles.end();
- i++)
- {
- Particle *p = particleEngine->addEffect(*i, 0, 0);
- this->controlParticle(p);
- }
- }
+ setupSpriteDisplay(NPCDB::get(subtype), false);
}
void NPC::talk()
@@ -93,11 +68,6 @@ void NPC::talk()
Net::getNpcHandler()->talk(mId);
}
-void NPC::setSprite(unsigned int slot, int id, const std::string &color)
-{
- // Do nothing
-}
-
bool NPC::isTalking()
{
return NpcDialog::isActive() || BuyDialog::isActive() ||
diff --git a/src/npc.h b/src/npc.h
index 0abd2395..a21731e7 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -22,12 +22,12 @@
#ifndef NPC_H
#define NPC_H
-#include "player.h"
+#include "being.h"
class Graphics;
class Text;
-class NPC : public Player
+class NPC : public Being
{
public:
NPC(int id, int subtype, Map *map);
@@ -40,9 +40,6 @@ class NPC : public Player
void talk();
- void setSprite(unsigned int slot, int id,
- const std::string &color = "");
-
/**
* Gets the way an NPC is blocked by other things on the map
*/
@@ -65,9 +62,6 @@ class NPC : public Player
*/
virtual Map::BlockType getBlockType() const
{ return Map::BLOCKTYPE_CHARACTER; } //blocks like a player character
-
- // Colors don't change for NPCs
- virtual void updateColors() {}
};
#endif
diff --git a/src/particle.cpp b/src/particle.cpp
index 398e6a9c..6a3fd7da 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -61,6 +61,7 @@ Particle::Particle(Map *map):
mLifetimePast(0),
mFadeOut(0),
mFadeIn(0),
+ mAlpha(1.0f),
mAutoDelete(true),
mAllowSizeAdjust(false),
mGravity(0.0f),
@@ -93,8 +94,9 @@ void Particle::setupEngine()
logger->log("Particle engine set up");
}
-void Particle::draw(Graphics *, int, int) const
+bool Particle::draw(Graphics *, int, int) const
{
+ return false;
}
bool Particle::update()
diff --git a/src/particle.h b/src/particle.h
index 64221514..2be169c1 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -83,7 +83,7 @@ class Particle : public Actor
/**
* Draws the particle image.
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
/**
* Necessary for sorting with the other sprites.
@@ -247,12 +247,18 @@ class Particle : public Actor
virtual int getNumberOfLayers() const
{ return 1; }
+ virtual float getAlpha() const
+ { return 1.0f; }
+
+ virtual void setAlpha(float alpha) {}
+
protected:
bool mAlive; /**< Is the particle supposed to be drawn and updated?*/
int mLifetimeLeft; /**< Lifetime left in game ticks*/
int mLifetimePast; /**< Age of the particle in game ticks*/
int mFadeOut; /**< Lifetime in game ticks left where fading out begins*/
int mFadeIn; /**< Age in game ticks where fading in is finished*/
+ float mAlpha; /**< Opacity of the graphical representation of the particle */
// generic properties
bool mAutoDelete; /**< May the particle request its deletion by the parent particle? */
diff --git a/src/player.cpp b/src/player.cpp
index 1f706cb8..10c4c500 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -43,23 +43,20 @@
#include "utils/stringutils.h"
-Player::Player(int id, int subtype, Map *map, bool isNPC):
+Player::Player(int id, int subtype, Map *map):
Being(id, subtype, map),
mGender(GENDER_UNSPECIFIED),
mParty(NULL),
mIsGM(false)
{
- if (!isNPC)
+ for (int i = 0; i < Net::getCharHandler()->maxSprite(); i++)
{
- for (int i = 0; i < Net::getCharHandler()->maxSprite(); i++)
- {
- mSprites.push_back(NULL);
- mSpriteIDs.push_back(0);
- mSpriteColors.push_back("");
- }
-
- setSubtype(subtype);
+ push_back(NULL);
+ mSpriteIDs.push_back(0);
+ mSpriteColors.push_back("");
}
+
+ setSubtype(subtype);
mShowName = config.getValue("visiblenames", 1);
config.addListener("visiblenames", this);
@@ -151,7 +148,7 @@ void Player::setGender(Gender gender)
mGender = gender;
// Reload all subsprites
- for (unsigned int i = 0; i < mSprites.size(); i++)
+ for (unsigned int i = 0; i < size(); i++)
{
if (mSpriteIDs.at(i) != 0)
setSprite(i, mSpriteIDs.at(i), mSpriteColors.at(i));
@@ -169,16 +166,13 @@ void Player::setGM(bool gm)
void Player::setSprite(int slot, int id, const std::string &color,
bool isWeapon)
{
- if (getType() == NPC)
- return;
-
assert(slot < Net::getCharHandler()->maxSprite());
// id = 0 means unequip
if (id == 0)
{
- delete mSprites[slot];
- mSprites[slot] = NULL;
+ delete at(slot);
+ at(slot) = NULL;
if (isWeapon)
mEquippedWeapon = NULL;
@@ -200,10 +194,10 @@ void Player::setSprite(int slot, int id, const std::string &color,
if (equipmentSprite)
equipmentSprite->setDirection(getSpriteDirection());
- if (mSprites[slot])
- delete mSprites[slot];
+ if (at(slot))
+ delete at(slot);
- mSprites[slot] = equipmentSprite;
+ at(slot) = equipmentSprite;
if (isWeapon)
mEquippedWeapon = &ItemDB::get(id);
diff --git a/src/player.h b/src/player.h
index e75870a0..0bb59428 100644
--- a/src/player.h
+++ b/src/player.h
@@ -47,7 +47,7 @@ class Player : public Being
/**
* Constructor.
*/
- Player(int id, int subtype, Map *map, bool isNPC = false);
+ Player(int id, int subtype, Map *map);
~Player();
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 4638f00e..57df6143 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -46,6 +46,7 @@ namespace
// Forward declarations
static void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node);
static void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node);
+static void loadFloorSprite(SpriteDisplay *display, xmlNodePtr node);
static char const *const fields[][2] =
{
@@ -114,7 +115,7 @@ void ItemDB::load()
mUnknown = new ItemInfo;
mUnknown->setName(_("Unknown item"));
- mUnknown->setImageName("");
+ mUnknown->setDisplay(SpriteDisplay());
mUnknown->setSprite("error.xml", GENDER_MALE);
mUnknown->setSprite("error.xml", GENDER_FEMALE);
@@ -154,9 +155,11 @@ void ItemDB::load()
int attackRange = XML::getProperty(node, "attack-range", 0);
std::string missileParticle = XML::getProperty(node, "missile-particle", "");
+ SpriteDisplay display;
+ display.image = image;
+
ItemInfo *itemInfo = new ItemInfo;
itemInfo->setId(id);
- itemInfo->setImageName(image);
itemInfo->setName(name.empty() ? _("unnamed") : name);
itemInfo->setDescription(description);
itemInfo->setType(itemTypeFromString(typeStr));
@@ -202,8 +205,14 @@ void ItemDB::load()
{
loadSoundRef(itemInfo, itemChild);
}
+ else if (xmlStrEqual(itemChild->name, BAD_CAST "floor"))
+ {
+ loadFloorSprite(&display, itemChild);
+ }
}
+ itemInfo->setDisplay(display);
+
mItemInfos[id] = itemInfo;
if (!name.empty())
{
@@ -334,3 +343,22 @@ void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node)
event.c_str());
}
}
+
+void loadFloorSprite(SpriteDisplay *display, xmlNodePtr floorNode)
+{
+ for_each_xml_child_node(spriteNode, floorNode)
+ {
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
+ {
+ SpriteReference *currentSprite = new SpriteReference;
+ currentSprite->sprite = (const char*)spriteNode->xmlChildrenNode->content;
+ currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ display->sprites.push_back(currentSprite);
+ }
+ else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
+ {
+ std::string particlefx = (const char*)spriteNode->xmlChildrenNode->content;
+ display->particles.push_back(particlefx);
+ }
+ }
+}
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index a7c0ddca..f42ac8e6 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -143,11 +143,11 @@ class ItemInfo
std::string getParticleEffect() const { return mParticle; }
- void setImageName(const std::string &imageName)
- { mImageName = imageName; }
+ void setDisplay(SpriteDisplay display)
+ { mDisplay = display; }
- const std::string &getImageName() const
- { return mImageName; }
+ const SpriteDisplay &getDisplay() const
+ { return mDisplay; }
void setDescription(const std::string &description)
{ mDescription = description; }
@@ -201,7 +201,7 @@ class ItemInfo
const std::string &getSound(EquipmentSoundEvent event) const;
protected:
- std::string mImageName; /**< The filename of the icon image. */
+ SpriteDisplay mDisplay; /**< Display info (like icon) */
std::string mName;
std::string mDescription; /**< Short description. */
std::string mEffect; /**< Description of effects. */
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
index e9afa7ef..658321f1 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -45,7 +45,16 @@ void MonsterDB::load()
if (mLoaded)
return;
- mUnknown.addSprite("error.xml");
+ {
+ SpriteReference *unknownSprite = new SpriteReference;
+ unknownSprite->sprite = "error.xml";
+ unknownSprite->variant = 0;
+
+ SpriteDisplay display;
+ display.sprites.push_front(unknownSprite);
+
+ mUnknown.setDisplay(display);
+ }
logger->log("Initializing monster database...");
@@ -94,13 +103,17 @@ void MonsterDB::load()
currentInfo->setTargetCursorSize(Being::TC_MEDIUM);
}
+ SpriteDisplay display;
+
//iterate <sprite>s and <sound>s
for_each_xml_child_node(spriteNode, monsterNode)
{
if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
{
- currentInfo->addSprite(
- (const char*) spriteNode->xmlChildrenNode->content);
+ SpriteReference *currentSprite = new SpriteReference;
+ currentSprite->sprite = (const char*)spriteNode->xmlChildrenNode->content;
+ currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ display.sprites.push_back(currentSprite);
}
else if (xmlStrEqual(spriteNode->name, BAD_CAST "sound"))
{
@@ -145,10 +158,12 @@ void MonsterDB::load()
}
else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
{
- currentInfo->addParticleEffect(
+ display.particles.push_back(
(const char*) spriteNode->xmlChildrenNode->content);
}
}
+ currentInfo->setDisplay(display);
+
mMonsterInfos[XML::getProperty(monsterNode, "id", 0) + offset] = currentInfo;
}
diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp
index 9104c721..41ce5b6b 100644
--- a/src/resources/monsterinfo.cpp
+++ b/src/resources/monsterinfo.cpp
@@ -91,8 +91,3 @@ void MonsterInfo::addMonsterAttack(int id,
a->action = action;
mMonsterAttacks[id] = a;
}
-
-void MonsterInfo::addParticleEffect(const std::string &filename)
-{
- mParticleEffects.push_back(filename);
-}
diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h
index f074254a..7741f762 100644
--- a/src/resources/monsterinfo.h
+++ b/src/resources/monsterinfo.h
@@ -24,6 +24,8 @@
#include "being.h"
+#include "resources/spritedef.h"
+
#include <list>
#include <map>
#include <string>
@@ -59,23 +61,21 @@ class MonsterInfo
void setName(const std::string &name) { mName = name; }
- void addSprite(const std::string &filename)
- { mSprites.push_back(filename); }
+ void setDisplay(SpriteDisplay display)
+ { mDisplay = display; }
+
+ const SpriteDisplay &getDisplay() const
+ { return mDisplay; }
void setTargetCursorSize(Being::TargetCursorSize targetCursorSize)
{ mTargetCursorSize = targetCursorSize; }
void addSound(MonsterSoundEvent event, const std::string &filename);
- void addParticleEffect(const std::string &filename);
-
const std::string &getName() const
{ return mName; }
- const std::list<std::string>& getSprites() const
- { return mSprites; }
-
- Being::TargetCursorSize getTargetCursorSize() const
+ ActorSprite::TargetCursorSize getTargetCursorSize() const
{ return mTargetCursorSize; }
const std::string &getSound(MonsterSoundEvent event) const;
@@ -91,16 +91,12 @@ class MonsterInfo
SpriteAction getAttackAction(int attackType) const;
- const std::list<std::string>& getParticleEffects() const
- { return mParticleEffects; }
-
private:
+ SpriteDisplay mDisplay;
std::string mName;
- std::list<std::string> mSprites;
Being::TargetCursorSize mTargetCursorSize;
std::map<MonsterSoundEvent, std::vector<std::string>* > mSounds;
std::map<int, MonsterAttack*> mMonsterAttacks;
- std::list<std::string> mParticleEffects;
};
#endif // MONSTERINFO_H
diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp
index 4bc5a6e4..e2628257 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -28,7 +28,7 @@
namespace
{
NPCInfos mNPCInfos;
- NPCInfo mUnknown;
+ SpriteDisplay mUnknown;
bool mLoaded = false;
}
@@ -37,10 +37,12 @@ void NPCDB::load()
if (mLoaded)
return;
- NPCsprite *unknownSprite = new NPCsprite;
- unknownSprite->sprite = "error.xml";
- unknownSprite->variant = 0;
- mUnknown.sprites.push_back(unknownSprite);
+ {
+ SpriteReference *unknownSprite = new SpriteReference;
+ unknownSprite->sprite = "error.xml";
+ unknownSprite->variant = 0;
+ mUnknown.sprites.push_back(unknownSprite);
+ }
logger->log("Initializing NPC database...");
@@ -65,13 +67,13 @@ void NPCDB::load()
continue;
}
- NPCInfo *currentInfo = new NPCInfo;
+ SpriteDisplay *currentInfo = new SpriteDisplay;
for_each_xml_child_node(spriteNode, npcNode)
{
if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
{
- NPCsprite *currentSprite = new NPCsprite;
+ SpriteReference *currentSprite = new SpriteReference;
currentSprite->sprite = (const char*)spriteNode->xmlChildrenNode->content;
currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
currentInfo->sprites.push_back(currentSprite);
@@ -113,7 +115,7 @@ void NPCDB::unload()
mLoaded = false;
}
-const NPCInfo& NPCDB::get(int id)
+const SpriteDisplay& NPCDB::get(int id)
{
NPCInfosIterator i = mNPCInfos.find(id);
diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h
index 9da873e4..84ae4e24 100644
--- a/src/resources/npcdb.h
+++ b/src/resources/npcdb.h
@@ -22,23 +22,11 @@
#ifndef NPC_DB_H
#define NPC_DB_H
-#include <list>
-#include <map>
-#include <string>
-
-struct NPCsprite
-{
- std::string sprite;
- int variant;
-};
+#include "resources/spritedef.h"
-struct NPCInfo
-{
- std::list<NPCsprite*> sprites;
- std::list<std::string> particles;
-};
+#include <map>
-typedef std::map<int, NPCInfo*> NPCInfos;
+typedef std::map<int, SpriteDisplay*> NPCInfos;
/**
* NPC information database.
@@ -49,7 +37,7 @@ namespace NPCDB
void unload();
- const NPCInfo& get(int id);
+ const SpriteDisplay& get(int id);
typedef NPCInfos::iterator NPCInfosIterator;
}
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index 24f346f7..3d23edcd 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -164,6 +164,8 @@ void ResourceManager::searchAndAddArchives(const std::string &path,
const char *dirSep = PHYSFS_getDirSeparator();
char **list = PHYSFS_enumerateFiles(path.c_str());
+ printf("Path: %s -> %s\n", path.c_str(), PHYSFS_getRealDir(path.c_str()));
+
for (char **i = list; *i; i++)
{
size_t len = strlen(*i);
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index 5bb6078e..d5db542c 100644
--- a/src/resources/spritedef.h
+++ b/src/resources/spritedef.h
@@ -26,12 +26,28 @@
#include <libxml/tree.h>
+#include <list>
#include <map>
#include <string>
class Action;
class ImageSet;
+struct SpriteReference
+{
+ std::string sprite;
+ int variant;
+};
+
+struct SpriteDisplay
+{
+ std::string image;
+ std::list<SpriteReference*> sprites;
+ std::list<std::string> particles;
+};
+
+typedef std::list<SpriteReference*>::const_iterator SpriteRefs;
+
enum SpriteAction
{
ACTION_DEFAULT = 0,
diff --git a/src/sprite.h b/src/sprite.h
new file mode 100644
index 00000000..d8345ab8
--- /dev/null
+++ b/src/sprite.h
@@ -0,0 +1,92 @@
+/*
+ * The Mana Client
+ * Copyright (C) 2010 The Mana Developers
+ *
+ * This file is part of The Mana Client.
+ *
+ * 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.
+ *
+ * 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SPRITE_H
+#define SPRITE_H
+
+#include "resources/spritedef.h"
+
+class Graphics;
+class Image;
+
+class Sprite
+{
+ public:
+ virtual ~Sprite() {}
+
+ /**
+ * Resets the sprite.
+ */
+ virtual void reset() = 0;
+
+ /**
+ * Plays an action using the current direction
+ */
+ virtual void play(SpriteAction action) = 0;
+
+ /**
+ * Inform the animation of the passed time so that it can output the
+ * correct animation frame.
+ */
+ virtual void update(int time) = 0;
+
+ /**
+ * Draw the current animation frame at the coordinates given in screen
+ * pixels.
+ */
+ virtual bool draw(Graphics* graphics, int posX, int posY) const = 0;
+
+ /**
+ * Gets the width in pixels of the image of the current frame
+ */
+ virtual int getWidth() const = 0;
+
+ /**
+ * Gets the height in pixels of the image of the current frame
+ */
+ virtual int getHeight() const = 0;
+
+ /**
+ * Returns a reference to the current image being drawn.
+ */
+ virtual Image* getImage() const = 0;
+
+ /**
+ * Sets the direction.
+ */
+ virtual void setDirection(SpriteDirection direction) = 0;
+
+ /**
+ * Sets the alpha value of the animated sprite
+ */
+ virtual void setAlpha(float alpha)
+ { mAlpha = alpha; }
+
+ /**
+ * Returns the current alpha opacity of the animated sprite.
+ */
+ virtual float getAlpha() const
+ { return mAlpha; }
+
+ protected:
+ float mAlpha; /**< The alpha opacity used to draw */
+};
+
+#endif // SPRITE_H
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index e6226449..827343fa 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -36,10 +36,10 @@ TextParticle::TextParticle(Map *map, const std::string &text,
{
}
-void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
+bool TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
{
if (!mAlive)
- return;
+ return false;
int screenX = (int) mPos.x + offsetX;
int screenY = (int) mPos.y - (int) mPos.z + offsetY;
@@ -58,4 +58,6 @@ void TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const
TextRenderer::renderText(graphics, mText,
screenX, screenY, gcn::Graphics::CENTER,
color, mTextFont, mOutline, false);
+
+ return true;
}
diff --git a/src/textparticle.h b/src/textparticle.h
index a61bf8d9..7d99a057 100644
--- a/src/textparticle.h
+++ b/src/textparticle.h
@@ -38,7 +38,7 @@ class TextParticle : public Particle
/**
* Draws the particle image.
*/
- virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual bool draw(Graphics *graphics, int offsetX, int offsetY) const;
// hack to improve text visibility
virtual int getPixelY() const