TankLib.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <tank/TankLib.h>
00022 #include <tank/TankContainer.h>
00023 #include <tank/TankPosition.h>
00024 #include <tank/TankState.h>
00025 #include <common/RandomGenerator.h>
00026 #include <common/OptionsTransient.h>
00027 #include <common/Defines.h>
00028 #include <landscapemap/LandscapeMaps.h>
00029 #ifndef S3D_SERVER
00030         #include <GLEXT/GLState.h>
00031 #endif
00032 #include <math.h>
00033 
00034 fixed TankLib::getDistanceToTank(FixedVector &position, Tank *targetTank)
00035 {
00036         FixedVector currentdirection = 
00037                         targetTank->getPosition().getTankPosition() - position;
00038         fixed maxdistance2D = (currentdirection[0] * 
00039                 currentdirection[0] + currentdirection[1] * currentdirection[1]).sqrt();
00040         return maxdistance2D;
00041 }
00042 
00043 void TankLib::getTanksSortedByDistance(ScorchedContext &context,
00044                                                                            FixedVector &position, 
00045                                                                           std::list<std::pair<fixed, Tank *> > &result,
00046                                                                           unsigned int teams,
00047                                                                           fixed maxDistance)
00048 {
00049         std::list<std::pair<fixed, Tank *> > tankDistList;
00050         std::map<unsigned int, Tank *> &allCurrentTanks = 
00051                 context.getTankContainer().getAllTanks();
00052         std::map<unsigned int, Tank *>::iterator itor;
00053         for (itor = allCurrentTanks.begin();
00054                 itor != allCurrentTanks.end();
00055                 itor++)
00056         {
00057                 Tank *targetTank = (*itor).second;
00058                 if (targetTank->getState().getState() == TankState::sNormal)
00059                 {
00060                         if (teams > 0 && teams == targetTank->getTeam()) continue;
00061 
00062                         fixed maxdistance2D = getDistanceToTank(position, targetTank);
00063                         tankDistList.push_back(std::pair<fixed, Tank*>(maxdistance2D, targetTank));
00064                 }
00065         }
00066 
00067         while (!tankDistList.empty())
00068         {
00069                 std::list<std::pair<fixed, Tank *> >::iterator removeItor = tankDistList.begin();
00070                 std::list<std::pair<fixed, Tank *> >::iterator itor = tankDistList.begin(); itor++;
00071                 for (;itor != tankDistList.end(); itor++)
00072                 {
00073                         if ((*itor).first <  (*removeItor).first) 
00074                         {
00075                                 removeItor = itor;
00076                         }
00077                 }
00078 
00079                 if ((*removeItor).first <= maxDistance || maxDistance == -1) result.push_back(*removeItor);
00080                 tankDistList.erase(removeItor);
00081         }
00082 }
00083 
00084 bool TankLib::intersection(ScorchedContext &context,
00085         FixedVector position, fixed xy, fixed yz, fixed power, 
00086         int dist)
00087 {
00088         FixedVector startPosition = position;
00089         FixedVector velocity = getVelocityVector(xy, yz) * power / fixed(250);
00090 
00091         do
00092         {
00093                 if (position[2] < context.getLandscapeMaps().getGroundMaps().getInterpHeight(
00094                         position[0], position[1]))
00095                 {
00096                         return true;
00097                 }
00098                 position += velocity;
00099                 velocity += FixedVector(0, 0, fixed(true, -0002));
00100         } while ((position - startPosition).Magnitude() < dist);
00101 
00102     return false;
00103 }
00104 
00105 bool TankLib::getSniperShotTowardsPosition(ScorchedContext &context,
00106         FixedVector &position, FixedVector &shootAt, fixed distForSniper, 
00107         fixed &angleXYDegs, fixed &angleYZDegs, fixed &power,
00108         bool checkIntersection)
00109 {
00110         // Calculate power
00111         power = fixed(1000);
00112 
00113         // Calculate direction
00114         FixedVector direction = shootAt - position;
00115         fixed angleXYRads = atan2x(direction[1], direction[0]);
00116         angleXYDegs = (angleXYRads / fixed::XPI) * fixed(180) - fixed(90);
00117         if (angleXYDegs > 88) angleXYDegs = 0; // Fix distance rounding error
00118 
00119         fixed distance2D = (direction[0] * direction[0] + 
00120                 direction[1] * direction[1]).sqrt();
00121         fixed angleYZRads = atan2x(distance2D, direction[2]);
00122         angleYZDegs = fixed(90) - ((angleYZRads /fixed::XPI) * fixed(180));     
00123 
00124         // Special case
00125         // If we are less than a certain distance and under the position we
00126         // will use a direct shot on full power
00127         bool useSniper = ((distance2D < distForSniper) && (shootAt[2] >= position[2] - fixed(2))) ||
00128                 (distForSniper == fixed(-1));
00129         if (!useSniper) return false;
00130 
00131         // If we check intersection
00132         if (checkIntersection)
00133         {
00134                 // Ensure that the sniper shot wont collide with the ground
00135                 // nearer than 10 units from the target
00136                 int allowedIntersectDist = (direction.Magnitude() - fixed(10)).asInt();
00137                 if (intersection(context, position - FixedVector(0, 0, 1), 
00138                         angleXYDegs, angleYZDegs, power, allowedIntersectDist))
00139                 {
00140                         return false;
00141                 }
00142         }
00143 
00144         return true;
00145 }
00146 
00147 void TankLib::getShotTowardsPosition(ScorchedContext &context,
00148         RandomGenerator &random,
00149         FixedVector &position, FixedVector &shootAt,
00150         fixed &angleXYDegs, fixed &angleYZDegs, fixed &power)
00151 {
00152         // Calculate direction
00153         FixedVector direction = shootAt - position;
00154         fixed angleXYRads = atan2x(direction[1], direction[0]);
00155         angleXYDegs = (angleXYRads / fixed::XPI) * fixed(180) - fixed(90);
00156         fixed distance2D = (direction[0] * direction[0] + 
00157                 direction[1] * direction[1]).sqrt();
00158 
00159         // Calculate power (very roughly)
00160         power = fixed(1000);
00161         if (distance2D < 200)
00162         {
00163                 power = 750;
00164                 if (distance2D < 100)
00165                 {
00166                         power = 550;
00167                         if (distance2D < 5)
00168                         {
00169                                 power = 350;
00170                         }
00171                 }
00172         }
00173 
00174         // Add some randomness to the power
00175         power += (random.getRandFixed() * 200) - 100;
00176         if (power < 100) power = 100;
00177 
00178         if (context.getOptionsTransient().getWindOn())
00179         {
00180                 // Make less adjustments for less wind
00181                 fixed windMag = context.getOptionsTransient().getWindSpeed() / 5;
00182 
00183                 // Try to account for the wind direction
00184                 FixedVector ndirection = direction;
00185                 ndirection[2] = 0;
00186                 ndirection = ndirection.Normalize();
00187                 ndirection = ndirection.get2DPerp();
00188                 fixed windoffsetLR = context.getOptionsTransient().getWindDirection().dotP(ndirection);
00189                 angleXYDegs += windoffsetLR * distance2D * (fixed(true, 1200) + random.getRandFixed()) * fixed(true, 400) * windMag;
00190 
00191                 fixed windoffsetFB = context.getOptionsTransient().getWindDirection().dotP(direction.Normalize());
00192                 windoffsetFB /= 10;
00193                 windoffsetFB *= windMag;
00194                 windoffsetFB += 1; // windowoffset FB 0.9 > 1.1
00195 
00196                 power *= windoffsetFB;
00197         }
00198 
00199         // Angle
00200         angleYZDegs = 45;
00201 }
00202 
00203 FixedVector &TankLib::getVelocityVector(fixed xy, fixed yz)
00204 {
00205         static FixedVector diff;
00206         diff = FixedVector(
00207                 (-xy / fixed(180) * fixed::XPI).sin() * (yz / fixed(180) * fixed::XPI).cos(),
00208                 (-xy / fixed(180) * fixed::XPI).cos() * (yz / fixed(180) * fixed::XPI).cos(),
00209                 ( yz / fixed(180) * fixed::XPI).sin()); 
00210         diff /= 20;
00211         diff *= fixed(true, 12000);
00212         return diff;
00213 }
00214 
00215 FixedVector &TankLib::getGunPosition(fixed xy, fixed yz)
00216 {
00217         static FixedVector pos;
00218         fixed gunLength = 1;
00219         fixed degToRad = fixed(180) * fixed::XPI;
00220         pos[0] = gunLength * (xy / degToRad).sin() * 
00221                 ((fixed(90) - yz) / degToRad).sin();
00222         pos[1] = gunLength * (xy / degToRad).cos() * 
00223                 ((fixed(90) - yz) / degToRad).sin();
00224         pos[2] = gunLength * ((fixed(90) - yz) / degToRad).cos();
00225 
00226         return pos;
00227 }
00228 

Generated on Mon Feb 16 15:14:51 2009 for Scorched3D by  doxygen 1.5.3