/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Jannis Holzer * Fabien Vultier * Co-authors: * ... * */ /** @file MineProjectile.h @brief Implementation of the MineProjectile class. */ #include "MineProjectile.h" #include "core/CoreIncludes.h" #include "graphics/Model.h" #include "core/command/Executor.h" #include "graphics/ParticleSpawner.h" #include "worldentities/pawns/Pawn.h" #include "core/EventIncludes.h" #include "sound/WorldSound.h" namespace orxonox { RegisterClass(MineProjectile); const float MineProjectile::collisionShapeRadius_ = 15.0f; const float MineProjectile::damageRadius_ = 200.0f; const float MineProjectile::triggerRadius_ = 100.0f; MineProjectile::MineProjectile(Context* context) : MovableEntity(context), BasicProjectile() { RegisterObject(MineProjectile); this->bAllowExplosion_ = false; this->maxTimeUntilExplosion_ = 10.0f; this->timeUntilActivation_ = 1.0f; //Create movable entities rings1_ = new MovableEntity(this->getContext()); this->attach(rings1_); rings1_->setPosition(Vector3(0.0,0.0,0.0)); rings1_->setAngularVelocity(Vector3(0.0,5.0,0.0)); rings2_ = new MovableEntity(this->getContext()); this->attach(rings2_); rings2_->setPosition(Vector3(0.0,0.0,0.0)); rings2_->setAngularVelocity(Vector3(0.0,0.0,5.0)); core_ = new MovableEntity(this->getContext()); this->attach(core_); core_->setPosition(Vector3(0.0,0.0,0.0)); core_->setAngularVelocity(Vector3(2.5,2.5,0.0)); //Create Models //Core modelCore_ = new Model(this->getContext()); modelCore_->setMeshSource("Mine_Core.mesh"); modelCore_->setScale(15.0); core_->attach(modelCore_); modelCore_->setPosition(Vector3(0,0,0)); //Ring 1 modelRing1_ = new Model(this->getContext()); modelRing1_->setMeshSource("Mine_Ring.mesh"); modelRing1_->setScale(15.0); rings1_->attach(modelRing1_); modelRing1_->setPosition(Vector3(0,0,0)); modelRing1_->yaw(Degree(0)); //Ring 2 modelRing2_ = new Model(this->getContext()); modelRing2_->setMeshSource("Mine_Ring.mesh"); modelRing2_->setScale(15.0); rings1_->attach(modelRing2_); modelRing2_->setPosition(Vector3(0,0,0)); modelRing2_->yaw(Degree(180)); //Ring 3 modelRing3_ = new Model(this->getContext()); modelRing3_->setMeshSource("Mine_Ring.mesh"); modelRing3_->setScale(15.0); rings2_->attach(modelRing3_); modelRing3_->setPosition(Vector3(0,0,0)); modelRing3_->yaw(Degree(90)); //Ring 4 modelRing4_ = new Model(this->getContext()); modelRing4_->setMeshSource("Mine_Ring.mesh"); modelRing4_->setScale(15.0); rings2_->attach(modelRing4_); modelRing4_->setPosition(Vector3(0,0,0)); modelRing4_->yaw(Degree(270)); emitter_ = nullptr; if (GameMode::isMaster()) { this->setMass(10.0f); this->setLinearDamping(0.5f); this->setAngularDamping(0.1f); this->enableCollisionCallback(); this->setCollisionResponse(true); this->setCollisionType(CollisionType::Dynamic); // Create a sphere collision shape and attach it to the projectile. collisionShape_ = new SphereCollisionShape(this->getContext()); collisionShape_->setRadius(collisionShapeRadius_); this->attachCollisionShape(collisionShape_); collisionShape_->setPosition(Vector3(0,0,0)); // Create a distance trigger and attach it to the projectile. distanceTrigger_ = new DistanceTrigger(this->getContext()); this->attach(distanceTrigger_); distanceTrigger_->setPosition(Vector3(0,0,0)); distanceTrigger_->setDistance(triggerRadius_); distanceTrigger_->addTarget("Pawn"); distanceTrigger_->setStayActive(false); this->addEventSource(distanceTrigger_, "explode"); } } MineProjectile::~MineProjectile() { if (this->isInitialized()) { modelCore_->destroy(); modelRing1_->destroy(); modelRing2_->destroy(); modelRing3_->destroy(); modelRing4_->destroy(); if (distanceTrigger_) { distanceTrigger_->destroy(); } if (emitter_) { emitter_->destroy(); } } } /** @brief XMLPort for MineProjectile. */ void MineProjectile::XMLEventPort(Element& xmlelement, XMLPort::Mode mode) { SUPER(MineProjectile, XMLEventPort, xmlelement, mode); XMLPortEventState(MineProjectile, BaseObject, "explode", explode, xmlelement, mode); } /** @brief Max Time; after this time runs out,the Mine explodes. */ void MineProjectile::setMaxTimeUntilExplosion(float maxTimeUntilExplosion) { if (maxTimeUntilExplosion >= 0) { this->maxTimeUntilExplosion_ = maxTimeUntilExplosion; if (GameMode::isMaster()) { this->explodeTimer_.setTimer(this->maxTimeUntilExplosion_, false, createExecutor(createFunctor(&MineProjectile::explode, this))); } } else { this->maxTimeUntilExplosion_ = 0; } } /** @brief The mine can only explode when the activation time has run out. */ void MineProjectile::setTimeUntilActivation(float timeUntilActivation) { timeUntilActivation_ = timeUntilActivation; if (GameMode::isMaster()) { this->activationTimer_.setTimer(this->timeUntilActivation_, false, createExecutor(createFunctor(&MineProjectile::allowExplosion, this))); } } /** @brief Mine explodes, deals damage to pawn within range and destroys itself. */ void MineProjectile::explode() { if (bAllowExplosion_) { if (GameMode::isMaster()) { // Damage all pawns within the damage radius for (Pawn* pawn : ObjectList()) { Vector3 distanceVector = pawn->getWorldPosition()-this->getWorldPosition(); if(distanceVector.length()< damageRadius_) { pawn->hit(this->getShooter(), pawn->getWorldPosition(), nullptr, this->getDamage(), this->getHealthDamage(), this->getShieldDamage()); } } } this->destructionEffect(); this->destroyLater(); } } /** @brief Mine is ready to explode. */ void MineProjectile::allowExplosion() { // Allow explosion bAllowExplosion_ = true; // Add particle effect emitter_ = new ParticleEmitter(this->getContext()); this->attach(emitter_); emitter_->setOrientation(this->getOrientation()); emitter_->setSource("Orxonox/mineparticle"); } void MineProjectile::destructionEffect() { ParticleSpawner *effect1, *effect2, *effect3; effect1 = new ParticleSpawner(this->getContext()); effect2 = new ParticleSpawner(this->getContext()); effect3 = new ParticleSpawner(this->getContext()); effect1->setPosition(this->getPosition()); effect1->setOrientation(this->getOrientation()); effect1->setDestroyAfterLife(true); effect1->setSource("Orxonox/MineExpl"); effect1->setLifetime(2.5f); effect2->setPosition(this->getPosition()); effect2->setOrientation(this->getOrientation()); effect2->setDestroyAfterLife(true); effect2->setSource("Orxonox/MineExpl1"); effect2->setLifetime(2.5f); effect3->setPosition(this->getPosition()); effect3->setOrientation(this->getOrientation()); effect3->setDestroyAfterLife(true); effect3->setSource("Orxonox/MineExpl2"); effect3->setLifetime(2.5f); // Explosion sound effect. WeakPtr explosionSound_ = new WorldSound(getContext()); explosionSound_->setSource("sounds/minesound.ogg"); explosionSound_->setVolume(1.0); explosionSound_->play(); } }