diff options
author | Fate <fate-tmw@googlemail.com> | 2008-12-07 04:00:55 -0700 |
---|---|---|
committer | Fate <fate-tmw@googlemail.com> | 2008-12-07 04:00:55 -0700 |
commit | 3fcd6a549fc825f4185a6dc248922e02988caed5 (patch) | |
tree | 2def3534088760ec3d06860eb0af936ec1e66b5b /src | |
parent | 68923d079602d8a8b7f35e1b56032e03e323ea09 (diff) | |
download | mana-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.am | 2 | ||||
-rw-r--r-- | src/being.cpp | 63 | ||||
-rw-r--r-- | src/being.h | 54 | ||||
-rw-r--r-- | src/graphics.cpp | 2 | ||||
-rw-r--r-- | src/gui/ministatus.cpp | 41 | ||||
-rw-r--r-- | src/gui/ministatus.h | 13 | ||||
-rw-r--r-- | src/gui/viewport.cpp | 6 | ||||
-rw-r--r-- | src/localplayer.cpp | 40 | ||||
-rw-r--r-- | src/localplayer.h | 7 | ||||
-rw-r--r-- | src/net/beinghandler.cpp | 71 | ||||
-rw-r--r-- | src/particlecontainer.cpp | 1 | ||||
-rw-r--r-- | src/resources/spritedef.h | 25 | ||||
-rw-r--r-- | src/statuseffect.cpp | 171 | ||||
-rw-r--r-- | src/statuseffect.h | 101 |
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) |