diff options
-rw-r--r-- | src/being.cpp | 9 | ||||
-rw-r--r-- | src/imageparticle.cpp | 2 | ||||
-rw-r--r-- | src/particle.cpp | 74 | ||||
-rw-r--r-- | src/particle.h | 30 | ||||
-rw-r--r-- | src/particleemitter.cpp | 29 | ||||
-rw-r--r-- | src/particleemitter.h | 8 | ||||
-rw-r--r-- | src/textparticle.cpp | 2 |
7 files changed, 124 insertions, 30 deletions
diff --git a/src/being.cpp b/src/being.cpp index 138e5c5a..20225f47 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -530,19 +530,20 @@ void Being::fireMissile(Being *victim, const std::string &particle) if (!victim || particle.empty()) return; - Particle *target = particleEngine->createChild(); - Particle *missile = target->addEffect(particle, getPixelX(), getPixelY()); + Particle *missile = particleEngine->addEffect(particle, getPixelX(), getPixelY()); if (missile) { - target->setLifetime(2000); + Particle *target = particleEngine->createChild(); target->moveBy(Vector(0.0f, 0.0f, 32.0f)); + target->setLifetime(1000); victim->controlParticle(target); missile->setDestination(target, 7, 0); missile->setDieDistance(8); missile->setLifetime(900); } + } void Being::setAction(Action action, int attackType) @@ -582,7 +583,7 @@ void Being::setAction(Action action, int attackType) { switch (mSpriteDirection) { - case DIRECTION_DOWN: rotation = 0; break; + case DIRECTION_DOWN: rotation = 0; break; case DIRECTION_LEFT: rotation = 90; break; case DIRECTION_UP: rotation = 180; break; case DIRECTION_RIGHT: rotation = 270; break; diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp index 76c05d64..2900239f 100644 --- a/src/imageparticle.cpp +++ b/src/imageparticle.cpp @@ -41,7 +41,7 @@ ImageParticle::~ImageParticle() bool ImageParticle::draw(Graphics *graphics, int offsetX, int offsetY) const { - if (!mAlive || !mImage) + if (!isAlive() || !mImage) return false; int screenX = (int) mPos.x + offsetX - mImage->getWidth() / 2; diff --git a/src/particle.cpp b/src/particle.cpp index e3c45a9f..cb2faa77 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -56,14 +56,15 @@ bool Particle::enabled = true; const float Particle::PARTICLE_SKY = 800.0f; Particle::Particle(Map *map): - mAlive(true), + mAlpha(1.0f), mLifetimeLeft(-1), mLifetimePast(0), mFadeOut(0), mFadeIn(0), - mAlpha(1.0f), + mAlive(ALIVE), mAutoDelete(true), mAllowSizeAdjust(false), + mDeathEffectConditions(0x00), mGravity(0.0f), mRandomness(0), mBounce(0.0f), @@ -81,6 +82,7 @@ Particle::~Particle() { // Delete child emitters and child particles clear(); + //update particle count Particle::particleCount--; } @@ -104,12 +106,12 @@ bool Particle::update() if (!mMap) return false; - if (mLifetimeLeft == 0) - mAlive = false; + if (mLifetimeLeft == 0 && mAlive == ALIVE) + mAlive = DEAD_TIMEOUT; Vector oldPos = mPos; - if (mAlive) + if (mAlive == ALIVE) { //calculate particle movement if (mMomentum != 1.0f) @@ -143,7 +145,7 @@ bool Particle::update() { if (mInvDieDistance > 0.0f && invHypotenuse > mInvDieDistance) { - mAlive = false; + mAlive = DEAD_IMPACT; } float accFactor = invHypotenuse * mAcceleration; mVelocity -= dist * accFactor; @@ -171,7 +173,7 @@ bool Particle::update() } mLifetimePast++; - if (mPos.z > PARTICLE_SKY || mPos.z < 0.0f) + if (mPos.z < 0.0f) { if (mBounce > 0.0f) { @@ -181,8 +183,11 @@ bool Particle::update() } else { - mAlive = false; + mAlive = DEAD_FLOOR; } + } else if (mPos.z > PARTICLE_SKY) + { + mAlive = DEAD_SKY; } // Update child emitters @@ -202,6 +207,17 @@ bool Particle::update() } } + // create death effect when the particle died + if (mAlive != ALIVE && mAlive != DEAD_LONG_AGO) + { + if ((mAlive & mDeathEffectConditions) > 0x00 && !mDeathEffect.empty()) + { + Particle* deathEffect = particleEngine->addEffect(mDeathEffect, 0, 0); + deathEffect->moveBy(mPos); + } + mAlive = DEAD_LONG_AGO; + } + Vector change = mPos - oldPos; // Update child particles @@ -225,7 +241,7 @@ bool Particle::update() p = mChildParticles.erase(p); } } - if (!mAlive && mChildParticles.empty() && mAutoDelete) + if (mAlive != ALIVE && mChildParticles.empty() && mAutoDelete) { return false; } @@ -325,13 +341,39 @@ Particle *Particle::addEffect(const std::string &particleEffectFile, // Look for additional emitters for this particle for_each_xml_child_node(emitterNode, effectChildNode) { - if (!xmlStrEqual(emitterNode->name, BAD_CAST "emitter")) - continue; - - ParticleEmitter *newEmitter; - newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap, - rotation); - newParticle->addEmitter(newEmitter); + if (xmlStrEqual(emitterNode->name, BAD_CAST "emitter")) + { + ParticleEmitter *newEmitter; + newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap, + rotation); + newParticle->addEmitter(newEmitter); + } + else if (xmlStrEqual(emitterNode->name, BAD_CAST "deatheffect")) + { + std::string deathEffect = (const char*)emitterNode->xmlChildrenNode->content; + char deathEffectConditions = 0x00; + if (XML::getBoolProperty(emitterNode, "on-floor", true)) + { + deathEffectConditions += Particle::DEAD_FLOOR; + } + if (XML::getBoolProperty(emitterNode, "on-sky", true)) + { + deathEffectConditions += Particle::DEAD_SKY; + } + if (XML::getBoolProperty(emitterNode, "on-other", false)) + { + deathEffectConditions += Particle::DEAD_OTHER; + } + if (XML::getBoolProperty(emitterNode, "on-impact", true)) + { + deathEffectConditions += Particle::DEAD_IMPACT; + } + if (XML::getBoolProperty(emitterNode, "on-timeout", true)) + { + deathEffectConditions += Particle::DEAD_TIMEOUT; + } + newParticle->setDeathEffect(deathEffect, deathEffectConditions); + } } mChildParticles.push_back(newParticle); diff --git a/src/particle.h b/src/particle.h index 2be169c1..8aa9e5f2 100644 --- a/src/particle.h +++ b/src/particle.h @@ -44,6 +44,16 @@ typedef Emitters::iterator EmitterIterator; class Particle : public Actor { public: + enum AliveStatus + { + ALIVE = 0, + DEAD_TIMEOUT = 1, + DEAD_FLOOR = 2, + DEAD_SKY = 4, + DEAD_IMPACT = 8, + DEAD_OTHER = 16, + DEAD_LONG_AGO = 128 + }; static const float PARTICLE_SKY; /**< Maximum Z position of particles */ static int fastPhysics; /**< Mode of squareroot calculation */ static int particleCount; /**< Current number of particles */ @@ -221,20 +231,20 @@ class Particle : public Actor void setAllowSizeAdjust(bool adjust) { mAllowSizeAdjust = adjust; } - bool isAlive() - { return mAlive; } + bool isAlive() const + { return mAlive == ALIVE; } /** * Determines whether the particle and its children are all dead */ - bool isExtinct() + bool isExtinct() const { return !isAlive() && mChildParticles.empty(); } /** * Manually marks the particle for deletion. */ void kill() - { mAlive = false; mAutoDelete = true; } + { mAlive = DEAD_OTHER; mAutoDelete = true; } /** * After calling this function the particle will only request @@ -252,22 +262,28 @@ class Particle : public Actor virtual void setAlpha(float alpha) {} + virtual void setDeathEffect(const std::string &effectFile, char conditions) + { mDeathEffect = effectFile; mDeathEffectConditions = conditions; } + protected: - bool mAlive; /**< Is the particle supposed to be drawn and updated?*/ + float mAlpha; /**< Opacity of the graphical representation of the particle */ 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 */ + Vector mVelocity; /**< Speed in pixels per game-tick. */ + private: + AliveStatus mAlive; /**< Is the particle supposed to be drawn and updated?*/ // generic properties bool mAutoDelete; /**< May the particle request its deletion by the parent particle? */ Emitters mChildEmitters; /**< List of child emitters. */ Particles mChildParticles; /**< List of particles controlled by this particle */ bool mAllowSizeAdjust; /**< Can the effect size be adjusted by the object props in the map file? */ + std::string mDeathEffect; /**< Particle effect file to be spawned when the particle dies */ + char mDeathEffectConditions;/**< Bitfield of death conditions which trigger spawning of the death particle */ // dynamic particle - Vector mVelocity; /**< Speed in pixels per game-tick. */ float mGravity; /**< Downward acceleration in pixels per game-tick. */ int mRandomness; /**< Ammount of random vector change */ float mBounce; /**< How much the particle bounces off when hitting the ground */ diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index dc9931a5..b9855c10 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -320,6 +320,30 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * mParticleAnimation.addTerminator(); } } // for frameNode + } else if (xmlStrEqual(propertyNode->name, BAD_CAST "deatheffect")) + { + mDeathEffect = (const char*)propertyNode->xmlChildrenNode->content; + mDeathEffectConditions = 0x00; + if (XML::getBoolProperty(propertyNode, "on-floor", true)) + { + mDeathEffectConditions += Particle::DEAD_FLOOR; + } + if (XML::getBoolProperty(propertyNode, "on-sky", true)) + { + mDeathEffectConditions += Particle::DEAD_SKY; + } + if (XML::getBoolProperty(propertyNode, "on-other", false)) + { + mDeathEffectConditions += Particle::DEAD_OTHER; + } + if (XML::getBoolProperty(propertyNode, "on-impact", true)) + { + mDeathEffectConditions += Particle::DEAD_IMPACT; + } + if (XML::getBoolProperty(propertyNode, "on-timeout", true)) + { + mDeathEffectConditions += Particle::DEAD_TIMEOUT; + } } } } @@ -469,6 +493,11 @@ std::list<Particle *> ParticleEmitter::createParticles(int tick) newParticle->addEmitter(new ParticleEmitter(*i)); } + if (!mDeathEffect.empty()) + { + newParticle->setDeathEffect(mDeathEffect, mDeathEffectConditions); + } + newParticles.push_back(newParticle); } diff --git a/src/particleemitter.h b/src/particleemitter.h index cc073c1c..9baaa73c 100644 --- a/src/particleemitter.h +++ b/src/particleemitter.h @@ -127,13 +127,19 @@ class ParticleEmitter int mOutputPauseLeft; /* - * Graphical representation of the particle + * Graphical representation of the particles */ Image *mParticleImage; /**< Particle image, if used */ Animation mParticleAnimation; /**< Filename of particle animation file */ Animation mParticleRotation; /**< Filename of particle rotation file */ ParticleEmitterProp<float> mParticleAlpha; /**< Opacity of the graphical representation of the particles */ + /* + * Death effect of the particles + */ + std::string mDeathEffect; + char mDeathEffectConditions; + /** List of emitters the spawned particles are equipped with */ std::list<ParticleEmitter> mParticleChildEmitters; }; diff --git a/src/textparticle.cpp b/src/textparticle.cpp index 827343fa..e8d99dca 100644 --- a/src/textparticle.cpp +++ b/src/textparticle.cpp @@ -38,7 +38,7 @@ TextParticle::TextParticle(Map *map, const std::string &text, bool TextParticle::draw(Graphics *graphics, int offsetX, int offsetY) const { - if (!mAlive) + if (!isAlive()) return false; int screenX = (int) mPos.x + offsetX; |