//////////////////////////////////////////////////////////////////////////////// // Scorched3D (c) 2000-2003 // // This file is part of Scorched3D. // // Scorched3D 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. // // Scorched3D 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 Scorched3D; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include void TargetDamageCalc::explosion(ScorchedContext &context, Weapon *weapon, unsigned int firer, Vector &position, float radius, float damageAmount, bool checkFall, bool shieldOnlyDamage, unsigned int data) { std::map::iterator itor; std::map &targets = context.targetContainer->getTargets(); for (itor = targets.begin(); itor != targets.end(); itor++) { Target *current = (*itor).second; if (!current->getAlive()) continue; Vector ¤tPosition = current->getCenterPosition(); Vector direction = position - currentPosition; float dist = 0.0f; // Get how close the exposion was if (current->getLife().getBoundingSphere()) { // Find how close the explosion was to the // outside of the sphere float sphereRadius = MAX( current->getLife().getSize()[0], current->getLife().getSize()[1]) / 2.0f; dist = direction.Magnitude() - sphereRadius; if (dist < 0.0f) dist = 0.0f; } else { // Make the direction relative to the geom // incase the geom has been rotated Vector relativeDirection = current->getLife().getGeomRelativePosition(direction); // Find how close the explosion was to the // outside edge of the cube Vector touchPosition = relativeDirection; // Check each size of the cube to see if the point is outside. // If it is, then scale it back until the point sits on the // outside edge of the cube. int inner = 0; for (int i=0; i<3; i++) { float halfSize = current->getLife().getSize()[i] / 2.0f; if (touchPosition[i] < -halfSize) { // Scale the point so it sits on this edge float diff = -halfSize / touchPosition[i]; touchPosition *= diff; } else if (touchPosition[i] > halfSize) { // Scale the point so it sits on this edge float diff = halfSize / touchPosition[i]; touchPosition *= diff; } else inner++; // The point is inside this edge } if (inner == 3) { // We are inside the cube dist = 0.0f; } else { // We are outside the cube relativeDirection -= touchPosition; dist = relativeDirection.Magnitude(); } //Logger::log(formatString("%.1f", dist)); } // Check if the explosion causes damage if (dist < radius) { // Direct hit by explosion float damage = 100.0f; if (dist > radius / 3.0f) { damage = ((dist - (radius / 3.0f)) / (radius * 0.66f)) * 100.0f; damage = 100.0f - damage; } damageTarget(context, current, weapon, firer, damage * damageAmount, true, checkFall, shieldOnlyDamage, data); } else { float dist2d = sqrtf(direction[0] * direction[0] + direction[1] * direction[1]); if (dist2d < radius + 5.0f) { // explosion under tank damageTarget(context, current, weapon, firer, 0, true, checkFall, shieldOnlyDamage, data); } } } } void TargetDamageCalc::damageTarget(ScorchedContext &context, Target *target, Weapon *weapon, unsigned int firer, float damage, bool useShieldDamage, bool checkFall, bool shieldOnlyDamage, unsigned int data) { // Remove the correct damage from the tanks TankDamage *tankDamage = new TankDamage( weapon, target->getPlayerId(), firer, damage, useShieldDamage, checkFall, shieldOnlyDamage, data); context.actionController->addAction(tankDamage); }