/* * 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: * Fabien Vultier * Co-authors: * ... * */ /** @file SplitGunProjectile.h @brief Implementation of the SplitGunProjectile class. */ #include "SplitGunProjectile.h" #include "core/CoreIncludes.h" #include "core/command/Executor.h" #include "util/Convert.h" #include "util/Math.h" namespace orxonox { RegisterClass(SplitGunProjectile); SplitGunProjectile::SplitGunProjectile(Context* context) : BillboardProjectile(context) { RegisterObject(SplitGunProjectile); this->numberOfSplits_ = 0; this->numberOfChilds_ = 0; this->splitTime_ = 1.0; this->spread_ = 0.2; } void SplitGunProjectile::setNumberOfSplits(int numberOfSplits) { if (numberOfSplits >= 0) { this->numberOfSplits_ = numberOfSplits; } else { this->numberOfSplits_ = 0; } } void SplitGunProjectile::setNumberOfChilds(int numberOfChilds) { if (numberOfChilds >= 0) { this->numberOfChilds_ = numberOfChilds; } else { this->numberOfChilds_ = 0; } } /** @brief This function starts a timer that will cause the projectile to split after a time defined by the argument @param splitTime. */ void SplitGunProjectile::setSplitTime(float splitTime) { if (splitTime >= 0) { this->splitTime_ = splitTime; this->textureTimer_.setTimer(this->splitTime_, false, createExecutor(createFunctor(&SplitGunProjectile::split, this))); } else { this->splitTime_ = 0; } } void SplitGunProjectile::setSpread(float spread) { spread_ = spread; } /** @brief If this function is called the projectile splits up into many child projectiles. The original projectiles does not get destroyed but it will never split up again. */ void SplitGunProjectile::split() { if (numberOfSplits_ > 0) { -- numberOfSplits_; // Reduce damage of this projectile by the number of childs plus one. This way the total amount of possible damage contained in the original projectile and its childs is unchanged after s aplit. this->setDamage(this->getDamage()/(numberOfChilds_+1)); // Calculate a normalized vector (velocityOffset) that is perpendicluar to the velocity of this projectile. Since there are infinitly many perpendicular vectors a random one is chosen. Vector3 velocityInitial = this->getVelocity(); Vector3 velocityOffset = velocityInitial.perpendicular(); velocityOffset.normalise(); Degree angle = Degree(rnd(0,360)); velocityOffset = Quaternion(angle, velocityInitial.normalisedCopy()) * velocityOffset; velocityOffset.normalise(); // Create as many childs as defined by numberOfChilds_ for (int i = 0; i < numberOfChilds_; ++i) { // Every child projectile should fly uniform in different directions -> Rotate the velocityOffset in every iteration velocityOffset = Quaternion(Degree(360/numberOfChilds_), velocityInitial.normalisedCopy()) * velocityOffset; velocityOffset.normalise(); SplitGunProjectile* projectile = new SplitGunProjectile(this->getContext()); projectile->setMaterial(this->getMaterial()); projectile->setOrientation(this->getOrientation()); projectile->setPosition(this->getPosition()); projectile->setVelocity(velocityInitial + spread_*velocityOffset*velocityInitial.length()); projectile->setNumberOfSplits(this->numberOfSplits_); projectile->setNumberOfChilds(this->numberOfChilds_); projectile->setSplitTime(this->splitTime_); projectile->setSpread(this->spread_); projectile->setShooter(this->getShooter()); projectile->setDamage(this->getDamage()); projectile->setShieldDamage(this->getShieldDamage()); projectile->setHealthDamage(this->getHealthDamage()); } numberOfSplits_ = 0; } } }