00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00082
00083 return false;
00084 }
00085 else if (maskPos[0] == 255 && maskPos[1] == 255 && maskPos[2] == 255)
00086 {
00087
00088
00089 return true;
00090 }
00091 else if (team > 0)
00092 {
00093
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
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
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
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
00227 if (tankPos[2] < minHeight || tankPos[2] > maxHeight) continue;
00228
00229
00230 if (normal[2] < flatness) continue;
00231
00232
00233 if (tankMask &&
00234 !tankMaskCloseness(context, team, tankPos, tankMask)) continue;
00235
00236
00237 fixed closeness = (tankCloseness * fixed(i)) / fixed(maxIt);
00238 if (!tankTargetCloseness(context, playerId, tankPos, closeness)) continue;
00239
00240
00241 break;
00242 }
00243 if (i == 0) Logger::log("Tank closeness exceeded");
00244
00245 delete tankMask;
00246
00247
00248 tankPos[2] = context.getLandscapeMaps().getGroundMaps().getInterpHeight(
00249 tankPos[0], tankPos[1]);
00250
00251 return tankPos;
00252 }