ParticleEmitter::ParticleEmitter(const xmlNodePtr &emitterNode, Particle *target, Map *map, const int rotation): mOutputPauseLeft(0), mParticleImage(0) { mMap = map; mParticleTarget = target; // Initializing default values mParticlePosX.set(0.0f); mParticlePosY.set(0.0f); mParticlePosZ.set(0.0f); mParticleAngleHorizontal.set(0.0f); mParticleAngleVertical.set(0.0f); mParticlePower.set(0.0f); mParticleGravity.set(0.0f); mParticleRandomness.set(0); mParticleBounce.set(0.0f); mParticleFollow = false; mParticleAcceleration.set(0.0f); mParticleDieDistance.set(-1.0f); mParticleMomentum.set(1.0f); mParticleLifetime.set(-1); mParticleFadeOut.set(0); mParticleFadeIn.set(0); mOutput.set(1); mOutputPause.set(0); mParticleAlpha.set(1.0f); for_each_xml_child_node(propertyNode, emitterNode) { if (xmlStrEqual(propertyNode->name, BAD_CAST "property")) { std::string name = XML::getProperty(propertyNode, "name", ""); if (name == "position-x") mParticlePosX = readParticleEmitterProp(propertyNode, 0.0f); else if (name == "position-y") { mParticlePosY = readParticleEmitterProp(propertyNode, 0.0f); mParticlePosY.minVal *= SIN45; mParticlePosY.maxVal *= SIN45; mParticlePosY.changeAmplitude *= SIN45; } else if (name == "position-z") { mParticlePosZ = readParticleEmitterProp(propertyNode, 0.0f); mParticlePosZ.minVal *= SIN45; mParticlePosZ.maxVal *= SIN45; mParticlePosZ.changeAmplitude *= SIN45; } else if (name == "image") { std::string image = XML::getProperty(propertyNode, "value", ""); // Don't leak when multiple images are defined if (!image.empty() && !mParticleImage) { ResourceManager *resman = ResourceManager::getInstance(); mParticleImage = resman->getImage(image); } } else if (name == "horizontal-angle") { mParticleAngleHorizontal = readParticleEmitterProp(propertyNode, 0.0f); mParticleAngleHorizontal.minVal += rotation; mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR; mParticleAngleHorizontal.maxVal += rotation; mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR; mParticleAngleHorizontal.changeAmplitude *= DEG_RAD_FACTOR; } else if (name == "vertical-angle") { mParticleAngleVertical = readParticleEmitterProp(propertyNode, 0.0f); mParticleAngleVertical.minVal *= DEG_RAD_FACTOR; mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR; mParticleAngleVertical.changeAmplitude *= DEG_RAD_FACTOR; } else if (name == "power") mParticlePower = readParticleEmitterProp(propertyNode, 0.0f); else if (name == "gravity") mParticleGravity = readParticleEmitterProp(propertyNode, 0.0f); else if (name == "randomnes" || name == "randomness") // legacy bug mParticleRandomness = readParticleEmitterProp(propertyNode, 0); else if (name == "bounce") mParticleBounce = readParticleEmitterProp(propertyNode, 0.0f); else if (name == "lifetime") { mParticleLifetime = readParticleEmitterProp(propertyNode, 0); mParticleLifetime.minVal += 1; } else if (name == "output") { mOutput = readParticleEmitterProp(propertyNode, 0); mOutput.maxVal +=1; } else if (name == "output-pause") { mOutputPause = readParticleEmitterProp(propertyNode, 0); mOutputPauseLeft = mOutputPause.value(0); } else if (name == "acceleration") mParticleAcceleration = readParticleEmitterProp(propertyNode, 0.0f); else if (name == "die-distance") mParticleDieDistance = readParticleEmitterProp(propertyNode, 0.0f); else if (name == "momentum") mParticleMomentum = readParticleEmitterProp(propertyNode, 1.0f); else if (name == "fade-out") mParticleFadeOut = readParticleEmitterProp(propertyNode, 0); else if (name == "fade-in") mParticleFadeIn = readParticleEmitterProp(propertyNode, 0); else if (name == "alpha") mParticleAlpha = readParticleEmitterProp(propertyNode, 1.0f); else if (name == "follow-parent") mParticleFollow = true; else { logger->log("Particle Engine: Warning, unknown emitter property \"%s\"", name.c_str()); } } else if (xmlStrEqual(propertyNode->name, BAD_CAST "emitter")) { ParticleEmitter newEmitter(propertyNode, mParticleTarget, map); mParticleChildEmitters.push_back(newEmitter); } else if (xmlStrEqual(propertyNode->name, BAD_CAST "rotation")) { ImageSet *imageset = ResourceManager::getInstance()->getImageSet( XML::getProperty(propertyNode, "imageset", ""), XML::getProperty(propertyNode, "width", 0), XML::getProperty(propertyNode, "height", 0)); // Get animation frames for_each_xml_child_node(frameNode, propertyNode) { int delay = XML::getProperty(frameNode, "delay", 0); int offsetX = XML::getProperty(frameNode, "offsetX", 0); int offsetY = XML::getProperty(frameNode, "offsetY", 0); offsetY -= imageset->getHeight() - mMap->getTileHeight(); offsetX -= (imageset->getWidth() - mMap->getTileWidth()) / 2; if (xmlStrEqual(frameNode->name, BAD_CAST "frame")) { int index = XML::getProperty(frameNode, "index", -1); if (index < 0) { logger->log("No valid value for 'index'"); continue; } Image *img = imageset->get(index); if (!img) { logger->log("No image at index %d", index); continue; } mParticleRotation.addFrame(img, delay, offsetX, offsetY); } else if (xmlStrEqual(frameNode->name, BAD_CAST "sequence")) { int start = XML::getProperty(frameNode, "start", -1); int end = XML::getProperty(frameNode, "end", -1); if (start < 0 || end < 0) { logger->log("No valid value for 'start' or 'end'"); continue; } while (end >= start) { Image *img = imageset->get(start); if (!img) { logger->log("No image at index %d", start); continue; } mParticleRotation.addFrame(img, delay, offsetX, offsetY); start++; } } else if (xmlStrEqual(frameNode->name, BAD_CAST "end")) mParticleRotation.addTerminator(); } // for frameNode }
ParticleEmitter::ParticleEmitter(const XmlNodePtrConst emitterNode, Particle *const target, Map *const map, const int rotation, const std::string& dyePalettes) : mParticleTarget(target), mMap(map), mParticleImage(nullptr), mOutputPauseLeft(0), mDeathEffectConditions(0), mParticleFollow(false) { // Initializing default values mParticlePosX.set(0.0F); mParticlePosY.set(0.0F); mParticlePosZ.set(0.0F); mParticleAngleHorizontal.set(0.0F); mParticleAngleVertical.set(0.0F); mParticlePower.set(0.0F); mParticleGravity.set(0.0F); mParticleRandomness.set(0); mParticleBounce.set(0.0F); mParticleAcceleration.set(0.0F); mParticleDieDistance.set(-1.0F); mParticleMomentum.set(1.0F); mParticleLifetime.set(-1); mParticleFadeOut.set(0); mParticleFadeIn.set(0); mOutput.set(1); mOutputPause.set(0); mParticleAlpha.set(1.0F); for_each_xml_child_node(propertyNode, emitterNode) { if (xmlNameEqual(propertyNode, "property")) { const std::string name = XML::getProperty( propertyNode, "name", ""); if (name == "position-x") { mParticlePosX = readParticleEmitterProp(propertyNode, 0.0F); } else if (name == "position-y") { mParticlePosY = readParticleEmitterProp(propertyNode, 0.0F); mParticlePosY.minVal *= SIN45; mParticlePosY.maxVal *= SIN45; mParticlePosY.changeAmplitude *= SIN45; } else if (name == "position-z") { mParticlePosZ = readParticleEmitterProp(propertyNode, 0.0F); mParticlePosZ.minVal *= SIN45; mParticlePosZ.maxVal *= SIN45; mParticlePosZ.changeAmplitude *= SIN45; } else if (name == "image") { std::string image = XML::getProperty( propertyNode, "value", ""); // Don't leak when multiple images are defined if (!image.empty() && !mParticleImage) { if (!dyePalettes.empty()) Dye::instantiate(image, dyePalettes); ResourceManager *const resman = ResourceManager::getInstance(); mParticleImage = resman->getImage(image); } } else if (name == "subimage") { std::string image = XML::getProperty( propertyNode, "value", ""); // Don't leak when multiple images are defined if (!image.empty() && !mParticleImage) { if (!dyePalettes.empty()) Dye::instantiate(image, dyePalettes); ResourceManager *const resman = ResourceManager::getInstance(); Image *img = resman->getImage(image); if (img) { mParticleImage = resman->getSubImage(img, XML::getProperty(propertyNode, "x", 0), XML::getProperty(propertyNode, "y", 0), XML::getProperty(propertyNode, "width", 0), XML::getProperty(propertyNode, "height", 0)); img->decRef(); } else { mParticleImage = nullptr; } } } else if (name == "horizontal-angle") { mParticleAngleHorizontal = readParticleEmitterProp(propertyNode, 0.0F); mParticleAngleHorizontal.minVal += static_cast<float>(rotation); mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR; mParticleAngleHorizontal.maxVal += static_cast<float>(rotation); mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR; mParticleAngleHorizontal.changeAmplitude *= DEG_RAD_FACTOR; } else if (name == "vertical-angle") { mParticleAngleVertical = readParticleEmitterProp(propertyNode, 0.0F); mParticleAngleVertical.minVal *= DEG_RAD_FACTOR; mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR; mParticleAngleVertical.changeAmplitude *= DEG_RAD_FACTOR; } else if (name == "power") { mParticlePower = readParticleEmitterProp(propertyNode, 0.0F); } else if (name == "gravity") { mParticleGravity = readParticleEmitterProp(propertyNode, 0.0F); } else if (name == "randomnes" || name == "randomness") // legacy bug { mParticleRandomness = readParticleEmitterProp(propertyNode, 0); } else if (name == "bounce") { mParticleBounce = readParticleEmitterProp(propertyNode, 0.0F); } else if (name == "lifetime") { mParticleLifetime = readParticleEmitterProp(propertyNode, 0); mParticleLifetime.minVal += 1; } else if (name == "output") { mOutput = readParticleEmitterProp(propertyNode, 0); mOutput.maxVal += 1; } else if (name == "output-pause") { mOutputPause = readParticleEmitterProp(propertyNode, 0); mOutputPauseLeft = mOutputPause.value(0); } else if (name == "acceleration") { mParticleAcceleration = readParticleEmitterProp( propertyNode, 0.0F); } else if (name == "die-distance") { mParticleDieDistance = readParticleEmitterProp( propertyNode, 0.0F); } else if (name == "momentum") { mParticleMomentum = readParticleEmitterProp( propertyNode, 1.0F); } else if (name == "fade-out") { mParticleFadeOut = readParticleEmitterProp(propertyNode, 0); } else if (name == "fade-in") { mParticleFadeIn = readParticleEmitterProp(propertyNode, 0); } else if (name == "alpha") { mParticleAlpha = readParticleEmitterProp(propertyNode, 1.0F); } else if (name == "follow-parent") { const std::string value = XML::getProperty(propertyNode, "value", "0"); if (value == "1" || value == "true") mParticleFollow = true; } else { logger->log("Particle Engine: Warning, " "unknown emitter property \"%s\"", name.c_str()); } } else if (xmlNameEqual(propertyNode, "emitter")) { ParticleEmitter newEmitter(propertyNode, mParticleTarget, map, rotation, dyePalettes); mParticleChildEmitters.push_back(newEmitter); } else if (xmlNameEqual(propertyNode, "rotation") || xmlNameEqual(propertyNode, "animation")) { ImageSet *const imageset = getImageSet(propertyNode); if (!imageset) { logger->log1("Error: no valid imageset"); continue; } mTempSets.push_back(imageset); Animation &animation = (xmlNameEqual(propertyNode, "rotation")) ? mParticleRotation : mParticleAnimation; // Get animation frames for_each_xml_child_node(frameNode, propertyNode) { const int delay = XML::getIntProperty( frameNode, "delay", 0, 0, 100000); const int offsetX = XML::getProperty(frameNode, "offsetX", 0) - imageset->getWidth() / 2 + mapTileSize / 2; const int offsetY = XML::getProperty(frameNode, "offsetY", 0) - imageset->getHeight() + mapTileSize; const int rand = XML::getIntProperty( frameNode, "rand", 100, 0, 100); if (xmlNameEqual(frameNode, "frame")) { const int index = XML::getProperty(frameNode, "index", -1); if (index < 0) { logger->log1("No valid value for 'index'"); continue; } Image *const img = imageset->get(index); if (!img) { logger->log("No image at index %d", index); continue; } animation.addFrame(img, delay, offsetX, offsetY, rand); } else if (xmlNameEqual(frameNode, "sequence")) { int start = XML::getProperty(frameNode, "start", -1); const int end = XML::getProperty(frameNode, "end", -1); if (start < 0 || end < 0) { logger->log1("No valid value for 'start' or 'end'"); continue; } while (end >= start) { Image *const img = imageset->get(start); if (!img) { logger->log("No image at index %d", start); continue; } animation.addFrame(img, delay, offsetX, offsetY, rand); start ++; } } else if (xmlNameEqual(frameNode, "end")) { animation.addTerminator(rand); } } // for frameNode } else if (xmlNameEqual(propertyNode, "deatheffect"))