diff --git a/data/gfx/smoke_short_burst.xml b/data/gfx/smoke_short_burst.xml
new file mode 100644
index 000000000..1d9aa96cc
--- /dev/null
+++ b/data/gfx/smoke_short_burst.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/animations/animation_base.cpp b/src/animations/animation_base.cpp
index 8a808d259..3a8037007 100644
--- a/src/animations/animation_base.cpp
+++ b/src/animations/animation_base.cpp
@@ -93,6 +93,8 @@ void AnimationBase::reset()
*/
void AnimationBase::update(float dt, Vec3 *xyz, Vec3 *hpr, Vec3 *scale)
{
+ TrackObject::update(dt);
+
// Don't do anything if the animation is disabled
if(!m_playing) return;
m_current_time += dt;
diff --git a/src/modes/cutscene_world.cpp b/src/modes/cutscene_world.cpp
index bee2a8b42..bd12ef54c 100644
--- a/src/modes/cutscene_world.cpp
+++ b/src/modes/cutscene_world.cpp
@@ -76,7 +76,26 @@ void CutsceneWorld::init()
TrackObject* curr;
for_in(curr, objects)
{
- if (curr->getType() == "sfx-emitter" && !curr->getTriggerCondition().empty())
+ if (curr->getType() == "particle-emitter" && !curr->getTriggerCondition().empty())
+ {
+ const std::string& condition = curr->getTriggerCondition();
+
+ if (StringUtils::startsWith(condition, "frame "))
+ {
+ std::string frameStr = condition.substr(6); // remove 'frame ' prefix
+ int frame;
+
+ if (!StringUtils::fromString(frameStr, frame))
+ {
+ fprintf(stderr, "[CutsceneWorld] Invalid condition '%s'\n", condition.c_str());
+ continue;
+ }
+
+ float FPS = 25.0f; // for now we assume the cutscene is saved at 25 FPS
+ m_particles_to_trigger[frame / FPS].push_back(curr);
+ }
+ }
+ else if (curr->getType() == "sfx-emitter" && !curr->getTriggerCondition().empty())
{
const std::string& condition = curr->getTriggerCondition();
@@ -153,6 +172,17 @@ const std::string& CutsceneWorld::getIdent() const
*/
void CutsceneWorld::update(float dt)
{
+ /*
+ {
+ PtrVector& objects = m_track->getTrackObjectManager()->getObjects();
+ TrackObject* curr;
+ for_in(curr, objects)
+ {
+ printf("* %s\n", curr->getType().c_str());
+ }
+ }
+ **/
+
m_time += dt;
if (m_time < 2.0f)
@@ -168,7 +198,6 @@ void CutsceneWorld::update(float dt)
dynamic_cast(m_race_gui)->setFadeLevel(0.0f);
}
-
float currFrame = m_time * 25.0f; // We assume 25 FPS
const std::vector& subtitles = m_track->getSubtitles();
@@ -232,9 +261,27 @@ void CutsceneWorld::update(float dt)
}
}
+ for (std::map >::iterator it = m_particles_to_trigger.begin();
+ it != m_particles_to_trigger.end(); )
+ {
+ if (m_time >= it->first)
+ {
+ std::vector objects = it->second;
+ for (unsigned int i = 0; i < objects.size(); i++)
+ {
+ objects[i]->triggerParticles();
+ }
+ m_particles_to_trigger.erase(it++);
+ }
+ else
+ {
+ it++;
+ }
+ }
+
for (std::map >::iterator it = m_sounds_to_stop.begin();
it != m_sounds_to_stop.end(); )
- {
+ {
if (m_time >= it->first)
{
std::vector objects = it->second;
@@ -248,7 +295,7 @@ void CutsceneWorld::update(float dt)
{
it++;
}
- }
+ }
} // update
//-----------------------------------------------------------------------------
diff --git a/src/modes/cutscene_world.hpp b/src/modes/cutscene_world.hpp
index 3aa3923a7..d67ab0bde 100644
--- a/src/modes/cutscene_world.hpp
+++ b/src/modes/cutscene_world.hpp
@@ -40,6 +40,7 @@ class CutsceneWorld : public World
std::map > m_sounds_to_trigger;
std::map > m_sounds_to_stop;
+ std::map > m_particles_to_trigger;
float m_duration;
bool m_aborted;
diff --git a/src/tracks/track_object.cpp b/src/tracks/track_object.cpp
index b0c62a417..6530234fc 100644
--- a/src/tracks/track_object.cpp
+++ b/src/tracks/track_object.cpp
@@ -81,6 +81,7 @@ TrackObject::TrackObject(const XMLNode &xml_node)
if (xml_node.getName() == "particle-emitter")
{
+ m_type = "particle-emitter";
std::string path;
irr::core::vector3df emitter_origin;
xml_node.get("kind", &path);
@@ -89,6 +90,8 @@ TrackObject::TrackObject(const XMLNode &xml_node)
int clip_distance = -1;
xml_node.get("clip_distance", &clip_distance);
+ xml_node.get("conditions", &m_trigger_condition);
+
try
{
ParticleKind* kind = ParticleKindManager::get()->getParticles( path.c_str() );
@@ -114,6 +117,11 @@ TrackObject::TrackObject(const XMLNode &xml_node)
m_node = emitter->getNode(); // FIXME: this leaks
m_emitter = emitter;
}
+
+ if (m_trigger_condition.size() > 0)
+ {
+ m_emitter->setCreationRateAbsolute(0.0f);
+ }
}
catch (std::runtime_error& e)
{
@@ -423,7 +431,6 @@ void TrackObject::OnAnimationEnd(scene::IAnimatedMeshSceneNode* node)
// ----------------------------------------------------------------------------
void TrackObject::update(float dt)
{
-
if (m_sound != NULL)
{
// muting when too far is implemented manually since not supported by OpenAL
@@ -431,6 +438,11 @@ void TrackObject::update(float dt)
// moved
m_sound->position(m_init_xyz);
}
+
+ if (m_emitter != NULL)
+ {
+ m_emitter->update(dt);
+ }
} // update
// ----------------------------------------------------------------------------
@@ -477,3 +489,14 @@ void TrackObject::stopSound()
// ----------------------------------------------------------------------------
+void TrackObject::triggerParticles()
+{
+ if (m_emitter != NULL)
+ {
+ m_emitter->setCreationRateAbsolute(1.0f);
+ m_emitter->setParticleType(m_emitter->getParticlesInfo());
+ }
+}
+
+// ----------------------------------------------------------------------------
+
diff --git a/src/tracks/track_object.hpp b/src/tracks/track_object.hpp
index 5fa94ad8b..49743518a 100644
--- a/src/tracks/track_object.hpp
+++ b/src/tracks/track_object.hpp
@@ -156,6 +156,7 @@ public:
void triggerSound(bool loop=false);
void stopSound();
+ void triggerParticles();
virtual void onTriggerItemApproached(Item* who);