summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-09-28 22:50:00 +0200
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-09-30 13:40:45 +0200
commitf7bccd4c7abe33c0f435a4c584d196d611f89674 (patch)
tree1d8646c213922eb0be09f3de48b10d19b5591cd0
parent61f21c0131bbb6631a16205ce5447e8eea2a2db2 (diff)
downloadmana-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.cpp8
-rw-r--r--src/being.cpp97
-rw-r--r--src/being.h22
-rw-r--r--src/particlecontainer.cpp4
-rw-r--r--src/resources/itemdb.cpp9
-rw-r--r--src/resources/iteminfo.h1
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. */