PlacementTankPosition.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 <placement/PlacementTankPosition.h>
00022 #include <landscapedef/LandscapeDefn.h>
00023 #include <landscapemap/LandscapeMaps.h>
00024 #include <landscapemap/DeformLandscape.h>
00025 #include <tank/TankContainer.h>
00026 #include <tank/TankPosition.h>
00027 #include <tank/TankState.h>
00028 #include <target/TargetLife.h>
00029 #include <target/TargetSpace.h>
00030 #include <target/TargetState.h>
00031 #include <image/ImageFactory.h>
00032 #include <common/Logger.h>
00033 
00034 void PlacementTankPosition::flattenTankPositions(
00035         ScorchedContext &context)
00036 {
00037         if (context.getServerMode())
00038         {
00039                 LandscapeDefinitionCache &definitions = 
00040                         context.getLandscapeMaps().getDefinitions();
00041 
00042                 RandomGenerator generator;
00043                 generator.seed(definitions.getSeed());
00044 
00045                 std::map<unsigned int, Tank *> &tanks = 
00046                         context.getTankContainer().getPlayingTanks();
00047                 std::map<unsigned int, Tank *>::iterator mainitor;
00048                 for (mainitor = tanks.begin();
00049                         mainitor != tanks.end();
00050                         mainitor++)
00051                 {
00052                         Tank *tank = (*mainitor).second;
00053 
00054                         if (!tank->getState().getSpectator() &&
00055                                 tank->getState().getState() == TankState::sNormal)
00056                         {
00057                                 FixedVector tankPos = PlacementTankPosition::placeTank(
00058                                         tank->getPlayerId(), tank->getTeam(), 
00059                                         context, generator);
00060 
00061                                 tank->getLife().setTargetPosition(tankPos);
00062                                 DeformLandscape::flattenArea(context, tankPos);
00063                         }
00064                 }
00065         }
00066 }
00067 
00068 static bool tankMaskCloseness(ScorchedContext &context, int team, 
00069         FixedVector &tankPos, Image *tankMask)
00070 {
00071         // Find the mask position
00072         int maskX = (tankPos[0] * fixed(tankMask->getWidth())).asInt() / 
00073                 context.getLandscapeMaps().getDefinitions().getDefn()->getLandscapeWidth();
00074         int maskY = (tankPos[1] * fixed(tankMask->getHeight())).asInt() / 
00075                 context.getLandscapeMaps().getDefinitions().getDefn()->getLandscapeHeight();
00076         unsigned char *maskPos = tankMask->getBits() +
00077                 maskX * 3 + maskY * tankMask->getWidth() * 3;
00078                 
00079         if (maskPos[0] == 0 && maskPos[1] == 0 && maskPos[2] == 0)
00080         {
00081                 // No tank is allowed on the black parts ot the mask
00082                 // regardless of the team
00083                 return false;
00084         }
00085         else if (maskPos[0] == 255 && maskPos[1] == 255 && maskPos[2] == 255)
00086         {
00087                 // All tanks are allowed on the white parts of the mask
00088                 // regardless of the team
00089                 return true;
00090         }
00091         else if (team > 0)
00092         {
00093                 // Check for team specific colors
00094                 switch(team)
00095                 {
00096                 case 1:
00097                         if (maskPos[0] != 255 || maskPos[1] != 0 || maskPos[2] != 0)
00098                         {
00099                                 return false;
00100                         }
00101                         break;
00102                 case 2:
00103                         if (maskPos[0] != 0 || maskPos[1] != 0 || maskPos[2] != 255)
00104                         {
00105                                 return false;
00106                         }
00107                         break;
00108                 case 3:
00109                         if (maskPos[0] != 0 || maskPos[1] != 255 || maskPos[2] != 0)
00110                         {
00111                                 return false;
00112                         }
00113                         break;
00114                 case 4:
00115                         if (maskPos[0] != 255 || maskPos[1] != 255 || maskPos[2] != 0)
00116                         {
00117                                 return false;
00118                         }
00119                         break;                                          
00120                 }
00121         }
00122         return true;
00123 }
00124 
00125 static bool tankTargetCloseness(ScorchedContext &context, unsigned int playerId, 
00126         FixedVector &tankPos, fixed tankCloseness)
00127 {
00128         // Make sure the tank is not too close to other targets
00129         std::map<unsigned int, Target *> targets;
00130         std::map<unsigned int, Target *>::iterator itor;
00131         context.getTargetSpace().getCollisionSet(tankPos, tankCloseness.asInt(), targets);
00132         for (itor = targets.begin();
00133                 itor != targets.end();
00134                 itor++)
00135         {
00136                 Target *thisTarget = (*itor).second;
00137                 if (!thisTarget->isTarget()) continue;
00138 
00139                 fixed closeness = MAX(tankCloseness/2, thisTarget->getBorder());
00140                 if ((tankPos - thisTarget->getLife().getTargetPosition()).Magnitude() < closeness) 
00141                 {
00142                         return false;
00143                 }
00144         }
00145 
00146         // Make sure the tank is not too close to other tanks
00147         std::map<unsigned int, Tank *> tanks = context.getTankContainer().getAllTanks();
00148         std::map<unsigned int, Tank *>::iterator tankItor;
00149         for (tankItor = tanks.begin();
00150                 tankItor != tanks.end();
00151                 tankItor++)
00152         {
00153                 Tank *thisTank = (*tankItor).second;
00154                 if (thisTank->getPlayerId() == playerId) continue;
00155 
00156                 if (!thisTank->getState().getSpectator() &&
00157                         ((thisTank->getState().getState() == TankState::sDead) ||
00158                         thisTank->getState().getState() == TankState::sNormal))
00159                 {
00160                         if ((tankPos - thisTank->getLife().getTargetPosition()).Magnitude() < tankCloseness) 
00161                         {
00162                                 return false;
00163                         }
00164                 }
00165         }
00166 
00167         return true;
00168 }
00169 
00170 FixedVector PlacementTankPosition::placeTank(unsigned int playerId, int team,
00171         ScorchedContext &context, RandomGenerator &generator)
00172 {
00173         FixedVector tankPos;
00174         const int tankBorder = 10;
00175 
00176         fixed minHeight = -1000;
00177         fixed maxHeight = 1000;
00178         fixed tankCloseness = 0;
00179         fixed flatness = 0;
00180         Image *tankMask = 0;
00181 
00182         LandscapeDefnType *defn =
00183                 context.getLandscapeMaps().getDefinitions().getDefn()->tankstart;
00184         if (defn->getType() == LandscapeDefnType::eStartHeight)
00185         {
00186                 LandscapeDefnStartHeight *height = 
00187                         (LandscapeDefnStartHeight *) defn;
00188                 minHeight = height->heightmin;
00189                 maxHeight = height->heightmax;
00190                 tankCloseness = height->startcloseness;
00191                 flatness = height->flatness;
00192                 if (!height->startmask.empty())
00193                 {
00194                         tankMask = ImageFactory::loadImage(
00195                                 S3D::getDataFile(height->startmask.c_str()));
00196                         DIALOG_ASSERT(tankMask->getBits());
00197                 }
00198         }
00199         else
00200         {
00201                 S3D::dialogExit("ServerNewGameState",
00202                         S3D::formatStringBuffer("Failed to find tank start type \"%i\"",
00203                         defn->getType()));
00204         }
00205     
00206         int arenaX = context.getLandscapeMaps().getGroundMaps().getArenaX();
00207         int arenaY = context.getLandscapeMaps().getGroundMaps().getArenaY();
00208         int arenaWidth = context.getLandscapeMaps().getGroundMaps().getArenaWidth();
00209         int arenaHeight = context.getLandscapeMaps().getGroundMaps().getArenaHeight();
00210 
00211         int maxIt = 100;
00212         int i;
00213         for (i=maxIt; i>0; i--)
00214         {
00215                 // Find a new position for the tank
00216                 fixed posX = fixed(arenaX) + (fixed(arenaWidth - tankBorder * 2) * 
00217                         generator.getRandFixed()) + fixed(tankBorder);
00218                 fixed posY = fixed(arenaY) + (fixed(arenaHeight - tankBorder * 2) * 
00219                         generator.getRandFixed()) + fixed(tankBorder);
00220                 fixed height = context.getLandscapeMaps().getGroundMaps().
00221                         getHeight(posX.asInt(), posY.asInt());
00222                 FixedVector normal = context.getLandscapeMaps().getGroundMaps().
00223                         getNormal(posX.asInt(), posY.asInt());
00224                 tankPos = FixedVector(posX, posY, height);
00225 
00226                 // Make sure not lower than water line
00227                 if (tankPos[2] < minHeight || tankPos[2] > maxHeight) continue;
00228 
00229                 // Make sure normal is less than given
00230                 if (normal[2] < flatness) continue;
00231 
00232                 // Make sure the mask allows the tank
00233                 if (tankMask && 
00234                         !tankMaskCloseness(context, team, tankPos, tankMask)) continue;
00235 
00236                 // Check tanks are not too close to others or targets
00237                 fixed closeness = (tankCloseness * fixed(i)) / fixed(maxIt);
00238                 if (!tankTargetCloseness(context, playerId, tankPos, closeness)) continue;
00239 
00240                 // Everything looks ok
00241                 break;
00242         }
00243         if (i == 0) Logger::log("Tank closeness exceeded");
00244 
00245         delete tankMask;
00246 
00247         // Get the height of the tank
00248         tankPos[2] = context.getLandscapeMaps().getGroundMaps().getInterpHeight(
00249                 tankPos[0], tankPos[1]);
00250 
00251         return tankPos;
00252 }

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