summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFate <fate-tmw@googlemail.com>2008-12-07 04:00:55 -0700
committerFate <fate-tmw@googlemail.com>2008-12-07 04:00:55 -0700
commit3fcd6a549fc825f4185a6dc248922e02988caed5 (patch)
tree2def3534088760ec3d06860eb0af936ec1e66b5b /src
parent68923d079602d8a8b7f35e1b56032e03e323ea09 (diff)
downloadmana-3fcd6a549fc825f4185a6dc248922e02988caed5.tar.gz
mana-3fcd6a549fc825f4185a6dc248922e02988caed5.tar.bz2
mana-3fcd6a549fc825f4185a6dc248922e02988caed5.tar.xz
mana-3fcd6a549fc825f4185a6dc248922e02988caed5.zip
Added client-side status change handlers (text, icon, particle effect, audio).
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/being.cpp63
-rw-r--r--src/being.h54
-rw-r--r--src/graphics.cpp2
-rw-r--r--src/gui/ministatus.cpp41
-rw-r--r--src/gui/ministatus.h13
-rw-r--r--src/gui/viewport.cpp6
-rw-r--r--src/localplayer.cpp40
-rw-r--r--src/localplayer.h7
-rw-r--r--src/net/beinghandler.cpp71
-rw-r--r--src/particlecontainer.cpp1
-rw-r--r--src/resources/spritedef.h25
-rw-r--r--src/statuseffect.cpp171
-rw-r--r--src/statuseffect.h101
14 files changed, 559 insertions, 38 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e9d69b5e..655c9ce0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -294,6 +294,8 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
sound.cpp \
sound.h \
sprite.h \
+ statuseffect.cpp \
+ statuseffect.h \
text.cpp \
text.h \
textmanager.cpp \
diff --git a/src/being.cpp b/src/being.cpp
index 7c6d91e7..5f7ad73f 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -33,6 +33,7 @@
#include "sound.h"
#include "localplayer.h"
#include "text.h"
+#include "statuseffect.h"
#include "resources/itemdb.h"
#include "resources/resourcemanager.h"
@@ -72,6 +73,7 @@ Being::Being(int id, int job, Map *map):
mGender(2),
mSpeechTime(0),
mPx(0), mPy(0),
+ mStunMode(0),
mSprites(VECTOREND_SPRITE, NULL),
mSpriteIDs(VECTOREND_SPRITE, 0),
mSpriteColors(VECTOREND_SPRITE, ""),
@@ -441,6 +443,67 @@ Being::getType() const
return UNKNOWN;
}
+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;
+
+ effect->playSFX();
+
+ SpriteAction action = effect->getAction();
+ if (action != ACTION_INVALID)
+ setAction(action);
+
+ Particle *particle = effect->getParticle();
+
+ if (particle) {
+ if (effectId >= 0)
+ mStatusParticleEffects.setLocally(effectId, particle);
+ else {
+ mStunParticleEffects.clearLocally();
+ 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);
+ }
+}
+
int
Being::getOffset(char pos, char neg) const
{
diff --git a/src/being.h b/src/being.h
index 15e1e6f9..9390dccd 100644
--- a/src/being.h
+++ b/src/being.h
@@ -26,7 +26,7 @@
#include <memory>
#include <string>
#include <SDL_types.h>
-#include <bitset>
+#include <set>
#include "sprite.h"
#include "map.h"
@@ -46,6 +46,9 @@ class ImageSet;
class Particle;
class Text;
+
+class StatusEffect;
+
/**
* A position along a being's path.
*/
@@ -109,7 +112,6 @@ class Being : public Sprite
NUM_TC
};
-
/**
* Directions, to be used as bitmask values
*/
@@ -356,6 +358,27 @@ class Being : public Sprite
}
/**
+ * 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
@@ -400,6 +423,29 @@ class Being : public Sprite
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);
+
Uint32 mId; /**< Unique sprite id */
Uint16 mWalkSpeed; /**< Walking speed */
Uint8 mDirection; /**< Facing direction */
@@ -407,8 +453,6 @@ class Being : public Sprite
std::string mName; /**< Name of character */
SpriteIterator mSpriteIterator;
- typedef std::bitset<STATUS_EFFECTS> StatusEffects;
-
/** Engine-related infos about weapon. */
const ItemInfo* mEquippedWeapon;
@@ -419,7 +463,7 @@ class Being : public Sprite
Uint32 mSpeechTime;
Sint32 mPx, mPy; /**< Pixel coordinates */
Uint16 mStunMode; /**< Stun mode; zero if not stunned */
- StatusEffects mStatusEffects; /**< Bitset of active status effects */
+ std::set<int> mStatusEffects; /**< set of active status effects */
std::vector<AnimatedSprite*> mSprites;
std::vector<int> mSpriteIDs;
diff --git a/src/graphics.cpp b/src/graphics.cpp
index 6920bcb0..c8cb0091 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -123,7 +123,7 @@ bool Graphics::drawImage(Image *image, int x, int y)
{
return drawImage(image, 0, 0, x, y, image->mBounds.w, image->mBounds.h);
}
-
+#include <cstdio>
bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY,
int width, int height, bool)
{
diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp
index baae14a7..436c90cd 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -79,6 +79,26 @@ MiniStatusWindow::MiniStatusWindow():
loadWindowState();
}
+void
+MiniStatusWindow::setIcon(int index, AnimatedSprite *sprite)
+{
+ if (index >= (int) mIcons.size())
+ mIcons.resize(index + 1, NULL);
+
+ if (mIcons[index])
+ delete mIcons[index];
+
+ mIcons[index] = sprite;
+}
+
+void
+MiniStatusWindow::eraseIcon(int index)
+{
+ mIcons.erase(mIcons.begin() + index);
+}
+
+extern volatile int tick_time;
+
void MiniStatusWindow::update()
{
// HP Bar coloration
@@ -128,10 +148,27 @@ void MiniStatusWindow::update()
*/
mXpLabel->setCaption(updatedText.str());
+
+ for (unsigned int i = 0; i < mIcons.size(); i++)
+ if (mIcons[i])
+ mIcons[i]->update(tick_time * 10);
+
}
-void MiniStatusWindow::draw(gcn::Graphics *graphics)
+void MiniStatusWindow::draw(gcn::Graphics *gcn_graphics)
{
update();
- drawChildren(graphics);
+ drawChildren(gcn_graphics);
+}
+
+void
+MiniStatusWindow::drawIcons(Graphics *graphics)
+{
+ // Draw icons
+ int icon_x = mXpBar->getX() + mXpBar->getWidth() + 4;
+ for (unsigned int i = 0; i < mIcons.size(); i++)
+ if (mIcons[i]) {
+ mIcons[i]->draw(graphics, icon_x, 3);
+ icon_x += 2 + mIcons[i]->getWidth();
+ }
}
diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h
index d7f6f68c..fa9d3d24 100644
--- a/src/gui/ministatus.h
+++ b/src/gui/ministatus.h
@@ -23,10 +23,12 @@
#define _TMW_MINISTATUS_H
#include <iosfwd>
+#include <vector>
#include "window.h"
#include "../guichanfwd.h"
+#include "../animatedsprite.h"
class ProgressBar;
@@ -48,6 +50,15 @@ class MiniStatusWindow : public Window
*/
void draw(gcn::Graphics *graphics);
+ /**
+ * Sets one of the icons
+ */
+ void setIcon(int index, AnimatedSprite *sprite);
+
+ void eraseIcon(int index);
+
+ void drawIcons(Graphics *graphics);
+
private:
/**
* Updates this dialog with values from player_node
@@ -63,6 +74,8 @@ class MiniStatusWindow : public Window
gcn::Label *mHpLabel;
gcn::Label *mMpLabel;
gcn::Label *mXpLabel;
+
+ std::vector<AnimatedSprite *> mIcons;
};
#endif
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 37e7bcce..4b661ba3 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -25,6 +25,7 @@
#include "gui.h"
#include "popupmenu.h"
+#include "ministatus.h"
#include "../simpleanimation.h"
#include "../beingmanager.h"
@@ -137,6 +138,8 @@ Viewport::setMap(Map *map)
mMap = map;
}
+extern MiniStatusWindow *miniStatusWindow;
+
void
Viewport::draw(gcn::Graphics *gcnGraphics)
{
@@ -268,6 +271,9 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
(*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
}
+ if (miniStatusWindow)
+ miniStatusWindow->drawIcons(graphics);
+
// Draw contained widgets
WindowContainer::draw(gcnGraphics);
}
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 3550b092..3df80f0b 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -30,8 +30,10 @@
#include "particle.h"
#include "sound.h"
#include "monster.h"
+#include "statuseffect.h"
#include "gui/gui.h"
+#include "gui/ministatus.h"
#include "net/messageout.h"
#include "net/protocol.h"
@@ -479,3 +481,41 @@ void LocalPlayer::setGotoTarget(Being *target)
mGoingToTarget = true;
setDestination(target->mX, target->mY);
}
+
+
+extern MiniStatusWindow *miniStatusWindow;
+
+void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId)
+{
+ Being::handleStatusEffect(effect, effectId);
+ if (effect) {
+ effect->deliverMessage();
+
+ AnimatedSprite *sprite = effect->getIcon();
+
+ if (!sprite) {
+ // delete sprite, if necessary
+ for (unsigned int i = 0; i < mStatusEffectIcons.size();)
+ if (mStatusEffectIcons[i] == effectId) {
+ mStatusEffectIcons.erase(mStatusEffectIcons.begin() + i);
+ miniStatusWindow->eraseIcon(i);
+ } else i++;
+ } else {
+ // replace sprite or append
+ bool found = false;
+
+ for (unsigned int i = 0; i < mStatusEffectIcons.size(); i++)
+ if (mStatusEffectIcons[i] == effectId) {
+ miniStatusWindow->setIcon(i, sprite);
+ found = true;
+ break;
+ }
+
+ if (!found) { // add new
+ int offset = mStatusEffectIcons.size();
+ miniStatusWindow->setIcon(offset, sprite);
+ mStatusEffectIcons.push_back(effectId);
+ }
+ }
+ }
+}
diff --git a/src/localplayer.h b/src/localplayer.h
index 34f10a4a..5e0a4419 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -22,6 +22,8 @@
#ifndef _TMW_LOCALPLAYER_H
#define _TMW_LOCALPLAYER_H
+#include <vector>
+
#include "player.h"
// TODO move into some sane place...
@@ -199,6 +201,9 @@ class LocalPlayer : public Player
float mLastAttackTime; /**< Used to synchronize the charge dialog */
protected:
+ virtual void
+ handleStatusEffect(StatusEffect *effect, int effectId);
+
void walk(unsigned char dir);
int mXp; /**< Experience points. */
@@ -214,6 +219,8 @@ class LocalPlayer : public Player
int mDestX; /**< X coordinate of destination. */
int mDestY; /**< Y coordinate of destination. */
+ std::vector<int> mStatusEffectIcons;
+
Inventory *mInventory;
};
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index 086b4280..9d91d988 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -60,6 +60,7 @@ BeingHandler::BeingHandler(bool enableSync):
SMSG_PLAYER_STOP,
SMSG_PLAYER_MOVE_TO_ATTACK,
0x0119,
+ 0x0196,
0
};
handledMessages = _messages;
@@ -70,12 +71,15 @@ void BeingHandler::handleMessage(MessageIn *msg)
Uint32 id;
Uint16 job, speed;
Uint16 headTop, headMid, headBottom;
- Uint16 shoes, gloves, cape, misc1, misc2;
+ Uint16 shoes, gloves;
Uint16 weapon, shield;
Sint16 param1;
+ int stunMode;
+ Uint32 statusEffects;
Sint8 type;
+ Uint16 status;
Being *srcBeing, *dstBeing;
- int hairStyle, hairColor;
+ int hairStyle, hairColor, flag;
switch (msg->getId())
{
@@ -84,9 +88,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
// Information about a being in range
id = msg->readInt32();
speed = msg->readInt16();
- msg->readInt16(); // opt1
- msg->readInt16(); // opt2
- msg->readInt16(); // option
+ stunMode = msg->readInt16(); // opt1
+ statusEffects = msg->readInt16(); // opt2
+ statusEffects |= ((Uint32)msg->readInt16()) << 16; // option
job = msg->readInt16(); // class
dstBeing = beingManager->findBeing(id);
@@ -110,6 +114,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setAction(Being::STAND);
}
+
// Prevent division by 0 when calculating frame
if (speed == 0) { speed = 150; }
@@ -134,8 +139,8 @@ void BeingHandler::handleMessage(MessageIn *msg)
msg->readInt16(); // unknown
msg->readInt16(); // unknown
msg->readInt16(); // manner
- msg->readInt16(); // karma
- msg->readInt8(); // unknown
+ dstBeing->setStatusEffectBlock(32, msg->readInt16()); // opt3
+ msg->readInt8(); // karma
dstBeing->setGender(1 - msg->readInt8()); // gender
// Set these after the gender, as the sprites may be gender-specific
@@ -165,6 +170,10 @@ void BeingHandler::handleMessage(MessageIn *msg)
msg->readInt8(); // unknown
msg->readInt8(); // unknown
msg->readInt8(); // unknown / sit
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
break;
case SMSG_BEING_MOVE2:
@@ -376,9 +385,10 @@ void BeingHandler::handleMessage(MessageIn *msg)
// An update about a player, potentially including movement.
id = msg->readInt32();
speed = msg->readInt16();
- cape = msg->readInt16();
- misc1 = msg->readInt16();
- misc2 = msg->readInt16();
+ stunMode = msg->readInt16(); // opt1; Aethyra use this as cape
+ statusEffects = msg->readInt16(); // opt2; Aethyra use this as misc1
+ statusEffects |= ((Uint32) msg->readInt16())
+ << 16; // status.options; Aethyra uses this as misc2
job = msg->readInt16();
dstBeing = beingManager->findBeing(id);
@@ -406,8 +416,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
msg->readInt16(); // clothes color - Aethyra-"abused" as shoes, we ignore it
msg->readInt16(); // head dir - Aethyra-"abused" as gloves, we ignore it
msg->readInt32(); // guild
- msg->readInt32(); // emblem
+ msg->readInt16(); // emblem
msg->readInt16(); // manner
+ dstBeing->setStatusEffectBlock(32, msg->readInt16()); // opt3
msg->readInt8(); // karma
dstBeing->setGender(1 - msg->readInt8()); // gender
@@ -417,9 +428,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
dstBeing->setSprite(Being::HAT_SPRITE, headTop);
- dstBeing->setSprite(Being::CAPE_SPRITE, cape);
- dstBeing->setSprite(Being::MISC1_SPRITE, misc1);
- dstBeing->setSprite(Being::MISC2_SPRITE, misc2);
+ //dstBeing->setSprite(Being::CAPE_SPRITE, cape);
+ //dstBeing->setSprite(Being::MISC1_SPRITE, misc1);
+ //dstBeing->setSprite(Being::MISC2_SPRITE, misc2);
dstBeing->setHairStyle(hairStyle, hairColor);
if (msg->getId() == SMSG_PLAYER_MOVE)
@@ -461,6 +472,10 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->mWalkTime = tick_time;
dstBeing->mFrame = 0;
+
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
break;
case SMSG_PLAYER_STOP:
@@ -500,10 +515,30 @@ void BeingHandler::handleMessage(MessageIn *msg)
break;
case 0x0119:
- // Change in players look
- logger->log("0x0119 %i %i %i %x %i", msg->readInt32(),
- msg->readInt16(), msg->readInt16(), msg->readInt16(),
- msg->readInt8());
+ // Change in players' flags
+ id = msg->readInt32();
+ dstBeing = beingManager->findBeing(id);
+ stunMode = msg->readInt16();
+ statusEffects = msg->readInt16();
+ statusEffects |= ((Uint32) msg->readInt16()) << 16;
+ msg->readInt8();
+
+ if (dstBeing) {
+ dstBeing->setStunMode(stunMode);
+ dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff);
+ dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff);
+ }
+ break;
+
+ case 0x0196:
+ // Status change
+ status = msg->readInt16();
+ id = msg->readInt32();
+ flag = msg->readInt8(); // 0: stop, 1: start
+
+ dstBeing = beingManager->findBeing(id);
+ if (dstBeing)
+ dstBeing->setStatusEffect(status, flag);
break;
}
}
diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp
index 12ef5733..f7672eac 100644
--- a/src/particlecontainer.cpp
+++ b/src/particlecontainer.cpp
@@ -130,6 +130,7 @@ ParticleVector::setLocally(int index, Particle *particle)
if (mIndexedElements.size() <= (unsigned) index)
mIndexedElements.resize(index + 1, NULL);
+ particle->disableAutoDelete();
mIndexedElements[index] = particle;
}
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index c7b94d9a..88f9b7b7 100644
--- a/src/resources/spritedef.h
+++ b/src/resources/spritedef.h
@@ -78,6 +78,19 @@ class SpriteDef : public Resource
*/
Action *getAction(SpriteAction action) const;
+ /**
+ * Converts a string into a SpriteAction enum.
+ */
+ static SpriteAction
+ makeSpriteAction(const std::string &action);
+
+ /**
+ * Converts a string into a SpriteDirection enum.
+ */
+ static SpriteDirection
+ makeSpriteDirection(const std::string &direction);
+
+
private:
/**
* Constructor.
@@ -132,18 +145,6 @@ class SpriteDef : public Resource
void
substituteAction(SpriteAction complete, SpriteAction with);
- /**
- * Converts a string into a SpriteAction enum.
- */
- static SpriteAction
- makeSpriteAction(const std::string &action);
-
- /**
- * Converts a string into a SpriteDirection enum.
- */
- static SpriteDirection
- makeSpriteDirection(const std::string &direction);
-
typedef std::map<std::string, ImageSet*> ImageSets;
typedef ImageSets::iterator ImageSetIterator;
diff --git a/src/statuseffect.cpp b/src/statuseffect.cpp
new file mode 100644
index 00000000..564d26f0
--- /dev/null
+++ b/src/statuseffect.cpp
@@ -0,0 +1,171 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <map>
+
+#include "gui/chat.h"
+#include "statuseffect.h"
+
+#include "log.h"
+#include "utils/xml.h"
+
+
+#define STATUS_EFFECTS_FILE "status-effects.xml"
+
+StatusEffect::StatusEffect() {};
+StatusEffect::~StatusEffect() {};
+
+void
+StatusEffect::playSFX()
+{
+ if (mSFXEffect != "")
+ sound.playSfx(mSFXEffect);
+}
+
+void
+StatusEffect::deliverMessage()
+{
+ if (mMessage != "")
+ chatWindow->chatLog(mMessage, BY_SERVER);
+}
+
+Particle *
+StatusEffect::getParticle()
+{
+ if (mParticleEffect == "")
+ return NULL;
+ else
+ return particleEngine->addEffect(mParticleEffect, 0, 0);
+}
+
+AnimatedSprite *
+StatusEffect::getIcon()
+{
+ if (mIcon == "")
+ return NULL;
+ else {
+ AnimatedSprite * sprite = AnimatedSprite::load("graphics/sprites/" + mIcon);
+ if (false && sprite) {
+ sprite->play(ACTION_DEFAULT);
+ sprite->reset();
+ }
+ return sprite;
+ }
+}
+
+SpriteAction
+StatusEffect::getAction()
+{
+ if (mAction == "")
+ return ACTION_INVALID;
+ else
+ return SpriteDef::makeSpriteAction(mAction);
+}
+
+
+// -- initialisation and static parts --
+
+
+typedef std::map<int, StatusEffect *> status_effect_map[2];
+
+static status_effect_map statusEffects;
+static status_effect_map stunEffects;
+static std::map<int, int> blockEffectIndexMap;
+
+int
+StatusEffect::blockEffectIndexToEffectIndex(int blockIndex)
+{
+ if (blockEffectIndexMap.find(blockIndex) == blockEffectIndexMap.end())
+ return -1;
+ return blockEffectIndexMap[blockIndex];
+}
+
+StatusEffect *
+StatusEffect::getStatusEffect(int index, bool enabling)
+{
+ load();
+ return statusEffects[enabling][index];
+}
+
+StatusEffect *
+StatusEffect::getStunEffect(int index, bool enabling)
+{
+ load();
+ return stunEffects[enabling][index];
+}
+
+static bool status_effects_loaded = false;
+
+
+
+void
+StatusEffect::load()
+{
+ if (status_effects_loaded)
+ return;
+
+ status_effects_loaded = true;
+
+ XML::Document doc(STATUS_EFFECTS_FILE);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "status-effects"))
+ {
+ logger->log("Error loading status effects file: "
+ STATUS_EFFECTS_FILE);
+ return;
+ }
+
+ for_each_xml_child_node(node, rootNode)
+ {
+ status_effect_map *the_map = NULL;
+
+ int index = atoi(XML::getProperty(node, "id", "-1").c_str());
+
+ if (xmlStrEqual(node->name, BAD_CAST "status-effect"))
+ {
+ the_map = &statusEffects;
+ int block_index = atoi(XML::getProperty(node, "block-id", "-1").c_str());
+
+ if (index >= 0 && block_index >= 0)
+ blockEffectIndexMap[block_index] = index;
+ } else if (xmlStrEqual(node->name, BAD_CAST "stun-effect"))
+ the_map = &stunEffects;
+
+ if (the_map) {
+ StatusEffect *startEffect = new StatusEffect();
+ StatusEffect *endEffect = new StatusEffect();
+
+ startEffect->mMessage = XML::getProperty(node, "start-message", "");
+ startEffect->mSFXEffect = XML::getProperty(node, "start-audio", "");
+ startEffect->mParticleEffect = XML::getProperty(node, "start-particle", "");
+ startEffect->mIcon = XML::getProperty(node, "icon", "");
+ startEffect->mAction = XML::getProperty(node, "action", "");
+
+ endEffect->mMessage = XML::getProperty(node, "end-message", "");
+ endEffect->mSFXEffect = XML::getProperty(node, "end-audio", "");
+ endEffect->mParticleEffect = XML::getProperty(node, "end-particle", "");
+
+ (*the_map)[1][index] = startEffect;
+ (*the_map)[0][index] = endEffect;
+ }
+ }
+}
diff --git a/src/statuseffect.h b/src/statuseffect.h
new file mode 100644
index 00000000..9db90687
--- /dev/null
+++ b/src/statuseffect.h
@@ -0,0 +1,101 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef STATUS_EFFECT_H
+#define STATUS_EFFECT_H
+
+#include "resources/animation.h"
+#include "particle.h"
+#include "animatedsprite.h"
+#include "sound.h"
+
+class StatusEffect
+{
+public:
+ StatusEffect();
+ ~StatusEffect();
+
+ /**
+ * Plays the sound effect associated with this status effect, if possible
+ */
+ void playSFX();
+
+ /**
+ * Delivers the chat message associated with this status effect, if possible
+ */
+ void deliverMessage();
+
+ /**
+ * Creates the particle effect associated with this status effect, if possible
+ */
+ Particle *
+ getParticle();
+
+ /**
+ * Retrieves the status icon for this effect, if applicable
+ */
+ AnimatedSprite *
+ getIcon();
+
+ /**
+ * Retrieves an action to perform, or ACTION_INVALID
+ */
+ SpriteAction
+ getAction();
+
+
+ /**
+ * Retrieves a status effect.
+ *
+ * \param index Index of the status effect.
+ * \param enabling Whether to retrieve the activating effect (true) or
+ * the deactivating effect (false).
+ */
+ static StatusEffect *getStatusEffect(int index, bool enabling);
+
+ /**
+ * Retrieves a stun effect.
+ *
+ * \param index Index of the stun effect.
+ * \param enabling Whether to retrieve the activating effect (true) or
+ * the deactivating effect (false).
+ */
+ static StatusEffect *getStunEffect(int index, bool enabling);
+
+ /**
+ * Maps a block effect index to its corresponding effect index. Block
+ * effect indices are used for opt2/opt3/status.option blocks; their
+ * mapping to regular effect indices is handled in the config file.
+ *
+ * Returns -1 on failure.
+ */
+ static int blockEffectIndexToEffectIndex(int blocKIndex);
+
+private:
+ static void load();
+
+ std::string mMessage;
+ std::string mSFXEffect;
+ std::string mParticleEffect;
+ std::string mIcon;
+ std::string mAction;
+};
+
+#endif // !defined(STATUS_EFFECT_H)