//////////////////////////////////////////////////////////////////////////////// // 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 #include float TankLib::getDistanceToTank(Vector &position, Tank *targetTank) { Vector currentdirection = targetTank->getPosition().getTankPosition() - position; float maxdistance2D = sqrtf(currentdirection[0] * currentdirection[0] + currentdirection[1] * currentdirection[1]); return maxdistance2D; } void TankLib::getTanksSortedByDistance(ScorchedContext &context, Vector &position, std::list > &result, unsigned int teams, float maxDistance) { std::list > tankDistList; std::map &allCurrentTanks = context.tankContainer->getAllTanks(); std::map::iterator itor; for (itor = allCurrentTanks.begin(); itor != allCurrentTanks.end(); itor++) { Tank *targetTank = (*itor).second; if (targetTank->getState().getState() == TankState::sNormal) { if (teams > 0 && teams == targetTank->getTeam()) continue; float maxdistance2D = getDistanceToTank(position, targetTank); tankDistList.push_back(std::pair(maxdistance2D, targetTank)); } } while (!tankDistList.empty()) { std::list >::iterator removeItor = tankDistList.begin(); std::list >::iterator itor = tankDistList.begin(); itor++; for (;itor != tankDistList.end(); itor++) { if ((*itor).first < (*removeItor).first) { removeItor = itor; } } if ((*removeItor).first <= maxDistance || maxDistance == -1) result.push_back(*removeItor); tankDistList.erase(removeItor); } } bool TankLib::intersection(ScorchedContext &context, Vector position, float xy, float yz, float power, int dist) { Vector startPosition = position; Vector velocity = getVelocityVector(xy, yz) * power / 250.0f; do { if (position[2] < context.landscapeMaps->getGroundMaps().getInterpHeight( position[0], position[1])) { return true; } position += velocity; velocity += Vector(0.0f, 0.0f, -0.00015f); } while ((position - startPosition).Magnitude() < dist); return false; } bool TankLib::getSniperShotTowardsPosition(ScorchedContext &context, Vector &position, Vector &shootAt, float distForSniper, float &angleXYDegs, float &angleYZDegs, float &power, bool checkIntersection) { // Calculate power power = 1000.0f; // Calculate direction Vector direction = shootAt - position; float angleXYRads = atan2f(direction[1], direction[0]); angleXYDegs = (angleXYRads / 3.14f) * 180.0f - 90.0f; float distance2D = sqrtf(direction[0] * direction[0] + direction[1] * direction[1]); float angleYZRads = atan2f(distance2D, direction[2]); angleYZDegs = 90.0f - ((angleYZRads / 3.14f) * 180.0f); // Special case // If we are less than a certain distance and under the position we // will use a direct shot on full power bool useSniper = ((distance2D < distForSniper) && (shootAt[2] >= position[2])) || (distForSniper == -1.0f); if (!useSniper) return false; // If we check intersection if (checkIntersection) { // Ensure that the sniper shot wont collide with the ground // nearer than 80% dist to target away int allowedIntersectDist = int(distance2D * 0.8f); if (intersection(context, position - Vector(0.0f, 0.0f, 1.0f), angleXYDegs, angleYZDegs, power, allowedIntersectDist)) { return false; } } return true; } void TankLib::getShotTowardsPosition(ScorchedContext &context, Vector &position, Vector &shootAt, float &angleXYDegs, float &angleYZDegs, float &power) { // Calculate direction Vector direction = shootAt - position; float angleXYRads = atan2f(direction[1], direction[0]); angleXYDegs = (angleXYRads / 3.14f) * 180.0f - 90.0f; float distance2D = sqrtf(direction[0] * direction[0] + direction[1] * direction[1]); // Calculate power (very roughly) power = 1000.0f; if (distance2D < 200.0f) { power = 750; if (distance2D < 100.0f) { power = 550; if (distance2D < 50.0f) { power = 350; } } } // Add some randomness to the power power += (RAND * 200.0f) - 100.0f; if (power < 100) power = 100; if (context.optionsTransient->getWindOn()) { // Make less adjustments for less wind float windMag = context.optionsTransient->getWindSpeed() / 5.0f; // Try to account for the wind direction Vector ndirection = direction; ndirection[2] = 0.0f; ndirection = ndirection.Normalize(); ndirection = ndirection.get2DPerp(); float windoffsetLR = context.optionsTransient->getWindDirection().dotP(ndirection); angleXYDegs += windoffsetLR * distance2D * (0.12f + RAND * 0.04f) * windMag; float windoffsetFB = context.optionsTransient->getWindDirection().dotP(direction.Normalize()); windoffsetFB /= 10.0f; windoffsetFB *= windMag; windoffsetFB += 1.0f; // windowoffset FB 0.9 > 1.1 power *= windoffsetFB; } // Angle angleYZDegs = 45.0f; } Vector &TankLib::getVelocityVector(float xy, float yz) { static Vector diff; diff = Vector((float) sinf(-xy / 180.0f * 3.14f) * cosf(yz / 180.0f * 3.14f), (float) cosf(-xy / 180.0f * 3.14f) * cosf(yz / 180.0f * 3.14f), (float) sinf(yz/ 180.0f * 3.14f)); diff /= 20.0f; return diff; } Vector &TankLib::getGunPosition(float xy, float yz) { static Vector pos; const float gunLength = 1.0f; const float degToRad = 180.0f * 3.14f; pos[0] = gunLength * sinf(xy / degToRad) * sinf((90.0f - yz) / degToRad); pos[1] = gunLength * cosf(xy / degToRad) * sinf((90.0f - yz) / degToRad); pos[2] = gunLength * cosf((90.0f - yz) / degToRad); return pos; }