diff options
Diffstat (limited to 'src/being.cpp')
-rw-r--r-- | src/being.cpp | 255 |
1 files changed, 237 insertions, 18 deletions
diff --git a/src/being.cpp b/src/being.cpp index 3a772fbd..f14fd64e 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -1,9 +1,8 @@ /* - * Aethyra + * The Mana World * Copyright (C) 2004 The Mana World Development Team * - * This file is part of Aethyra based on original code - * from The Mana World. + * This file is part of The Mana World. * * 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 @@ -20,11 +19,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> -#include <cmath> +#include "being.h" #include "animatedsprite.h" -#include "being.h" #include "configuration.h" #include "effectmanager.h" #include "game.h" @@ -36,6 +33,7 @@ #include "simpleanimation.h" #include "sound.h" #include "text.h" +#include "statuseffect.h" #include "gui/speechbubble.h" @@ -53,8 +51,17 @@ #include "utils/dtor.h" #include "utils/gettext.h" #include "utils/stringutils.h" +#include "utils/xml.h" + +#include <cassert> +#include <cmath> +#define BEING_EFFECTS_FILE "effects.xml" +#define HAIR_FILE "hair.xml" + +int Being::mNumberOfHairColors = 1; int Being::mNumberOfHairstyles = 1; +std::vector<std::string> Being::hairColors; static const int X_SPEECH_OFFSET = 18; static const int Y_SPEECH_OFFSET = 60; @@ -81,15 +88,18 @@ Being::Being(int id, int job, Map *map): mHairStyle(1), mHairColor(0), mGender(GENDER_UNSPECIFIED), mPx(0), mPy(0), + mStunMode(0), mSprites(VECTOREND_SPRITE, NULL), mSpriteIDs(VECTOREND_SPRITE, 0), mSpriteColors(VECTOREND_SPRITE, ""), - mChildParticleEffects(), + mStatusParticleEffects(&mStunParticleEffects, false), + mChildParticleEffects(&mStatusParticleEffects, false), + mMustResetParticles(false), mUsedTargetCursor(NULL) { setMap(map); - mSpeechBubble = new SpeechBubble(); + mSpeechBubble = new SpeechBubble; mSpeech = ""; mNameColor = &guiPalette->getColor(Palette::CHAT); @@ -224,15 +234,21 @@ void Being::takeDamage(Being *attacker, int amount, AttackType type) color = &guiPalette->getColor(Palette::HIT_MONSTER_PLAYER); } - if (amount > 0 && type == CRITICAL) - { - particleEngine->addTextSplashEffect("crit!", mPx + 16, mPy + 16, - color, font, true); - } - // Show damage number particleEngine->addTextSplashEffect(damage, mPx + 16, mPy + 16, - color, font, true); + color, font, true); + + if (amount > 0) + { + if (type != CRITICAL) + { + effectManager->trigger(26, this); + } + else + { + effectManager->trigger(28, this); + } + } } void Being::handleAttack(Being *victim, int damage, AttackType type) @@ -256,6 +272,7 @@ void Being::setMap(Map *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) @@ -410,7 +427,7 @@ void Being::logic() } // Update sprite animations - if (mUsedTargetCursor != NULL) + if (mUsedTargetCursor) mUsedTargetCursor->update(tick_time * 10); for (int i = 0; i < VECTOREND_SPRITE; i++) @@ -419,6 +436,17 @@ void Being::logic() mSprites[i]->update(tick_time * 10); } + // 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((float) mPx + 16.0f, (float) mPy + 32.0f); } @@ -428,7 +456,7 @@ void Being::draw(Graphics *graphics, int offsetX, int offsetY) const int px = mPx + offsetX; int py = mPy + offsetY; - if (mUsedTargetCursor != NULL) + if (mUsedTargetCursor) mUsedTargetCursor->draw(graphics, px, py); for (int i = 0; i < VECTOREND_SPRITE; i++) @@ -512,6 +540,62 @@ Being::Type 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; + + // 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); + } +} + int Being::getOffset(char pos, char neg) const { // Check whether we're walking in the requested direction @@ -568,6 +652,114 @@ void Being::setTargetAnimation(SimpleAnimation* 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]; + + if (!ed) + return default_effect; + else + return ed; +} + +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); + } +} + +int Being::getHairStyleCount() +{ + return mNumberOfHairstyles; +} + +int Being::getHairColorCount() +{ + return mNumberOfHairColors; +} + +std::string Being::getHairColor(int index) +{ + if (index < 0 || index >= mNumberOfHairColors) + return "#000000"; + + return hairColors[index]; +} + void Being::load() { // Hairstyles are encoded as negative numbers. Count how far negative @@ -579,5 +771,32 @@ void Being::load() hairstyles++; } mNumberOfHairstyles = hairstyles; -} + XML::Document doc(HAIR_FILE); + xmlNodePtr root = doc.rootNode(); + + // Add an initial hair color + hairColors.resize(1, "#000000"); + + if (!root || !xmlStrEqual(root->name, BAD_CAST "colors")) + { + logger->log("Error loading being hair configuration file"); + } else { + for_each_xml_child_node(node, root) + { + if (xmlStrEqual(node->name, BAD_CAST "color")) + { + int index = atoi(XML::getProperty(node, "id", "-1").c_str()); + std::string value = XML::getProperty(node, "value", ""); + + if (index >= 0 && !value.empty()) { + if (index >= mNumberOfHairColors) { + mNumberOfHairColors = index + 1; + hairColors.resize(mNumberOfHairColors, "#000000"); + } + hairColors[index] = value; + } + } + } + } +} |