/* Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière for any question or comment contact us at or This program 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 3 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "Game.h" #include "GlobalContainer.h" #include "Map.h" #include "MapGenerationDescriptor.h" #include "Unit.h" #include "Utilities.h" #include "HeightMapGenerator.h" ///generates a map that is of one terrain type only void Map::makeHomogenMap(TerrainType terrainType) { for (int y=0; y=0)&&(d<40)&&(syncRand()&4)) { if (l<=(int)(syncRand()&3)) setTerrain(x, y, d+273); else { // we extand ressource: int dx, dy; Unit::dxdyfromDirection(syncRand()&7, &dx, &dy); int nx=x+dx; int ny=y+dy; if (getGroundUnit(nx, ny)==NOGUID) if (((r==WOOD||r==CORN||r==STONE)&&isGrass(nx, ny))||((r==ALGA)&&isWater(nx, ny))) setTerrain(nx, ny, 272+(r*10)+((syncRand()&1)*5)); } } } } void simulateRandomMap(int smooth, double baseWater, double baseSand, double baseGrass, double *finalWater, double *finalSand, double *finalGrass) { int w=32<<(smooth>>2); int h=w; int s=w*h; int m=s-1; VARARRAY(int,undermap,w*h); int totalRatio=0x7FFF; int waterRatio=(int)(baseWater*((double)totalRatio)); int sandRatio =(int)(baseSand *((double)totalRatio)); int grassRatio=(int)(baseGrass*((double)totalRatio)); totalRatio=waterRatio+sandRatio+grassRatio; /// First, we create a fully random patchwork: for (int y=0; yfinalWaters[j]) ws++; else we++; if (sffinalSands[j]) ss++; else se++; if (gffinalGrasss[j]) gs++; else ge++; } if (abs(wb-ws)0) allowed[0]=(Uint32)(pow(errWaterRatioCount, 0.125)*4294967296.0); else allowed[0]=0; if (errSandRatioCount>0) allowed[1]=(Uint32)(pow(errSandRatioCount , 0.125)*4294967296.0); else allowed[1]=0; if (errGrassRatioCount>0) allowed[2]=(Uint32)(pow(errGrassRatioCount, 0.125)*4294967296.0); else allowed[2]=0; assert(allowed[0]<=(Uint32)0xFFFFFFFF); assert(allowed[1]<=(Uint32)0xFFFFFFFF); assert(allowed[2]<=(Uint32)0xFFFFFFFF); if (i==0) { allowed[0]=0; allowed[1]=0; allowed[2]=0; } for (int y=0; y0); int* bootX=descriptor.bootX; int* bootY=descriptor.bootY; //TODO: First pass to find the number of available places. for (int team=0; team7) { int centerx=((x+startx)>>1); int top, bot; for (top=0; top0); int centery=y+((bot-top)>>1); bool farEnough=true; for (int ti=0; timaxSurface && farEnough) { maxSurface=surface; maxX=centerx; maxY=centery; } } width=0; startx=x; } } } if (maxSurface<=0) return false; assert(maxSurface); bootX[team]=maxX; bootY[team]=maxY; for (int dx=-1; dx<6; dx++) for (int dy=0; dy<6; dy++) setUMTerrain(maxX+dx, maxY+dy, GRASS); } // Let's add some green space for teams: int squareSize=5+(int)(sqrt((double)minDistSquare)/4.5); if (verbose) printf("squareSize=%d.\n", squareSize); for (int team=0; teamh/(pow(2,hPower2Divider))) wPower2Divider++; else hPower2Divider++; unsigned int wHeightMap=(unsigned int)(w/(pow(2,wPower2Divider))); unsigned int hHeightMap=(unsigned int)(h/(pow(2,hPower2Divider))); /// lets generate a patch of perlin noise. That's a smooth mapping R^2 to ]0;1[ HeightMap hm(wHeightMap,hHeightMap); /// 1 to avoid division by zero, unsigned int tmpTotal=1+descriptor.waterRatio+descriptor.grassRatio; switch (descriptor.methode) { case MapGenerationDescriptor::eSWAMP: hm.makeSwamp(smoothingFactor); waterTiles=(unsigned int)((float)descriptor.waterRatio*wHeightMap*hHeightMap/(float)tmpTotal); sandTiles=0; grassTiles=wHeightMap*hHeightMap-waterTiles; break; case MapGenerationDescriptor::eRIVER: hm.makeRiver(descriptor.riverDiameter*(wHeightMap+hHeightMap)/2/100,smoothingFactor); waterTiles=(unsigned int)((float)descriptor.waterRatio/(float)totalGSWFromUI*wHeightMap*hHeightMap); sandTiles=(unsigned int)((float)descriptor.sandRatio/(float)totalGSWFromUI*wHeightMap*hHeightMap); grassTiles =(unsigned int)((float)descriptor.grassRatio /(float)totalGSWFromUI*wHeightMap*hHeightMap); break; case MapGenerationDescriptor::eCRATERLAKES: hm.makeCraters(wHeightMap*hHeightMap*descriptor.craterDensity/30000, 30, smoothingFactor); waterTiles=(unsigned int)((float)descriptor.waterRatio/(float)totalGSWFromUI*wHeightMap*hHeightMap); sandTiles=(unsigned int)((float)descriptor.sandRatio/(float)totalGSWFromUI*wHeightMap*hHeightMap); grassTiles =(unsigned int)((float)descriptor.grassRatio /(float)totalGSWFromUI*wHeightMap*hHeightMap); break; case MapGenerationDescriptor::eISLANDS: hm.makeIslands(descriptor.nbTeams+descriptor.extraIslands, smoothingFactor); waterTiles=(unsigned int)((float)descriptor.waterRatio/(float)totalGSWFromUI*wHeightMap*hHeightMap); sandTiles=(unsigned int)((float)descriptor.sandRatio/(float)totalGSWFromUI*wHeightMap*hHeightMap); grassTiles =(unsigned int)((float)descriptor.grassRatio /(float)totalGSWFromUI*wHeightMap*hHeightMap); break; default: assert(false); break; } /// wheat/wood needs ground to stand on and water. So: wheatWoodTiles=waterTiles= algaeTiles) algaeLevel = (float)(i-1)/2048.0; if (accumulatedHistogram >= waterTiles) waterLevel = (float)(i-1)/2048.0; } while ((sandLevel==0) && (i<2048)) { accumulatedHistogram+=histogram[i++]; if (accumulatedHistogram >= waterTiles+sandTiles) sandLevel = (float)(i-1)/2048.0; } while ((grassLevel==0) && (i<2048)) { accumulatedHistogram+=histogram[i++]; if (wheatWoodLevel==0 && accumulatedHistogram >= waterTiles+sandTiles+wheatWoodTiles) wheatWoodLevel = (float)(i-1)/2048.0; if (stoneLevel==0 && accumulatedHistogram >= waterTiles+sandTiles+(wheatWoodTiles / 3)) stoneLevel = (float)(i-1)/2048.0; if (accumulatedHistogram >= waterTiles+sandTiles+grassTiles) grassLevel = (float)(i-1)/2048.0; } for (unsigned y=0; y0); int* bootX=descriptor.bootX; int* bootY=descriptor.bootY; //TODO: First pass to find the number of available places. for (int team=0; team7) { int centerx=((x+startx)>>1); int top, bot; for (top=0; top0); int centery=y+((bot-top)>>1); bool farEnough=true; for (int ti=0; timaxSurface && farEnough) { maxSurface=surface; maxX=centerx; maxY=centery; } } width=0; startx=x; } } } if (maxSurface<=0) { std::cout << "debugoutput 2\n"; return false; } assert(maxSurface); bootX[team]=maxX; bootY[team]=maxY; } controlSand(); regenerateMap(0, 0, w, h); //now to add primary resources for current map generator for (unsigned y=0; y 0) { for (int q1=0; q13) break; else width=1; if (dist*distWeight[resi]+width*widthWeight[resi]>maxDist*distWeight[resi]+maxWidth*widthWeight[resi]) { maxWidth=width; maxDist=dist; maxDir=dir; } } dirUsed[maxDir]=true; if (maxWidth>1); dx*=d; dy*=d; int amount=descriptor.ressource[ress]; if (amount>0) setRessource(bootX[team]+dx, bootY[team]+dy, ress, amount); } if (smallestWidth3) break; else width=1; if (dist+width>maxDist+maxWidth) { maxWidth=width; maxDist=dist; maxDir=dir; } } dirUsed[maxDir]=true; int dx, dy; Unit::dxdyfromDirection(maxDir, &dx, &dy); int d=maxDist-(maxWidth>>1); dx*=d; dy*=d; int amount=descriptor.ressource[smallestRessource]; if (amount>0) setRessource(bootX[team]+dx, bootY[team]+dy, smallestRessource, amount); } int maxDir=0; int maxWidth=0; int maxDist=0; for (int dir=0; dir<8; dir++) { int width=0; int dx, dy, dist; Unit::dxdyfromDirection(dir, &dx, &dy); for (dist=0; dist<2*limiteDist; dist++) if (isWater(bootX[team]+dx*dist, bootY[team]+dy*dist)) width++; else if (width>3) break; else width=1; if (dist+width>width+maxWidth) { maxWidth=width; maxDist=dist; maxDir=dir; } } int dx, dy; Unit::dxdyfromDirection(maxDir, &dx, &dy); int d=maxDist-(maxWidth>>1); dx*=d; dy*=d; int amount=descriptor.ressource[ALGA]; if (amount>0) setRessource(bootX[team]+dx, bootY[team]+dy, ALGA, amount); } // Let's smooth ressources... int maxAmount=0; for (int r=0; r<4; r++) if (maxAmount65536) { minDistSquare=minDistSquare>>1; //I think that you need to do this only once, in worst case. //With a few luck you doesn't need to. c=0; } } else { bootX[i]=x; bootY[i]=y; for (int dx=-1; dx<6; dx++) for (int dy=0; dy<6; dy++) setUMTerrain(x+dx, y+dy, GRASS); } } // Three, expands islands for (int s=0; s0) setRessource(bootX[s], bootY[s]-p, WOOD, amount); smallestAmount=amount; smallestRessource=WOOD; //WHEAT for (d=0; d0) setRessource(bootX[s]-p, bootY[s], CORN, amount); if (amount0) setRessource(bootX[s]+p, bootY[s]+p, smallestRessource, amount); //ALGAE for (d=0; d<2*islandsSize; d++) if (isWater(bootX[s]+d, bootY[s])) break; amount=descriptor.ressource[ALGA]; amount=smoothRessources; p=d+smoothRessources-1+amount/2; if (amount>0) setRessource(bootX[s]+p, bootY[s], ALGA, amount); } // Let's smooth ressources... this->smoothRessources(smoothRessources*2); } bool Game::oldMakeIslandsMap(MapGenerationDescriptor &descriptor) { for (int s=0; sbuildingsTypes.getTypeNum("swarm", 0, false); if (!checkRoomForBuilding(descriptor.bootX[s], descriptor.bootY[s], globalContainer->buildingsTypes.get(typeNum), -1, false)) { if (verbose) printf("Failed to add swarm of team %d\n", s); return false; } teams[s]->startPosX=descriptor.bootX[s]; teams[s]->startPosY=descriptor.bootY[s]; Building *b=addBuilding(descriptor.bootX[s], descriptor.bootY[s], typeNum, s); assert(b); for (int i=0; icreateLists(); } map.smoothRessources(descriptor.oldIslandSize/10); return true; } bool Game::makeRandomMap(MapGenerationDescriptor &descriptor) { for (int s=0; sbuildingsTypes.getTypeNum("swarm", 0, false); if (!checkRoomForBuilding(descriptor.bootX[s], descriptor.bootY[s], globalContainer->buildingsTypes.get(typeNum), -1, false)) { if (verbose) printf("Failed to add swarm of team %d\n", s); return false; } teams[s]->startPosX=descriptor.bootX[s]; teams[s]->startPosY=descriptor.bootY[s]; Building *b=addBuilding(descriptor.bootX[s], descriptor.bootY[s], typeNum, s); assert(b); for (int i=0; icreateLists(); } return true; } bool Game::generateMap(MapGenerationDescriptor &descriptor) { if (verbose) printf("Generating map, please wait ....\n"); descriptor.synchronizeNow(); map.setSize(descriptor.wDec, descriptor.hDec); map.setGame(this); switch (descriptor.methode) { case MapGenerationDescriptor::eUNIFORM: map.makeHomogenMap(descriptor.terrainType); addTeam(); break; case MapGenerationDescriptor::eSWAMP: case MapGenerationDescriptor::eISLANDS: case MapGenerationDescriptor::eRIVER: case MapGenerationDescriptor::eCRATERLAKES: if (!map.makeRandomMap(descriptor)) return false; if (!makeRandomMap(descriptor)) return false; break; case MapGenerationDescriptor::eOLDRANDOM: if (!map.oldMakeRandomMap(descriptor)) return false; if (!makeRandomMap(descriptor)) return false; break; case MapGenerationDescriptor::eOLDISLANDS: if (!map.oldMakeIslandsMap(descriptor)) return false; if (!oldMakeIslandsMap(descriptor)) return false; break; default: assert(false); } // compile script script.compileScript(this); if (verbose) printf(".... map generated.\n"); return true; }