diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-09-28 22:50:00 +0200 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2024-09-30 13:40:45 +0200 |
commit | f7bccd4c7abe33c0f435a4c584d196d611f89674 (patch) | |
tree | 1d8646c213922eb0be09f3de48b10d19b5591cd0 | |
parent | 61f21c0131bbb6631a16205ce5447e8eea2a2db2 (diff) | |
download | mana-f7bccd4c7abe33c0f435a4c584d196d611f89674.tar.gz mana-f7bccd4c7abe33c0f435a4c584d196d611f89674.tar.bz2 mana-f7bccd4c7abe33c0f435a4c584d196d611f89674.tar.xz mana-f7bccd4c7abe33c0f435a4c584d196d611f89674.zip |
Added support for particle effects on equipment
The effect is also there when the equipment is dropped, because it uses
the same field as the floor item.
Removed unused ItemInfo::particle.
Based roughly on M+ commit 44e5d8bcb7fea443ca9ed3844454b11ac6e4dbed.
Closes #85
-rw-r--r-- | src/actorsprite.cpp | 8 | ||||
-rw-r--r-- | src/being.cpp | 97 | ||||
-rw-r--r-- | src/being.h | 22 | ||||
-rw-r--r-- | src/particlecontainer.cpp | 4 | ||||
-rw-r--r-- | src/resources/itemdb.cpp | 9 | ||||
-rw-r--r-- | src/resources/iteminfo.h | 1 |
6 files changed, 104 insertions, 37 deletions
diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp index e279ba5f..62c5d1dc 100644 --- a/src/actorsprite.cpp +++ b/src/actorsprite.cpp @@ -235,8 +235,7 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display, for (const auto &sprite : display.sprites) { std::string file = paths.getStringValue("sprites") + sprite.sprite; - int variant = sprite.variant; - addSprite(AnimatedSprite::load(file, variant)); + addSprite(AnimatedSprite::load(file, sprite.variant)); } // Ensure that something is shown, if desired @@ -268,10 +267,7 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display, if (Particle::enabled) { for (const auto &particle : display.particles) - { - Particle *p = particleEngine->addEffect(particle, 0, 0); - controlParticle(p); - } + controlParticle(particleEngine->addEffect(particle, 0, 0)); } mMustResetParticles = true; diff --git a/src/being.cpp b/src/being.cpp index 0e344873..c9eee2c6 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -91,6 +91,8 @@ Being::~Being() mSpeechBubble = nullptr; mDispName = nullptr; mText = nullptr; + + removeAllSpriteParticles(); } void Being::setSubtype(Uint16 subtype) @@ -765,6 +767,12 @@ void Being::logic() mText = nullptr; } + if (mRestoreSpriteParticlesOnLogic) + { + mRestoreSpriteParticlesOnLogic = false; + restoreAllSpriteParticles(); + } + if ((mAction != DEAD) && !mSpeedPixelsPerTick.isNull()) { const Vector dest = (mPath.empty()) ? @@ -979,6 +987,45 @@ void Being::showName() updateCoords(); } +void Being::addSpriteParticles(SpriteState &spriteState, const SpriteDisplay &display) +{ + if (!spriteState.particles.empty()) + return; + + for (const auto &particle : display.particles) + { + Particle *p = particleEngine->addEffect(particle, 0, 0, 0); + controlParticle(p); + spriteState.particles.push_back(p); + } +} + +void Being::removeSpriteParticles(SpriteState &spriteState) +{ + for (auto particle : spriteState.particles) + mChildParticleEffects.removeLocally(particle); + + spriteState.particles.clear(); +} + +void Being::removeAllSpriteParticles() +{ + for (auto &spriteState : mSpriteStates) + removeSpriteParticles(spriteState); +} + +void Being::restoreAllSpriteParticles() +{ + for (auto &spriteState : mSpriteStates) + { + if (spriteState.id) + { + auto &itemInfo = itemDb->get(spriteState.id); + addSpriteParticles(spriteState, itemInfo.display); + } + } +} + void Being::updateColors() { if (getType() == MONSTER) @@ -1021,20 +1068,25 @@ void Being::updateColors() } } -void Being::setSprite(unsigned int slot, int id, const std::string &color, +void Being::setSprite(unsigned slot, int id, const std::string &color, bool isWeapon) { if (slot >= size()) ensureSize(slot + 1); - if (slot >= mSpriteIDs.size()) - mSpriteIDs.resize(slot + 1); + if (slot >= mSpriteStates.size()) + mSpriteStates.resize(slot + 1); + + auto &spriteState = mSpriteStates[slot]; + + // Clear current particles when the ID changes + if (spriteState.id != id) + removeSpriteParticles(spriteState); - if (slot >= mSpriteColors.size()) - mSpriteColors.resize(slot + 1); + spriteState.id = id; + spriteState.color = color; - // id = 0 means unequip - if (id == 0) + if (id == 0) // id = 0 means unequip { removeSprite(slot); @@ -1043,7 +1095,8 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color, } else { - std::string filename = itemDb->get(id).getSprite(mGender, mSubType); + auto &itemInfo = itemDb->get(id); + std::string filename = itemInfo.getSprite(mGender, mSubType); AnimatedSprite *equipmentSprite = nullptr; if (!filename.empty()) @@ -1060,24 +1113,25 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color, CompoundSprite::setSprite(slot, equipmentSprite); + addSpriteParticles(spriteState, itemInfo.display); + if (isWeapon) - mEquippedWeapon = &itemDb->get(id); + mEquippedWeapon = &itemInfo; setAction(mAction); } - - mSpriteIDs[slot] = id; - mSpriteColors[slot] = color; } -void Being::setSpriteID(unsigned int slot, int id) +void Being::setSpriteID(unsigned slot, int id) { - setSprite(slot, id, mSpriteColors[slot]); + assert(slot < mSpriteStates.size()); + setSprite(slot, id, mSpriteStates[slot].color); } -void Being::setSpriteColor(unsigned int slot, const std::string &color) +void Being::setSpriteColor(unsigned slot, const std::string &color) { - setSprite(slot, mSpriteIDs[slot], color); + assert(slot < mSpriteStates.size()); + setSprite(slot, mSpriteStates[slot].id, color); } int Being::getNumberOfLayers() const @@ -1098,10 +1152,11 @@ void Being::setGender(Gender gender) mGender = gender; // Reload all subsprites - for (unsigned int i = 0; i < mSpriteIDs.size(); i++) + for (size_t i = 0; i < mSpriteStates.size(); i++) { - if (mSpriteIDs.at(i) != 0) - setSprite(i, mSpriteIDs.at(i), mSpriteColors.at(i)); + auto &sprite = mSpriteStates[i]; + if (sprite.id != 0) + setSprite(i, sprite.id, sprite.color); } updateName(); @@ -1155,6 +1210,10 @@ void Being::event(Event::Channel channel, const Event &event) void Being::setMap(Map *map) { + // Remove sprite particles because ActorSprite is going to kill them all + removeAllSpriteParticles(); + mRestoreSpriteParticlesOnLogic = true; + ActorSprite::setMap(map); // Recalculate pixel/tick speed diff --git a/src/being.h b/src/being.h index 0c1d54d6..3bd66b06 100644 --- a/src/being.h +++ b/src/being.h @@ -259,13 +259,13 @@ class Being : public ActorSprite, public EventListener /** * Sets visible equipments for this being. */ - void setSprite(unsigned int slot, int id, + void setSprite(unsigned slot, int id, const std::string &color = std::string(), bool isWeapon = false); - void setSpriteID(unsigned int slot, int id); + void setSpriteID(unsigned slot, int id); - void setSpriteColor(unsigned int slot, + void setSpriteColor(unsigned slot, const std::string &color = std::string()); /** @@ -452,6 +452,12 @@ class Being : public ActorSprite, public EventListener { lookAt(Vector(destPos.x, destPos.y)); } protected: + struct SpriteState { + int id = 0; + std::string color; + std::vector<Particle*> particles; + }; + /** * Sets the new path for this being. */ @@ -464,6 +470,11 @@ class Being : public ActorSprite, public EventListener void showName(); + void addSpriteParticles(SpriteState &spriteState, const SpriteDisplay &display); + void removeSpriteParticles(SpriteState &spriteState); + void removeAllSpriteParticles(); + void restoreAllSpriteParticles(); + void updateColors(); /** @@ -505,8 +516,9 @@ class Being : public ActorSprite, public EventListener Vector mDest; /**< destination coordinates. */ - std::vector<int> mSpriteIDs; - std::vector<std::string> mSpriteColors; + std::vector<SpriteState> mSpriteStates; + bool mRestoreSpriteParticlesOnLogic = false; + Gender mGender = Gender::UNSPECIFIED; // Character guild information diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp index 9dfb8585..60485c44 100644 --- a/src/particlecontainer.cpp +++ b/src/particlecontainer.cpp @@ -70,9 +70,7 @@ void ParticleList::addLocally(Particle *particle) void ParticleList::removeLocally(Particle *particle) { - std::list<Particle *>::iterator it, it_end; - for (it = mElements.begin(), it_end = mElements.end(); - it != it_end;) + for (auto it = mElements.begin(), it_end = mElements.end(); it != it_end;) { if (*it == particle) { diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 543caf8a..bb5b5abd 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -216,11 +216,14 @@ void ItemDB::loadCommonRef(ItemInfo &itemInfo, xmlNodePtr node, const std::strin { if (xmlStrEqual(itemChild->name, BAD_CAST "sprite")) { - itemInfo.particle = XML::getProperty( - itemChild, "particle-effect", std::string()); - loadSpriteRef(itemInfo, itemChild); } + else if (xmlStrEqual(itemChild->name, BAD_CAST "particlefx")) + { + if (itemChild->children && itemChild->children->content) + itemInfo.display.particles.emplace_back( + (const char*)itemChild->children->content); + } else if (xmlStrEqual(itemChild->name, BAD_CAST "sound")) { loadSoundRef(itemInfo, itemChild); diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 90a70695..a5b62fdc 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -86,7 +86,6 @@ public: int id = 0; /**< Item ID */ std::string name; - std::string particle; /**< Particle effect used with this item */ SpriteDisplay display; /**< Display info (like icon) */ std::string description; /**< Short description. */ std::vector<std::string> effect; /**< Description of effects. */ |